merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
@@ -235,8 +235,8 @@ if (!isDevtools) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const gInterestingCategories = new Set([
|
const gInterestingCategories = new Set([
|
||||||
"agent-style-sheets", "addon-provider-module", "webextension-scripts",
|
"agent-style-sheets", "addon-provider-module", "webextension-modules",
|
||||||
"webextension-schemas", "webextension-scripts-addon",
|
"webextension-scripts", "webextension-schemas", "webextension-scripts-addon",
|
||||||
"webextension-scripts-content", "webextension-scripts-devtools"
|
"webextension-scripts-content", "webextension-scripts-devtools"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -503,13 +503,13 @@ add_task(async function checkAllTheFiles() {
|
|||||||
findChromeUrlsFromArray(uint16, "chrome://");
|
findChromeUrlsFromArray(uint16, "chrome://");
|
||||||
findChromeUrlsFromArray(uint16, "resource://");
|
findChromeUrlsFromArray(uint16, "resource://");
|
||||||
|
|
||||||
const kCodeExtensions = [".xul", ".xml", ".xsl", ".js", ".jsm", ".html", ".xhtml"];
|
const kCodeExtensions = [".xul", ".xml", ".xsl", ".js", ".jsm", ".json", ".html", ".xhtml"];
|
||||||
|
|
||||||
let appDir = Services.dirsvc.get("GreD", Ci.nsIFile);
|
let appDir = Services.dirsvc.get("GreD", Ci.nsIFile);
|
||||||
// This asynchronously produces a list of URLs (sadly, mostly sync on our
|
// This asynchronously produces a list of URLs (sadly, mostly sync on our
|
||||||
// test infrastructure because it runs against jarfiles there, and
|
// test infrastructure because it runs against jarfiles there, and
|
||||||
// our zipreader APIs are all sync)
|
// our zipreader APIs are all sync)
|
||||||
let uris = await generateURIsFromDirTree(appDir, [".css", ".manifest", ".json", ".jpg", ".png", ".gif", ".svg", ".dtd", ".properties"].concat(kCodeExtensions));
|
let uris = await generateURIsFromDirTree(appDir, [".css", ".manifest", ".jpg", ".png", ".gif", ".svg", ".dtd", ".properties"].concat(kCodeExtensions));
|
||||||
|
|
||||||
// Parse and remove all manifests from the list.
|
// Parse and remove all manifests from the list.
|
||||||
// NOTE that this must be done before filtering out devtools paths
|
// NOTE that this must be done before filtering out devtools paths
|
||||||
|
|||||||
@@ -1446,6 +1446,9 @@ var CustomizableUIInternal = {
|
|||||||
name = aWidget.id + "." + aProp;
|
name = aWidget.id + "." + aProp;
|
||||||
def = aDef || "";
|
def = aDef || "";
|
||||||
}
|
}
|
||||||
|
if (aWidget.localized === false) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (Array.isArray(aFormatArgs) && aFormatArgs.length) {
|
if (Array.isArray(aFormatArgs) && aFormatArgs.length) {
|
||||||
return gWidgetsBundle.formatStringFromName(name, aFormatArgs,
|
return gWidgetsBundle.formatStringFromName(name, aFormatArgs,
|
||||||
@@ -2318,6 +2321,7 @@ var CustomizableUIInternal = {
|
|||||||
source: aSource || CustomizableUI.SOURCE_EXTERNAL,
|
source: aSource || CustomizableUI.SOURCE_EXTERNAL,
|
||||||
instances: new Map(),
|
instances: new Map(),
|
||||||
currentArea: null,
|
currentArea: null,
|
||||||
|
localized: true,
|
||||||
removable: true,
|
removable: true,
|
||||||
overflows: true,
|
overflows: true,
|
||||||
defaultArea: null,
|
defaultArea: null,
|
||||||
@@ -2353,7 +2357,8 @@ var CustomizableUIInternal = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const kOptBoolProps = ["removable", "showInPrivateBrowsing", "overflows", "tabSpecific"];
|
const kOptBoolProps = ["removable", "showInPrivateBrowsing", "overflows", "tabSpecific",
|
||||||
|
"localized"];
|
||||||
for (let prop of kOptBoolProps) {
|
for (let prop of kOptBoolProps) {
|
||||||
if (typeof aData[prop] == "boolean") {
|
if (typeof aData[prop] == "boolean") {
|
||||||
widget[prop] = aData[prop];
|
widget[prop] = aData[prop];
|
||||||
@@ -3296,6 +3301,9 @@ this.CustomizableUI = {
|
|||||||
* invoked when a user hides your view.
|
* invoked when a user hides your view.
|
||||||
* - tooltiptext: string to use for the tooltip of the widget
|
* - tooltiptext: string to use for the tooltip of the widget
|
||||||
* - label: string to use for the label of the widget
|
* - label: string to use for the label of the widget
|
||||||
|
* - localized: If true, or undefined, attempt to retrieve the
|
||||||
|
* widget's string properties from the customizable
|
||||||
|
* widgets string bundle.
|
||||||
* - removable: whether the widget is removable (optional, default: true)
|
* - removable: whether the widget is removable (optional, default: true)
|
||||||
* NB: if you specify false here, you must provide a
|
* NB: if you specify false here, you must provide a
|
||||||
* defaultArea, too.
|
* defaultArea, too.
|
||||||
|
|||||||
@@ -80,12 +80,16 @@ const convertBookmarks = result => {
|
|||||||
return node;
|
return node;
|
||||||
};
|
};
|
||||||
|
|
||||||
let observer = {
|
let observer = new class extends EventEmitter {
|
||||||
skipTags: true,
|
constructor() {
|
||||||
skipDescendantsOnItemRemoval: true,
|
super();
|
||||||
|
|
||||||
onBeginUpdateBatch() {},
|
this.skipTags = true;
|
||||||
onEndUpdateBatch() {},
|
this.skipDescendantsOnItemRemoval = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeginUpdateBatch() {}
|
||||||
|
onEndUpdateBatch() {}
|
||||||
|
|
||||||
onItemAdded(id, parentId, index, itemType, uri, title, dateAdded, guid, parentGuid, source) {
|
onItemAdded(id, parentId, index, itemType, uri, title, dateAdded, guid, parentGuid, source) {
|
||||||
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
|
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
|
||||||
@@ -107,9 +111,9 @@ let observer = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.emit("created", bookmark);
|
this.emit("created", bookmark);
|
||||||
},
|
}
|
||||||
|
|
||||||
onItemVisited() {},
|
onItemVisited() {}
|
||||||
|
|
||||||
onItemMoved(id, oldParentId, oldIndex, newParentId, newIndex, itemType, guid, oldParentGuid, newParentGuid, source) {
|
onItemMoved(id, oldParentId, oldIndex, newParentId, newIndex, itemType, guid, oldParentGuid, newParentGuid, source) {
|
||||||
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
|
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
|
||||||
@@ -123,7 +127,7 @@ let observer = {
|
|||||||
oldIndex,
|
oldIndex,
|
||||||
};
|
};
|
||||||
this.emit("moved", {guid, info});
|
this.emit("moved", {guid, info});
|
||||||
},
|
}
|
||||||
|
|
||||||
onItemRemoved(id, parentId, index, itemType, uri, guid, parentGuid, source) {
|
onItemRemoved(id, parentId, index, itemType, uri, guid, parentGuid, source) {
|
||||||
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
|
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
|
||||||
@@ -141,7 +145,7 @@ let observer = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.emit("removed", {guid, info: {parentId: parentGuid, index, node}});
|
this.emit("removed", {guid, info: {parentId: parentGuid, index, node}});
|
||||||
},
|
}
|
||||||
|
|
||||||
onItemChanged(id, prop, isAnno, val, lastMod, itemType, parentId, guid, parentGuid, oldVal, source) {
|
onItemChanged(id, prop, isAnno, val, lastMod, itemType, parentId, guid, parentGuid, oldVal, source) {
|
||||||
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
|
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
|
||||||
@@ -159,9 +163,8 @@ let observer = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.emit("changed", {guid, info});
|
this.emit("changed", {guid, info});
|
||||||
},
|
}
|
||||||
};
|
}();
|
||||||
EventEmitter.decorate(observer);
|
|
||||||
|
|
||||||
const decrementListeners = () => {
|
const decrementListeners = () => {
|
||||||
listenerCount -= 1;
|
listenerCount -= 1;
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
|
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||||
|
/* vim: set sts=2 sw=2 et tw=80: */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// This file provides some useful code for the |tabs| and |windows|
|
||||||
/* import-globals-from ext-utils.js */
|
// modules. All of the code is installed on |global|, which is a scope
|
||||||
|
// shared among the different ext-*.js scripts.
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(global, "EventEmitter",
|
/* global EventEmitter:false, TabContext:false, WindowEventManager:false,
|
||||||
"resource://gre/modules/EventEmitter.jsm");
|
makeWidgetId:false, tabTracker:true, windowTracker:true */
|
||||||
|
/* import-globals-from ../../../toolkit/components/extensions/ext-toolkit.js */
|
||||||
|
|
||||||
|
/* globals TabBase, WindowBase, TabTrackerBase, WindowTrackerBase, TabManagerBase, WindowManagerBase */
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||||
|
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||||
|
|
||||||
|
var {
|
||||||
|
ExtensionError,
|
||||||
|
defineLazyGetter,
|
||||||
|
} = ExtensionUtils;
|
||||||
|
|
||||||
|
let tabTracker;
|
||||||
|
let windowTracker;
|
||||||
|
|
||||||
// This function is pretty tightly tied to Extension.jsm.
|
// This function is pretty tightly tied to Extension.jsm.
|
||||||
// Its job is to fill in the |tab| property of the sender.
|
// Its job is to fill in the |tab| property of the sender.
|
||||||
@@ -76,164 +93,796 @@ global.openOptionsPage = (extension) => {
|
|||||||
return window.BrowserOpenAddonsMgr(viewId);
|
return window.BrowserOpenAddonsMgr(viewId);
|
||||||
};
|
};
|
||||||
|
|
||||||
extensions.registerModules({
|
global.makeWidgetId = id => {
|
||||||
bookmarks: {
|
id = id.toLowerCase();
|
||||||
url: "chrome://browser/content/ext-bookmarks.js",
|
// FIXME: This allows for collisions.
|
||||||
schema: "chrome://browser/content/schemas/bookmarks.json",
|
return id.replace(/[^a-z0-9_-]/g, "_");
|
||||||
scopes: ["addon_parent"],
|
};
|
||||||
paths: [
|
|
||||||
["bookmarks"],
|
// Manages tab-specific context data, and dispatching tab select events
|
||||||
],
|
// across all windows.
|
||||||
},
|
global.TabContext = class extends EventEmitter {
|
||||||
browserAction: {
|
constructor(getDefaults, extension) {
|
||||||
url: "chrome://browser/content/ext-browserAction.js",
|
super();
|
||||||
schema: "chrome://browser/content/schemas/browser_action.json",
|
|
||||||
scopes: ["addon_parent"],
|
this.extension = extension;
|
||||||
manifest: ["browser_action"],
|
this.getDefaults = getDefaults;
|
||||||
paths: [
|
|
||||||
["browserAction"],
|
this.tabData = new WeakMap();
|
||||||
],
|
this.lastLocation = new WeakMap();
|
||||||
},
|
|
||||||
browsingData: {
|
windowTracker.addListener("progress", this);
|
||||||
url: "chrome://browser/content/ext-browsingData.js",
|
windowTracker.addListener("TabSelect", this);
|
||||||
schema: "chrome://browser/content/schemas/browsing_data.json",
|
}
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
get(nativeTab) {
|
||||||
["browsingData"],
|
if (!this.tabData.has(nativeTab)) {
|
||||||
],
|
this.tabData.set(nativeTab, this.getDefaults(nativeTab));
|
||||||
},
|
}
|
||||||
chrome_settings_overrides: {
|
|
||||||
url: "chrome://browser/content/ext-chrome-settings-overrides.js",
|
return this.tabData.get(nativeTab);
|
||||||
scopes: [],
|
}
|
||||||
schema: "chrome://browser/content/schemas/chrome_settings_overrides.json",
|
|
||||||
manifest: ["chrome_settings_overrides"],
|
clear(nativeTab) {
|
||||||
},
|
this.tabData.delete(nativeTab);
|
||||||
commands: {
|
}
|
||||||
url: "chrome://browser/content/ext-commands.js",
|
|
||||||
schema: "chrome://browser/content/schemas/commands.json",
|
handleEvent(event) {
|
||||||
scopes: ["addon_parent"],
|
if (event.type == "TabSelect") {
|
||||||
manifest: ["commands"],
|
let nativeTab = event.target;
|
||||||
paths: [
|
this.emit("tab-select", nativeTab);
|
||||||
["commands"],
|
this.emit("location-change", nativeTab);
|
||||||
],
|
}
|
||||||
},
|
}
|
||||||
devtools: {
|
|
||||||
url: "chrome://browser/content/ext-devtools.js",
|
onStateChange(browser, webProgress, request, stateFlags, statusCode) {
|
||||||
schema: "chrome://browser/content/schemas/devtools.json",
|
let flags = Ci.nsIWebProgressListener;
|
||||||
scopes: ["devtools_parent"],
|
|
||||||
manifest: ["devtools_page"],
|
if (!(~stateFlags & (flags.STATE_IS_WINDOW | flags.STATE_START) ||
|
||||||
paths: [
|
this.lastLocation.has(browser))) {
|
||||||
["devtools"],
|
this.lastLocation.set(browser, request.URI);
|
||||||
],
|
}
|
||||||
},
|
}
|
||||||
devtools_inspectedWindow: {
|
|
||||||
url: "chrome://browser/content/ext-devtools-inspectedWindow.js",
|
onLocationChange(browser, webProgress, request, locationURI, flags) {
|
||||||
schema: "chrome://browser/content/schemas/devtools_inspected_window.json",
|
let gBrowser = browser.ownerGlobal.gBrowser;
|
||||||
scopes: ["devtools_parent"],
|
let lastLocation = this.lastLocation.get(browser);
|
||||||
paths: [
|
if (browser === gBrowser.selectedBrowser &&
|
||||||
["devtools", "inspectedWindow"],
|
!(lastLocation && lastLocation.equalsExceptRef(browser.currentURI))) {
|
||||||
],
|
let nativeTab = gBrowser.getTabForBrowser(browser);
|
||||||
},
|
this.emit("location-change", nativeTab, true);
|
||||||
devtools_network: {
|
}
|
||||||
url: "chrome://browser/content/ext-devtools-network.js",
|
this.lastLocation.set(browser, browser.currentURI);
|
||||||
schema: "chrome://browser/content/schemas/devtools_network.json",
|
}
|
||||||
scopes: ["devtools_parent"],
|
|
||||||
paths: [
|
shutdown() {
|
||||||
["devtools", "network"],
|
windowTracker.removeListener("progress", this);
|
||||||
],
|
windowTracker.removeListener("TabSelect", this);
|
||||||
},
|
}
|
||||||
devtools_panels: {
|
};
|
||||||
url: "chrome://browser/content/ext-devtools-panels.js",
|
|
||||||
schema: "chrome://browser/content/schemas/devtools_panels.json",
|
|
||||||
scopes: ["devtools_parent"],
|
class WindowTracker extends WindowTrackerBase {
|
||||||
paths: [
|
addProgressListener(window, listener) {
|
||||||
["devtools", "panels"],
|
window.gBrowser.addTabsProgressListener(listener);
|
||||||
],
|
}
|
||||||
},
|
|
||||||
history: {
|
removeProgressListener(window, listener) {
|
||||||
url: "chrome://browser/content/ext-history.js",
|
window.gBrowser.removeTabsProgressListener(listener);
|
||||||
schema: "chrome://browser/content/schemas/history.json",
|
}
|
||||||
scopes: ["addon_parent"],
|
}
|
||||||
paths: [
|
|
||||||
["history"],
|
/**
|
||||||
],
|
* An event manager API provider which listens for a DOM event in any browser
|
||||||
},
|
* window, and calls the given listener function whenever an event is received.
|
||||||
// This module supports the "menus" and "contextMenus" namespaces,
|
* That listener function receives a `fire` object, which it can use to dispatch
|
||||||
// and because of permissions, the module name must differ from both.
|
* events to the extension, and a DOM event object.
|
||||||
menusInternal: {
|
*
|
||||||
url: "chrome://browser/content/ext-menus.js",
|
* @param {BaseContext} context
|
||||||
schema: "chrome://browser/content/schemas/menus.json",
|
* The extension context which the event manager belongs to.
|
||||||
scopes: ["addon_parent"],
|
* @param {string} name
|
||||||
paths: [
|
* The API name of the event manager, e.g.,"runtime.onMessage".
|
||||||
["menusInternal"],
|
* @param {string} event
|
||||||
],
|
* The name of the DOM event to listen for.
|
||||||
},
|
* @param {function} listener
|
||||||
omnibox: {
|
* The listener function to call when a DOM event is received.
|
||||||
url: "chrome://browser/content/ext-omnibox.js",
|
*/
|
||||||
schema: "chrome://browser/content/schemas/omnibox.json",
|
global.WindowEventManager = class extends EventManager {
|
||||||
scopes: ["addon_parent"],
|
constructor(context, name, event, listener) {
|
||||||
manifest: ["omnibox"],
|
super(context, name, fire => {
|
||||||
paths: [
|
let listener2 = listener.bind(null, fire);
|
||||||
["omnibox"],
|
|
||||||
],
|
windowTracker.addListener(event, listener2);
|
||||||
},
|
return () => {
|
||||||
pageAction: {
|
windowTracker.removeListener(event, listener2);
|
||||||
url: "chrome://browser/content/ext-pageAction.js",
|
};
|
||||||
schema: "chrome://browser/content/schemas/page_action.json",
|
});
|
||||||
scopes: ["addon_parent"],
|
}
|
||||||
manifest: ["page_action"],
|
};
|
||||||
paths: [
|
|
||||||
["pageAction"],
|
class TabTracker extends TabTrackerBase {
|
||||||
],
|
constructor() {
|
||||||
},
|
super();
|
||||||
geckoProfiler: {
|
|
||||||
url: "chrome://browser/content/ext-geckoProfiler.js",
|
this._tabs = new WeakMap();
|
||||||
schema: "chrome://browser/content/schemas/geckoProfiler.json",
|
this._tabIds = new Map();
|
||||||
scopes: ["addon_parent"],
|
this._nextId = 1;
|
||||||
paths: [
|
|
||||||
["geckoProfiler"],
|
this._handleTabDestroyed = this._handleTabDestroyed.bind(this);
|
||||||
],
|
}
|
||||||
},
|
|
||||||
sessions: {
|
init() {
|
||||||
url: "chrome://browser/content/ext-sessions.js",
|
if (this.initialized) {
|
||||||
schema: "chrome://browser/content/schemas/sessions.json",
|
return;
|
||||||
scopes: ["addon_parent"],
|
}
|
||||||
paths: [
|
this.initialized = true;
|
||||||
["sessions"],
|
|
||||||
],
|
this.adoptedTabs = new WeakMap();
|
||||||
},
|
|
||||||
sidebarAction: {
|
this._handleWindowOpen = this._handleWindowOpen.bind(this);
|
||||||
url: "chrome://browser/content/ext-sidebarAction.js",
|
this._handleWindowClose = this._handleWindowClose.bind(this);
|
||||||
schema: "chrome://browser/content/schemas/sidebar_action.json",
|
|
||||||
scopes: ["addon_parent"],
|
windowTracker.addListener("TabClose", this);
|
||||||
manifest: ["sidebar_action"],
|
windowTracker.addListener("TabOpen", this);
|
||||||
paths: [
|
windowTracker.addListener("TabSelect", this);
|
||||||
["sidebarAction"],
|
windowTracker.addOpenListener(this._handleWindowOpen);
|
||||||
],
|
windowTracker.addCloseListener(this._handleWindowClose);
|
||||||
},
|
|
||||||
tabs: {
|
/* eslint-disable mozilla/balanced-listeners */
|
||||||
url: "chrome://browser/content/ext-tabs.js",
|
this.on("tab-detached", this._handleTabDestroyed);
|
||||||
schema: "chrome://browser/content/schemas/tabs.json",
|
this.on("tab-removed", this._handleTabDestroyed);
|
||||||
scopes: ["addon_parent"],
|
/* eslint-enable mozilla/balanced-listeners */
|
||||||
paths: [
|
}
|
||||||
["tabs"],
|
|
||||||
],
|
getId(nativeTab) {
|
||||||
},
|
if (this._tabs.has(nativeTab)) {
|
||||||
urlOverrides: {
|
return this._tabs.get(nativeTab);
|
||||||
url: "chrome://browser/content/ext-url-overrides.js",
|
}
|
||||||
schema: "chrome://browser/content/schemas/url_overrides.json",
|
|
||||||
scopes: ["addon_parent"],
|
this.init();
|
||||||
manifest: ["chrome_url_overrides"],
|
|
||||||
paths: [
|
let id = this._nextId++;
|
||||||
["urlOverrides"],
|
this.setId(nativeTab, id);
|
||||||
],
|
return id;
|
||||||
},
|
}
|
||||||
windows: {
|
|
||||||
url: "chrome://browser/content/ext-windows.js",
|
setId(nativeTab, id) {
|
||||||
schema: "chrome://browser/content/schemas/windows.json",
|
this._tabs.set(nativeTab, id);
|
||||||
scopes: ["addon_parent"],
|
this._tabIds.set(id, nativeTab);
|
||||||
paths: [
|
}
|
||||||
["windows"],
|
|
||||||
],
|
_handleTabDestroyed(event, {nativeTab}) {
|
||||||
},
|
let id = this._tabs.get(nativeTab);
|
||||||
|
if (id) {
|
||||||
|
this._tabs.delete(nativeTab);
|
||||||
|
if (this._tabIds.get(id) === nativeTab) {
|
||||||
|
this._tabIds.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the XUL <tab> element associated with the given tab ID. If no tab
|
||||||
|
* with the given ID exists, and no default value is provided, an error is
|
||||||
|
* raised, belonging to the scope of the given context.
|
||||||
|
*
|
||||||
|
* @param {integer} tabId
|
||||||
|
* The ID of the tab to retrieve.
|
||||||
|
* @param {*} default_
|
||||||
|
* The value to return if no tab exists with the given ID.
|
||||||
|
* @returns {Element<tab>}
|
||||||
|
* A XUL <tab> element.
|
||||||
|
*/
|
||||||
|
getTab(tabId, default_ = undefined) {
|
||||||
|
let nativeTab = this._tabIds.get(tabId);
|
||||||
|
if (nativeTab) {
|
||||||
|
return nativeTab;
|
||||||
|
}
|
||||||
|
if (default_ !== undefined) {
|
||||||
|
return default_;
|
||||||
|
}
|
||||||
|
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Event} event
|
||||||
|
* The DOM Event to handle.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
handleEvent(event) {
|
||||||
|
let nativeTab = event.target;
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
case "TabOpen":
|
||||||
|
let {adoptedTab} = event.detail;
|
||||||
|
if (adoptedTab) {
|
||||||
|
this.adoptedTabs.set(adoptedTab, event.target);
|
||||||
|
|
||||||
|
// This tab is being created to adopt a tab from a different window.
|
||||||
|
// Copy the ID from the old tab to the new.
|
||||||
|
this.setId(nativeTab, this.getId(adoptedTab));
|
||||||
|
|
||||||
|
adoptedTab.linkedBrowser.messageManager.sendAsyncMessage("Extension:SetFrameData", {
|
||||||
|
windowId: windowTracker.getId(nativeTab.ownerGlobal),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the current tab, since the newly-created tab will likely be
|
||||||
|
// active by the time the promise below resolves and the event is
|
||||||
|
// dispatched.
|
||||||
|
let currentTab = nativeTab.ownerGlobal.gBrowser.selectedTab;
|
||||||
|
|
||||||
|
// We need to delay sending this event until the next tick, since the
|
||||||
|
// tab does not have its final index when the TabOpen event is dispatched.
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
if (event.detail.adoptedTab) {
|
||||||
|
this.emitAttached(event.originalTarget);
|
||||||
|
} else {
|
||||||
|
this.emitCreated(event.originalTarget, currentTab);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "TabClose":
|
||||||
|
let {adoptedBy} = event.detail;
|
||||||
|
if (adoptedBy) {
|
||||||
|
// This tab is being closed because it was adopted by a new window.
|
||||||
|
// Copy its ID to the new tab, in case it was created as the first tab
|
||||||
|
// of a new window, and did not have an `adoptedTab` detail when it was
|
||||||
|
// opened.
|
||||||
|
this.setId(adoptedBy, this.getId(nativeTab));
|
||||||
|
|
||||||
|
this.emitDetached(nativeTab, adoptedBy);
|
||||||
|
} else {
|
||||||
|
this.emitRemoved(nativeTab, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "TabSelect":
|
||||||
|
// Because we are delaying calling emitCreated above, we also need to
|
||||||
|
// delay sending this event because it shouldn't fire before onCreated.
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
this.emitActivated(nativeTab);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A private method which is called whenever a new browser window is opened,
|
||||||
|
* and dispatches the necessary events for it.
|
||||||
|
*
|
||||||
|
* @param {DOMWindow} window
|
||||||
|
* The window being opened.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_handleWindowOpen(window) {
|
||||||
|
if (window.arguments && window.arguments[0] instanceof window.XULElement) {
|
||||||
|
// If the first window argument is a XUL element, it means the
|
||||||
|
// window is about to adopt a tab from another window to replace its
|
||||||
|
// initial tab.
|
||||||
|
//
|
||||||
|
// Note that this event handler depends on running before the
|
||||||
|
// delayed startup code in browser.js, which is currently triggered
|
||||||
|
// by the first MozAfterPaint event. That code handles finally
|
||||||
|
// adopting the tab, and clears it from the arguments list in the
|
||||||
|
// process, so if we run later than it, we're too late.
|
||||||
|
let nativeTab = window.arguments[0];
|
||||||
|
let adoptedBy = window.gBrowser.tabs[0];
|
||||||
|
|
||||||
|
this.adoptedTabs.set(nativeTab, adoptedBy);
|
||||||
|
this.setId(adoptedBy, this.getId(nativeTab));
|
||||||
|
|
||||||
|
// We need to be sure to fire this event after the onDetached event
|
||||||
|
// for the original tab.
|
||||||
|
let listener = (event, details) => {
|
||||||
|
if (details.nativeTab === nativeTab) {
|
||||||
|
this.off("tab-detached", listener);
|
||||||
|
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
this.emitAttached(details.adoptedBy);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.on("tab-detached", listener);
|
||||||
|
} else {
|
||||||
|
for (let nativeTab of window.gBrowser.tabs) {
|
||||||
|
this.emitCreated(nativeTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
// emitActivated to trigger tab.onActivated/tab.onHighlighted for a newly opened window.
|
||||||
|
this.emitActivated(window.gBrowser.tabs[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A private method which is called whenever a browser window is closed,
|
||||||
|
* and dispatches the necessary events for it.
|
||||||
|
*
|
||||||
|
* @param {DOMWindow} window
|
||||||
|
* The window being closed.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_handleWindowClose(window) {
|
||||||
|
for (let nativeTab of window.gBrowser.tabs) {
|
||||||
|
if (this.adoptedTabs.has(nativeTab)) {
|
||||||
|
this.emitDetached(nativeTab, this.adoptedTabs.get(nativeTab));
|
||||||
|
} else {
|
||||||
|
this.emitRemoved(nativeTab, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits a "tab-activated" event for the given tab element.
|
||||||
|
*
|
||||||
|
* @param {NativeTab} nativeTab
|
||||||
|
* The tab element which has been activated.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
emitActivated(nativeTab) {
|
||||||
|
this.emit("tab-activated", {
|
||||||
|
tabId: this.getId(nativeTab),
|
||||||
|
windowId: windowTracker.getId(nativeTab.ownerGlobal)});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits a "tab-attached" event for the given tab element.
|
||||||
|
*
|
||||||
|
* @param {NativeTab} nativeTab
|
||||||
|
* The tab element in the window to which the tab is being attached.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
emitAttached(nativeTab) {
|
||||||
|
let newWindowId = windowTracker.getId(nativeTab.ownerGlobal);
|
||||||
|
let tabId = this.getId(nativeTab);
|
||||||
|
|
||||||
|
this.emit("tab-attached", {nativeTab, tabId, newWindowId, newPosition: nativeTab._tPos});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits a "tab-detached" event for the given tab element.
|
||||||
|
*
|
||||||
|
* @param {NativeTab} nativeTab
|
||||||
|
* The tab element in the window from which the tab is being detached.
|
||||||
|
* @param {NativeTab} adoptedBy
|
||||||
|
* The tab element in the window to which detached tab is being moved,
|
||||||
|
* and will adopt this tab's contents.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
emitDetached(nativeTab, adoptedBy) {
|
||||||
|
let oldWindowId = windowTracker.getId(nativeTab.ownerGlobal);
|
||||||
|
let tabId = this.getId(nativeTab);
|
||||||
|
|
||||||
|
this.emit("tab-detached", {nativeTab, adoptedBy, tabId, oldWindowId, oldPosition: nativeTab._tPos});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits a "tab-created" event for the given tab element.
|
||||||
|
*
|
||||||
|
* @param {NativeTab} nativeTab
|
||||||
|
* The tab element which is being created.
|
||||||
|
* @param {NativeTab} [currentTab]
|
||||||
|
* The tab element for the currently active tab.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
emitCreated(nativeTab, currentTab) {
|
||||||
|
this.emit("tab-created", {nativeTab, currentTab});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits a "tab-removed" event for the given tab element.
|
||||||
|
*
|
||||||
|
* @param {NativeTab} nativeTab
|
||||||
|
* The tab element which is being removed.
|
||||||
|
* @param {boolean} isWindowClosing
|
||||||
|
* True if the tab is being removed because the browser window is
|
||||||
|
* closing.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
emitRemoved(nativeTab, isWindowClosing) {
|
||||||
|
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
|
||||||
|
let tabId = this.getId(nativeTab);
|
||||||
|
|
||||||
|
// When addons run in-process, `window.close()` is synchronous. Most other
|
||||||
|
// addon-invoked calls are asynchronous since they go through a proxy
|
||||||
|
// context via the message manager. This includes event registrations such
|
||||||
|
// as `tabs.onRemoved.addListener`.
|
||||||
|
//
|
||||||
|
// So, even if `window.close()` were to be called (in-process) after calling
|
||||||
|
// `tabs.onRemoved.addListener`, then the tab would be closed before the
|
||||||
|
// event listener is registered. To make sure that the event listener is
|
||||||
|
// notified, we dispatch `tabs.onRemoved` asynchronously.
|
||||||
|
Services.tm.dispatchToMainThread(() => {
|
||||||
|
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getBrowserData(browser) {
|
||||||
|
if (browser.ownerGlobal.location.href === "about:addons") {
|
||||||
|
// When we're loaded into a <browser> inside about:addons, we need to go up
|
||||||
|
// one more level.
|
||||||
|
browser = browser.ownerGlobal.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDocShell)
|
||||||
|
.chromeEventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
tabId: -1,
|
||||||
|
windowId: -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let {gBrowser} = browser.ownerGlobal;
|
||||||
|
// Some non-browser windows have gBrowser but not
|
||||||
|
// getTabForBrowser!
|
||||||
|
if (gBrowser && gBrowser.getTabForBrowser) {
|
||||||
|
result.windowId = windowTracker.getId(browser.ownerGlobal);
|
||||||
|
|
||||||
|
let nativeTab = gBrowser.getTabForBrowser(browser);
|
||||||
|
if (nativeTab) {
|
||||||
|
result.tabId = this.getId(nativeTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
get activeTab() {
|
||||||
|
let window = windowTracker.topWindow;
|
||||||
|
if (window && window.gBrowser) {
|
||||||
|
return window.gBrowser.selectedTab;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
windowTracker = new WindowTracker();
|
||||||
|
tabTracker = new TabTracker();
|
||||||
|
|
||||||
|
Object.assign(global, {tabTracker, windowTracker});
|
||||||
|
|
||||||
|
class Tab extends TabBase {
|
||||||
|
get _favIconUrl() {
|
||||||
|
return this.window.gBrowser.getIcon(this.nativeTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
get audible() {
|
||||||
|
return this.nativeTab.soundPlaying;
|
||||||
|
}
|
||||||
|
|
||||||
|
get browser() {
|
||||||
|
return this.nativeTab.linkedBrowser;
|
||||||
|
}
|
||||||
|
|
||||||
|
get frameLoader() {
|
||||||
|
// If we don't have a frameLoader yet, just return a dummy with no width and
|
||||||
|
// height.
|
||||||
|
return super.frameLoader || {lazyWidth: 0, lazyHeight: 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
get cookieStoreId() {
|
||||||
|
return getCookieStoreIdForTab(this, this.nativeTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
get height() {
|
||||||
|
return this.frameLoader.lazyHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
get index() {
|
||||||
|
return this.nativeTab._tPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
get mutedInfo() {
|
||||||
|
let {nativeTab} = this;
|
||||||
|
|
||||||
|
let mutedInfo = {muted: nativeTab.muted};
|
||||||
|
if (nativeTab.muteReason === null) {
|
||||||
|
mutedInfo.reason = "user";
|
||||||
|
} else if (nativeTab.muteReason) {
|
||||||
|
mutedInfo.reason = "extension";
|
||||||
|
mutedInfo.extensionId = nativeTab.muteReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mutedInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
get lastAccessed() {
|
||||||
|
return this.nativeTab.lastAccessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
get pinned() {
|
||||||
|
return this.nativeTab.pinned;
|
||||||
|
}
|
||||||
|
|
||||||
|
get active() {
|
||||||
|
return this.nativeTab.selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
get selected() {
|
||||||
|
return this.nativeTab.selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
get status() {
|
||||||
|
if (this.nativeTab.getAttribute("busy") === "true") {
|
||||||
|
return "loading";
|
||||||
|
}
|
||||||
|
return "complete";
|
||||||
|
}
|
||||||
|
|
||||||
|
get width() {
|
||||||
|
return this.frameLoader.lazyWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
get window() {
|
||||||
|
return this.nativeTab.ownerGlobal;
|
||||||
|
}
|
||||||
|
|
||||||
|
get windowId() {
|
||||||
|
return windowTracker.getId(this.window);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts session store data to an object compatible with the return value
|
||||||
|
* of the convert() method, representing that data.
|
||||||
|
*
|
||||||
|
* @param {Extension} extension
|
||||||
|
* The extension for which to convert the data.
|
||||||
|
* @param {Object} tabData
|
||||||
|
* Session store data for a closed tab, as returned by
|
||||||
|
* `SessionStore.getClosedTabData()`.
|
||||||
|
* @param {DOMWindow} [window = null]
|
||||||
|
* The browser window which the tab belonged to before it was closed.
|
||||||
|
* May be null if the window the tab belonged to no longer exists.
|
||||||
|
*
|
||||||
|
* @returns {Object}
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
static convertFromSessionStoreClosedData(extension, tabData, window = null) {
|
||||||
|
let result = {
|
||||||
|
sessionId: String(tabData.closedId),
|
||||||
|
index: tabData.pos ? tabData.pos : 0,
|
||||||
|
windowId: window && windowTracker.getId(window),
|
||||||
|
highlighted: false,
|
||||||
|
active: false,
|
||||||
|
pinned: false,
|
||||||
|
incognito: Boolean(tabData.state && tabData.state.isPrivate),
|
||||||
|
lastAccessed: tabData.state ? tabData.state.lastAccessed : tabData.lastAccessed,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (extension.tabManager.hasTabPermission(tabData)) {
|
||||||
|
let entries = tabData.state ? tabData.state.entries : tabData.entries;
|
||||||
|
let entry = entries[entries.length - 1];
|
||||||
|
result.url = entry.url;
|
||||||
|
result.title = entry.title;
|
||||||
|
if (tabData.image) {
|
||||||
|
result.favIconUrl = tabData.image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Window extends WindowBase {
|
||||||
|
/**
|
||||||
|
* Update the geometry of the browser window.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* An object containing new values for the window's geometry.
|
||||||
|
* @param {integer} [options.left]
|
||||||
|
* The new pixel distance of the left side of the browser window from
|
||||||
|
* the left of the screen.
|
||||||
|
* @param {integer} [options.top]
|
||||||
|
* The new pixel distance of the top side of the browser window from
|
||||||
|
* the top of the screen.
|
||||||
|
* @param {integer} [options.width]
|
||||||
|
* The new pixel width of the window.
|
||||||
|
* @param {integer} [options.height]
|
||||||
|
* The new pixel height of the window.
|
||||||
|
*/
|
||||||
|
updateGeometry(options) {
|
||||||
|
let {window} = this;
|
||||||
|
|
||||||
|
if (options.left !== null || options.top !== null) {
|
||||||
|
let left = options.left !== null ? options.left : window.screenX;
|
||||||
|
let top = options.top !== null ? options.top : window.screenY;
|
||||||
|
window.moveTo(left, top);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.width !== null || options.height !== null) {
|
||||||
|
let width = options.width !== null ? options.width : window.outerWidth;
|
||||||
|
let height = options.height !== null ? options.height : window.outerHeight;
|
||||||
|
window.resizeTo(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return this.window.document.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTitlePreface(titlePreface) {
|
||||||
|
this.window.document.documentElement.setAttribute("titlepreface", titlePreface);
|
||||||
|
}
|
||||||
|
|
||||||
|
get focused() {
|
||||||
|
return this.window.document.hasFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
get top() {
|
||||||
|
return this.window.screenY;
|
||||||
|
}
|
||||||
|
|
||||||
|
get left() {
|
||||||
|
return this.window.screenX;
|
||||||
|
}
|
||||||
|
|
||||||
|
get width() {
|
||||||
|
return this.window.outerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
get height() {
|
||||||
|
return this.window.outerHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
get incognito() {
|
||||||
|
return PrivateBrowsingUtils.isWindowPrivate(this.window);
|
||||||
|
}
|
||||||
|
|
||||||
|
get alwaysOnTop() {
|
||||||
|
return this.xulWindow.zLevel >= Ci.nsIXULWindow.raisedZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isLastFocused() {
|
||||||
|
return this.window === windowTracker.topWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getState(window) {
|
||||||
|
const STATES = {
|
||||||
|
[window.STATE_MAXIMIZED]: "maximized",
|
||||||
|
[window.STATE_MINIMIZED]: "minimized",
|
||||||
|
[window.STATE_NORMAL]: "normal",
|
||||||
|
};
|
||||||
|
let state = STATES[window.windowState];
|
||||||
|
if (window.fullScreen) {
|
||||||
|
state = "fullscreen";
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
get state() {
|
||||||
|
return Window.getState(this.window);
|
||||||
|
}
|
||||||
|
|
||||||
|
set state(state) {
|
||||||
|
let {window} = this;
|
||||||
|
if (state !== "fullscreen" && window.fullScreen) {
|
||||||
|
window.fullScreen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case "maximized":
|
||||||
|
window.maximize();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "minimized":
|
||||||
|
case "docked":
|
||||||
|
window.minimize();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "normal":
|
||||||
|
// Restore sometimes returns the window to its previous state, rather
|
||||||
|
// than to the "normal" state, so it may need to be called anywhere from
|
||||||
|
// zero to two times.
|
||||||
|
window.restore();
|
||||||
|
if (window.windowState !== window.STATE_NORMAL) {
|
||||||
|
window.restore();
|
||||||
|
}
|
||||||
|
if (window.windowState !== window.STATE_NORMAL) {
|
||||||
|
// And on OS-X, where normal vs. maximized is basically a heuristic,
|
||||||
|
// we need to cheat.
|
||||||
|
window.sizeToContent();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "fullscreen":
|
||||||
|
window.fullScreen = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unexpected window state: ${state}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* getTabs() {
|
||||||
|
let {tabManager} = this.extension;
|
||||||
|
|
||||||
|
for (let nativeTab of this.window.gBrowser.tabs) {
|
||||||
|
yield tabManager.getWrapper(nativeTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts session store data to an object compatible with the return value
|
||||||
|
* of the convert() method, representing that data.
|
||||||
|
*
|
||||||
|
* @param {Extension} extension
|
||||||
|
* The extension for which to convert the data.
|
||||||
|
* @param {Object} windowData
|
||||||
|
* Session store data for a closed window, as returned by
|
||||||
|
* `SessionStore.getClosedWindowData()`.
|
||||||
|
*
|
||||||
|
* @returns {Object}
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
static convertFromSessionStoreClosedData(extension, windowData) {
|
||||||
|
let result = {
|
||||||
|
sessionId: String(windowData.closedId),
|
||||||
|
focused: false,
|
||||||
|
incognito: false,
|
||||||
|
type: "normal", // this is always "normal" for a closed window
|
||||||
|
// Surely this does not actually work?
|
||||||
|
state: this.getState(windowData),
|
||||||
|
alwaysOnTop: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (windowData.tabs.length) {
|
||||||
|
result.tabs = windowData.tabs.map(tabData => {
|
||||||
|
return Tab.convertFromSessionStoreClosedData(extension, tabData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(global, {Tab, Window});
|
||||||
|
|
||||||
|
class TabManager extends TabManagerBase {
|
||||||
|
get(tabId, default_ = undefined) {
|
||||||
|
let nativeTab = tabTracker.getTab(tabId, default_);
|
||||||
|
|
||||||
|
if (nativeTab) {
|
||||||
|
return this.getWrapper(nativeTab);
|
||||||
|
}
|
||||||
|
return default_;
|
||||||
|
}
|
||||||
|
|
||||||
|
addActiveTabPermission(nativeTab = tabTracker.activeTab) {
|
||||||
|
return super.addActiveTabPermission(nativeTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
revokeActiveTabPermission(nativeTab = tabTracker.activeTab) {
|
||||||
|
return super.revokeActiveTabPermission(nativeTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapTab(nativeTab) {
|
||||||
|
return new Tab(this.extension, nativeTab, tabTracker.getId(nativeTab));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WindowManager extends WindowManagerBase {
|
||||||
|
get(windowId, context) {
|
||||||
|
let window = windowTracker.getWindow(windowId, context);
|
||||||
|
|
||||||
|
return this.getWrapper(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
* getAll() {
|
||||||
|
for (let window of windowTracker.browserWindows()) {
|
||||||
|
yield this.getWrapper(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapWindow(window) {
|
||||||
|
return new Window(this.extension, window, windowTracker.getId(window));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extensions.on("startup", (type, extension) => { // eslint-disable-line mozilla/balanced-listeners
|
||||||
|
defineLazyGetter(extension, "tabManager",
|
||||||
|
() => new TabManager(extension));
|
||||||
|
defineLazyGetter(extension, "windowManager",
|
||||||
|
() => new WindowManager(extension));
|
||||||
});
|
});
|
||||||
|
|||||||
159
browser/components/extensions/ext-browser.json
Normal file
159
browser/components/extensions/ext-browser.json
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
{
|
||||||
|
"bookmarks": {
|
||||||
|
"url": "chrome://browser/content/ext-bookmarks.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/bookmarks.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["bookmarks"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browserAction": {
|
||||||
|
"url": "chrome://browser/content/ext-browserAction.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/browser_action.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["browser_action"],
|
||||||
|
"paths": [
|
||||||
|
["browserAction"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browsingData": {
|
||||||
|
"url": "chrome://browser/content/ext-browsingData.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/browsing_data.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["browsingData"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"chrome_settings_overrides": {
|
||||||
|
"url": "chrome://browser/content/ext-chrome-settings-overrides.js",
|
||||||
|
"scopes": [],
|
||||||
|
"schema": "chrome://browser/content/schemas/chrome_settings_overrides.json",
|
||||||
|
"manifest": ["chrome_settings_overrides"]
|
||||||
|
},
|
||||||
|
"commands": {
|
||||||
|
"url": "chrome://browser/content/ext-commands.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/commands.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["commands"],
|
||||||
|
"paths": [
|
||||||
|
["commands"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devtools": {
|
||||||
|
"url": "chrome://browser/content/ext-devtools.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/devtools.json",
|
||||||
|
"scopes": ["devtools_parent"],
|
||||||
|
"manifest": ["devtools_page"],
|
||||||
|
"paths": [
|
||||||
|
["devtools"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devtools_inspectedWindow": {
|
||||||
|
"url": "chrome://browser/content/ext-devtools-inspectedWindow.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/devtools_inspected_window.json",
|
||||||
|
"scopes": ["devtools_parent"],
|
||||||
|
"paths": [
|
||||||
|
["devtools", "inspectedWindow"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devtools_network": {
|
||||||
|
"url": "chrome://browser/content/ext-devtools-network.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/devtools_network.json",
|
||||||
|
"scopes": ["devtools_parent"],
|
||||||
|
"paths": [
|
||||||
|
["devtools", "network"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devtools_panels": {
|
||||||
|
"url": "chrome://browser/content/ext-devtools-panels.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/devtools_panels.json",
|
||||||
|
"scopes": ["devtools_parent"],
|
||||||
|
"paths": [
|
||||||
|
["devtools", "panels"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"url": "chrome://browser/content/ext-history.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/history.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["history"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"menusInternal": {
|
||||||
|
"url": "chrome://browser/content/ext-menus.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/menus.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["menusInternal"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"omnibox": {
|
||||||
|
"url": "chrome://browser/content/ext-omnibox.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/omnibox.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["omnibox"],
|
||||||
|
"paths": [
|
||||||
|
["omnibox"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pageAction": {
|
||||||
|
"url": "chrome://browser/content/ext-pageAction.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/page_action.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["page_action"],
|
||||||
|
"paths": [
|
||||||
|
["pageAction"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"geckoProfiler": {
|
||||||
|
"url": "chrome://browser/content/ext-geckoProfiler.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/geckoProfiler.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["geckoProfiler"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sessions": {
|
||||||
|
"url": "chrome://browser/content/ext-sessions.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/sessions.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["sessions"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sidebarAction": {
|
||||||
|
"url": "chrome://browser/content/ext-sidebarAction.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/sidebar_action.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["sidebar_action"],
|
||||||
|
"paths": [
|
||||||
|
["sidebarAction"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tabs": {
|
||||||
|
"url": "chrome://browser/content/ext-tabs.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/tabs.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["tabs"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"urlOverrides": {
|
||||||
|
"url": "chrome://browser/content/ext-url-overrides.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/url_overrides.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["chrome_url_overrides"],
|
||||||
|
"paths": [
|
||||||
|
["urlOverrides"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"windows": {
|
||||||
|
"url": "chrome://browser/content/ext-windows.js",
|
||||||
|
"schema": "chrome://browser/content/schemas/windows.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["windows"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
/* global browserActionFor:false, sidebarActionFor:false, pageActionFor:false */
|
/* global browserActionFor:false, sidebarActionFor:false, pageActionFor:false */
|
||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
||||||
"resource:///modules/CustomizableUI.jsm");
|
"resource:///modules/CustomizableUI.jsm");
|
||||||
@@ -31,6 +31,7 @@ Cu.import("resource://gre/modules/ExtensionParent.jsm");
|
|||||||
|
|
||||||
var {
|
var {
|
||||||
IconDetails,
|
IconDetails,
|
||||||
|
StartupCache,
|
||||||
} = ExtensionParent;
|
} = ExtensionParent;
|
||||||
|
|
||||||
const POPUP_PRELOAD_TIMEOUT_MS = 200;
|
const POPUP_PRELOAD_TIMEOUT_MS = 200;
|
||||||
@@ -65,7 +66,7 @@ this.browserAction = class extends ExtensionAPI {
|
|||||||
return browserActionMap.get(extension);
|
return browserActionMap.get(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
onManifestEntry(entryName) {
|
async onManifestEntry(entryName) {
|
||||||
let {extension} = this;
|
let {extension} = this;
|
||||||
|
|
||||||
let options = extension.manifest.browser_action;
|
let options = extension.manifest.browser_action;
|
||||||
@@ -88,10 +89,6 @@ this.browserAction = class extends ExtensionAPI {
|
|||||||
title: options.default_title || extension.name,
|
title: options.default_title || extension.name,
|
||||||
badgeText: "",
|
badgeText: "",
|
||||||
badgeBackgroundColor: null,
|
badgeBackgroundColor: null,
|
||||||
icon: IconDetails.normalize({
|
|
||||||
path: options.default_icon,
|
|
||||||
themeIcons: options.theme_icons,
|
|
||||||
}, extension),
|
|
||||||
popup: options.default_popup || "",
|
popup: options.default_popup || "",
|
||||||
area: browserAreas[options.default_area || "navbar"],
|
area: browserAreas[options.default_area || "navbar"],
|
||||||
};
|
};
|
||||||
@@ -102,13 +99,25 @@ this.browserAction = class extends ExtensionAPI {
|
|||||||
"or not in your browser_action options.");
|
"or not in your browser_action options.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
browserActionMap.set(extension, this);
|
||||||
|
|
||||||
|
this.defaults.icon = await StartupCache.get(
|
||||||
|
extension, ["browserAction", "default_icon"],
|
||||||
|
() => IconDetails.normalize({
|
||||||
|
path: options.default_icon,
|
||||||
|
themeIcons: options.theme_icons,
|
||||||
|
}, extension));
|
||||||
|
|
||||||
|
this.iconData.set(
|
||||||
|
this.defaults.icon,
|
||||||
|
await StartupCache.get(
|
||||||
|
extension, ["browserAction", "default_icon_data"],
|
||||||
|
() => this.getIconData(this.defaults.icon)));
|
||||||
|
|
||||||
this.tabContext = new TabContext(tab => Object.create(this.defaults),
|
this.tabContext = new TabContext(tab => Object.create(this.defaults),
|
||||||
extension);
|
extension);
|
||||||
|
|
||||||
EventEmitter.decorate(this);
|
|
||||||
|
|
||||||
this.build();
|
this.build();
|
||||||
browserActionMap.set(extension, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onShutdown(reason) {
|
onShutdown(reason) {
|
||||||
@@ -130,6 +139,10 @@ this.browserAction = class extends ExtensionAPI {
|
|||||||
tooltiptext: this.defaults.title || "",
|
tooltiptext: this.defaults.title || "",
|
||||||
defaultArea: this.defaults.area,
|
defaultArea: this.defaults.area,
|
||||||
|
|
||||||
|
// Don't attempt to load properties from the built-in widget string
|
||||||
|
// bundle.
|
||||||
|
localized: false,
|
||||||
|
|
||||||
onBeforeCreated: document => {
|
onBeforeCreated: document => {
|
||||||
let view = document.createElementNS(XUL_NS, "panelview");
|
let view = document.createElementNS(XUL_NS, "panelview");
|
||||||
view.id = this.viewId;
|
view.id = this.viewId;
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ../../../toolkit/components/extensions/ext-c-toolkit.js */
|
/* import-globals-from ../../../toolkit/components/extensions/ext-c-toolkit.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
|
||||||
"resource://gre/modules/EventEmitter.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionChildDevToolsUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionChildDevToolsUtils",
|
||||||
"resource://gre/modules/ExtensionChildDevToolsUtils.jsm");
|
"resource://gre/modules/ExtensionChildDevToolsUtils.jsm");
|
||||||
|
|
||||||
@@ -23,7 +21,7 @@ var {
|
|||||||
* @param {string} panelOptions.id
|
* @param {string} panelOptions.id
|
||||||
* The id of the addon devtools panel registered in the main process.
|
* The id of the addon devtools panel registered in the main process.
|
||||||
*/
|
*/
|
||||||
class ChildDevToolsPanel extends EventEmitter {
|
class ChildDevToolsPanel extends ExtensionUtils.EventEmitter {
|
||||||
constructor(context, {id}) {
|
constructor(context, {id}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-browserAction.js */
|
/* import-globals-from ext-browserAction.js */
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
|
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
|
||||||
"resource://gre/modules/ExtensionParent.jsm");
|
"resource://gre/modules/ExtensionParent.jsm");
|
||||||
@@ -25,7 +25,6 @@ this.commands = class extends ExtensionAPI {
|
|||||||
this.keysetsMap = new WeakMap();
|
this.keysetsMap = new WeakMap();
|
||||||
|
|
||||||
this.register();
|
this.register();
|
||||||
EventEmitter.decorate(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onShutdown(reason) {
|
onShutdown(reason) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-devtools.js */
|
/* import-globals-from ext-devtools.js */
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/ExtensionParent.jsm");
|
Cu.import("resource://gre/modules/ExtensionParent.jsm");
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* global getTargetTabIdForToolbox, getDevToolsTargetForContext */
|
/* global getTargetTabIdForToolbox, getDevToolsTargetForContext */
|
||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This module provides helpers used by the other specialized `ext-devtools-*.js` modules
|
* This module provides helpers used by the other specialized `ext-devtools-*.js` modules
|
||||||
|
|||||||
@@ -92,11 +92,11 @@ var _observer;
|
|||||||
|
|
||||||
const getHistoryObserver = () => {
|
const getHistoryObserver = () => {
|
||||||
if (!_observer) {
|
if (!_observer) {
|
||||||
_observer = {
|
_observer = new class extends EventEmitter {
|
||||||
onDeleteURI: function(uri, guid, reason) {
|
onDeleteURI(uri, guid, reason) {
|
||||||
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
|
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
|
||||||
},
|
}
|
||||||
onVisit: function(uri, visitId, time, sessionId, referringId, transitionType, guid, hidden, visitCount, typed, lastKnownTitle) {
|
onVisit(uri, visitId, time, sessionId, referringId, transitionType, guid, hidden, visitCount, typed, lastKnownTitle) {
|
||||||
let data = {
|
let data = {
|
||||||
id: guid,
|
id: guid,
|
||||||
url: uri.spec,
|
url: uri.spec,
|
||||||
@@ -106,23 +106,22 @@ const getHistoryObserver = () => {
|
|||||||
typedCount: typed,
|
typedCount: typed,
|
||||||
};
|
};
|
||||||
this.emit("visited", data);
|
this.emit("visited", data);
|
||||||
},
|
}
|
||||||
onBeginUpdateBatch: function() {},
|
onBeginUpdateBatch() {}
|
||||||
onEndUpdateBatch: function() {},
|
onEndUpdateBatch() {}
|
||||||
onTitleChanged: function(uri, title) {
|
onTitleChanged(uri, title) {
|
||||||
this.emit("titleChanged", {url: uri.spec, title: title});
|
this.emit("titleChanged", {url: uri.spec, title: title});
|
||||||
},
|
}
|
||||||
onClearHistory: function() {
|
onClearHistory() {
|
||||||
this.emit("visitRemoved", {allHistory: true, urls: []});
|
this.emit("visitRemoved", {allHistory: true, urls: []});
|
||||||
},
|
}
|
||||||
onPageChanged: function() {},
|
onPageChanged() {}
|
||||||
onFrecencyChanged: function() {},
|
onFrecencyChanged() {}
|
||||||
onManyFrecenciesChanged: function() {},
|
onManyFrecenciesChanged() {}
|
||||||
onDeleteVisits: function(uri, time, guid, reason) {
|
onDeleteVisits(uri, time, guid, reason) {
|
||||||
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
|
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
|
||||||
},
|
}
|
||||||
};
|
}();
|
||||||
EventEmitter.decorate(_observer);
|
|
||||||
PlacesUtils.history.addObserver(_observer);
|
PlacesUtils.history.addObserver(_observer);
|
||||||
}
|
}
|
||||||
return _observer;
|
return _observer;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-browserAction.js */
|
/* import-globals-from ext-browserAction.js */
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PanelPopup",
|
XPCOMUtils.defineLazyModuleGetter(this, "PanelPopup",
|
||||||
"resource:///modules/ExtensionPopups.jsm");
|
"resource:///modules/ExtensionPopups.jsm");
|
||||||
@@ -20,6 +20,7 @@ Cu.import("resource://gre/modules/ExtensionParent.jsm");
|
|||||||
|
|
||||||
var {
|
var {
|
||||||
IconDetails,
|
IconDetails,
|
||||||
|
StartupCache,
|
||||||
} = ExtensionParent;
|
} = ExtensionParent;
|
||||||
|
|
||||||
const popupOpenTimingHistogram = "WEBEXT_PAGEACTION_POPUP_OPEN_MS";
|
const popupOpenTimingHistogram = "WEBEXT_PAGEACTION_POPUP_OPEN_MS";
|
||||||
@@ -32,7 +33,7 @@ this.pageAction = class extends ExtensionAPI {
|
|||||||
return pageActionMap.get(extension);
|
return pageActionMap.get(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
onManifestEntry(entryName) {
|
async onManifestEntry(entryName) {
|
||||||
let {extension} = this;
|
let {extension} = this;
|
||||||
let options = extension.manifest.page_action;
|
let options = extension.manifest.page_action;
|
||||||
|
|
||||||
@@ -45,7 +46,6 @@ this.pageAction = class extends ExtensionAPI {
|
|||||||
this.defaults = {
|
this.defaults = {
|
||||||
show: false,
|
show: false,
|
||||||
title: options.default_title || extension.name,
|
title: options.default_title || extension.name,
|
||||||
icon: IconDetails.normalize({path: options.default_icon}, extension),
|
|
||||||
popup: options.default_popup || "",
|
popup: options.default_popup || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,9 +63,17 @@ this.pageAction = class extends ExtensionAPI {
|
|||||||
// WeakMap[ChromeWindow -> <xul:image>]
|
// WeakMap[ChromeWindow -> <xul:image>]
|
||||||
this.buttons = new WeakMap();
|
this.buttons = new WeakMap();
|
||||||
|
|
||||||
EventEmitter.decorate(this);
|
|
||||||
|
|
||||||
pageActionMap.set(extension, this);
|
pageActionMap.set(extension, this);
|
||||||
|
|
||||||
|
this.defaults.icon = await StartupCache.get(
|
||||||
|
extension, ["pageAction", "default_icon"],
|
||||||
|
() => IconDetails.normalize({path: options.default_icon}, extension));
|
||||||
|
|
||||||
|
this.iconData.set(
|
||||||
|
this.defaults.icon,
|
||||||
|
await StartupCache.get(
|
||||||
|
extension, ["pageAction", "default_icon_data"],
|
||||||
|
() => this.getIconData(this.defaults.icon)));
|
||||||
}
|
}
|
||||||
|
|
||||||
onShutdown(reason) {
|
onShutdown(reason) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
var {
|
var {
|
||||||
ExtensionError,
|
ExtensionError,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
||||||
"resource:///modules/CustomizableUI.jsm");
|
"resource:///modules/CustomizableUI.jsm");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "strBundle", function() {
|
XPCOMUtils.defineLazyGetter(this, "strBundle", function() {
|
||||||
const stringSvc = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
|
const stringSvc = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
|
||||||
|
|||||||
@@ -1,819 +0,0 @@
|
|||||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* vim: set sts=2 sw=2 et tw=80: */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* exported WindowEventManager, makeWidgetId */
|
|
||||||
/* global EventEmitter:false, TabContext:false, WindowEventManager:false,
|
|
||||||
makeWidgetId:false, tabTracker:true, windowTracker:true */
|
|
||||||
/* import-globals-from ../../../toolkit/components/extensions/ext-toolkit.js */
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
|
||||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/ExtensionTabs.jsm");
|
|
||||||
|
|
||||||
var {
|
|
||||||
ExtensionError,
|
|
||||||
defineLazyGetter,
|
|
||||||
} = ExtensionUtils;
|
|
||||||
|
|
||||||
let tabTracker;
|
|
||||||
let windowTracker;
|
|
||||||
|
|
||||||
// This file provides some useful code for the |tabs| and |windows|
|
|
||||||
// modules. All of the code is installed on |global|, which is a scope
|
|
||||||
// shared among the different ext-*.js scripts.
|
|
||||||
|
|
||||||
global.makeWidgetId = id => {
|
|
||||||
id = id.toLowerCase();
|
|
||||||
// FIXME: This allows for collisions.
|
|
||||||
return id.replace(/[^a-z0-9_-]/g, "_");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Manages tab-specific context data, and dispatching tab select events
|
|
||||||
// across all windows.
|
|
||||||
global.TabContext = function TabContext(getDefaults, extension) {
|
|
||||||
this.extension = extension;
|
|
||||||
this.getDefaults = getDefaults;
|
|
||||||
|
|
||||||
this.tabData = new WeakMap();
|
|
||||||
this.lastLocation = new WeakMap();
|
|
||||||
|
|
||||||
windowTracker.addListener("progress", this);
|
|
||||||
windowTracker.addListener("TabSelect", this);
|
|
||||||
|
|
||||||
EventEmitter.decorate(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
TabContext.prototype = {
|
|
||||||
get(nativeTab) {
|
|
||||||
if (!this.tabData.has(nativeTab)) {
|
|
||||||
this.tabData.set(nativeTab, this.getDefaults(nativeTab));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.tabData.get(nativeTab);
|
|
||||||
},
|
|
||||||
|
|
||||||
clear(nativeTab) {
|
|
||||||
this.tabData.delete(nativeTab);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleEvent(event) {
|
|
||||||
if (event.type == "TabSelect") {
|
|
||||||
let nativeTab = event.target;
|
|
||||||
this.emit("tab-select", nativeTab);
|
|
||||||
this.emit("location-change", nativeTab);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onStateChange(browser, webProgress, request, stateFlags, statusCode) {
|
|
||||||
let flags = Ci.nsIWebProgressListener;
|
|
||||||
|
|
||||||
if (!(~stateFlags & (flags.STATE_IS_WINDOW | flags.STATE_START) ||
|
|
||||||
this.lastLocation.has(browser))) {
|
|
||||||
this.lastLocation.set(browser, request.URI);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onLocationChange(browser, webProgress, request, locationURI, flags) {
|
|
||||||
let gBrowser = browser.ownerGlobal.gBrowser;
|
|
||||||
let lastLocation = this.lastLocation.get(browser);
|
|
||||||
if (browser === gBrowser.selectedBrowser &&
|
|
||||||
!(lastLocation && lastLocation.equalsExceptRef(browser.currentURI))) {
|
|
||||||
let nativeTab = gBrowser.getTabForBrowser(browser);
|
|
||||||
this.emit("location-change", nativeTab, true);
|
|
||||||
}
|
|
||||||
this.lastLocation.set(browser, browser.currentURI);
|
|
||||||
},
|
|
||||||
|
|
||||||
shutdown() {
|
|
||||||
windowTracker.removeListener("progress", this);
|
|
||||||
windowTracker.removeListener("TabSelect", this);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class WindowTracker extends WindowTrackerBase {
|
|
||||||
addProgressListener(window, listener) {
|
|
||||||
window.gBrowser.addTabsProgressListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeProgressListener(window, listener) {
|
|
||||||
window.gBrowser.removeTabsProgressListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An event manager API provider which listens for a DOM event in any browser
|
|
||||||
* window, and calls the given listener function whenever an event is received.
|
|
||||||
* That listener function receives a `fire` object, which it can use to dispatch
|
|
||||||
* events to the extension, and a DOM event object.
|
|
||||||
*
|
|
||||||
* @param {BaseContext} context
|
|
||||||
* The extension context which the event manager belongs to.
|
|
||||||
* @param {string} name
|
|
||||||
* The API name of the event manager, e.g.,"runtime.onMessage".
|
|
||||||
* @param {string} event
|
|
||||||
* The name of the DOM event to listen for.
|
|
||||||
* @param {function} listener
|
|
||||||
* The listener function to call when a DOM event is received.
|
|
||||||
*/
|
|
||||||
global.WindowEventManager = class extends EventManager {
|
|
||||||
constructor(context, name, event, listener) {
|
|
||||||
super(context, name, fire => {
|
|
||||||
let listener2 = listener.bind(null, fire);
|
|
||||||
|
|
||||||
windowTracker.addListener(event, listener2);
|
|
||||||
return () => {
|
|
||||||
windowTracker.removeListener(event, listener2);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class TabTracker extends TabTrackerBase {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this._tabs = new WeakMap();
|
|
||||||
this._tabIds = new Map();
|
|
||||||
this._nextId = 1;
|
|
||||||
|
|
||||||
this._handleTabDestroyed = this._handleTabDestroyed.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.initialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.initialized = true;
|
|
||||||
|
|
||||||
this.adoptedTabs = new WeakMap();
|
|
||||||
|
|
||||||
this._handleWindowOpen = this._handleWindowOpen.bind(this);
|
|
||||||
this._handleWindowClose = this._handleWindowClose.bind(this);
|
|
||||||
|
|
||||||
windowTracker.addListener("TabClose", this);
|
|
||||||
windowTracker.addListener("TabOpen", this);
|
|
||||||
windowTracker.addListener("TabSelect", this);
|
|
||||||
windowTracker.addOpenListener(this._handleWindowOpen);
|
|
||||||
windowTracker.addCloseListener(this._handleWindowClose);
|
|
||||||
|
|
||||||
/* eslint-disable mozilla/balanced-listeners */
|
|
||||||
this.on("tab-detached", this._handleTabDestroyed);
|
|
||||||
this.on("tab-removed", this._handleTabDestroyed);
|
|
||||||
/* eslint-enable mozilla/balanced-listeners */
|
|
||||||
}
|
|
||||||
|
|
||||||
getId(nativeTab) {
|
|
||||||
if (this._tabs.has(nativeTab)) {
|
|
||||||
return this._tabs.get(nativeTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.init();
|
|
||||||
|
|
||||||
let id = this._nextId++;
|
|
||||||
this.setId(nativeTab, id);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
setId(nativeTab, id) {
|
|
||||||
this._tabs.set(nativeTab, id);
|
|
||||||
this._tabIds.set(id, nativeTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
_handleTabDestroyed(event, {nativeTab}) {
|
|
||||||
let id = this._tabs.get(nativeTab);
|
|
||||||
if (id) {
|
|
||||||
this._tabs.delete(nativeTab);
|
|
||||||
if (this._tabIds.get(id) === nativeTab) {
|
|
||||||
this._tabIds.delete(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the XUL <tab> element associated with the given tab ID. If no tab
|
|
||||||
* with the given ID exists, and no default value is provided, an error is
|
|
||||||
* raised, belonging to the scope of the given context.
|
|
||||||
*
|
|
||||||
* @param {integer} tabId
|
|
||||||
* The ID of the tab to retrieve.
|
|
||||||
* @param {*} default_
|
|
||||||
* The value to return if no tab exists with the given ID.
|
|
||||||
* @returns {Element<tab>}
|
|
||||||
* A XUL <tab> element.
|
|
||||||
*/
|
|
||||||
getTab(tabId, default_ = undefined) {
|
|
||||||
let nativeTab = this._tabIds.get(tabId);
|
|
||||||
if (nativeTab) {
|
|
||||||
return nativeTab;
|
|
||||||
}
|
|
||||||
if (default_ !== undefined) {
|
|
||||||
return default_;
|
|
||||||
}
|
|
||||||
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Event} event
|
|
||||||
* The DOM Event to handle.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
handleEvent(event) {
|
|
||||||
let nativeTab = event.target;
|
|
||||||
|
|
||||||
switch (event.type) {
|
|
||||||
case "TabOpen":
|
|
||||||
let {adoptedTab} = event.detail;
|
|
||||||
if (adoptedTab) {
|
|
||||||
this.adoptedTabs.set(adoptedTab, event.target);
|
|
||||||
|
|
||||||
// This tab is being created to adopt a tab from a different window.
|
|
||||||
// Copy the ID from the old tab to the new.
|
|
||||||
this.setId(nativeTab, this.getId(adoptedTab));
|
|
||||||
|
|
||||||
adoptedTab.linkedBrowser.messageManager.sendAsyncMessage("Extension:SetFrameData", {
|
|
||||||
windowId: windowTracker.getId(nativeTab.ownerGlobal),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the current tab, since the newly-created tab will likely be
|
|
||||||
// active by the time the promise below resolves and the event is
|
|
||||||
// dispatched.
|
|
||||||
let currentTab = nativeTab.ownerGlobal.gBrowser.selectedTab;
|
|
||||||
|
|
||||||
// We need to delay sending this event until the next tick, since the
|
|
||||||
// tab does not have its final index when the TabOpen event is dispatched.
|
|
||||||
Promise.resolve().then(() => {
|
|
||||||
if (event.detail.adoptedTab) {
|
|
||||||
this.emitAttached(event.originalTarget);
|
|
||||||
} else {
|
|
||||||
this.emitCreated(event.originalTarget, currentTab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "TabClose":
|
|
||||||
let {adoptedBy} = event.detail;
|
|
||||||
if (adoptedBy) {
|
|
||||||
// This tab is being closed because it was adopted by a new window.
|
|
||||||
// Copy its ID to the new tab, in case it was created as the first tab
|
|
||||||
// of a new window, and did not have an `adoptedTab` detail when it was
|
|
||||||
// opened.
|
|
||||||
this.setId(adoptedBy, this.getId(nativeTab));
|
|
||||||
|
|
||||||
this.emitDetached(nativeTab, adoptedBy);
|
|
||||||
} else {
|
|
||||||
this.emitRemoved(nativeTab, false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "TabSelect":
|
|
||||||
// Because we are delaying calling emitCreated above, we also need to
|
|
||||||
// delay sending this event because it shouldn't fire before onCreated.
|
|
||||||
Promise.resolve().then(() => {
|
|
||||||
this.emitActivated(nativeTab);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A private method which is called whenever a new browser window is opened,
|
|
||||||
* and dispatches the necessary events for it.
|
|
||||||
*
|
|
||||||
* @param {DOMWindow} window
|
|
||||||
* The window being opened.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_handleWindowOpen(window) {
|
|
||||||
if (window.arguments && window.arguments[0] instanceof window.XULElement) {
|
|
||||||
// If the first window argument is a XUL element, it means the
|
|
||||||
// window is about to adopt a tab from another window to replace its
|
|
||||||
// initial tab.
|
|
||||||
//
|
|
||||||
// Note that this event handler depends on running before the
|
|
||||||
// delayed startup code in browser.js, which is currently triggered
|
|
||||||
// by the first MozAfterPaint event. That code handles finally
|
|
||||||
// adopting the tab, and clears it from the arguments list in the
|
|
||||||
// process, so if we run later than it, we're too late.
|
|
||||||
let nativeTab = window.arguments[0];
|
|
||||||
let adoptedBy = window.gBrowser.tabs[0];
|
|
||||||
|
|
||||||
this.adoptedTabs.set(nativeTab, adoptedBy);
|
|
||||||
this.setId(adoptedBy, this.getId(nativeTab));
|
|
||||||
|
|
||||||
// We need to be sure to fire this event after the onDetached event
|
|
||||||
// for the original tab.
|
|
||||||
let listener = (event, details) => {
|
|
||||||
if (details.nativeTab === nativeTab) {
|
|
||||||
this.off("tab-detached", listener);
|
|
||||||
|
|
||||||
Promise.resolve().then(() => {
|
|
||||||
this.emitAttached(details.adoptedBy);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.on("tab-detached", listener);
|
|
||||||
} else {
|
|
||||||
for (let nativeTab of window.gBrowser.tabs) {
|
|
||||||
this.emitCreated(nativeTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
// emitActivated to trigger tab.onActivated/tab.onHighlighted for a newly opened window.
|
|
||||||
this.emitActivated(window.gBrowser.tabs[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A private method which is called whenever a browser window is closed,
|
|
||||||
* and dispatches the necessary events for it.
|
|
||||||
*
|
|
||||||
* @param {DOMWindow} window
|
|
||||||
* The window being closed.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_handleWindowClose(window) {
|
|
||||||
for (let nativeTab of window.gBrowser.tabs) {
|
|
||||||
if (this.adoptedTabs.has(nativeTab)) {
|
|
||||||
this.emitDetached(nativeTab, this.adoptedTabs.get(nativeTab));
|
|
||||||
} else {
|
|
||||||
this.emitRemoved(nativeTab, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a "tab-activated" event for the given tab element.
|
|
||||||
*
|
|
||||||
* @param {NativeTab} nativeTab
|
|
||||||
* The tab element which has been activated.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
emitActivated(nativeTab) {
|
|
||||||
this.emit("tab-activated", {
|
|
||||||
tabId: this.getId(nativeTab),
|
|
||||||
windowId: windowTracker.getId(nativeTab.ownerGlobal)});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a "tab-attached" event for the given tab element.
|
|
||||||
*
|
|
||||||
* @param {NativeTab} nativeTab
|
|
||||||
* The tab element in the window to which the tab is being attached.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
emitAttached(nativeTab) {
|
|
||||||
let newWindowId = windowTracker.getId(nativeTab.ownerGlobal);
|
|
||||||
let tabId = this.getId(nativeTab);
|
|
||||||
|
|
||||||
this.emit("tab-attached", {nativeTab, tabId, newWindowId, newPosition: nativeTab._tPos});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a "tab-detached" event for the given tab element.
|
|
||||||
*
|
|
||||||
* @param {NativeTab} nativeTab
|
|
||||||
* The tab element in the window from which the tab is being detached.
|
|
||||||
* @param {NativeTab} adoptedBy
|
|
||||||
* The tab element in the window to which detached tab is being moved,
|
|
||||||
* and will adopt this tab's contents.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
emitDetached(nativeTab, adoptedBy) {
|
|
||||||
let oldWindowId = windowTracker.getId(nativeTab.ownerGlobal);
|
|
||||||
let tabId = this.getId(nativeTab);
|
|
||||||
|
|
||||||
this.emit("tab-detached", {nativeTab, adoptedBy, tabId, oldWindowId, oldPosition: nativeTab._tPos});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a "tab-created" event for the given tab element.
|
|
||||||
*
|
|
||||||
* @param {NativeTab} nativeTab
|
|
||||||
* The tab element which is being created.
|
|
||||||
* @param {NativeTab} [currentTab]
|
|
||||||
* The tab element for the currently active tab.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
emitCreated(nativeTab, currentTab) {
|
|
||||||
this.emit("tab-created", {nativeTab, currentTab});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a "tab-removed" event for the given tab element.
|
|
||||||
*
|
|
||||||
* @param {NativeTab} nativeTab
|
|
||||||
* The tab element which is being removed.
|
|
||||||
* @param {boolean} isWindowClosing
|
|
||||||
* True if the tab is being removed because the browser window is
|
|
||||||
* closing.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
emitRemoved(nativeTab, isWindowClosing) {
|
|
||||||
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
|
|
||||||
let tabId = this.getId(nativeTab);
|
|
||||||
|
|
||||||
// When addons run in-process, `window.close()` is synchronous. Most other
|
|
||||||
// addon-invoked calls are asynchronous since they go through a proxy
|
|
||||||
// context via the message manager. This includes event registrations such
|
|
||||||
// as `tabs.onRemoved.addListener`.
|
|
||||||
//
|
|
||||||
// So, even if `window.close()` were to be called (in-process) after calling
|
|
||||||
// `tabs.onRemoved.addListener`, then the tab would be closed before the
|
|
||||||
// event listener is registered. To make sure that the event listener is
|
|
||||||
// notified, we dispatch `tabs.onRemoved` asynchronously.
|
|
||||||
Services.tm.dispatchToMainThread(() => {
|
|
||||||
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getBrowserData(browser) {
|
|
||||||
if (browser.ownerGlobal.location.href === "about:addons") {
|
|
||||||
// When we're loaded into a <browser> inside about:addons, we need to go up
|
|
||||||
// one more level.
|
|
||||||
browser = browser.ownerGlobal.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDocShell)
|
|
||||||
.chromeEventHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = {
|
|
||||||
tabId: -1,
|
|
||||||
windowId: -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
let {gBrowser} = browser.ownerGlobal;
|
|
||||||
// Some non-browser windows have gBrowser but not
|
|
||||||
// getTabForBrowser!
|
|
||||||
if (gBrowser && gBrowser.getTabForBrowser) {
|
|
||||||
result.windowId = windowTracker.getId(browser.ownerGlobal);
|
|
||||||
|
|
||||||
let nativeTab = gBrowser.getTabForBrowser(browser);
|
|
||||||
if (nativeTab) {
|
|
||||||
result.tabId = this.getId(nativeTab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
get activeTab() {
|
|
||||||
let window = windowTracker.topWindow;
|
|
||||||
if (window && window.gBrowser) {
|
|
||||||
return window.gBrowser.selectedTab;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
windowTracker = new WindowTracker();
|
|
||||||
tabTracker = new TabTracker();
|
|
||||||
|
|
||||||
Object.assign(global, {tabTracker, windowTracker});
|
|
||||||
|
|
||||||
class Tab extends TabBase {
|
|
||||||
get _favIconUrl() {
|
|
||||||
return this.window.gBrowser.getIcon(this.nativeTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
get audible() {
|
|
||||||
return this.nativeTab.soundPlaying;
|
|
||||||
}
|
|
||||||
|
|
||||||
get browser() {
|
|
||||||
return this.nativeTab.linkedBrowser;
|
|
||||||
}
|
|
||||||
|
|
||||||
get frameLoader() {
|
|
||||||
// If we don't have a frameLoader yet, just return a dummy with no width and
|
|
||||||
// height.
|
|
||||||
return super.frameLoader || {lazyWidth: 0, lazyHeight: 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
get cookieStoreId() {
|
|
||||||
return getCookieStoreIdForTab(this, this.nativeTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
get height() {
|
|
||||||
return this.frameLoader.lazyHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
get index() {
|
|
||||||
return this.nativeTab._tPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
get mutedInfo() {
|
|
||||||
let {nativeTab} = this;
|
|
||||||
|
|
||||||
let mutedInfo = {muted: nativeTab.muted};
|
|
||||||
if (nativeTab.muteReason === null) {
|
|
||||||
mutedInfo.reason = "user";
|
|
||||||
} else if (nativeTab.muteReason) {
|
|
||||||
mutedInfo.reason = "extension";
|
|
||||||
mutedInfo.extensionId = nativeTab.muteReason;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mutedInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
get lastAccessed() {
|
|
||||||
return this.nativeTab.lastAccessed;
|
|
||||||
}
|
|
||||||
|
|
||||||
get pinned() {
|
|
||||||
return this.nativeTab.pinned;
|
|
||||||
}
|
|
||||||
|
|
||||||
get active() {
|
|
||||||
return this.nativeTab.selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
get selected() {
|
|
||||||
return this.nativeTab.selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
get status() {
|
|
||||||
if (this.nativeTab.getAttribute("busy") === "true") {
|
|
||||||
return "loading";
|
|
||||||
}
|
|
||||||
return "complete";
|
|
||||||
}
|
|
||||||
|
|
||||||
get width() {
|
|
||||||
return this.frameLoader.lazyWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
get window() {
|
|
||||||
return this.nativeTab.ownerGlobal;
|
|
||||||
}
|
|
||||||
|
|
||||||
get windowId() {
|
|
||||||
return windowTracker.getId(this.window);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts session store data to an object compatible with the return value
|
|
||||||
* of the convert() method, representing that data.
|
|
||||||
*
|
|
||||||
* @param {Extension} extension
|
|
||||||
* The extension for which to convert the data.
|
|
||||||
* @param {Object} tabData
|
|
||||||
* Session store data for a closed tab, as returned by
|
|
||||||
* `SessionStore.getClosedTabData()`.
|
|
||||||
* @param {DOMWindow} [window = null]
|
|
||||||
* The browser window which the tab belonged to before it was closed.
|
|
||||||
* May be null if the window the tab belonged to no longer exists.
|
|
||||||
*
|
|
||||||
* @returns {Object}
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
static convertFromSessionStoreClosedData(extension, tabData, window = null) {
|
|
||||||
let result = {
|
|
||||||
sessionId: String(tabData.closedId),
|
|
||||||
index: tabData.pos ? tabData.pos : 0,
|
|
||||||
windowId: window && windowTracker.getId(window),
|
|
||||||
highlighted: false,
|
|
||||||
active: false,
|
|
||||||
pinned: false,
|
|
||||||
incognito: Boolean(tabData.state && tabData.state.isPrivate),
|
|
||||||
lastAccessed: tabData.state ? tabData.state.lastAccessed : tabData.lastAccessed,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (extension.tabManager.hasTabPermission(tabData)) {
|
|
||||||
let entries = tabData.state ? tabData.state.entries : tabData.entries;
|
|
||||||
let entry = entries[entries.length - 1];
|
|
||||||
result.url = entry.url;
|
|
||||||
result.title = entry.title;
|
|
||||||
if (tabData.image) {
|
|
||||||
result.favIconUrl = tabData.image;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Window extends WindowBase {
|
|
||||||
/**
|
|
||||||
* Update the geometry of the browser window.
|
|
||||||
*
|
|
||||||
* @param {Object} options
|
|
||||||
* An object containing new values for the window's geometry.
|
|
||||||
* @param {integer} [options.left]
|
|
||||||
* The new pixel distance of the left side of the browser window from
|
|
||||||
* the left of the screen.
|
|
||||||
* @param {integer} [options.top]
|
|
||||||
* The new pixel distance of the top side of the browser window from
|
|
||||||
* the top of the screen.
|
|
||||||
* @param {integer} [options.width]
|
|
||||||
* The new pixel width of the window.
|
|
||||||
* @param {integer} [options.height]
|
|
||||||
* The new pixel height of the window.
|
|
||||||
*/
|
|
||||||
updateGeometry(options) {
|
|
||||||
let {window} = this;
|
|
||||||
|
|
||||||
if (options.left !== null || options.top !== null) {
|
|
||||||
let left = options.left !== null ? options.left : window.screenX;
|
|
||||||
let top = options.top !== null ? options.top : window.screenY;
|
|
||||||
window.moveTo(left, top);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.width !== null || options.height !== null) {
|
|
||||||
let width = options.width !== null ? options.width : window.outerWidth;
|
|
||||||
let height = options.height !== null ? options.height : window.outerHeight;
|
|
||||||
window.resizeTo(width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get title() {
|
|
||||||
return this.window.document.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTitlePreface(titlePreface) {
|
|
||||||
this.window.document.documentElement.setAttribute("titlepreface", titlePreface);
|
|
||||||
}
|
|
||||||
|
|
||||||
get focused() {
|
|
||||||
return this.window.document.hasFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
get top() {
|
|
||||||
return this.window.screenY;
|
|
||||||
}
|
|
||||||
|
|
||||||
get left() {
|
|
||||||
return this.window.screenX;
|
|
||||||
}
|
|
||||||
|
|
||||||
get width() {
|
|
||||||
return this.window.outerWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
get height() {
|
|
||||||
return this.window.outerHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
get incognito() {
|
|
||||||
return PrivateBrowsingUtils.isWindowPrivate(this.window);
|
|
||||||
}
|
|
||||||
|
|
||||||
get alwaysOnTop() {
|
|
||||||
return this.xulWindow.zLevel >= Ci.nsIXULWindow.raisedZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isLastFocused() {
|
|
||||||
return this.window === windowTracker.topWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
static getState(window) {
|
|
||||||
const STATES = {
|
|
||||||
[window.STATE_MAXIMIZED]: "maximized",
|
|
||||||
[window.STATE_MINIMIZED]: "minimized",
|
|
||||||
[window.STATE_NORMAL]: "normal",
|
|
||||||
};
|
|
||||||
let state = STATES[window.windowState];
|
|
||||||
if (window.fullScreen) {
|
|
||||||
state = "fullscreen";
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
get state() {
|
|
||||||
return Window.getState(this.window);
|
|
||||||
}
|
|
||||||
|
|
||||||
set state(state) {
|
|
||||||
let {window} = this;
|
|
||||||
if (state !== "fullscreen" && window.fullScreen) {
|
|
||||||
window.fullScreen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case "maximized":
|
|
||||||
window.maximize();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "minimized":
|
|
||||||
case "docked":
|
|
||||||
window.minimize();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "normal":
|
|
||||||
// Restore sometimes returns the window to its previous state, rather
|
|
||||||
// than to the "normal" state, so it may need to be called anywhere from
|
|
||||||
// zero to two times.
|
|
||||||
window.restore();
|
|
||||||
if (window.windowState !== window.STATE_NORMAL) {
|
|
||||||
window.restore();
|
|
||||||
}
|
|
||||||
if (window.windowState !== window.STATE_NORMAL) {
|
|
||||||
// And on OS-X, where normal vs. maximized is basically a heuristic,
|
|
||||||
// we need to cheat.
|
|
||||||
window.sizeToContent();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "fullscreen":
|
|
||||||
window.fullScreen = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`Unexpected window state: ${state}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
* getTabs() {
|
|
||||||
let {tabManager} = this.extension;
|
|
||||||
|
|
||||||
for (let nativeTab of this.window.gBrowser.tabs) {
|
|
||||||
yield tabManager.getWrapper(nativeTab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts session store data to an object compatible with the return value
|
|
||||||
* of the convert() method, representing that data.
|
|
||||||
*
|
|
||||||
* @param {Extension} extension
|
|
||||||
* The extension for which to convert the data.
|
|
||||||
* @param {Object} windowData
|
|
||||||
* Session store data for a closed window, as returned by
|
|
||||||
* `SessionStore.getClosedWindowData()`.
|
|
||||||
*
|
|
||||||
* @returns {Object}
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
static convertFromSessionStoreClosedData(extension, windowData) {
|
|
||||||
let result = {
|
|
||||||
sessionId: String(windowData.closedId),
|
|
||||||
focused: false,
|
|
||||||
incognito: false,
|
|
||||||
type: "normal", // this is always "normal" for a closed window
|
|
||||||
// Surely this does not actually work?
|
|
||||||
state: this.getState(windowData),
|
|
||||||
alwaysOnTop: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (windowData.tabs.length) {
|
|
||||||
result.tabs = windowData.tabs.map(tabData => {
|
|
||||||
return Tab.convertFromSessionStoreClosedData(extension, tabData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(global, {Tab, Window});
|
|
||||||
|
|
||||||
class TabManager extends TabManagerBase {
|
|
||||||
get(tabId, default_ = undefined) {
|
|
||||||
let nativeTab = tabTracker.getTab(tabId, default_);
|
|
||||||
|
|
||||||
if (nativeTab) {
|
|
||||||
return this.getWrapper(nativeTab);
|
|
||||||
}
|
|
||||||
return default_;
|
|
||||||
}
|
|
||||||
|
|
||||||
addActiveTabPermission(nativeTab = tabTracker.activeTab) {
|
|
||||||
return super.addActiveTabPermission(nativeTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
revokeActiveTabPermission(nativeTab = tabTracker.activeTab) {
|
|
||||||
return super.revokeActiveTabPermission(nativeTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapTab(nativeTab) {
|
|
||||||
return new Tab(this.extension, nativeTab, tabTracker.getId(nativeTab));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WindowManager extends WindowManagerBase {
|
|
||||||
get(windowId, context) {
|
|
||||||
let window = windowTracker.getWindow(windowId, context);
|
|
||||||
|
|
||||||
return this.getWrapper(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
* getAll() {
|
|
||||||
for (let window of windowTracker.browserWindows()) {
|
|
||||||
yield this.getWrapper(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapWindow(window) {
|
|
||||||
return new Window(this.extension, window, windowTracker.getId(window));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extensions.on("startup", (type, extension) => { // eslint-disable-line mozilla/balanced-listeners
|
|
||||||
defineLazyGetter(extension, "tabManager",
|
|
||||||
() => new TabManager(extension));
|
|
||||||
defineLazyGetter(extension, "windowManager",
|
|
||||||
() => new WindowManager(extension));
|
|
||||||
});
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-utils.js */
|
/* import-globals-from ext-browser.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
|
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
|
||||||
"@mozilla.org/browser/aboutnewtab-service;1",
|
"@mozilla.org/browser/aboutnewtab-service;1",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
category webextension-scripts browser chrome://browser/content/ext-browser.js
|
category webextension-modules browser chrome://browser/content/ext-browser.json
|
||||||
category webextension-scripts utils chrome://browser/content/ext-utils.js
|
|
||||||
|
category webextension-scripts c-browser chrome://browser/content/ext-browser.js
|
||||||
category webextension-scripts-devtools browser chrome://browser/content/ext-c-browser.js
|
category webextension-scripts-devtools browser chrome://browser/content/ext-c-browser.js
|
||||||
category webextension-scripts-addon browser chrome://browser/content/ext-c-browser.js
|
category webextension-scripts-addon browser chrome://browser/content/ext-c-browser.js
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ browser.jar:
|
|||||||
content/browser/extension.svg
|
content/browser/extension.svg
|
||||||
content/browser/ext-bookmarks.js
|
content/browser/ext-bookmarks.js
|
||||||
content/browser/ext-browser.js
|
content/browser/ext-browser.js
|
||||||
|
content/browser/ext-browser.json
|
||||||
content/browser/ext-browserAction.js
|
content/browser/ext-browserAction.js
|
||||||
content/browser/ext-browsingData.js
|
content/browser/ext-browsingData.js
|
||||||
content/browser/ext-chrome-settings-overrides.js
|
content/browser/ext-chrome-settings-overrides.js
|
||||||
@@ -31,7 +32,6 @@ browser.jar:
|
|||||||
content/browser/ext-sidebarAction.js
|
content/browser/ext-sidebarAction.js
|
||||||
content/browser/ext-tabs.js
|
content/browser/ext-tabs.js
|
||||||
content/browser/ext-url-overrides.js
|
content/browser/ext-url-overrides.js
|
||||||
content/browser/ext-utils.js
|
|
||||||
content/browser/ext-windows.js
|
content/browser/ext-windows.js
|
||||||
content/browser/ext-c-browser.js
|
content/browser/ext-c-browser.js
|
||||||
content/browser/ext-c-devtools-inspectedWindow.js
|
content/browser/ext-c-devtools-inspectedWindow.js
|
||||||
|
|||||||
@@ -509,10 +509,18 @@ Section "-Application" APP_IDX
|
|||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; Update lastwritetime of the Start Menu shortcut to clear the tile cache.
|
; Update lastwritetime of the Start Menu shortcut to clear the tile cache.
|
||||||
|
; Do this for both shell contexts in case the user has shortcuts in multiple
|
||||||
|
; locations, then restore the previous context at the end.
|
||||||
${If} ${AtLeastWin8}
|
${If} ${AtLeastWin8}
|
||||||
${AndIf} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk"
|
SetShellVarContext all
|
||||||
FileOpen $0 "$SMPROGRAMS\${BrandFullName}.lnk" a
|
${TouchStartMenuShortcut}
|
||||||
FileClose $0
|
SetShellVarContext current
|
||||||
|
${TouchStartMenuShortcut}
|
||||||
|
${If} $TmpVal == "HKLM"
|
||||||
|
SetShellVarContext all
|
||||||
|
${ElseIf} $TmpVal == "HKCU"
|
||||||
|
SetShellVarContext current
|
||||||
|
${EndIf}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
${If} $AddDesktopSC == 1
|
${If} $AddDesktopSC == 1
|
||||||
|
|||||||
@@ -71,10 +71,18 @@
|
|||||||
${MigrateStartMenuShortcut}
|
${MigrateStartMenuShortcut}
|
||||||
|
|
||||||
; Update lastwritetime of the Start Menu shortcut to clear the tile cache.
|
; Update lastwritetime of the Start Menu shortcut to clear the tile cache.
|
||||||
|
; Do this for both shell contexts in case the user has shortcuts in multiple
|
||||||
|
; locations, then restore the previous context at the end.
|
||||||
${If} ${AtLeastWin8}
|
${If} ${AtLeastWin8}
|
||||||
${AndIf} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk"
|
SetShellVarContext all
|
||||||
FileOpen $0 "$SMPROGRAMS\${BrandFullName}.lnk" a
|
${TouchStartMenuShortcut}
|
||||||
FileClose $0
|
SetShellVarContext current
|
||||||
|
${TouchStartMenuShortcut}
|
||||||
|
${If} $TmpVal == "HKLM"
|
||||||
|
SetShellVarContext all
|
||||||
|
${ElseIf} $TmpVal == "HKCU"
|
||||||
|
SetShellVarContext current
|
||||||
|
${EndIf}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
|
; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
|
||||||
@@ -152,6 +160,22 @@
|
|||||||
!macroend
|
!macroend
|
||||||
!define PostUpdate "!insertmacro PostUpdate"
|
!define PostUpdate "!insertmacro PostUpdate"
|
||||||
|
|
||||||
|
; Update the last modified time on the Start Menu shortcut, so that its icon
|
||||||
|
; gets refreshed. Should be called on Win8+ after MigrateStartMenuShortcut.
|
||||||
|
!macro TouchStartMenuShortcut
|
||||||
|
${If} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk"
|
||||||
|
FileOpen $0 "$SMPROGRAMS\${BrandFullName}.lnk" a
|
||||||
|
${IfNot} ${Errors}
|
||||||
|
System::Call '*(i, i) p .r1'
|
||||||
|
System::Call 'kernel32::GetSystemTimeAsFileTime(p r1)'
|
||||||
|
System::Call 'kernel32::SetFileTime(p r0, i 0, i 0, p r1) i .r2'
|
||||||
|
System::Free $1
|
||||||
|
FileClose $0
|
||||||
|
${EndIf}
|
||||||
|
${EndIf}
|
||||||
|
!macroend
|
||||||
|
!define TouchStartMenuShortcut "!insertmacro TouchStartMenuShortcut"
|
||||||
|
|
||||||
!macro SetAsDefaultAppGlobal
|
!macro SetAsDefaultAppGlobal
|
||||||
${RemoveDeprecatedKeys} ; Does not use SHCTX
|
${RemoveDeprecatedKeys} ; Does not use SHCTX
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ gyp_vars.update({
|
|||||||
'use_official_google_api_keys': 0,
|
'use_official_google_api_keys': 0,
|
||||||
'have_clock_monotonic': 1 if CONFIG['HAVE_CLOCK_MONOTONIC'] else 0,
|
'have_clock_monotonic': 1 if CONFIG['HAVE_CLOCK_MONOTONIC'] else 0,
|
||||||
'have_ethtool_cmd_speed_hi': 1 if CONFIG['MOZ_WEBRTC_HAVE_ETHTOOL_SPEED_HI'] else 0,
|
'have_ethtool_cmd_speed_hi': 1 if CONFIG['MOZ_WEBRTC_HAVE_ETHTOOL_SPEED_HI'] else 0,
|
||||||
'include_alsa_audio': 0,
|
'include_alsa_audio': 1 if CONFIG['MOZ_ALSA'] else 0,
|
||||||
'include_pulse_audio': 1 if CONFIG['MOZ_PULSEAUDIO'] else 0,
|
'include_pulse_audio': 1 if CONFIG['MOZ_PULSEAUDIO'] else 0,
|
||||||
# basic stuff for everything
|
# basic stuff for everything
|
||||||
'include_internal_video_render': 0,
|
'include_internal_video_render': 0,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
* (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
* (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
* Underscore may be freely distributed under the MIT license.
|
* Underscore may be freely distributed under the MIT license.
|
||||||
*
|
*
|
||||||
* [and in turn extracted from "sdk/lang/functional/concurrent.js"]
|
* [and in turn extracted from the SDK's "lang/functional/concurrent.js"]
|
||||||
*/
|
*/
|
||||||
exports.debounce = function (fn, wait) {
|
exports.debounce = function (fn, wait) {
|
||||||
let timeout, args, context, timestamp, result;
|
let timeout, args, context, timestamp, result;
|
||||||
|
|||||||
@@ -47,10 +47,18 @@ enum {
|
|||||||
// bit is set, and if so it indicates whether we're only whitespace or
|
// bit is set, and if so it indicates whether we're only whitespace or
|
||||||
// not.
|
// not.
|
||||||
NS_TEXT_IS_ONLY_WHITESPACE = DATA_NODE_FLAG_BIT(3),
|
NS_TEXT_IS_ONLY_WHITESPACE = DATA_NODE_FLAG_BIT(3),
|
||||||
|
|
||||||
|
// This bit is set if there is a NewlineProperty attached to the node
|
||||||
|
// (used by nsTextFrame).
|
||||||
|
NS_HAS_NEWLINE_PROPERTY = DATA_NODE_FLAG_BIT(4),
|
||||||
|
|
||||||
|
// This bit is set if there is a FlowLengthProperty attached to the node
|
||||||
|
// (used by nsTextFrame).
|
||||||
|
NS_HAS_FLOWLENGTH_PROPERTY = DATA_NODE_FLAG_BIT(5),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure we have enough space for those bits
|
// Make sure we have enough space for those bits
|
||||||
ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET + 4);
|
ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET + 6);
|
||||||
|
|
||||||
#undef DATA_NODE_FLAG_BIT
|
#undef DATA_NODE_FLAG_BIT
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ const int32_t kTimeBetweenChecks = 45; /* seconds */
|
|||||||
nsWindowMemoryReporter::nsWindowMemoryReporter()
|
nsWindowMemoryReporter::nsWindowMemoryReporter()
|
||||||
: mLastCheckForGhostWindows(TimeStamp::NowLoRes()),
|
: mLastCheckForGhostWindows(TimeStamp::NowLoRes()),
|
||||||
mCycleCollectorIsRunning(false),
|
mCycleCollectorIsRunning(false),
|
||||||
mCheckTimerWaitingForCCEnd(false),
|
mCheckTimerWaitingForCCEnd(false)
|
||||||
mGhostWindowCount(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +119,8 @@ nsWindowMemoryReporter::Init()
|
|||||||
/* weakRef = */ true);
|
/* weakRef = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterGhostWindowsDistinguishedAmount(GhostWindowsDistinguishedAmount);
|
RegisterStrongMemoryReporter(new GhostWindowsReporter());
|
||||||
|
RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsWindowMemoryReporter*
|
/* static */ nsWindowMemoryReporter*
|
||||||
@@ -506,17 +506,6 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
|
|||||||
aData);
|
aData);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_COLLECT_REPORT(
|
|
||||||
"ghost-windows", KIND_OTHER, UNITS_COUNT, ghostWindows.Count(),
|
|
||||||
"The number of ghost windows present (the number of nodes underneath "
|
|
||||||
"explicit/window-objects/top(none)/ghost, modulo race conditions). A ghost "
|
|
||||||
"window is not shown in any tab, does not share a domain with any non-detached "
|
|
||||||
"windows, and has met these criteria for at least "
|
|
||||||
"memory.ghost_window_timeout_seconds, or has survived a round of "
|
|
||||||
"about:memory's minimize memory usage button.\n\n"
|
|
||||||
"Ghost windows can happen legitimately, but they are often indicative of "
|
|
||||||
"leaks in the browser or add-ons.");
|
|
||||||
|
|
||||||
WindowPaths windowPaths;
|
WindowPaths windowPaths;
|
||||||
WindowPaths topWindowPaths;
|
WindowPaths topWindowPaths;
|
||||||
|
|
||||||
@@ -761,7 +750,6 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
|||||||
KillCheckTimer();
|
KillCheckTimer();
|
||||||
|
|
||||||
nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
|
nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
|
||||||
nsDataHashtable<nsISupportsHashKey, nsCString> domainMap;
|
|
||||||
|
|
||||||
// Populate nonDetachedWindowDomains.
|
// Populate nonDetachedWindowDomains.
|
||||||
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
||||||
@@ -776,13 +764,8 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
|||||||
nsCOMPtr<nsIURI> uri = GetWindowURI(window);
|
nsCOMPtr<nsIURI> uri = GetWindowURI(window);
|
||||||
nsAutoCString domain;
|
nsAutoCString domain;
|
||||||
if (uri) {
|
if (uri) {
|
||||||
domain = domainMap.LookupForAdd(uri).OrInsert([&]() {
|
tldService->GetBaseDomain(uri, 0, domain);
|
||||||
nsCString d;
|
|
||||||
tldService->GetBaseDomain(uri, 0, d);
|
|
||||||
return d;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nonDetachedWindowDomains.PutEntry(domain);
|
nonDetachedWindowDomains.PutEntry(domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,7 +773,6 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
|||||||
// if it's not null.
|
// if it's not null.
|
||||||
uint32_t ghostTimeout = GetGhostTimeout();
|
uint32_t ghostTimeout = GetGhostTimeout();
|
||||||
TimeStamp now = mLastCheckForGhostWindows;
|
TimeStamp now = mLastCheckForGhostWindows;
|
||||||
mGhostWindowCount = 0;
|
|
||||||
for (auto iter = mDetachedWindows.Iter(); !iter.Done(); iter.Next()) {
|
for (auto iter = mDetachedWindows.Iter(); !iter.Done(); iter.Next()) {
|
||||||
nsWeakPtr weakKey = do_QueryInterface(iter.Key());
|
nsWeakPtr weakKey = do_QueryInterface(iter.Key());
|
||||||
nsCOMPtr<mozIDOMWindow> iwindow = do_QueryReferent(weakKey);
|
nsCOMPtr<mozIDOMWindow> iwindow = do_QueryReferent(weakKey);
|
||||||
@@ -841,7 +823,6 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
|||||||
} else if ((now - timeStamp).ToSeconds() > ghostTimeout) {
|
} else if ((now - timeStamp).ToSeconds() > ghostTimeout) {
|
||||||
// This definitely is a ghost window, so add it to aOutGhostIDs, if
|
// This definitely is a ghost window, so add it to aOutGhostIDs, if
|
||||||
// that is not null.
|
// that is not null.
|
||||||
mGhostWindowCount++;
|
|
||||||
if (aOutGhostIDs && window) {
|
if (aOutGhostIDs && window) {
|
||||||
aOutGhostIDs->PutEntry(window->WindowID());
|
aOutGhostIDs->PutEntry(window->WindowID());
|
||||||
}
|
}
|
||||||
@@ -850,10 +831,15 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(nsWindowMemoryReporter::GhostWindowsReporter,
|
||||||
|
nsIMemoryReporter)
|
||||||
|
|
||||||
/* static */ int64_t
|
/* static */ int64_t
|
||||||
nsWindowMemoryReporter::GhostWindowsDistinguishedAmount()
|
nsWindowMemoryReporter::GhostWindowsReporter::DistinguishedAmount()
|
||||||
{
|
{
|
||||||
return sWindowReporter->mGhostWindowCount;
|
nsTHashtable<nsUint64HashKey> ghostWindows;
|
||||||
|
sWindowReporter->CheckForGhostWindows(&ghostWindows);
|
||||||
|
return ghostWindows.Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -164,11 +164,40 @@ public:
|
|||||||
static nsWindowMemoryReporter* Get();
|
static nsWindowMemoryReporter* Get();
|
||||||
void ObserveDOMWindowDetached(nsGlobalWindow* aWindow);
|
void ObserveDOMWindowDetached(nsGlobalWindow* aWindow);
|
||||||
|
|
||||||
static int64_t GhostWindowsDistinguishedAmount();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~nsWindowMemoryReporter();
|
~nsWindowMemoryReporter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nsGhostWindowReporter generates the "ghost-windows" report, which counts
|
||||||
|
* the number of ghost windows present.
|
||||||
|
*/
|
||||||
|
class GhostWindowsReporter final : public nsIMemoryReporter
|
||||||
|
{
|
||||||
|
~GhostWindowsReporter() {}
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
static int64_t DistinguishedAmount();
|
||||||
|
|
||||||
|
NS_IMETHOD
|
||||||
|
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
|
||||||
|
bool aAnonymize) override
|
||||||
|
{
|
||||||
|
MOZ_COLLECT_REPORT(
|
||||||
|
"ghost-windows", KIND_OTHER, UNITS_COUNT, DistinguishedAmount(),
|
||||||
|
"The number of ghost windows present (the number of nodes underneath "
|
||||||
|
"explicit/window-objects/top(none)/ghost, modulo race conditions). A ghost "
|
||||||
|
"window is not shown in any tab, does not share a domain with any non-detached "
|
||||||
|
"windows, and has met these criteria for at least "
|
||||||
|
"memory.ghost_window_timeout_seconds, or has survived a round of "
|
||||||
|
"about:memory's minimize memory usage button.\n\n"
|
||||||
|
"Ghost windows can happen legitimately, but they are often indicative of "
|
||||||
|
"leaks in the browser or add-ons.");
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Protect ctor, use Init() instead.
|
// Protect ctor, use Init() instead.
|
||||||
nsWindowMemoryReporter();
|
nsWindowMemoryReporter();
|
||||||
|
|
||||||
@@ -231,8 +260,6 @@ private:
|
|||||||
bool mCycleCollectorIsRunning;
|
bool mCycleCollectorIsRunning;
|
||||||
|
|
||||||
bool mCheckTimerWaitingForCCEnd;
|
bool mCheckTimerWaitingForCCEnd;
|
||||||
|
|
||||||
int64_t mGhostWindowCount;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsWindowMemoryReporter_h__
|
#endif // nsWindowMemoryReporter_h__
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ function runTest() {
|
|||||||
win.focus();
|
win.focus();
|
||||||
}, 0);
|
}, 0);
|
||||||
}, {once: true});
|
}, {once: true});
|
||||||
iframe.src = "data:text/html,";
|
iframe.srcdoc = "foo";
|
||||||
}, SimpleTest.finish);
|
}, SimpleTest.finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -823,6 +823,9 @@ public:
|
|||||||
|
|
||||||
const RefPtr<UnscaledFont>& GetUnscaledFont() const { return mUnscaledFont; }
|
const RefPtr<UnscaledFont>& GetUnscaledFont() const { return mUnscaledFont; }
|
||||||
|
|
||||||
|
virtual cairo_scaled_font_t* GetCairoScaledFont() { return nullptr; }
|
||||||
|
virtual void SetCairoScaledFont(cairo_scaled_font_t* font) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit ScaledFont(const RefPtr<UnscaledFont>& aUnscaledFont)
|
explicit ScaledFont(const RefPtr<UnscaledFont>& aUnscaledFont)
|
||||||
: mUnscaledFont(aUnscaledFont)
|
: mUnscaledFont(aUnscaledFont)
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ public:
|
|||||||
|
|
||||||
#ifdef USE_CAIRO_SCALED_FONT
|
#ifdef USE_CAIRO_SCALED_FONT
|
||||||
bool PopulateCairoScaledFont();
|
bool PopulateCairoScaledFont();
|
||||||
cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; }
|
virtual cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; }
|
||||||
void SetCairoScaledFont(cairo_scaled_font_t* font);
|
virtual void SetCairoScaledFont(cairo_scaled_font_t* font);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -262,12 +262,6 @@ gfxAndroidPlatform::GetFTLibrary()
|
|||||||
return gPlatformFTLibrary;
|
return gPlatformFTLibrary;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<ScaledFont>
|
|
||||||
gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
|
|
||||||
{
|
|
||||||
return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
gfxAndroidPlatform::FontHintingEnabled()
|
gfxAndroidPlatform::FontHintingEnabled()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ public:
|
|||||||
|
|
||||||
virtual gfxImageFormat GetOffscreenFormat() override { return mOffscreenFormat; }
|
virtual gfxImageFormat GetOffscreenFormat() override { return mOffscreenFormat; }
|
||||||
|
|
||||||
already_AddRefed<mozilla::gfx::ScaledFont>
|
|
||||||
GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont) override;
|
|
||||||
|
|
||||||
// to support IPC font list (sharing between chrome and content)
|
// to support IPC font list (sharing between chrome and content)
|
||||||
void GetSystemFontList(InfallibleTArray<FontListEntry>* retValue);
|
void GetSystemFontList(InfallibleTArray<FontListEntry>* retValue);
|
||||||
|
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ gfxDWriteFont::GetSpaceGlyph()
|
|||||||
bool
|
bool
|
||||||
gfxDWriteFont::SetupCairoFont(DrawTarget* aDrawTarget)
|
gfxDWriteFont::SetupCairoFont(DrawTarget* aDrawTarget)
|
||||||
{
|
{
|
||||||
cairo_scaled_font_t *scaledFont = GetCairoScaledFont();
|
cairo_scaled_font_t *scaledFont = InitCairoScaledFont();
|
||||||
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
|
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
|
||||||
// Don't cairo_set_scaled_font as that would propagate the error to
|
// Don't cairo_set_scaled_font as that would propagate the error to
|
||||||
// the cairo_t, precluding any further drawing.
|
// the cairo_t, precluding any further drawing.
|
||||||
@@ -497,7 +497,7 @@ gfxDWriteFont::CairoFontFace()
|
|||||||
|
|
||||||
|
|
||||||
cairo_scaled_font_t *
|
cairo_scaled_font_t *
|
||||||
gfxDWriteFont::GetCairoScaledFont()
|
gfxDWriteFont::InitCairoScaledFont()
|
||||||
{
|
{
|
||||||
if (!mScaledFont) {
|
if (!mScaledFont) {
|
||||||
cairo_matrix_t sizeMatrix;
|
cairo_matrix_t sizeMatrix;
|
||||||
@@ -679,31 +679,19 @@ gfxDWriteFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|||||||
already_AddRefed<ScaledFont>
|
already_AddRefed<ScaledFont>
|
||||||
gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
|
gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
|
||||||
{
|
{
|
||||||
bool wantCairo = aTarget->GetBackendType() == BackendType::CAIRO;
|
if (!mAzureScaledFont) {
|
||||||
if (mAzureScaledFont && mAzureScaledFontIsCairo == wantCairo) {
|
|
||||||
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
|
||||||
return scaledFont.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeFont nativeFont;
|
|
||||||
nativeFont.mType = NativeFontType::DWRITE_FONT_FACE;
|
|
||||||
nativeFont.mFont = GetFontFace();
|
|
||||||
|
|
||||||
if (wantCairo) {
|
|
||||||
mAzureScaledFont = Factory::CreateScaledFontWithCairo(nativeFont,
|
|
||||||
GetUnscaledFont(),
|
|
||||||
GetAdjustedSize(),
|
|
||||||
GetCairoScaledFont());
|
|
||||||
} else {
|
|
||||||
gfxDWriteFontEntry *fe =
|
gfxDWriteFontEntry *fe =
|
||||||
static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
|
static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
|
||||||
bool useEmbeddedBitmap = (fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize)));
|
bool useEmbeddedBitmap =
|
||||||
|
fe->IsCJKFont() &&
|
||||||
|
HasBitmapStrikeForSize(NS_lround(mAdjustedSize));
|
||||||
bool forceGDI = GetForceGDIClassic();
|
bool forceGDI = GetForceGDIClassic();
|
||||||
|
|
||||||
IDWriteRenderingParams* params = gfxWindowsPlatform::GetPlatform()->GetRenderingParams(
|
IDWriteRenderingParams* params = gfxWindowsPlatform::GetPlatform()->GetRenderingParams(
|
||||||
mUseClearType ?
|
mUseClearType ?
|
||||||
(forceGDI ?
|
(forceGDI ?
|
||||||
gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC : gfxWindowsPlatform::TEXT_RENDERING_NORMAL) :
|
gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC :
|
||||||
|
gfxWindowsPlatform::TEXT_RENDERING_NORMAL) :
|
||||||
gfxWindowsPlatform::TEXT_RENDERING_NO_CLEARTYPE);
|
gfxWindowsPlatform::TEXT_RENDERING_NO_CLEARTYPE);
|
||||||
|
|
||||||
const gfxFontStyle* fontStyle = GetStyle();
|
const gfxFontStyle* fontStyle = GetStyle();
|
||||||
@@ -716,9 +704,20 @@ gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
|
|||||||
params,
|
params,
|
||||||
params->GetGamma(),
|
params->GetGamma(),
|
||||||
params->GetEnhancedContrast());
|
params->GetEnhancedContrast());
|
||||||
|
if (!mAzureScaledFont) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mAzureScaledFontIsCairo = wantCairo;
|
if (aTarget->GetBackendType() == BackendType::CAIRO) {
|
||||||
|
if (!mAzureScaledFont->GetCairoScaledFont()) {
|
||||||
|
cairo_scaled_font_t* cairoScaledFont = InitCairoScaledFont();
|
||||||
|
if (!cairoScaledFont) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
mAzureScaledFont->SetCairoScaledFont(cairoScaledFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
||||||
return scaledFont.forget();
|
return scaledFont.forget();
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ public:
|
|||||||
virtual already_AddRefed<mozilla::gfx::ScaledFont>
|
virtual already_AddRefed<mozilla::gfx::ScaledFont>
|
||||||
GetScaledFont(mozilla::gfx::DrawTarget *aTarget) override;
|
GetScaledFont(mozilla::gfx::DrawTarget *aTarget) override;
|
||||||
|
|
||||||
virtual cairo_scaled_font_t *GetCairoScaledFont() override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
cairo_scaled_font_t *InitCairoScaledFont();
|
||||||
|
|
||||||
virtual const Metrics& GetHorizontalMetrics() override;
|
virtual const Metrics& GetHorizontalMetrics() override;
|
||||||
|
|
||||||
bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics);
|
bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics);
|
||||||
@@ -105,7 +105,6 @@ protected:
|
|||||||
bool mNeedsBold;
|
bool mNeedsBold;
|
||||||
bool mUseSubpixelPositions;
|
bool mUseSubpixelPositions;
|
||||||
bool mAllowManualShowGlyphs;
|
bool mAllowManualShowGlyphs;
|
||||||
bool mAzureScaledFontIsCairo;
|
|
||||||
static bool mUseClearType;
|
static bool mUseClearType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ gfxFT2FontBase::GetGlyph(uint32_t aCharCode)
|
|||||||
// lightweight cache, which is stored on the cairo_font_face_t.
|
// lightweight cache, which is stored on the cairo_font_face_t.
|
||||||
|
|
||||||
cairo_font_face_t *face =
|
cairo_font_face_t *face =
|
||||||
cairo_scaled_font_get_font_face(CairoScaledFont());
|
cairo_scaled_font_get_font_face(GetCairoScaledFont());
|
||||||
|
|
||||||
if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS)
|
if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -113,7 +113,7 @@ gfxFT2FontBase::GetGlyphExtents(uint32_t aGlyph, cairo_text_extents_t* aExtents)
|
|||||||
// so caching only the advance could allow many requests to be cached with
|
// so caching only the advance could allow many requests to be cached with
|
||||||
// little memory use. Ideally this cache would be merged with
|
// little memory use. Ideally this cache would be merged with
|
||||||
// gfxGlyphExtents.
|
// gfxGlyphExtents.
|
||||||
cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs, 1, aExtents);
|
cairo_scaled_font_glyph_extents(GetCairoScaledFont(), glyphs, 1, aExtents);
|
||||||
}
|
}
|
||||||
|
|
||||||
// aScale is intended for a 16.16 x/y_scale of an FT_Size_Metrics
|
// aScale is intended for a 16.16 x/y_scale of an FT_Size_Metrics
|
||||||
@@ -486,7 +486,7 @@ gfxFT2FontBase::SetupCairoFont(DrawTarget* aDrawTarget)
|
|||||||
// for the target can be different from the scaled_font passed to
|
// for the target can be different from the scaled_font passed to
|
||||||
// cairo_set_scaled_font. (Unfortunately we have measured only for an
|
// cairo_set_scaled_font. (Unfortunately we have measured only for an
|
||||||
// identity ctm.)
|
// identity ctm.)
|
||||||
cairo_scaled_font_t *cairoFont = CairoScaledFont();
|
cairo_scaled_font_t *cairoFont = GetCairoScaledFont();
|
||||||
|
|
||||||
if (cairo_scaled_font_status(cairoFont) != CAIRO_STATUS_SUCCESS) {
|
if (cairo_scaled_font_status(cairoFont) != CAIRO_STATUS_SUCCESS) {
|
||||||
// Don't cairo_set_scaled_font as that would propagate the error to
|
// Don't cairo_set_scaled_font as that would propagate the error to
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ public:
|
|||||||
virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget,
|
virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget,
|
||||||
uint16_t aGID) override;
|
uint16_t aGID) override;
|
||||||
|
|
||||||
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
|
|
||||||
virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
|
virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
|
||||||
|
|
||||||
virtual FontType GetType() const override { return FONT_TYPE_FT2; }
|
virtual FontType GetType() const override { return FONT_TYPE_FT2; }
|
||||||
|
|||||||
@@ -34,6 +34,9 @@
|
|||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/gfx/2D.h"
|
#include "mozilla/gfx/2D.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::gfx;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gfxFT2Font
|
* gfxFT2Font
|
||||||
*/
|
*/
|
||||||
@@ -157,7 +160,7 @@ gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxFT2Font::gfxFT2Font(const RefPtr<mozilla::gfx::UnscaledFontFreeType>& aUnscaledFont,
|
gfxFT2Font::gfxFT2Font(const RefPtr<UnscaledFontFreeType>& aUnscaledFont,
|
||||||
cairo_scaled_font_t *aCairoFont,
|
cairo_scaled_font_t *aCairoFont,
|
||||||
FT2FontEntry *aFontEntry,
|
FT2FontEntry *aFontEntry,
|
||||||
const gfxFontStyle *aFontStyle,
|
const gfxFontStyle *aFontStyle,
|
||||||
@@ -173,6 +176,23 @@ gfxFT2Font::~gfxFT2Font()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<ScaledFont>
|
||||||
|
gfxFT2Font::GetScaledFont(DrawTarget *aTarget)
|
||||||
|
{
|
||||||
|
if (!mAzureScaledFont) {
|
||||||
|
NativeFont nativeFont;
|
||||||
|
nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
|
||||||
|
nativeFont.mFont = GetCairoScaledFont();
|
||||||
|
mAzureScaledFont =
|
||||||
|
Factory::CreateScaledFontForNativeFont(nativeFont,
|
||||||
|
GetUnscaledFont(),
|
||||||
|
GetAdjustedSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
||||||
|
return scaledFont.forget();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxFT2Font::FillGlyphDataForChar(FT_Face face, uint32_t ch, CachedGlyphData *gd)
|
gfxFT2Font::FillGlyphDataForChar(FT_Face face, uint32_t ch, CachedGlyphData *gd)
|
||||||
{
|
{
|
||||||
@@ -208,7 +228,7 @@ gfxFT2Font::FillGlyphDataForChar(FT_Face face, uint32_t ch, CachedGlyphData *gd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxFT2Font::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
gfxFT2Font::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
||||||
FontCacheSizes* aSizes) const
|
FontCacheSizes* aSizes) const
|
||||||
{
|
{
|
||||||
gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
||||||
@@ -217,7 +237,7 @@ gfxFT2Font::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxFT2Font::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
gfxFT2Font::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||||
FontCacheSizes* aSizes) const
|
FontCacheSizes* aSizes) const
|
||||||
{
|
{
|
||||||
aSizes->mFontInstances += aMallocSizeOf(this);
|
aSizes->mFontInstances += aMallocSizeOf(this);
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ public: // new functions
|
|||||||
|
|
||||||
FT2FontEntry *GetFontEntry();
|
FT2FontEntry *GetFontEntry();
|
||||||
|
|
||||||
|
virtual already_AddRefed<mozilla::gfx::ScaledFont>
|
||||||
|
GetScaledFont(DrawTarget *aTarget) override;
|
||||||
|
|
||||||
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||||
FontCacheSizes* aSizes) const override;
|
FontCacheSizes* aSizes) const override;
|
||||||
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ class gfxFT2LockedFace {
|
|||||||
public:
|
public:
|
||||||
explicit gfxFT2LockedFace(gfxFT2FontBase *aFont) :
|
explicit gfxFT2LockedFace(gfxFT2FontBase *aFont) :
|
||||||
mGfxFont(aFont),
|
mGfxFont(aFont),
|
||||||
mFace(cairo_ft_scaled_font_lock_face(aFont->CairoScaledFont()))
|
mFace(cairo_ft_scaled_font_lock_face(aFont->GetCairoScaledFont()))
|
||||||
{ }
|
{ }
|
||||||
~gfxFT2LockedFace()
|
~gfxFT2LockedFace()
|
||||||
{
|
{
|
||||||
if (mFace) {
|
if (mFace) {
|
||||||
cairo_ft_scaled_font_unlock_face(mGfxFont->CairoScaledFont());
|
cairo_ft_scaled_font_unlock_face(mGfxFont->GetCairoScaledFont());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,20 @@ using namespace mozilla::unicode;
|
|||||||
gfxPlatform::GetLog(eGfxLog_cmapdata), \
|
gfxPlatform::GetLog(eGfxLog_cmapdata), \
|
||||||
LogLevel::Debug)
|
LogLevel::Debug)
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class nsAutoRefTraits<FcFontSet> : public nsPointerRefTraits<FcFontSet>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void Release(FcFontSet *ptr) { FcFontSetDestroy(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class nsAutoRefTraits<FcObjectSet> : public nsPointerRefTraits<FcObjectSet>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void Release(FcObjectSet *ptr) { FcObjectSetDestroy(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
static const FcChar8*
|
static const FcChar8*
|
||||||
ToFcChar8Ptr(const char* aStr)
|
ToFcChar8Ptr(const char* aStr)
|
||||||
{
|
{
|
||||||
@@ -1181,8 +1195,9 @@ gfxFontconfigFont::gfxFontconfigFont(const RefPtr<UnscaledFontFontconfig>& aUnsc
|
|||||||
gfxFloat aAdjustedSize,
|
gfxFloat aAdjustedSize,
|
||||||
gfxFontEntry *aFontEntry,
|
gfxFontEntry *aFontEntry,
|
||||||
const gfxFontStyle *aFontStyle,
|
const gfxFontStyle *aFontStyle,
|
||||||
bool aNeedsBold) :
|
bool aNeedsBold)
|
||||||
gfxFontconfigFontBase(aUnscaledFont, aScaledFont, aPattern, aFontEntry, aFontStyle)
|
: gfxFT2FontBase(aUnscaledFont, aScaledFont, aFontEntry, aFontStyle)
|
||||||
|
, mPattern(aPattern)
|
||||||
{
|
{
|
||||||
mAdjustedSize = aAdjustedSize;
|
mAdjustedSize = aAdjustedSize;
|
||||||
}
|
}
|
||||||
@@ -1191,6 +1206,21 @@ gfxFontconfigFont::~gfxFontconfigFont()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<ScaledFont>
|
||||||
|
gfxFontconfigFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
|
||||||
|
{
|
||||||
|
if (!mAzureScaledFont) {
|
||||||
|
mAzureScaledFont =
|
||||||
|
Factory::CreateScaledFontForFontconfigFont(GetCairoScaledFont(),
|
||||||
|
GetPattern(),
|
||||||
|
GetUnscaledFont(),
|
||||||
|
GetAdjustedSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
||||||
|
return scaledFont.forget();
|
||||||
|
}
|
||||||
|
|
||||||
gfxFcPlatformFontList::gfxFcPlatformFontList()
|
gfxFcPlatformFontList::gfxFcPlatformFontList()
|
||||||
: mLocalNames(64)
|
: mLocalNames(64)
|
||||||
, mGenericMappings(32)
|
, mGenericMappings(32)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "gfxFT2FontBase.h"
|
#include "gfxFT2FontBase.h"
|
||||||
#include "gfxPlatformFontList.h"
|
#include "gfxPlatformFontList.h"
|
||||||
#include "mozilla/mozalloc.h"
|
#include "mozilla/mozalloc.h"
|
||||||
|
#include "nsAutoRef.h"
|
||||||
#include "nsClassHashtable.h"
|
#include "nsClassHashtable.h"
|
||||||
|
|
||||||
#include <fontconfig/fontconfig.h>
|
#include <fontconfig/fontconfig.h>
|
||||||
@@ -20,13 +21,12 @@
|
|||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <cairo-ft.h>
|
#include <cairo-ft.h>
|
||||||
|
|
||||||
#include "gfxFontconfigUtils.h" // xxx - only for nsAutoRefTraits<FcPattern>, etc.
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class nsAutoRefTraits<FcObjectSet> : public nsPointerRefTraits<FcObjectSet>
|
class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Release(FcObjectSet *ptr) { FcObjectSetDestroy(ptr); }
|
static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); }
|
||||||
|
static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@@ -209,7 +209,7 @@ protected:
|
|||||||
bool mForceScalable;
|
bool mForceScalable;
|
||||||
};
|
};
|
||||||
|
|
||||||
class gfxFontconfigFont : public gfxFontconfigFontBase {
|
class gfxFontconfigFont : public gfxFT2FontBase {
|
||||||
public:
|
public:
|
||||||
gfxFontconfigFont(const RefPtr<mozilla::gfx::UnscaledFontFontconfig> &aUnscaledFont,
|
gfxFontconfigFont(const RefPtr<mozilla::gfx::UnscaledFontFontconfig> &aUnscaledFont,
|
||||||
cairo_scaled_font_t *aScaledFont,
|
cairo_scaled_font_t *aScaledFont,
|
||||||
@@ -219,8 +219,16 @@ public:
|
|||||||
const gfxFontStyle *aFontStyle,
|
const gfxFontStyle *aFontStyle,
|
||||||
bool aNeedsBold);
|
bool aNeedsBold);
|
||||||
|
|
||||||
protected:
|
virtual FontType GetType() const override { return FONT_TYPE_FONTCONFIG; }
|
||||||
|
virtual FcPattern *GetPattern() const { return mPattern; }
|
||||||
|
|
||||||
|
virtual already_AddRefed<mozilla::gfx::ScaledFont>
|
||||||
|
GetScaledFont(DrawTarget *aTarget) override;
|
||||||
|
|
||||||
|
private:
|
||||||
virtual ~gfxFontconfigFont();
|
virtual ~gfxFontconfigFont();
|
||||||
|
|
||||||
|
nsCountedRef<FcPattern> mPattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
class gfxFcPlatformFontList : public gfxPlatformFontList {
|
class gfxFcPlatformFontList : public gfxPlatformFontList {
|
||||||
|
|||||||
@@ -1446,7 +1446,7 @@ public:
|
|||||||
const nsString& GetName() const { return mFontEntry->Name(); }
|
const nsString& GetName() const { return mFontEntry->Name(); }
|
||||||
const gfxFontStyle *GetStyle() const { return &mStyle; }
|
const gfxFontStyle *GetStyle() const { return &mStyle; }
|
||||||
|
|
||||||
virtual cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; }
|
cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; }
|
||||||
|
|
||||||
virtual mozilla::UniquePtr<gfxFont>
|
virtual mozilla::UniquePtr<gfxFont>
|
||||||
CopyWithAntialiasOption(AntialiasOption anAAOption) {
|
CopyWithAntialiasOption(AntialiasOption anAAOption) {
|
||||||
@@ -1831,10 +1831,7 @@ public:
|
|||||||
return mUnscaledFont;
|
return mUnscaledFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(DrawTarget* aTarget)
|
virtual already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(DrawTarget* aTarget) = 0;
|
||||||
{
|
|
||||||
return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KerningDisabled() {
|
bool KerningDisabled() {
|
||||||
return mKerningSet && !mKerningEnabled;
|
return mKerningSet && !mKerningEnabled;
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* 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/. */
|
|
||||||
|
|
||||||
#ifndef GFX_FONTCONFIG_UTILS_H
|
|
||||||
#define GFX_FONTCONFIG_UTILS_H
|
|
||||||
|
|
||||||
#include "gfxPlatform.h"
|
|
||||||
|
|
||||||
#include "nsAutoRef.h"
|
|
||||||
#include "gfxFT2FontBase.h"
|
|
||||||
|
|
||||||
#include <fontconfig/fontconfig.h>
|
|
||||||
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); }
|
|
||||||
static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class nsAutoRefTraits<FcFontSet> : public nsPointerRefTraits<FcFontSet>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void Release(FcFontSet *ptr) { FcFontSetDestroy(ptr); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class nsAutoRefTraits<FcCharSet> : public nsPointerRefTraits<FcCharSet>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class gfxFontconfigFontBase : public gfxFT2FontBase {
|
|
||||||
public:
|
|
||||||
gfxFontconfigFontBase(const RefPtr<mozilla::gfx::UnscaledFontFontconfig>& aUnscaledFont,
|
|
||||||
cairo_scaled_font_t *aScaledFont,
|
|
||||||
FcPattern *aPattern,
|
|
||||||
gfxFontEntry *aFontEntry,
|
|
||||||
const gfxFontStyle *aFontStyle)
|
|
||||||
: gfxFT2FontBase(aUnscaledFont, aScaledFont, aFontEntry, aFontStyle)
|
|
||||||
, mPattern(aPattern) { }
|
|
||||||
|
|
||||||
virtual FontType GetType() const override { return FONT_TYPE_FONTCONFIG; }
|
|
||||||
virtual FcPattern *GetPattern() const { return mPattern; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsCountedRef<FcPattern> mPattern;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* GFX_FONTCONFIG_UTILS_H */
|
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#define ROUND(x) floor((x) + 0.5)
|
#define ROUND(x) floor((x) + 0.5)
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::gfx;
|
||||||
using namespace mozilla::unicode;
|
using namespace mozilla::unicode;
|
||||||
|
|
||||||
static inline cairo_antialias_t
|
static inline cairo_antialias_t
|
||||||
@@ -135,6 +136,27 @@ gfxGDIFont::SetupCairoFont(DrawTarget* aDrawTarget)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<ScaledFont>
|
||||||
|
gfxGDIFont::GetScaledFont(DrawTarget *aTarget)
|
||||||
|
{
|
||||||
|
if (!mAzureScaledFont) {
|
||||||
|
NativeFont nativeFont;
|
||||||
|
nativeFont.mType = NativeFontType::GDI_FONT_FACE;
|
||||||
|
LOGFONT lf;
|
||||||
|
GetObject(GetHFONT(), sizeof(LOGFONT), &lf);
|
||||||
|
nativeFont.mFont = &lf;
|
||||||
|
|
||||||
|
mAzureScaledFont =
|
||||||
|
Factory::CreateScaledFontWithCairo(nativeFont,
|
||||||
|
GetUnscaledFont(),
|
||||||
|
GetAdjustedSize(),
|
||||||
|
GetCairoScaledFont());
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
||||||
|
return scaledFont.forget();
|
||||||
|
}
|
||||||
|
|
||||||
gfxFont::RunMetrics
|
gfxFont::RunMetrics
|
||||||
gfxGDIFont::Measure(const gfxTextRun *aTextRun,
|
gfxGDIFont::Measure(const gfxTextRun *aTextRun,
|
||||||
uint32_t aStart, uint32_t aEnd,
|
uint32_t aStart, uint32_t aEnd,
|
||||||
|
|||||||
@@ -29,13 +29,15 @@ public:
|
|||||||
HFONT GetHFONT() { return mFont; }
|
HFONT GetHFONT() { return mFont; }
|
||||||
|
|
||||||
cairo_font_face_t* CairoFontFace() { return mFontFace; }
|
cairo_font_face_t* CairoFontFace() { return mFontFace; }
|
||||||
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; }
|
|
||||||
|
|
||||||
/* overrides for the pure virtual methods in gfxFont */
|
/* overrides for the pure virtual methods in gfxFont */
|
||||||
virtual uint32_t GetSpaceGlyph() override;
|
virtual uint32_t GetSpaceGlyph() override;
|
||||||
|
|
||||||
virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
|
virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
|
||||||
|
|
||||||
|
virtual already_AddRefed<mozilla::gfx::ScaledFont>
|
||||||
|
GetScaledFont(DrawTarget *aTarget) override;
|
||||||
|
|
||||||
/* override Measure to add padding for antialiasing */
|
/* override Measure to add padding for antialiasing */
|
||||||
virtual RunMetrics Measure(const gfxTextRun *aTextRun,
|
virtual RunMetrics Measure(const gfxTextRun *aTextRun,
|
||||||
uint32_t aStart, uint32_t aEnd,
|
uint32_t aStart, uint32_t aEnd,
|
||||||
|
|||||||
@@ -1276,17 +1276,6 @@ gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
|
|||||||
return result.forget();
|
return result.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<ScaledFont>
|
|
||||||
gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
|
|
||||||
{
|
|
||||||
NativeFont nativeFont;
|
|
||||||
nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
|
|
||||||
nativeFont.mFont = aFont->GetCairoScaledFont();
|
|
||||||
return Factory::CreateScaledFontForNativeFont(nativeFont,
|
|
||||||
aFont->GetUnscaledFont(),
|
|
||||||
aFont->GetAdjustedSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxPlatform::ComputeTileSize()
|
gfxPlatform::ComputeTileSize()
|
||||||
{
|
{
|
||||||
@@ -2579,17 +2568,6 @@ gfxPlatform::DisableBufferRotation()
|
|||||||
sBufferRotationCheckPref = false;
|
sBufferRotationCheckPref = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<ScaledFont>
|
|
||||||
gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont)
|
|
||||||
{
|
|
||||||
NativeFont nativeFont;
|
|
||||||
nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
|
|
||||||
nativeFont.mFont = aFont->GetCairoScaledFont();
|
|
||||||
return Factory::CreateScaledFontForNativeFont(nativeFont,
|
|
||||||
aFont->GetUnscaledFont(),
|
|
||||||
aFont->GetAdjustedSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
gfxPlatform::UsesOffMainThreadCompositing()
|
gfxPlatform::UsesOffMainThreadCompositing()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -239,9 +239,6 @@ public:
|
|||||||
static already_AddRefed<DataSourceSurface>
|
static already_AddRefed<DataSourceSurface>
|
||||||
GetWrappedDataSourceSurface(gfxASurface *aSurface);
|
GetWrappedDataSourceSurface(gfxASurface *aSurface);
|
||||||
|
|
||||||
virtual already_AddRefed<mozilla::gfx::ScaledFont>
|
|
||||||
GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
|
|
||||||
|
|
||||||
already_AddRefed<DrawTarget>
|
already_AddRefed<DrawTarget>
|
||||||
CreateOffscreenContentDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
|
CreateOffscreenContentDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
|
||||||
|
|
||||||
@@ -780,9 +777,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
static mozilla::gfx::BackendType BackendTypeForName(const nsCString& aName);
|
static mozilla::gfx::BackendType BackendTypeForName(const nsCString& aName);
|
||||||
|
|
||||||
static already_AddRefed<mozilla::gfx::ScaledFont>
|
|
||||||
GetScaledFontForFontWithCairoSkia(mozilla::gfx::DrawTarget* aTarget, gfxFont* aFont);
|
|
||||||
|
|
||||||
virtual bool CanUseHardwareVideoDecoding();
|
virtual bool CanUseHardwareVideoDecoding();
|
||||||
|
|
||||||
int8_t mAllowDownloadableFonts;
|
int8_t mAllowDownloadableFonts;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include "nsUnicodeProperties.h"
|
#include "nsUnicodeProperties.h"
|
||||||
#include "gfx2DGlue.h"
|
#include "gfx2DGlue.h"
|
||||||
#include "gfxFcPlatformFontList.h"
|
#include "gfxFcPlatformFontList.h"
|
||||||
#include "gfxFontconfigUtils.h"
|
|
||||||
#include "gfxFontconfigFonts.h"
|
#include "gfxFontconfigFonts.h"
|
||||||
#include "gfxConfig.h"
|
#include "gfxConfig.h"
|
||||||
#include "gfxContext.h"
|
#include "gfxContext.h"
|
||||||
@@ -568,20 +567,6 @@ gfxPlatformGtk::GetGdkDrawable(cairo_surface_t *target)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
already_AddRefed<ScaledFont>
|
|
||||||
gfxPlatformGtk::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
|
|
||||||
{
|
|
||||||
if (aFont->GetType() == gfxFont::FONT_TYPE_FONTCONFIG) {
|
|
||||||
gfxFontconfigFontBase* fcFont = static_cast<gfxFontconfigFontBase*>(aFont);
|
|
||||||
return Factory::CreateScaledFontForFontconfigFont(
|
|
||||||
fcFont->GetCairoScaledFont(),
|
|
||||||
fcFont->GetPattern(),
|
|
||||||
fcFont->GetUnscaledFont(),
|
|
||||||
fcFont->GetAdjustedSize());
|
|
||||||
}
|
|
||||||
return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef GL_PROVIDER_GLX
|
#ifdef GL_PROVIDER_GLX
|
||||||
|
|
||||||
class GLXVsyncSource final : public VsyncSource
|
class GLXVsyncSource final : public VsyncSource
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ struct _XDisplay;
|
|||||||
typedef struct _XDisplay Display;
|
typedef struct _XDisplay Display;
|
||||||
#endif // MOZ_X11
|
#endif // MOZ_X11
|
||||||
|
|
||||||
class gfxFontconfigUtils;
|
|
||||||
|
|
||||||
class gfxPlatformGtk : public gfxPlatform {
|
class gfxPlatformGtk : public gfxPlatform {
|
||||||
public:
|
public:
|
||||||
gfxPlatformGtk();
|
gfxPlatformGtk();
|
||||||
@@ -37,9 +35,6 @@ public:
|
|||||||
CreateOffscreenSurface(const IntSize& aSize,
|
CreateOffscreenSurface(const IntSize& aSize,
|
||||||
gfxImageFormat aFormat) override;
|
gfxImageFormat aFormat) override;
|
||||||
|
|
||||||
virtual already_AddRefed<mozilla::gfx::ScaledFont>
|
|
||||||
GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont) override;
|
|
||||||
|
|
||||||
virtual nsresult GetFontList(nsIAtom *aLangGroup,
|
virtual nsresult GetFontList(nsIAtom *aLangGroup,
|
||||||
const nsACString& aGenericFamily,
|
const nsACString& aGenericFamily,
|
||||||
nsTArray<nsString>& aListOfFonts) override;
|
nsTArray<nsString>& aListOfFonts) override;
|
||||||
@@ -138,8 +133,6 @@ public:
|
|||||||
#endif // MOZ_X11
|
#endif // MOZ_X11
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static gfxFontconfigUtils *sFontconfigUtils;
|
|
||||||
|
|
||||||
int8_t mMaxGenericSubstitutions;
|
int8_t mMaxGenericSubstitutions;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -133,13 +133,6 @@ gfxPlatformMac::CreateOffscreenSurface(const IntSize& aSize,
|
|||||||
return newSurface.forget();
|
return newSurface.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<ScaledFont>
|
|
||||||
gfxPlatformMac::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
|
|
||||||
{
|
|
||||||
gfxMacFont *font = static_cast<gfxMacFont*>(aFont);
|
|
||||||
return font->GetScaledFont(aTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
gfxFontGroup *
|
gfxFontGroup *
|
||||||
gfxPlatformMac::CreateFontGroup(const FontFamilyList& aFontFamilyList,
|
gfxPlatformMac::CreateFontGroup(const FontFamilyList& aFontFamilyList,
|
||||||
const gfxFontStyle *aStyle,
|
const gfxFontStyle *aStyle,
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ public:
|
|||||||
CreateOffscreenSurface(const IntSize& aSize,
|
CreateOffscreenSurface(const IntSize& aSize,
|
||||||
gfxImageFormat aFormat) override;
|
gfxImageFormat aFormat) override;
|
||||||
|
|
||||||
already_AddRefed<mozilla::gfx::ScaledFont>
|
|
||||||
GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont) override;
|
|
||||||
|
|
||||||
gfxFontGroup*
|
gfxFontGroup*
|
||||||
CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
|
CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
|
||||||
const gfxFontStyle *aStyle,
|
const gfxFontStyle *aStyle,
|
||||||
|
|||||||
@@ -554,34 +554,6 @@ gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& aSize,
|
|||||||
return surf.forget();
|
return surf.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<ScaledFont>
|
|
||||||
gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
|
|
||||||
{
|
|
||||||
if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) {
|
|
||||||
return aFont->GetScaledFont(aTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_GDI,
|
|
||||||
"Fonts on windows should be GDI or DWrite!");
|
|
||||||
|
|
||||||
NativeFont nativeFont;
|
|
||||||
nativeFont.mType = NativeFontType::GDI_FONT_FACE;
|
|
||||||
LOGFONT lf;
|
|
||||||
GetObject(static_cast<gfxGDIFont*>(aFont)->GetHFONT(), sizeof(LOGFONT), &lf);
|
|
||||||
nativeFont.mFont = &lf;
|
|
||||||
|
|
||||||
if (aTarget->GetBackendType() == BackendType::CAIRO) {
|
|
||||||
return Factory::CreateScaledFontWithCairo(nativeFont,
|
|
||||||
aFont->GetUnscaledFont(),
|
|
||||||
aFont->GetAdjustedSize(),
|
|
||||||
aFont->GetCairoScaledFont());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Factory::CreateScaledFontForNativeFont(nativeFont,
|
|
||||||
aFont->GetUnscaledFont(),
|
|
||||||
aFont->GetAdjustedSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char kFontAparajita[] = "Aparajita";
|
static const char kFontAparajita[] = "Aparajita";
|
||||||
static const char kFontArabicTypesetting[] = "Arabic Typesetting";
|
static const char kFontArabicTypesetting[] = "Arabic Typesetting";
|
||||||
static const char kFontArial[] = "Arial";
|
static const char kFontArial[] = "Arial";
|
||||||
|
|||||||
@@ -121,9 +121,6 @@ public:
|
|||||||
CreateOffscreenSurface(const IntSize& aSize,
|
CreateOffscreenSurface(const IntSize& aSize,
|
||||||
gfxImageFormat aFormat) override;
|
gfxImageFormat aFormat) override;
|
||||||
|
|
||||||
virtual already_AddRefed<mozilla::gfx::ScaledFont>
|
|
||||||
GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont) override;
|
|
||||||
|
|
||||||
enum RenderMode {
|
enum RenderMode {
|
||||||
/* Use GDI and windows surfaces */
|
/* Use GDI and windows surfaces */
|
||||||
RENDER_GDI = 0,
|
RENDER_GDI = 0,
|
||||||
|
|||||||
@@ -181,8 +181,7 @@ Version(JSContext *cx,
|
|||||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||||
args.rval().setInt32(JS_GetVersion(cx));
|
args.rval().setInt32(JS_GetVersion(cx));
|
||||||
if (args.get(0).isInt32())
|
if (args.get(0).isInt32())
|
||||||
JS_SetVersionForCompartment(js::GetContextCompartment(cx),
|
JS::SetVersionForCurrentRealm(cx, JSVersion(args[0].toInt32()));
|
||||||
JSVersion(args[0].toInt32()));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,8 @@ struct GCPolicy<mozilla::Maybe<T>>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct GCPolicy<JS::Realm*>; // see Realm.h
|
||||||
|
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
||||||
#endif // GCPolicyAPI_h
|
#endif // GCPolicyAPI_h
|
||||||
|
|||||||
@@ -13,13 +13,82 @@
|
|||||||
#ifndef js_Realm_h
|
#ifndef js_Realm_h
|
||||||
#define js_Realm_h
|
#define js_Realm_h
|
||||||
|
|
||||||
#include "jstypes.h"
|
#include "jspubtd.h"
|
||||||
|
#include "js/GCPolicyAPI.h"
|
||||||
|
#include "js/TypeDecls.h" // forward-declaration of JS::Realm
|
||||||
|
|
||||||
struct JSContext;
|
namespace js {
|
||||||
class JSObject;
|
namespace gc {
|
||||||
|
JS_PUBLIC_API(void) TraceRealm(JSTracer* trc, JS::Realm* realm, const char* name);
|
||||||
|
JS_PUBLIC_API(bool) RealmNeedsSweep(JS::Realm* realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
// Each Realm holds a strong reference to its GlobalObject, and vice versa.
|
||||||
|
template <>
|
||||||
|
struct GCPolicy<Realm*>
|
||||||
|
{
|
||||||
|
static Realm* initial() { return nullptr; }
|
||||||
|
static void trace(JSTracer* trc, Realm** vp, const char* name) {
|
||||||
|
if (*vp)
|
||||||
|
::js::gc::TraceRealm(trc, *vp, name);
|
||||||
|
}
|
||||||
|
static bool needsSweep(Realm** vp) {
|
||||||
|
return *vp && ::js::gc::RealmNeedsSweep(*vp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the current realm, if any. The ECMAScript spec calls this "the current
|
||||||
|
// Realm Record".
|
||||||
|
extern JS_PUBLIC_API(Realm*)
|
||||||
|
GetCurrentRealmOrNull(JSContext* cx);
|
||||||
|
|
||||||
|
// Return the compartment that contains a given realm.
|
||||||
|
inline JSCompartment*
|
||||||
|
GetCompartmentForRealm(Realm* realm) {
|
||||||
|
// Implementation note: For now, realms are a fiction; we treat realms and
|
||||||
|
// compartments as being one-to-one, but they are actually identical.
|
||||||
|
return reinterpret_cast<JSCompartment*>(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the realm in a given compartment.
|
||||||
|
inline Realm*
|
||||||
|
GetRealmForCompartment(JSCompartment* compartment) {
|
||||||
|
return reinterpret_cast<Realm*>(compartment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the value of the "private data" internal field of the given Realm.
|
||||||
|
// This field is initially null and is set using SetRealmPrivate.
|
||||||
|
// It's a pointer to embeddding-specific data that SpiderMonkey never uses.
|
||||||
|
extern JS_PUBLIC_API(void*)
|
||||||
|
GetRealmPrivate(Realm* realm);
|
||||||
|
|
||||||
|
// Set the "private data" internal field of the given Realm.
|
||||||
|
extern JS_PUBLIC_API(void)
|
||||||
|
SetRealmPrivate(Realm* realm, void* data);
|
||||||
|
|
||||||
|
typedef void
|
||||||
|
(* DestroyRealmCallback)(JSFreeOp* fop, Realm* realm);
|
||||||
|
|
||||||
|
// Set the callback SpiderMonkey calls just before garbage-collecting a realm.
|
||||||
|
// Embeddings can use this callback to free private data associated with the
|
||||||
|
// realm via SetRealmPrivate.
|
||||||
|
//
|
||||||
|
// By the time this is called, the global object for the realm has already been
|
||||||
|
// collected.
|
||||||
|
extern JS_PUBLIC_API(void)
|
||||||
|
SetDestroyRealmCallback(JSContext* cx, DestroyRealmCallback callback);
|
||||||
|
|
||||||
|
typedef void
|
||||||
|
(* RealmNameCallback)(JSContext* cx, Handle<Realm*> realm, char* buf, size_t bufsize);
|
||||||
|
|
||||||
|
// Set the callback SpiderMonkey calls to get the name of a realm, for
|
||||||
|
// diagnostic output.
|
||||||
|
extern JS_PUBLIC_API(void)
|
||||||
|
SetRealmNameCallback(JSContext* cx, RealmNameCallback callback);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSObject*)
|
extern JS_PUBLIC_API(JSObject*)
|
||||||
GetRealmObjectPrototype(JSContext* cx);
|
GetRealmObjectPrototype(JSContext* cx);
|
||||||
|
|
||||||
@@ -35,6 +104,17 @@ GetRealmErrorPrototype(JSContext* cx);
|
|||||||
extern JS_PUBLIC_API(JSObject*)
|
extern JS_PUBLIC_API(JSObject*)
|
||||||
GetRealmIteratorPrototype(JSContext* cx);
|
GetRealmIteratorPrototype(JSContext* cx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the JS language version for the current Realm. This is discouraged,
|
||||||
|
* but necessary to support the `version()` builtin function in the js and xpc
|
||||||
|
* shells.
|
||||||
|
*
|
||||||
|
* It would be nice to put this in jsfriendapi, but the linkage requirements
|
||||||
|
* of the shells make that impossible.
|
||||||
|
*/
|
||||||
|
JS_PUBLIC_API(void)
|
||||||
|
SetVersionForCurrentRealm(JSContext* cx, JSVersion version);
|
||||||
|
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
||||||
#endif // js_Realm_h
|
#endif // js_Realm_h
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF)
|
|||||||
#undef JS_EXPAND_DEF
|
#undef JS_EXPAND_DEF
|
||||||
|
|
||||||
// Specify the RootKind for all types. Value and jsid map to special cases;
|
// Specify the RootKind for all types. Value and jsid map to special cases;
|
||||||
// pointer types we can derive directly from the TraceKind; everything else
|
// Cell pointer types we can derive directly from the TraceKind; everything else
|
||||||
// should go in the Traceable list and use GCPolicy<T>::trace for tracing.
|
// should go in the Traceable list and use GCPolicy<T>::trace for tracing.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct MapTypeToRootKind {
|
struct MapTypeToRootKind {
|
||||||
@@ -144,6 +144,10 @@ struct MapTypeToRootKind<T*> {
|
|||||||
static const JS::RootKind kind =
|
static const JS::RootKind kind =
|
||||||
JS::MapTraceKindToRootKind<JS::MapTypeToTraceKind<T>::kind>::kind;
|
JS::MapTraceKindToRootKind<JS::MapTypeToTraceKind<T>::kind>::kind;
|
||||||
};
|
};
|
||||||
|
template <> struct MapTypeToRootKind<JS::Realm*> {
|
||||||
|
// Not a pointer to a GC cell. Use GCPolicy.
|
||||||
|
static const JS::RootKind kind = JS::RootKind::Traceable;
|
||||||
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct MapTypeToRootKind<mozilla::UniquePtr<T>> {
|
struct MapTypeToRootKind<mozilla::UniquePtr<T>> {
|
||||||
static const JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
|
static const JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class JSObject;
|
|||||||
class JSScript;
|
class JSScript;
|
||||||
class JSString;
|
class JSString;
|
||||||
class JSAddonId;
|
class JSAddonId;
|
||||||
|
struct JSFreeOp;
|
||||||
|
|
||||||
struct jsid;
|
struct jsid;
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ typedef unsigned char Latin1Char;
|
|||||||
|
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class Value;
|
class Value;
|
||||||
|
class Realm;
|
||||||
template <typename T> class Handle;
|
template <typename T> class Handle;
|
||||||
template <typename T> class MutableHandle;
|
template <typename T> class MutableHandle;
|
||||||
template <typename T> class Rooted;
|
template <typename T> class Rooted;
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class RegExpStack
|
|||||||
static const uintptr_t kMemoryTop = static_cast<uintptr_t>(-1);
|
static const uintptr_t kMemoryTop = static_cast<uintptr_t>(-1);
|
||||||
|
|
||||||
// Minimal size of allocated stack area, in bytes.
|
// Minimal size of allocated stack area, in bytes.
|
||||||
static const size_t kMinimumStackSize = 1 * 1024;
|
static const size_t kMinimumStackSize = 256;
|
||||||
|
|
||||||
// Maximal size of allocated stack area, in bytes.
|
// Maximal size of allocated stack area, in bytes.
|
||||||
static const size_t kMaximumStackSize = 64 * 1024 * 1024;
|
static const size_t kMaximumStackSize = 64 * 1024 * 1024;
|
||||||
|
|||||||
@@ -588,12 +588,6 @@ JS_GetVersion(JSContext* cx)
|
|||||||
return VersionNumber(cx->findVersion());
|
return VersionNumber(cx->findVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
|
||||||
JS_SetVersionForCompartment(JSCompartment* compartment, JSVersion version)
|
|
||||||
{
|
|
||||||
compartment->behaviors().setVersion(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct v2smap {
|
static const struct v2smap {
|
||||||
JSVersion version;
|
JSVersion version;
|
||||||
const char* string;
|
const char* string;
|
||||||
|
|||||||
@@ -1135,17 +1135,6 @@ class MOZ_RAII JSAutoRequest
|
|||||||
extern JS_PUBLIC_API(JSVersion)
|
extern JS_PUBLIC_API(JSVersion)
|
||||||
JS_GetVersion(JSContext* cx);
|
JS_GetVersion(JSContext* cx);
|
||||||
|
|
||||||
/**
|
|
||||||
* Mutate the version on the compartment. This is generally discouraged, but
|
|
||||||
* necessary to support the version mutation in the js and xpc shell command
|
|
||||||
* set.
|
|
||||||
*
|
|
||||||
* It would be nice to put this in jsfriendapi, but the linkage requirements
|
|
||||||
* of the shells make that impossible.
|
|
||||||
*/
|
|
||||||
JS_PUBLIC_API(void)
|
|
||||||
JS_SetVersionForCompartment(JSCompartment* compartment, JSVersion version);
|
|
||||||
|
|
||||||
extern JS_PUBLIC_API(const char*)
|
extern JS_PUBLIC_API(const char*)
|
||||||
JS_VersionToString(JSVersion version);
|
JS_VersionToString(JSVersion version);
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
|
|||||||
enterCompartmentDepth(0),
|
enterCompartmentDepth(0),
|
||||||
performanceMonitoring(runtime_),
|
performanceMonitoring(runtime_),
|
||||||
data(nullptr),
|
data(nullptr),
|
||||||
|
realmData(nullptr),
|
||||||
allocationMetadataBuilder(nullptr),
|
allocationMetadataBuilder(nullptr),
|
||||||
lastAnimationTime(0),
|
lastAnimationTime(0),
|
||||||
regExps(zone),
|
regExps(zone),
|
||||||
|
|||||||
@@ -669,12 +669,12 @@ struct JSCompartment
|
|||||||
return runtime_;
|
return runtime_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* The global object for this compartment.
|
||||||
* Nb: global_ might be nullptr, if (a) it's the atoms compartment, or
|
*
|
||||||
* (b) the compartment's global has been collected. The latter can happen
|
* This returns nullptr if this is the atoms compartment. (The global_
|
||||||
* if e.g. a string in a compartment is rooted but no object is, and thus
|
* field is also null briefly during GC, after the global object is
|
||||||
* the global isn't rooted, and thus the global can be finalized while the
|
* collected; but when that happens the JSCompartment is destroyed during
|
||||||
* compartment lives on.
|
* the same GC.)
|
||||||
*
|
*
|
||||||
* In contrast, JSObject::global() is infallible because marking a JSObject
|
* In contrast, JSObject::global() is infallible because marking a JSObject
|
||||||
* always marks its global as well.
|
* always marks its global as well.
|
||||||
@@ -685,10 +685,14 @@ struct JSCompartment
|
|||||||
/* An unbarriered getter for use while tracing. */
|
/* An unbarriered getter for use while tracing. */
|
||||||
inline js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const;
|
inline js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const;
|
||||||
|
|
||||||
|
/* True if a global object exists, but it's being collected. */
|
||||||
|
inline bool globalIsAboutToBeFinalized();
|
||||||
|
|
||||||
inline void initGlobal(js::GlobalObject& global);
|
inline void initGlobal(js::GlobalObject& global);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void* data;
|
void* data;
|
||||||
|
void* realmData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const js::AllocationMetadataBuilder *allocationMetadataBuilder;
|
const js::AllocationMetadataBuilder *allocationMetadataBuilder;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "jsiter.h"
|
#include "jsiter.h"
|
||||||
|
|
||||||
#include "gc/Barrier.h"
|
#include "gc/Barrier.h"
|
||||||
|
#include "gc/Marking.h"
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
|
||||||
@@ -35,6 +36,13 @@ JSCompartment::unsafeUnbarrieredMaybeGlobal() const
|
|||||||
return *global_.unsafeGet();
|
return *global_.unsafeGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
JSCompartment::globalIsAboutToBeFinalized()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(zone_->isGCSweeping());
|
||||||
|
return global_ && js::gc::IsAboutToBeFinalizedUnbarriered(global_.unsafeGet());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
js::AutoCompartment::AutoCompartment(JSContext* cx, const T& target)
|
js::AutoCompartment::AutoCompartment(JSContext* cx, const T& target)
|
||||||
: cx_(cx),
|
: cx_(cx),
|
||||||
|
|||||||
@@ -3444,6 +3444,8 @@ void
|
|||||||
JSCompartment::destroy(FreeOp* fop)
|
JSCompartment::destroy(FreeOp* fop)
|
||||||
{
|
{
|
||||||
JSRuntime* rt = fop->runtime();
|
JSRuntime* rt = fop->runtime();
|
||||||
|
if (auto callback = rt->destroyRealmCallback)
|
||||||
|
callback(fop, JS::GetRealmForCompartment(this));
|
||||||
if (auto callback = rt->destroyCompartmentCallback)
|
if (auto callback = rt->destroyCompartmentCallback)
|
||||||
callback(fop, this);
|
callback(fop, this);
|
||||||
if (principals())
|
if (principals())
|
||||||
@@ -3464,10 +3466,9 @@ Zone::destroy(FreeOp* fop)
|
|||||||
* It's simpler if we preserve the invariant that every zone has at least one
|
* It's simpler if we preserve the invariant that every zone has at least one
|
||||||
* compartment. If we know we're deleting the entire zone, then
|
* compartment. If we know we're deleting the entire zone, then
|
||||||
* SweepCompartments is allowed to delete all compartments. In this case,
|
* SweepCompartments is allowed to delete all compartments. In this case,
|
||||||
* |keepAtleastOne| is false. If some objects remain in the zone so that it
|
* |keepAtleastOne| is false. If any cells remain alive in the zone, set
|
||||||
* cannot be deleted, then we set |keepAtleastOne| to true, which prohibits
|
* |keepAtleastOne| true to prohibit sweepCompartments from deleting every
|
||||||
* SweepCompartments from deleting every compartment. Instead, it preserves an
|
* compartment. Instead, it preserves an arbitrary compartment in the zone.
|
||||||
* arbitrary compartment in the zone.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime)
|
Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime)
|
||||||
|
|||||||
@@ -132,8 +132,6 @@ enum JSShellExitCode {
|
|||||||
EXITCODE_TIMEOUT = 6
|
EXITCODE_TIMEOUT = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t gStackChunkSize = 8192;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: This limit should match the stack limit set by the browser in
|
* Note: This limit should match the stack limit set by the browser in
|
||||||
* js/xpconnect/src/XPCJSContext.cpp
|
* js/xpconnect/src/XPCJSContext.cpp
|
||||||
@@ -994,7 +992,7 @@ Version(JSContext* cx, unsigned argc, Value* vp)
|
|||||||
"version");
|
"version");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
JS_SetVersionForCompartment(js::GetContextCompartment(cx), JSVersion(v));
|
SetVersionForCurrentRealm(cx, JSVersion(v));
|
||||||
args.rval().setInt32(origVersion);
|
args.rval().setInt32(origVersion);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -7,12 +7,57 @@
|
|||||||
#include "js/Realm.h"
|
#include "js/Realm.h"
|
||||||
|
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
#include "jscompartment.h" // For JSContext::global
|
#include "jscompartment.h"
|
||||||
|
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
|
|
||||||
|
#include "jscompartmentinlines.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
|
||||||
|
JS_PUBLIC_API(void)
|
||||||
|
gc::TraceRealm(JSTracer* trc, JS::Realm* realm, const char* name)
|
||||||
|
{
|
||||||
|
// The way GC works with compartments is basically incomprehensible.
|
||||||
|
// For Realms, what we want is very simple: each Realm has a strong
|
||||||
|
// reference to its GlobalObject, and vice versa.
|
||||||
|
//
|
||||||
|
// Here we simply trace our side of that edge. During GC,
|
||||||
|
// GCRuntime::traceRuntimeCommon() marks all other compartment roots, for
|
||||||
|
// all compartments.
|
||||||
|
JS::GetCompartmentForRealm(realm)->traceGlobal(trc);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(bool)
|
||||||
|
gc::RealmNeedsSweep(JS::Realm* realm)
|
||||||
|
{
|
||||||
|
return JS::GetCompartmentForRealm(realm)->globalIsAboutToBeFinalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(void*)
|
||||||
|
JS::GetRealmPrivate(JS::Realm* realm)
|
||||||
|
{
|
||||||
|
return GetCompartmentForRealm(realm)->realmData;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(void)
|
||||||
|
JS::SetRealmPrivate(JS::Realm* realm, void* data)
|
||||||
|
{
|
||||||
|
GetCompartmentForRealm(realm)->realmData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(void)
|
||||||
|
JS::SetDestroyRealmCallback(JSContext* cx, JS::DestroyRealmCallback callback)
|
||||||
|
{
|
||||||
|
cx->runtime()->destroyRealmCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(void)
|
||||||
|
JS::SetRealmNameCallback(JSContext* cx, JS::RealmNameCallback callback)
|
||||||
|
{
|
||||||
|
cx->runtime()->realmNameCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject*)
|
JS_PUBLIC_API(JSObject*)
|
||||||
JS::GetRealmObjectPrototype(JSContext* cx)
|
JS::GetRealmObjectPrototype(JSContext* cx)
|
||||||
{
|
{
|
||||||
@@ -47,3 +92,10 @@ JS::GetRealmIteratorPrototype(JSContext* cx)
|
|||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
return GlobalObject::getOrCreateIteratorPrototype(cx, cx->global());
|
return GlobalObject::getOrCreateIteratorPrototype(cx, cx->global());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(void)
|
||||||
|
JS::SetVersionForCurrentRealm(JSContext* cx, JSVersion version)
|
||||||
|
{
|
||||||
|
JSCompartment* compartment = GetContextCompartment(cx);
|
||||||
|
compartment->behaviors().setVersion(version);
|
||||||
|
}
|
||||||
|
|||||||
@@ -119,6 +119,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||||||
destroyCompartmentCallback(nullptr),
|
destroyCompartmentCallback(nullptr),
|
||||||
sizeOfIncludingThisCompartmentCallback(nullptr),
|
sizeOfIncludingThisCompartmentCallback(nullptr),
|
||||||
compartmentNameCallback(nullptr),
|
compartmentNameCallback(nullptr),
|
||||||
|
destroyRealmCallback(nullptr),
|
||||||
|
realmNameCallback(nullptr),
|
||||||
externalStringSizeofCallback(nullptr),
|
externalStringSizeofCallback(nullptr),
|
||||||
securityCallbacks(&NullSecurityCallbacks),
|
securityCallbacks(&NullSecurityCallbacks),
|
||||||
DOMcallbacks(nullptr),
|
DOMcallbacks(nullptr),
|
||||||
|
|||||||
@@ -501,6 +501,12 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||||||
/* Call this to get the name of a compartment. */
|
/* Call this to get the name of a compartment. */
|
||||||
js::ActiveThreadData<JSCompartmentNameCallback> compartmentNameCallback;
|
js::ActiveThreadData<JSCompartmentNameCallback> compartmentNameCallback;
|
||||||
|
|
||||||
|
/* Realm destroy callback. */
|
||||||
|
js::ActiveThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
|
||||||
|
|
||||||
|
/* Call this to get the name of a realm. */
|
||||||
|
js::ActiveThreadData<JS::RealmNameCallback> realmNameCallback;
|
||||||
|
|
||||||
/* Callback for doing memory reporting on external strings. */
|
/* Callback for doing memory reporting on external strings. */
|
||||||
js::ActiveThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
|
js::ActiveThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
|
||||||
|
|
||||||
|
|||||||
@@ -3350,10 +3350,8 @@ nsXPCComponents_Utils::SetAddonCallInterposition(HandleValue target,
|
|||||||
RootedObject targetObj(cx, &target.toObject());
|
RootedObject targetObj(cx, &target.toObject());
|
||||||
targetObj = js::CheckedUnwrap(targetObj);
|
targetObj = js::CheckedUnwrap(targetObj);
|
||||||
NS_ENSURE_TRUE(targetObj, NS_ERROR_INVALID_ARG);
|
NS_ENSURE_TRUE(targetObj, NS_ERROR_INVALID_ARG);
|
||||||
XPCWrappedNativeScope* xpcScope = ObjectScope(targetObj);
|
|
||||||
NS_ENSURE_TRUE(xpcScope, NS_ERROR_INVALID_ARG);
|
|
||||||
|
|
||||||
xpcScope->SetAddonCallInterposition();
|
xpc::CompartmentPrivate::Get(targetObj)->SetAddonCallInterposition();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ CompartmentPrivate::CompartmentPrivate(JSCompartment* c)
|
|||||||
, skipWriteToGlobalPrototype(false)
|
, skipWriteToGlobalPrototype(false)
|
||||||
, isWebExtensionContentScript(false)
|
, isWebExtensionContentScript(false)
|
||||||
, waiveInterposition(false)
|
, waiveInterposition(false)
|
||||||
|
, addonCallInterposition(false)
|
||||||
, allowCPOWs(false)
|
, allowCPOWs(false)
|
||||||
, universalXPConnectEnabled(false)
|
, universalXPConnectEnabled(false)
|
||||||
, forcePermissiveCOWs(false)
|
, forcePermissiveCOWs(false)
|
||||||
@@ -2663,6 +2664,13 @@ CompartmentNameCallback(JSContext* cx, JSCompartment* comp,
|
|||||||
memcpy(buf, name.get(), name.Length() + 1);
|
memcpy(buf, name.get(), name.Length() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GetRealmName(JSContext* cx, JS::Handle<JS::Realm*> realm, char* buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
JSCompartment* comp = JS::GetCompartmentForRealm(realm);
|
||||||
|
CompartmentNameCallback(cx, comp, buf, bufsize);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
PreserveWrapper(JSContext* cx, JSObject* obj)
|
PreserveWrapper(JSContext* cx, JSObject* obj)
|
||||||
{
|
{
|
||||||
@@ -2834,6 +2842,7 @@ XPCJSRuntime::Initialize(JSContext* cx)
|
|||||||
JS_SetDestroyCompartmentCallback(cx, CompartmentDestroyedCallback);
|
JS_SetDestroyCompartmentCallback(cx, CompartmentDestroyedCallback);
|
||||||
JS_SetSizeOfIncludingThisCompartmentCallback(cx, CompartmentSizeOfIncludingThisCallback);
|
JS_SetSizeOfIncludingThisCompartmentCallback(cx, CompartmentSizeOfIncludingThisCallback);
|
||||||
JS_SetCompartmentNameCallback(cx, CompartmentNameCallback);
|
JS_SetCompartmentNameCallback(cx, CompartmentNameCallback);
|
||||||
|
JS::SetRealmNameCallback(cx, GetRealmName);
|
||||||
mPrevGCSliceCallback = JS::SetGCSliceCallback(cx, GCSliceCallback);
|
mPrevGCSliceCallback = JS::SetGCSliceCallback(cx, GCSliceCallback);
|
||||||
mPrevDoCycleCollectionCallback = JS::SetDoCycleCollectionCallback(cx,
|
mPrevDoCycleCollectionCallback = JS::SetDoCycleCollectionCallback(cx,
|
||||||
DoCycleCollectionCallback);
|
DoCycleCollectionCallback);
|
||||||
|
|||||||
@@ -392,8 +392,7 @@ Version(JSContext* cx, unsigned argc, Value* vp)
|
|||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
args.rval().setInt32(JS_GetVersion(cx));
|
args.rval().setInt32(JS_GetVersion(cx));
|
||||||
if (args.get(0).isInt32())
|
if (args.get(0).isInt32())
|
||||||
JS_SetVersionForCompartment(js::GetContextCompartment(cx),
|
SetVersionForCurrentRealm(cx, JSVersion(args[0].toInt32()));
|
||||||
JSVersion(args[0].toInt32()));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1086,8 +1085,7 @@ ProcessArgs(AutoJSAPI& jsapi, char** argv, int argc, XPCShellDirProvider* aDirPr
|
|||||||
if (++i == argc) {
|
if (++i == argc) {
|
||||||
return printUsageAndSetExitCode();
|
return printUsageAndSetExitCode();
|
||||||
}
|
}
|
||||||
JS_SetVersionForCompartment(js::GetContextCompartment(cx),
|
SetVersionForCurrentRealm(cx, JSVersion(atoi(argv[i])));
|
||||||
JSVersion(atoi(argv[i])));
|
|
||||||
break;
|
break;
|
||||||
case 'W':
|
case 'W':
|
||||||
reportWarnings = false;
|
reportWarnings = false;
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
|
|||||||
mComponents(nullptr),
|
mComponents(nullptr),
|
||||||
mNext(nullptr),
|
mNext(nullptr),
|
||||||
mGlobalJSObject(aGlobal),
|
mGlobalJSObject(aGlobal),
|
||||||
mHasCallInterpositions(false),
|
|
||||||
mIsContentXBLScope(false),
|
mIsContentXBLScope(false),
|
||||||
mIsAddonScope(false)
|
mIsAddonScope(false)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1022,9 +1022,6 @@ public:
|
|||||||
static bool UpdateInterpositionWhitelist(JSContext* cx,
|
static bool UpdateInterpositionWhitelist(JSContext* cx,
|
||||||
nsIAddonInterposition* interposition);
|
nsIAddonInterposition* interposition);
|
||||||
|
|
||||||
void SetAddonCallInterposition() { mHasCallInterpositions = true; }
|
|
||||||
bool HasCallInterposition() { return mHasCallInterpositions; };
|
|
||||||
|
|
||||||
static bool AllowCPOWsInAddon(JSContext* cx, JSAddonId* addonId, bool allow);
|
static bool AllowCPOWsInAddon(JSContext* cx, JSAddonId* addonId, bool allow);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -1072,10 +1069,6 @@ private:
|
|||||||
// objects from other scope, for add-on compatibility reasons.
|
// objects from other scope, for add-on compatibility reasons.
|
||||||
nsCOMPtr<nsIAddonInterposition> mInterposition;
|
nsCOMPtr<nsIAddonInterposition> mInterposition;
|
||||||
|
|
||||||
// If this flag is set, we intercept function calls on vanilla JS function objects
|
|
||||||
// from this scope if the caller scope has mInterposition set.
|
|
||||||
bool mHasCallInterpositions;
|
|
||||||
|
|
||||||
JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos;
|
JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos;
|
||||||
|
|
||||||
bool mIsContentXBLScope;
|
bool mIsContentXBLScope;
|
||||||
@@ -3018,6 +3011,9 @@ bool ReportWrapperDenial(JSContext* cx, JS::HandleId id, WrapperDenialType type,
|
|||||||
|
|
||||||
class CompartmentPrivate
|
class CompartmentPrivate
|
||||||
{
|
{
|
||||||
|
CompartmentPrivate() = delete;
|
||||||
|
CompartmentPrivate(const CompartmentPrivate&) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum LocationHint {
|
enum LocationHint {
|
||||||
LocationHintRegular,
|
LocationHintRegular,
|
||||||
@@ -3063,15 +3059,20 @@ public:
|
|||||||
// classes, for example).
|
// classes, for example).
|
||||||
bool skipWriteToGlobalPrototype;
|
bool skipWriteToGlobalPrototype;
|
||||||
|
|
||||||
// This scope corresponds to a WebExtension content script, and receives
|
// This compartment corresponds to a WebExtension content script, and
|
||||||
// various bits of special compatibility behavior.
|
// receives various bits of special compatibility behavior.
|
||||||
bool isWebExtensionContentScript;
|
bool isWebExtensionContentScript;
|
||||||
|
|
||||||
// Even if an add-on needs interposition, it does not necessary need it
|
// Even if an add-on needs interposition, it does not necessary need it
|
||||||
// for every scope. If this flag is set we waive interposition for this
|
// for every compartment. If this flag is set we waive interposition for
|
||||||
// scope.
|
// this compartment.
|
||||||
bool waiveInterposition;
|
bool waiveInterposition;
|
||||||
|
|
||||||
|
// If this flag is set, we intercept function calls on vanilla JS function
|
||||||
|
// objects from this compartment if the caller compartment has the
|
||||||
|
// hasInterposition flag set.
|
||||||
|
bool addonCallInterposition;
|
||||||
|
|
||||||
// If CPOWs are disabled for browser code via the
|
// If CPOWs are disabled for browser code via the
|
||||||
// dom.ipc.cpows.forbid-unsafe-from-browser preferences, then only
|
// dom.ipc.cpows.forbid-unsafe-from-browser preferences, then only
|
||||||
// add-ons can use CPOWs. This flag allows a non-addon scope
|
// add-ons can use CPOWs. This flag allows a non-addon scope
|
||||||
@@ -3152,6 +3153,8 @@ public:
|
|||||||
locationURI = aLocationURI;
|
locationURI = aLocationURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetAddonCallInterposition() { addonCallInterposition = true; }
|
||||||
|
|
||||||
JSObject2WrappedJSMap* GetWrappedJSMap() const { return mWrappedJSMap; }
|
JSObject2WrappedJSMap* GetWrappedJSMap() const { return mWrappedJSMap; }
|
||||||
void UpdateWeakPointersAfterGC();
|
void UpdateWeakPointersAfterGC();
|
||||||
|
|
||||||
|
|||||||
@@ -114,8 +114,7 @@ InterposeCall(JSContext* cx, JS::HandleObject target, const JS::CallArgs& args,
|
|||||||
nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
|
nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
|
||||||
|
|
||||||
RootedObject unwrappedTarget(cx, UncheckedUnwrap(target));
|
RootedObject unwrappedTarget(cx, UncheckedUnwrap(target));
|
||||||
XPCWrappedNativeScope* targetScope = ObjectScope(unwrappedTarget);
|
bool hasInterpostion = xpc::CompartmentPrivate::Get(unwrappedTarget)->addonCallInterposition;
|
||||||
bool hasInterpostion = targetScope->HasCallInterposition();
|
|
||||||
|
|
||||||
if (!hasInterpostion)
|
if (!hasInterpostion)
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -64,7 +64,6 @@
|
|||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsLineBreaker.h"
|
#include "nsLineBreaker.h"
|
||||||
#include "nsIWordBreaker.h"
|
#include "nsIWordBreaker.h"
|
||||||
#include "nsGenericDOMDataNode.h"
|
|
||||||
#include "nsIFrameInlines.h"
|
#include "nsIFrameInlines.h"
|
||||||
#include "mozilla/StyleSetHandle.h"
|
#include "mozilla/StyleSetHandle.h"
|
||||||
#include "mozilla/StyleSetHandleInlines.h"
|
#include "mozilla/StyleSetHandleInlines.h"
|
||||||
@@ -736,7 +735,9 @@ int32_t nsTextFrame::GetInFlowContentLength() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FlowLengthProperty* flowLength =
|
FlowLengthProperty* flowLength =
|
||||||
static_cast<FlowLengthProperty*>(mContent->GetProperty(nsGkAtoms::flowlength));
|
mContent->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)
|
||||||
|
? static_cast<FlowLengthProperty*>(mContent->GetProperty(nsGkAtoms::flowlength))
|
||||||
|
: nullptr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This frame must start inside the cached flow. If the flow starts at
|
* This frame must start inside the cached flow. If the flow starts at
|
||||||
@@ -764,6 +765,7 @@ int32_t nsTextFrame::GetInFlowContentLength() {
|
|||||||
delete flowLength;
|
delete flowLength;
|
||||||
flowLength = nullptr;
|
flowLength = nullptr;
|
||||||
}
|
}
|
||||||
|
mContent->SetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
|
||||||
}
|
}
|
||||||
if (flowLength) {
|
if (flowLength) {
|
||||||
flowLength->mStartOffset = mContentOffset;
|
flowLength->mStartOffset = mContentOffset;
|
||||||
@@ -4380,9 +4382,13 @@ nsTextFrame::Init(nsIContent* aContent,
|
|||||||
|
|
||||||
// Remove any NewlineOffsetProperty or InFlowContentLengthProperty since they
|
// Remove any NewlineOffsetProperty or InFlowContentLengthProperty since they
|
||||||
// might be invalid if the content was modified while there was no frame
|
// might be invalid if the content was modified while there was no frame
|
||||||
|
if (aContent->HasFlag(NS_HAS_NEWLINE_PROPERTY)) {
|
||||||
aContent->DeleteProperty(nsGkAtoms::newline);
|
aContent->DeleteProperty(nsGkAtoms::newline);
|
||||||
if (PresContext()->BidiEnabled()) {
|
aContent->UnsetFlags(NS_HAS_NEWLINE_PROPERTY);
|
||||||
|
}
|
||||||
|
if (aContent->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
|
||||||
aContent->DeleteProperty(nsGkAtoms::flowlength);
|
aContent->DeleteProperty(nsGkAtoms::flowlength);
|
||||||
|
aContent->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since our content has a frame now, this flag is no longer needed.
|
// Since our content has a frame now, this flag is no longer needed.
|
||||||
@@ -4830,9 +4836,13 @@ nsTextFrame::DisconnectTextRuns()
|
|||||||
nsresult
|
nsresult
|
||||||
nsTextFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
|
nsTextFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
|
||||||
{
|
{
|
||||||
|
if (mContent->HasFlag(NS_HAS_NEWLINE_PROPERTY)) {
|
||||||
mContent->DeleteProperty(nsGkAtoms::newline);
|
mContent->DeleteProperty(nsGkAtoms::newline);
|
||||||
if (PresContext()->BidiEnabled()) {
|
mContent->UnsetFlags(NS_HAS_NEWLINE_PROPERTY);
|
||||||
|
}
|
||||||
|
if (mContent->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
|
||||||
mContent->DeleteProperty(nsGkAtoms::flowlength);
|
mContent->DeleteProperty(nsGkAtoms::flowlength);
|
||||||
|
mContent->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the first frame whose text has changed. Frames that are entirely
|
// Find the first frame whose text has changed. Frames that are entirely
|
||||||
@@ -9278,7 +9288,9 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||||||
NewlineProperty* cachedNewlineOffset = nullptr;
|
NewlineProperty* cachedNewlineOffset = nullptr;
|
||||||
if (textStyle->NewlineIsSignificant(this)) {
|
if (textStyle->NewlineIsSignificant(this)) {
|
||||||
cachedNewlineOffset =
|
cachedNewlineOffset =
|
||||||
static_cast<NewlineProperty*>(mContent->GetProperty(nsGkAtoms::newline));
|
mContent->HasFlag(NS_HAS_NEWLINE_PROPERTY)
|
||||||
|
? static_cast<NewlineProperty*>(mContent->GetProperty(nsGkAtoms::newline))
|
||||||
|
: nullptr;
|
||||||
if (cachedNewlineOffset && cachedNewlineOffset->mStartOffset <= offset &&
|
if (cachedNewlineOffset && cachedNewlineOffset->mStartOffset <= offset &&
|
||||||
(cachedNewlineOffset->mNewlineOffset == -1 ||
|
(cachedNewlineOffset->mNewlineOffset == -1 ||
|
||||||
cachedNewlineOffset->mNewlineOffset >= offset)) {
|
cachedNewlineOffset->mNewlineOffset >= offset)) {
|
||||||
@@ -9763,6 +9775,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||||||
delete cachedNewlineOffset;
|
delete cachedNewlineOffset;
|
||||||
cachedNewlineOffset = nullptr;
|
cachedNewlineOffset = nullptr;
|
||||||
}
|
}
|
||||||
|
mContent->SetFlags(NS_HAS_NEWLINE_PROPERTY);
|
||||||
}
|
}
|
||||||
if (cachedNewlineOffset) {
|
if (cachedNewlineOffset) {
|
||||||
cachedNewlineOffset->mStartOffset = offset;
|
cachedNewlineOffset->mStartOffset = offset;
|
||||||
@@ -9770,6 +9783,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||||||
}
|
}
|
||||||
} else if (cachedNewlineOffset) {
|
} else if (cachedNewlineOffset) {
|
||||||
mContent->DeleteProperty(nsGkAtoms::newline);
|
mContent->DeleteProperty(nsGkAtoms::newline);
|
||||||
|
mContent->UnsetFlags(NS_HAS_NEWLINE_PROPERTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute space and letter counts for justification, if required
|
// Compute space and letter counts for justification, if required
|
||||||
@@ -10252,7 +10266,10 @@ void
|
|||||||
nsTextFrame::AdjustOffsetsForBidi(int32_t aStart, int32_t aEnd)
|
nsTextFrame::AdjustOffsetsForBidi(int32_t aStart, int32_t aEnd)
|
||||||
{
|
{
|
||||||
AddStateBits(NS_FRAME_IS_BIDI);
|
AddStateBits(NS_FRAME_IS_BIDI);
|
||||||
|
if (mContent->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
|
||||||
mContent->DeleteProperty(nsGkAtoms::flowlength);
|
mContent->DeleteProperty(nsGkAtoms::flowlength);
|
||||||
|
mContent->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* After Bidi resolution we may need to reassign text runs.
|
* After Bidi resolution we may need to reassign text runs.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "nsFrame.h"
|
#include "nsFrame.h"
|
||||||
#include "nsFrameSelection.h"
|
#include "nsFrameSelection.h"
|
||||||
|
#include "nsGenericDOMDataNode.h"
|
||||||
#include "nsSplittableFrame.h"
|
#include "nsSplittableFrame.h"
|
||||||
#include "nsLineBox.h"
|
#include "nsLineBox.h"
|
||||||
#include "gfxSkipChars.h"
|
#include "gfxSkipChars.h"
|
||||||
@@ -96,7 +97,10 @@ public:
|
|||||||
aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
||||||
// Setting a non-fluid continuation might affect our flow length (they're
|
// Setting a non-fluid continuation might affect our flow length (they're
|
||||||
// quite rare so we assume it always does) so we delete our cached value:
|
// quite rare so we assume it always does) so we delete our cached value:
|
||||||
|
if (GetContent()->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
|
||||||
GetContent()->DeleteProperty(nsGkAtoms::flowlength);
|
GetContent()->DeleteProperty(nsGkAtoms::flowlength);
|
||||||
|
GetContent()->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
nsIFrame* GetNextInFlowVirtual() const override { return GetNextInFlow(); }
|
nsIFrame* GetNextInFlowVirtual() const override { return GetNextInFlow(); }
|
||||||
nsTextFrame* GetNextInFlow() const
|
nsTextFrame* GetNextInFlow() const
|
||||||
@@ -119,7 +123,10 @@ public:
|
|||||||
!mNextContinuation->HasAnyStateBits(NS_FRAME_IS_FLUID_CONTINUATION)) {
|
!mNextContinuation->HasAnyStateBits(NS_FRAME_IS_FLUID_CONTINUATION)) {
|
||||||
// Changing from non-fluid to fluid continuation might affect our flow
|
// Changing from non-fluid to fluid continuation might affect our flow
|
||||||
// length, so we delete our cached value:
|
// length, so we delete our cached value:
|
||||||
|
if (GetContent()->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
|
||||||
GetContent()->DeleteProperty(nsGkAtoms::flowlength);
|
GetContent()->DeleteProperty(nsGkAtoms::flowlength);
|
||||||
|
GetContent()->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (aNextInFlow) {
|
if (aNextInFlow) {
|
||||||
aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ random-if(winWidget) == 305643-1.html 305643-1-ref.html # depends on windows ver
|
|||||||
== 413542-1.html 413542-1-ref.html
|
== 413542-1.html 413542-1-ref.html
|
||||||
== 413542-2.html 413542-2-ref.html
|
== 413542-2.html 413542-2-ref.html
|
||||||
fails-if(webrender) == 413928-1.html 413928-1-ref.html
|
fails-if(webrender) == 413928-1.html 413928-1-ref.html
|
||||||
== 413928-2.html 413928-2-ref.html
|
fails-if(webrender) == 413928-2.html 413928-2-ref.html
|
||||||
== 425338-1a.html 425338-1-ref.html
|
== 425338-1a.html 425338-1-ref.html
|
||||||
== 425338-1b.html 425338-1-ref.html
|
== 425338-1b.html 425338-1-ref.html
|
||||||
== 489517-1.html 489517-1-ref.html
|
== 489517-1.html 489517-1-ref.html
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ parser.add_argument('-sfl', '--max-stack-frame-length', type=int,
|
|||||||
parser.add_argument('-a', '--ignore-alloc-fns', action='store_true',
|
parser.add_argument('-a', '--ignore-alloc-fns', action='store_true',
|
||||||
help='ignore allocation functions at the start of traces')
|
help='ignore allocation functions at the start of traces')
|
||||||
|
|
||||||
parser.add_argument('-f', '--max-frames', type=range_1_24,
|
parser.add_argument('-f', '--max-frames', type=range_1_24, default=8,
|
||||||
help='maximum number of frames to consider in each trace')
|
help='maximum number of frames to consider in each trace')
|
||||||
|
|
||||||
parser.add_argument('-c', '--chain-reports', action='store_true',
|
parser.add_argument('-c', '--chain-reports', action='store_true',
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ variable is used to find breakpad symbols for stack fixing.
|
|||||||
p.add_argument('-o', '--output', type=argparse.FileType('w'),
|
p.add_argument('-o', '--output', type=argparse.FileType('w'),
|
||||||
help='output file; stdout if unspecified')
|
help='output file; stdout if unspecified')
|
||||||
|
|
||||||
p.add_argument('-f', '--max-frames', type=range_1_24,
|
p.add_argument('-f', '--max-frames', type=range_1_24, default=8,
|
||||||
help='maximum number of frames to consider in each trace')
|
help='maximum number of frames to consider in each trace')
|
||||||
|
|
||||||
p.add_argument('-s', '--sort-by', choices=sortByChoices.keys(),
|
p.add_argument('-s', '--sort-by', choices=sortByChoices.keys(),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#-----------------------------------------------------------------
|
#-----------------------------------------------------------------
|
||||||
# dmd.py --filter-stacks-for-testing -o script-max-frames-8-actual.txt --max-frames=8 script-max-frames.json
|
# dmd.py --filter-stacks-for-testing -o script-max-frames-8-actual.txt script-max-frames.json
|
||||||
|
|
||||||
Invocation {
|
Invocation {
|
||||||
$DMD = '--mode=live --stacks=full'
|
$DMD = '--mode=live --stacks=full'
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ function run_test() {
|
|||||||
// of the tested values.
|
// of the tested values.
|
||||||
jsonFile = FileUtils.getFile("CurWorkD", ["script-max-frames.json"]);
|
jsonFile = FileUtils.getFile("CurWorkD", ["script-max-frames.json"]);
|
||||||
test("script-max-frames-8",
|
test("script-max-frames-8",
|
||||||
["--max-frames=8", jsonFile.path]);
|
[jsonFile.path]); // --max-frames=8 is the default
|
||||||
test("script-max-frames-3",
|
test("script-max-frames-3",
|
||||||
["--max-frames=3", "--no-fix-stacks", jsonFile.path]);
|
["--max-frames=3", "--no-fix-stacks", jsonFile.path]);
|
||||||
test("script-max-frames-1",
|
test("script-max-frames-1",
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
|||||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||||
|
|
||||||
/* globals TabBase, WindowBase, TabTrackerBase, WindowTrackerBase, TabManagerBase, WindowManagerBase */
|
/* globals TabBase, WindowBase, TabTrackerBase, WindowTrackerBase, TabManagerBase, WindowManagerBase */
|
||||||
Cu.import("resource://gre/modules/ExtensionTabs.jsm");
|
|
||||||
/* globals EventDispatcher */
|
/* globals EventDispatcher */
|
||||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ from mozboot.util import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
APPLICATION_CHOICE = '''
|
APPLICATION_CHOICE = '''
|
||||||
Please choose the version of Firefox you want to build:
|
|
||||||
%s
|
|
||||||
|
|
||||||
Note on Artifact Mode:
|
Note on Artifact Mode:
|
||||||
|
|
||||||
Firefox for Desktop and Android supports a fast build mode called
|
Firefox for Desktop and Android supports a fast build mode called
|
||||||
@@ -56,6 +53,8 @@ But don't worry! You can always switch configurations later.
|
|||||||
You can learn more about Artifact mode builds at
|
You can learn more about Artifact mode builds at
|
||||||
https://developer.mozilla.org/en-US/docs/Artifact_builds.
|
https://developer.mozilla.org/en-US/docs/Artifact_builds.
|
||||||
|
|
||||||
|
Please choose the version of Firefox you want to build:
|
||||||
|
%s
|
||||||
Your choice: '''
|
Your choice: '''
|
||||||
|
|
||||||
APPLICATIONS_LIST=[
|
APPLICATIONS_LIST=[
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ HistoryStore.prototype = {
|
|||||||
|
|
||||||
async applyIncomingBatch(records) {
|
async applyIncomingBatch(records) {
|
||||||
let failed = [];
|
let failed = [];
|
||||||
|
let blockers = [];
|
||||||
|
|
||||||
// Convert incoming records to mozIPlaceInfo objects. Some records can be
|
// Convert incoming records to mozIPlaceInfo objects. Some records can be
|
||||||
// ignored or handled directly, so we're rewriting the array in-place.
|
// ignored or handled directly, so we're rewriting the array in-place.
|
||||||
@@ -184,7 +185,9 @@ HistoryStore.prototype = {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (record.deleted) {
|
if (record.deleted) {
|
||||||
await this.remove(record);
|
let promise = this.remove(record);
|
||||||
|
promise = promise.catch(ex => failed.push(record.id));
|
||||||
|
blockers.push(promise);
|
||||||
|
|
||||||
// No further processing needed. Remove it from the list.
|
// No further processing needed. Remove it from the list.
|
||||||
shouldApply = false;
|
shouldApply = false;
|
||||||
@@ -206,9 +209,20 @@ HistoryStore.prototype = {
|
|||||||
records.length = k; // truncate array
|
records.length = k; // truncate array
|
||||||
|
|
||||||
if (records.length) {
|
if (records.length) {
|
||||||
await PlacesUtils.history.insertMany(records)
|
blockers.push(new Promise(resolve => {
|
||||||
|
let updatePlacesCallback = {
|
||||||
|
handleResult: function handleResult() {},
|
||||||
|
handleError: function handleError(resultCode, placeInfo) {
|
||||||
|
failed.push(placeInfo.guid);
|
||||||
|
},
|
||||||
|
handleCompletion: resolve,
|
||||||
|
};
|
||||||
|
this._asyncHistory.updatePlaces(records, updatePlacesCallback);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// failed is updated asynchronously, hence the await on blockers.
|
||||||
|
await Promise.all(blockers);
|
||||||
return failed;
|
return failed;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -221,8 +235,11 @@ HistoryStore.prototype = {
|
|||||||
*/
|
*/
|
||||||
async _recordToPlaceInfo(record) {
|
async _recordToPlaceInfo(record) {
|
||||||
// Sort out invalid URIs and ones Places just simply doesn't want.
|
// Sort out invalid URIs and ones Places just simply doesn't want.
|
||||||
record.url = PlacesUtils.normalizeToURLOrGUID(record.histUri);
|
|
||||||
record.uri = Utils.makeURI(record.histUri);
|
record.uri = Utils.makeURI(record.histUri);
|
||||||
|
if (!record.uri) {
|
||||||
|
this._log.warn("Attempted to process invalid URI, skipping.");
|
||||||
|
throw new Error("Invalid URI in record");
|
||||||
|
}
|
||||||
|
|
||||||
if (!Utils.checkGUID(record.id)) {
|
if (!Utils.checkGUID(record.id)) {
|
||||||
this._log.warn("Encountered record with invalid GUID: " + record.id);
|
this._log.warn("Encountered record with invalid GUID: " + record.id);
|
||||||
@@ -279,8 +296,8 @@ HistoryStore.prototype = {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
visit.date = PlacesUtils.toDate(visit.date);
|
visit.visitDate = visit.date;
|
||||||
visit.transition = visit.type;
|
visit.transitionType = visit.type;
|
||||||
k += 1;
|
k += 1;
|
||||||
}
|
}
|
||||||
record.visits.length = k; // truncate array
|
record.visits.length = k; // truncate array
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
mar==2.1.2
|
mar==2.1.2
|
||||||
|
backports.lzma==0.0.8
|
||||||
redo
|
redo
|
||||||
|
|||||||
@@ -88,7 +88,12 @@ function step2() {
|
|||||||
// top window time and iframe window time.
|
// top window time and iframe window time.
|
||||||
assert_greater_than(topWindowTimeBeforeNotification, iframeWindowTimeAfterNotification,
|
assert_greater_than(topWindowTimeBeforeNotification, iframeWindowTimeAfterNotification,
|
||||||
"Time ranges for top and iframe windows are disjoint. Times: " +
|
"Time ranges for top and iframe windows are disjoint. Times: " +
|
||||||
[topWindowTimeOnTestStart, topWindowTimeBeforeCreatingIframe, topWindowTimeBeforeNotification, topWindowTimeAfterNotification, iframeWindowTimeBeforeNotification, iframeWindowTimeAfterNotification]);
|
[topWindowTimeOnTestStart, topWindowTimeBeforeCreatingIframe,
|
||||||
|
topWindowTimeBeforeNotification, topWindowTimeAfterNotification,
|
||||||
|
iframeWindowTimeBeforeNotification, iframeWindowTimeAfterNotification,
|
||||||
|
topWindowEntries[1].time - topWindowTimeBeforeNotification,
|
||||||
|
iframeWindowEntries[1].time - iframeWindowTimeBeforeNotification
|
||||||
|
]);
|
||||||
|
|
||||||
assert_equals(topWindowEntries.length, 2, "Top window observer has two notifications.");
|
assert_equals(topWindowEntries.length, 2, "Top window observer has two notifications.");
|
||||||
assert_between_inclusive(
|
assert_between_inclusive(
|
||||||
|
|||||||
@@ -18,10 +18,14 @@ XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI",
|
|||||||
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
|
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
|
||||||
"resource://gre/modules/Schemas.jsm");
|
"resource://gre/modules/Schemas.jsm");
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||||
|
|
||||||
const global = this;
|
const global = this;
|
||||||
|
|
||||||
class ExtensionAPI {
|
class ExtensionAPI extends ExtensionUtils.EventEmitter {
|
||||||
constructor(extension) {
|
constructor(extension) {
|
||||||
|
super();
|
||||||
|
|
||||||
this.extension = extension;
|
this.extension = extension;
|
||||||
|
|
||||||
extension.once("shutdown", () => {
|
extension.once("shutdown", () => {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["ExtensionCommon"];
|
this.EXPORTED_SYMBOLS = ["ExtensionCommon"];
|
||||||
|
|
||||||
|
Cu.importGlobalProperties(["fetch"]);
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
@@ -618,6 +620,26 @@ function deepCopy(dest, source) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getChild(map, key) {
|
||||||
|
let child = map.children.get(key);
|
||||||
|
if (!child) {
|
||||||
|
child = {
|
||||||
|
modules: new Set(),
|
||||||
|
children: new Map(),
|
||||||
|
};
|
||||||
|
|
||||||
|
map.children.set(key, child);
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPath(map, path) {
|
||||||
|
for (let key of path) {
|
||||||
|
map = getChild(map, key);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages loading and accessing a set of APIs for a specific extension
|
* Manages loading and accessing a set of APIs for a specific extension
|
||||||
* context.
|
* context.
|
||||||
@@ -712,7 +734,7 @@ class CanOfAPIs {
|
|||||||
if (!obj) {
|
if (!obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
modules = modules.get(key);
|
modules = getChild(modules, key);
|
||||||
|
|
||||||
for (let name of modules.modules) {
|
for (let name of modules.modules) {
|
||||||
if (!this.apis.has(name)) {
|
if (!this.apis.has(name)) {
|
||||||
@@ -748,7 +770,7 @@ class CanOfAPIs {
|
|||||||
if (!obj) {
|
if (!obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
modules = modules.get(key);
|
modules = getChild(modules, key);
|
||||||
|
|
||||||
for (let name of modules.modules) {
|
for (let name of modules.modules) {
|
||||||
if (!this.apis.has(name)) {
|
if (!this.apis.has(name)) {
|
||||||
@@ -768,18 +790,6 @@ class CanOfAPIs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeepMap extends DefaultMap {
|
|
||||||
constructor() {
|
|
||||||
super(() => new DeepMap());
|
|
||||||
|
|
||||||
this.modules = new Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPath(path) {
|
|
||||||
return path.reduce((map, key) => map.get(key), this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class APIModule
|
* @class APIModule
|
||||||
* @abstract
|
* @abstract
|
||||||
@@ -832,10 +842,12 @@ class SchemaAPIManager extends EventEmitter {
|
|||||||
this.global = this._createExtGlobal();
|
this.global = this._createExtGlobal();
|
||||||
|
|
||||||
this.modules = new Map();
|
this.modules = new Map();
|
||||||
this.modulePaths = new DeepMap();
|
this.modulePaths = {children: new Map(), modules: new Set()};
|
||||||
this.manifestKeys = new Map();
|
this.manifestKeys = new Map();
|
||||||
this.eventModules = new DefaultMap(() => new Set());
|
this.eventModules = new DefaultMap(() => new Set());
|
||||||
|
|
||||||
|
this._modulesJSONLoaded = false;
|
||||||
|
|
||||||
this.schemaURLs = new Set();
|
this.schemaURLs = new Set();
|
||||||
|
|
||||||
this.apis = new DefaultWeakMap(() => new Map());
|
this.apis = new DefaultWeakMap(() => new Map());
|
||||||
@@ -843,6 +855,41 @@ class SchemaAPIManager extends EventEmitter {
|
|||||||
this._scriptScopes = [];
|
this._scriptScopes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async loadModuleJSON(urls) {
|
||||||
|
function fetchJSON(url) {
|
||||||
|
return fetch(url).then(resp => resp.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let json of await Promise.all(urls.map(fetchJSON))) {
|
||||||
|
this.registerModules(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._modulesJSONLoaded = true;
|
||||||
|
|
||||||
|
return new StructuredCloneHolder({
|
||||||
|
modules: this.modules,
|
||||||
|
modulePaths: this.modulePaths,
|
||||||
|
manifestKeys: this.manifestKeys,
|
||||||
|
eventModules: this.eventModules,
|
||||||
|
schemaURLs: this.schemaURLs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initModuleData(moduleData) {
|
||||||
|
if (!this._modulesJSONLoaded) {
|
||||||
|
let data = moduleData.deserialize({});
|
||||||
|
|
||||||
|
this.modules = data.modules;
|
||||||
|
this.modulePaths = data.modulePaths;
|
||||||
|
this.manifestKeys = data.manifestKeys;
|
||||||
|
this.eventModules = new DefaultMap(() => new Set(),
|
||||||
|
data.eventModules);
|
||||||
|
this.schemaURLs = data.schemaURLs;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._modulesJSONLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a set of ExtensionAPI modules to be lazily loaded and
|
* Registers a set of ExtensionAPI modules to be lazily loaded and
|
||||||
* managed by this manager.
|
* managed by this manager.
|
||||||
@@ -878,7 +925,7 @@ class SchemaAPIManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let path of details.paths || []) {
|
for (let path of details.paths || []) {
|
||||||
this.modulePaths.getPath(path).modules.add(name);
|
getPath(this.modulePaths, path).modules.add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ var {
|
|||||||
} = ExtensionUtils;
|
} = ExtensionUtils;
|
||||||
|
|
||||||
const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
|
const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
|
||||||
|
const CATEGORY_EXTENSION_MODULES = "webextension-modules";
|
||||||
const CATEGORY_EXTENSION_SCHEMAS = "webextension-schemas";
|
const CATEGORY_EXTENSION_SCHEMAS = "webextension-schemas";
|
||||||
const CATEGORY_EXTENSION_SCRIPTS = "webextension-scripts";
|
const CATEGORY_EXTENSION_SCRIPTS = "webextension-scripts";
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ schemaURLs.add("chrome://extensions/content/schemas/experiments.json");
|
|||||||
let GlobalManager;
|
let GlobalManager;
|
||||||
let ParentAPIManager;
|
let ParentAPIManager;
|
||||||
let ProxyMessenger;
|
let ProxyMessenger;
|
||||||
|
let StartupCache;
|
||||||
|
|
||||||
// This object loads the ext-*.js scripts that define the extension API.
|
// This object loads the ext-*.js scripts that define the extension API.
|
||||||
let apiManager = new class extends SchemaAPIManager {
|
let apiManager = new class extends SchemaAPIManager {
|
||||||
@@ -93,18 +95,31 @@ let apiManager = new class extends SchemaAPIManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getModuleJSONURLs() {
|
||||||
|
return Array.from(XPCOMUtils.enumerateCategoryEntries(CATEGORY_EXTENSION_MODULES),
|
||||||
|
([name, url]) => url);
|
||||||
|
}
|
||||||
|
|
||||||
// Loads all the ext-*.js scripts currently registered.
|
// Loads all the ext-*.js scripts currently registered.
|
||||||
lazyInit() {
|
lazyInit() {
|
||||||
if (this.initialized) {
|
if (this.initialized) {
|
||||||
return this.initialized;
|
return this.initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
let scripts = [];
|
let modulesPromise = StartupCache.other.get(
|
||||||
|
["parentModules"],
|
||||||
|
() => this.loadModuleJSON(this.getModuleJSONURLs()));
|
||||||
|
|
||||||
|
let scriptURLs = [];
|
||||||
for (let [/* name */, value] of XPCOMUtils.enumerateCategoryEntries(CATEGORY_EXTENSION_SCRIPTS)) {
|
for (let [/* name */, value] of XPCOMUtils.enumerateCategoryEntries(CATEGORY_EXTENSION_SCRIPTS)) {
|
||||||
scripts.push(value);
|
scriptURLs.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let promise = Promise.all(scripts.map(url => ChromeUtils.compileScript(url))).then(scripts => {
|
let promise = (async () => {
|
||||||
|
let scripts = await Promise.all(scriptURLs.map(url => ChromeUtils.compileScript(url)));
|
||||||
|
|
||||||
|
this.initModuleData(await modulesPromise);
|
||||||
|
|
||||||
for (let script of scripts) {
|
for (let script of scripts) {
|
||||||
script.executeInGlobal(this.global);
|
script.executeInGlobal(this.global);
|
||||||
}
|
}
|
||||||
@@ -124,7 +139,7 @@ let apiManager = new class extends SchemaAPIManager {
|
|||||||
}
|
}
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
});
|
});
|
||||||
});
|
})();
|
||||||
|
|
||||||
/* eslint-disable mozilla/balanced-listeners */
|
/* eslint-disable mozilla/balanced-listeners */
|
||||||
Services.mm.addMessageListener("Extension:GetTabAndWindowId", this);
|
Services.mm.addMessageListener("Extension:GetTabAndWindowId", this);
|
||||||
@@ -1361,10 +1376,10 @@ let IconDetails = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let StartupCache = {
|
StartupCache = {
|
||||||
DB_NAME: "ExtensionStartupCache",
|
DB_NAME: "ExtensionStartupCache",
|
||||||
|
|
||||||
STORE_NAMES: Object.freeze(["locales", "manifests", "permissions", "schemas"]),
|
STORE_NAMES: Object.freeze(["general", "locales", "manifests", "other", "permissions", "schemas"]),
|
||||||
|
|
||||||
get file() {
|
get file() {
|
||||||
return FileUtils.getFile("ProfLD", ["startupCache", "webext.sc.lz4"]);
|
return FileUtils.getFile("ProfLD", ["startupCache", "webext.sc.lz4"]);
|
||||||
@@ -1413,6 +1428,7 @@ let StartupCache = {
|
|||||||
|
|
||||||
clearAddonData(id) {
|
clearAddonData(id) {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
|
this.general.delete(id),
|
||||||
this.locales.delete(id),
|
this.locales.delete(id),
|
||||||
this.manifests.delete(id),
|
this.manifests.delete(id),
|
||||||
this.permissions.delete(id),
|
this.permissions.delete(id),
|
||||||
@@ -1428,6 +1444,15 @@ let StartupCache = {
|
|||||||
this._dataPromise = Promise.resolve(this._data);
|
this._dataPromise = Promise.resolve(this._data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get(extension, path, createFunc) {
|
||||||
|
return this.general.get([extension.id, extension.version, ...path],
|
||||||
|
createFunc);
|
||||||
|
},
|
||||||
|
|
||||||
|
delete(extension, path) {
|
||||||
|
return this.general.delete([extension.id, extension.version, ...path]);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// void StartupCache.dataPromise;
|
// void StartupCache.dataPromise;
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
|||||||
"resource://gre/modules/osfile.jsm");
|
"resource://gre/modules/osfile.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||||
"resource://gre/modules/FileUtils.jsm");
|
"resource://gre/modules/FileUtils.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
|
||||||
"resource://gre/modules/EventEmitter.jsm");
|
|
||||||
|
|
||||||
var {
|
var {
|
||||||
|
EventEmitter,
|
||||||
normalizeTime,
|
normalizeTime,
|
||||||
} = ExtensionUtils;
|
} = ExtensionUtils;
|
||||||
|
|
||||||
@@ -142,19 +141,22 @@ class DownloadItem {
|
|||||||
// DownloadMap maps back and forth betwen the numeric identifiers used in
|
// DownloadMap maps back and forth betwen the numeric identifiers used in
|
||||||
// the downloads WebExtension API and a Download object from the Downloads jsm.
|
// the downloads WebExtension API and a Download object from the Downloads jsm.
|
||||||
// todo: make id and extension info persistent (bug 1247794)
|
// todo: make id and extension info persistent (bug 1247794)
|
||||||
const DownloadMap = {
|
const DownloadMap = new class extends EventEmitter {
|
||||||
currentId: 0,
|
constructor() {
|
||||||
loadPromise: null,
|
super();
|
||||||
|
|
||||||
|
this.currentId = 0;
|
||||||
|
this.loadPromise = null;
|
||||||
|
|
||||||
// Maps numeric id -> DownloadItem
|
// Maps numeric id -> DownloadItem
|
||||||
byId: new Map(),
|
this.byId = new Map();
|
||||||
|
|
||||||
// Maps Download object -> DownloadItem
|
// Maps Download object -> DownloadItem
|
||||||
byDownload: new WeakMap(),
|
this.byDownload = new WeakMap();
|
||||||
|
}
|
||||||
|
|
||||||
lazyInit() {
|
lazyInit() {
|
||||||
if (this.loadPromise == null) {
|
if (this.loadPromise == null) {
|
||||||
EventEmitter.decorate(this);
|
|
||||||
this.loadPromise = Downloads.getList(Downloads.ALL).then(list => {
|
this.loadPromise = Downloads.getList(Downloads.ALL).then(list => {
|
||||||
let self = this;
|
let self = this;
|
||||||
return list.addView({
|
return list.addView({
|
||||||
@@ -192,15 +194,15 @@ const DownloadMap = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this.loadPromise;
|
return this.loadPromise;
|
||||||
},
|
}
|
||||||
|
|
||||||
getDownloadList() {
|
getDownloadList() {
|
||||||
return this.lazyInit();
|
return this.lazyInit();
|
||||||
},
|
}
|
||||||
|
|
||||||
getAll() {
|
getAll() {
|
||||||
return this.lazyInit().then(() => this.byId.values());
|
return this.lazyInit().then(() => this.byId.values());
|
||||||
},
|
}
|
||||||
|
|
||||||
fromId(id) {
|
fromId(id) {
|
||||||
const download = this.byId.get(id);
|
const download = this.byId.get(id);
|
||||||
@@ -208,7 +210,7 @@ const DownloadMap = {
|
|||||||
throw new Error(`Invalid download id ${id}`);
|
throw new Error(`Invalid download id ${id}`);
|
||||||
}
|
}
|
||||||
return download;
|
return download;
|
||||||
},
|
}
|
||||||
|
|
||||||
newFromDownload(download, extension) {
|
newFromDownload(download, extension) {
|
||||||
if (this.byDownload.has(download)) {
|
if (this.byDownload.has(download)) {
|
||||||
@@ -220,7 +222,7 @@ const DownloadMap = {
|
|||||||
this.byId.set(id, item);
|
this.byId.set(id, item);
|
||||||
this.byDownload.set(download, item);
|
this.byDownload.set(download, item);
|
||||||
return item;
|
return item;
|
||||||
},
|
}
|
||||||
|
|
||||||
erase(item) {
|
erase(item) {
|
||||||
// This will need to get more complicated for bug 1255507 but for now we
|
// This will need to get more complicated for bug 1255507 but for now we
|
||||||
@@ -228,8 +230,8 @@ const DownloadMap = {
|
|||||||
return this.getDownloadList().then(list => {
|
return this.getDownloadList().then(list => {
|
||||||
list.remove(item.download);
|
list.remove(item.download);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
};
|
}();
|
||||||
|
|
||||||
// Create a callable function that filters a DownloadItem based on a
|
// Create a callable function that filters a DownloadItem based on a
|
||||||
// query object of the type passed to search() or erase().
|
// query object of the type passed to search() or erase().
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-toolkit.js */
|
/* import-globals-from ext-toolkit.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
|
||||||
"resource://gre/modules/EventEmitter.jsm");
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "idleService",
|
XPCOMUtils.defineLazyServiceGetter(this, "idleService",
|
||||||
"@mozilla.org/widget/idleservice;1",
|
"@mozilla.org/widget/idleservice;1",
|
||||||
"nsIIdleService");
|
"nsIIdleService");
|
||||||
@@ -37,14 +35,13 @@ const getIdleObserver = (extension, context) => {
|
|||||||
let observerInfo = getIdleObserverInfo(extension, context);
|
let observerInfo = getIdleObserverInfo(extension, context);
|
||||||
let {observer, detectionInterval} = observerInfo;
|
let {observer, detectionInterval} = observerInfo;
|
||||||
if (!observer) {
|
if (!observer) {
|
||||||
observer = {
|
observer = new class extends ExtensionUtils.EventEmitter {
|
||||||
observe: function(subject, topic, data) {
|
observe(subject, topic, data) {
|
||||||
if (topic == "idle" || topic == "active") {
|
if (topic == "idle" || topic == "active") {
|
||||||
this.emit("stateChanged", topic);
|
this.emit("stateChanged", topic);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
}();
|
||||||
EventEmitter.decorate(observer);
|
|
||||||
idleService.addIdleObserver(observer, detectionInterval);
|
idleService.addIdleObserver(observer, detectionInterval);
|
||||||
observerInfo.observer = observer;
|
observerInfo.observer = observer;
|
||||||
observerInfo.detectionInterval = detectionInterval;
|
observerInfo.detectionInterval = detectionInterval;
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
|||||||
XPCOMUtils.defineLazyServiceGetter(this, "promptService",
|
XPCOMUtils.defineLazyServiceGetter(this, "promptService",
|
||||||
"@mozilla.org/embedcomp/prompt-service;1",
|
"@mozilla.org/embedcomp/prompt-service;1",
|
||||||
"nsIPromptService");
|
"nsIPromptService");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
|
||||||
"resource://gre/modules/EventEmitter.jsm");
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "GlobalManager", () => {
|
XPCOMUtils.defineLazyGetter(this, "GlobalManager", () => {
|
||||||
const {GlobalManager} = Cu.import("resource://gre/modules/Extension.jsm", {});
|
const {GlobalManager} = Cu.import("resource://gre/modules/Extension.jsm", {});
|
||||||
@@ -91,10 +89,10 @@ const listenerMap = new WeakMap();
|
|||||||
// Some management APIs are intentionally limited.
|
// Some management APIs are intentionally limited.
|
||||||
const allowedTypes = ["theme", "extension"];
|
const allowedTypes = ["theme", "extension"];
|
||||||
|
|
||||||
class AddonListener {
|
class AddonListener extends ExtensionUtils.EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super();
|
||||||
AddonManager.addAddonListener(this);
|
AddonManager.addAddonListener(this);
|
||||||
EventEmitter.decorate(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
release() {
|
release() {
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
// The ext-* files are imported into the same scopes.
|
// The ext-* files are imported into the same scopes.
|
||||||
/* import-globals-from ext-toolkit.js */
|
/* import-globals-from ext-toolkit.js */
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
const ToolkitModules = {};
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(ToolkitModules, "EventEmitter",
|
||||||
"resource://gre/modules/EventEmitter.jsm");
|
"resource://gre/modules/EventEmitter.jsm");
|
||||||
|
|
||||||
var {
|
var {
|
||||||
@@ -98,7 +100,7 @@ this.notifications = class extends ExtensionAPI {
|
|||||||
let {extension} = context;
|
let {extension} = context;
|
||||||
|
|
||||||
let map = new Map();
|
let map = new Map();
|
||||||
EventEmitter.decorate(map);
|
ToolkitModules.EventEmitter.decorate(map);
|
||||||
notificationsMap.set(extension, map);
|
notificationsMap.set(extension, map);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -5,11 +5,7 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
/* globals EventEmitter */
|
||||||
|
|
||||||
/* exported TabTrackerBase, TabManagerBase, TabBase, WindowTrackerBase, WindowManagerBase, WindowBase */
|
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ["TabTrackerBase", "TabManagerBase", "TabBase", "WindowTrackerBase", "WindowManagerBase", "WindowBase"];
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
@@ -18,12 +14,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
|||||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||||
"resource://gre/modules/Services.jsm");
|
"resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
var {
|
||||||
|
|
||||||
const {
|
|
||||||
DefaultMap,
|
DefaultMap,
|
||||||
DefaultWeakMap,
|
DefaultWeakMap,
|
||||||
EventEmitter,
|
|
||||||
ExtensionError,
|
ExtensionError,
|
||||||
defineLazyGetter,
|
defineLazyGetter,
|
||||||
getWinUtils,
|
getWinUtils,
|
||||||
@@ -1847,3 +1840,5 @@ class WindowManagerBase {
|
|||||||
}
|
}
|
||||||
/* eslint-enable valid-jsdoc */
|
/* eslint-enable valid-jsdoc */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object.assign(global, {TabTrackerBase, TabManagerBase, TabBase, WindowTrackerBase, WindowManagerBase, WindowBase});
|
||||||
@@ -17,6 +17,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
|
|||||||
|
|
||||||
Cu.import("resource://gre/modules/ExtensionCommon.jsm");
|
Cu.import("resource://gre/modules/ExtensionCommon.jsm");
|
||||||
|
|
||||||
|
global.EventEmitter = ExtensionUtils.EventEmitter;
|
||||||
global.EventManager = ExtensionCommon.EventManager;
|
global.EventManager = ExtensionCommon.EventManager;
|
||||||
global.InputEventManager = class extends EventManager {
|
global.InputEventManager = class extends EventManager {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
@@ -78,185 +79,6 @@ global.isValidCookieStoreId = function(storeId) {
|
|||||||
isContainerCookieStoreId(storeId);
|
isContainerCookieStoreId(storeId);
|
||||||
};
|
};
|
||||||
|
|
||||||
extensions.registerModules({
|
|
||||||
manifest: {
|
|
||||||
schema: "chrome://extensions/content/schemas/extension_types.json",
|
|
||||||
scopes: [],
|
|
||||||
},
|
|
||||||
alarms: {
|
|
||||||
url: "chrome://extensions/content/ext-alarms.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/alarms.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["alarms"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
backgroundPage: {
|
|
||||||
url: "chrome://extensions/content/ext-backgroundPage.js",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
manifest: ["background"],
|
|
||||||
},
|
|
||||||
browserSettings: {
|
|
||||||
url: "chrome://extensions/content/ext-browserSettings.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/browser_settings.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["browserSettings"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
contextualIdentities: {
|
|
||||||
url: "chrome://extensions/content/ext-contextualIdentities.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/contextual_identities.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["contextualIdentities"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
cookies: {
|
|
||||||
url: "chrome://extensions/content/ext-cookies.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/cookies.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["cookies"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
downloads: {
|
|
||||||
url: "chrome://extensions/content/ext-downloads.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/downloads.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["downloads"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
extension: {
|
|
||||||
url: "chrome://extensions/content/ext-extension.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/extension.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["extension"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
geolocation: {
|
|
||||||
url: "chrome://extensions/content/ext-geolocation.js",
|
|
||||||
events: ["startup"],
|
|
||||||
},
|
|
||||||
i18n: {
|
|
||||||
url: "chrome://extensions/content/ext-i18n.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/i18n.json",
|
|
||||||
scopes: ["addon_parent", "content_child", "devtools_child"],
|
|
||||||
paths: [
|
|
||||||
["i18n"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
idle: {
|
|
||||||
url: "chrome://extensions/content/ext-idle.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/idle.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["idle"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
management: {
|
|
||||||
url: "chrome://extensions/content/ext-management.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/management.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["management"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
notifications: {
|
|
||||||
url: "chrome://extensions/content/ext-notifications.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/notifications.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["notifications"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
permissions: {
|
|
||||||
url: "chrome://extensions/content/ext-permissions.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/permissions.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["permissions"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
privacy: {
|
|
||||||
url: "chrome://extensions/content/ext-privacy.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/privacy.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["privacy"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
protocolHandlers: {
|
|
||||||
url: "chrome://extensions/content/ext-protocolHandlers.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/extension_protocol_handlers.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
manifest: ["protocol_handlers"],
|
|
||||||
},
|
|
||||||
proxy: {
|
|
||||||
url: "chrome://extensions/content/ext-proxy.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/proxy.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["proxy"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
runtime: {
|
|
||||||
url: "chrome://extensions/content/ext-runtime.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/runtime.json",
|
|
||||||
scopes: ["addon_parent", "content_parent", "devtools_parent"],
|
|
||||||
paths: [
|
|
||||||
["runtime"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
storage: {
|
|
||||||
url: "chrome://extensions/content/ext-storage.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/storage.json",
|
|
||||||
scopes: ["addon_parent", "content_parent", "devtools_parent"],
|
|
||||||
paths: [
|
|
||||||
["storage"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
test: {
|
|
||||||
schema: "chrome://extensions/content/schemas/test.json",
|
|
||||||
scopes: [],
|
|
||||||
},
|
|
||||||
theme: {
|
|
||||||
url: "chrome://extensions/content/ext-theme.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/theme.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
manifest: ["theme"],
|
|
||||||
paths: [
|
|
||||||
["theme"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
topSites: {
|
|
||||||
url: "chrome://extensions/content/ext-topSites.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/top_sites.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["topSites"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
webNavigation: {
|
|
||||||
url: "chrome://extensions/content/ext-webNavigation.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/web_navigation.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["webNavigation"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
webRequest: {
|
|
||||||
url: "chrome://extensions/content/ext-webRequest.js",
|
|
||||||
schema: "chrome://extensions/content/schemas/web_request.json",
|
|
||||||
scopes: ["addon_parent"],
|
|
||||||
paths: [
|
|
||||||
["webRequest"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (AppConstants.MOZ_BUILD_APP === "browser") {
|
if (AppConstants.MOZ_BUILD_APP === "browser") {
|
||||||
extensions.registerModules({
|
extensions.registerModules({
|
||||||
identity: {
|
identity: {
|
||||||
|
|||||||
178
toolkit/components/extensions/ext-toolkit.json
Normal file
178
toolkit/components/extensions/ext-toolkit.json
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
{
|
||||||
|
"manifest": {
|
||||||
|
"schema": "chrome://extensions/content/schemas/extension_types.json",
|
||||||
|
"scopes": []
|
||||||
|
},
|
||||||
|
"alarms": {
|
||||||
|
"url": "chrome://extensions/content/ext-alarms.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/alarms.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["alarms"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"backgroundPage": {
|
||||||
|
"url": "chrome://extensions/content/ext-backgroundPage.js",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["background"]
|
||||||
|
},
|
||||||
|
"browserSettings": {
|
||||||
|
"url": "chrome://extensions/content/ext-browserSettings.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/browser_settings.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["browserSettings"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"contextualIdentities": {
|
||||||
|
"url": "chrome://extensions/content/ext-contextualIdentities.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/contextual_identities.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["contextualIdentities"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"cookies": {
|
||||||
|
"url": "chrome://extensions/content/ext-cookies.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/cookies.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["cookies"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"downloads": {
|
||||||
|
"url": "chrome://extensions/content/ext-downloads.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/downloads.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["downloads"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extension": {
|
||||||
|
"url": "chrome://extensions/content/ext-extension.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/extension.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["extension"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"geolocation": {
|
||||||
|
"url": "chrome://extensions/content/ext-geolocation.js",
|
||||||
|
"events": ["startup"]
|
||||||
|
},
|
||||||
|
"i18n": {
|
||||||
|
"url": "chrome://extensions/content/ext-i18n.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/i18n.json",
|
||||||
|
"scopes": ["addon_parent", "content_child", "devtools_child"],
|
||||||
|
"paths": [
|
||||||
|
["i18n"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"idle": {
|
||||||
|
"url": "chrome://extensions/content/ext-idle.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/idle.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["idle"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"management": {
|
||||||
|
"url": "chrome://extensions/content/ext-management.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/management.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["management"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"url": "chrome://extensions/content/ext-notifications.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/notifications.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["notifications"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"url": "chrome://extensions/content/ext-permissions.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/permissions.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["permissions"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"privacy": {
|
||||||
|
"url": "chrome://extensions/content/ext-privacy.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/privacy.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["privacy"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"protocolHandlers": {
|
||||||
|
"url": "chrome://extensions/content/ext-protocolHandlers.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/extension_protocol_handlers.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["protocol_handlers"]
|
||||||
|
},
|
||||||
|
"proxy": {
|
||||||
|
"url": "chrome://extensions/content/ext-proxy.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/proxy.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["proxy"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"url": "chrome://extensions/content/ext-runtime.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/runtime.json",
|
||||||
|
"scopes": ["addon_parent", "content_parent", "devtools_parent"],
|
||||||
|
"paths": [
|
||||||
|
["runtime"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"url": "chrome://extensions/content/ext-storage.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/storage.json",
|
||||||
|
"scopes": ["addon_parent", "content_parent", "devtools_parent"],
|
||||||
|
"paths": [
|
||||||
|
["storage"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"schema": "chrome://extensions/content/schemas/test.json",
|
||||||
|
"scopes": []
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"url": "chrome://extensions/content/ext-theme.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/theme.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"manifest": ["theme"],
|
||||||
|
"paths": [
|
||||||
|
["theme"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"topSites": {
|
||||||
|
"url": "chrome://extensions/content/ext-topSites.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/top_sites.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["topSites"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"webNavigation": {
|
||||||
|
"url": "chrome://extensions/content/ext-webNavigation.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/web_navigation.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["webNavigation"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"webRequest": {
|
||||||
|
"url": "chrome://extensions/content/ext-webRequest.js",
|
||||||
|
"schema": "chrome://extensions/content/schemas/web_request.json",
|
||||||
|
"scopes": ["addon_parent"],
|
||||||
|
"paths": [
|
||||||
|
["webRequest"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
# scripts
|
# scripts
|
||||||
category webextension-scripts toolkit chrome://extensions/content/ext-toolkit.js
|
category webextension-modules toolkit chrome://extensions/content/ext-toolkit.json
|
||||||
|
|
||||||
|
category webextension-scripts a-toolkit chrome://extensions/content/ext-toolkit.js
|
||||||
|
category webextension-scripts b-tabs-base chrome://extensions/content/ext-tabs-base.js
|
||||||
|
|
||||||
category webextension-scripts-content toolkit chrome://extensions/content/ext-c-toolkit.js
|
category webextension-scripts-content toolkit chrome://extensions/content/ext-c-toolkit.js
|
||||||
category webextension-scripts-devtools toolkit chrome://extensions/content/ext-c-toolkit.js
|
category webextension-scripts-devtools toolkit chrome://extensions/content/ext-c-toolkit.js
|
||||||
category webextension-scripts-addon toolkit chrome://extensions/content/ext-c-toolkit.js
|
category webextension-scripts-addon toolkit chrome://extensions/content/ext-c-toolkit.js
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ toolkit.jar:
|
|||||||
content/extensions/ext-proxy.js
|
content/extensions/ext-proxy.js
|
||||||
content/extensions/ext-runtime.js
|
content/extensions/ext-runtime.js
|
||||||
content/extensions/ext-storage.js
|
content/extensions/ext-storage.js
|
||||||
|
content/extensions/ext-tabs-base.js
|
||||||
content/extensions/ext-theme.js
|
content/extensions/ext-theme.js
|
||||||
content/extensions/ext-toolkit.js
|
content/extensions/ext-toolkit.js
|
||||||
|
content/extensions/ext-toolkit.json
|
||||||
content/extensions/ext-topSites.js
|
content/extensions/ext-topSites.js
|
||||||
content/extensions/ext-webRequest.js
|
content/extensions/ext-webRequest.js
|
||||||
content/extensions/ext-webNavigation.js
|
content/extensions/ext-webNavigation.js
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ EXTRA_JS_MODULES += [
|
|||||||
'ExtensionSettingsStore.jsm',
|
'ExtensionSettingsStore.jsm',
|
||||||
'ExtensionStorage.jsm',
|
'ExtensionStorage.jsm',
|
||||||
'ExtensionStorageSync.jsm',
|
'ExtensionStorageSync.jsm',
|
||||||
'ExtensionTabs.jsm',
|
|
||||||
'ExtensionUtils.jsm',
|
'ExtensionUtils.jsm',
|
||||||
'LegacyExtensionsUtils.jsm',
|
'LegacyExtensionsUtils.jsm',
|
||||||
'MessageChannel.jsm',
|
'MessageChannel.jsm',
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user