mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
092e5dc5f1
@ -461,11 +461,15 @@ DocAccessibleParent::Destroy()
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mChildDocs.IsEmpty(),
|
||||
"why weren't the child docs destroyed already?");
|
||||
mShutdown = true;
|
||||
|
||||
uint32_t childDocCount = mChildDocs.Length();
|
||||
for (uint32_t i = 0; i < childDocCount; i++) {
|
||||
for (uint32_t j = i + 1; j < childDocCount; j++) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mChildDocs[i] != mChildDocs[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
|
||||
mChildDocs[i]->Destroy();
|
||||
|
||||
|
@ -221,7 +221,7 @@ BrowserAction.prototype = {
|
||||
// If we have a pending pre-loaded popup, cancel it after we've waited
|
||||
// long enough that we can be relatively certain it won't be opening.
|
||||
if (this.pendingPopup) {
|
||||
let {node} = this.widget.forWindow(window);
|
||||
let node = window.gBrowser && this.widget.forWindow(window).node;
|
||||
if (isAncestorOrSelf(node, event.originalTarget)) {
|
||||
this.pendingPopupTimeout = setTimeout(() => this.clearPopup(),
|
||||
POPUP_PRELOAD_TIMEOUT_MS);
|
||||
|
@ -58,9 +58,9 @@ extensions.on("page-shutdown", (type, context) => {
|
||||
}
|
||||
let {gBrowser} = context.xulBrowser.ownerGlobal;
|
||||
if (gBrowser) {
|
||||
let tab = gBrowser.getTabForBrowser(context.xulBrowser);
|
||||
if (tab) {
|
||||
gBrowser.removeTab(tab);
|
||||
let nativeTab = gBrowser.getTabForBrowser(context.xulBrowser);
|
||||
if (nativeTab) {
|
||||
gBrowser.removeTab(nativeTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,16 +83,16 @@ let tabListener = {
|
||||
onLocationChange(browser, webProgress, request, locationURI, flags) {
|
||||
if (webProgress.isTopLevel) {
|
||||
let {gBrowser} = browser.ownerGlobal;
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
let nativeTab = gBrowser.getTabForBrowser(browser);
|
||||
|
||||
// Now we are certain that the first page in the tab was loaded.
|
||||
this.initializingTabs.delete(tab);
|
||||
this.initializingTabs.delete(nativeTab);
|
||||
|
||||
// browser.innerWindowID is now set, resolve the promises if any.
|
||||
let deferred = this.tabReadyPromises.get(tab);
|
||||
let deferred = this.tabReadyPromises.get(nativeTab);
|
||||
if (deferred) {
|
||||
deferred.resolve(tab);
|
||||
this.tabReadyPromises.delete(tab);
|
||||
deferred.resolve(nativeTab);
|
||||
this.tabReadyPromises.delete(nativeTab);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -103,19 +103,20 @@ let tabListener = {
|
||||
* changes to the requested URL. Other tabs are assumed to be ready once their
|
||||
* inner window ID is known.
|
||||
*
|
||||
* @param {XULElement} tab The <tab> element.
|
||||
* @param {XULElement} nativeTab The <tab> element.
|
||||
* @returns {Promise} Resolves with the given tab once ready.
|
||||
*/
|
||||
awaitTabReady(tab) {
|
||||
let deferred = this.tabReadyPromises.get(tab);
|
||||
awaitTabReady(nativeTab) {
|
||||
let deferred = this.tabReadyPromises.get(nativeTab);
|
||||
if (!deferred) {
|
||||
deferred = PromiseUtils.defer();
|
||||
if (!this.initializingTabs.has(tab) && (tab.linkedBrowser.innerWindowID ||
|
||||
tab.linkedBrowser.currentURI.spec === "about:blank")) {
|
||||
deferred.resolve(tab);
|
||||
if (!this.initializingTabs.has(nativeTab) &&
|
||||
(nativeTab.linkedBrowser.innerWindowID ||
|
||||
nativeTab.linkedBrowser.currentURI.spec === "about:blank")) {
|
||||
deferred.resolve(nativeTab);
|
||||
} else {
|
||||
this.initTabReady();
|
||||
this.tabReadyPromises.set(tab, deferred);
|
||||
this.tabReadyPromises.set(nativeTab, deferred);
|
||||
}
|
||||
}
|
||||
return deferred.promise;
|
||||
@ -142,7 +143,7 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
tab = tabManager.getWrapper(tabTracker.activeTab);
|
||||
}
|
||||
|
||||
await tabListener.awaitTabReady(tab.tab);
|
||||
await tabListener.awaitTabReady(tab.nativeTab);
|
||||
|
||||
return tab;
|
||||
}
|
||||
@ -150,15 +151,15 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
let self = {
|
||||
tabs: {
|
||||
onActivated: new WindowEventManager(context, "tabs.onActivated", "TabSelect", (fire, event) => {
|
||||
let tab = event.originalTarget;
|
||||
let tabId = tabTracker.getId(tab);
|
||||
let windowId = windowTracker.getId(tab.ownerGlobal);
|
||||
let nativeTab = event.originalTarget;
|
||||
let tabId = tabTracker.getId(nativeTab);
|
||||
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
|
||||
fire.async({tabId, windowId});
|
||||
}).api(),
|
||||
|
||||
onCreated: new SingletonEventManager(context, "tabs.onCreated", fire => {
|
||||
let listener = (eventName, event) => {
|
||||
fire.async(tabManager.convert(event.tab));
|
||||
fire.async(tabManager.convert(event.nativeTab));
|
||||
};
|
||||
|
||||
tabTracker.on("tab-created", listener);
|
||||
@ -174,9 +175,9 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
|
||||
*/
|
||||
onHighlighted: new WindowEventManager(context, "tabs.onHighlighted", "TabSelect", (fire, event) => {
|
||||
let tab = event.originalTarget;
|
||||
let tabIds = [tabTracker.getId(tab)];
|
||||
let windowId = windowTracker.getId(tab.ownerGlobal);
|
||||
let nativeTab = event.originalTarget;
|
||||
let tabIds = [tabTracker.getId(nativeTab)];
|
||||
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
|
||||
fire.async({tabIds, windowId});
|
||||
}).api(),
|
||||
|
||||
@ -236,17 +237,17 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
};
|
||||
|
||||
let moveListener = event => {
|
||||
let tab = event.originalTarget;
|
||||
let nativeTab = event.originalTarget;
|
||||
|
||||
if (ignoreNextMove.has(tab)) {
|
||||
ignoreNextMove.delete(tab);
|
||||
if (ignoreNextMove.has(nativeTab)) {
|
||||
ignoreNextMove.delete(nativeTab);
|
||||
return;
|
||||
}
|
||||
|
||||
fire.async(tabTracker.getId(tab), {
|
||||
windowId: windowTracker.getId(tab.ownerGlobal),
|
||||
fire.async(tabTracker.getId(nativeTab), {
|
||||
windowId: windowTracker.getId(nativeTab.ownerGlobal),
|
||||
fromIndex: event.detail,
|
||||
toIndex: tab._tPos,
|
||||
toIndex: nativeTab._tPos,
|
||||
});
|
||||
};
|
||||
|
||||
@ -400,22 +401,22 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
options.disallowInheritPrincipal = true;
|
||||
|
||||
tabListener.initTabReady();
|
||||
let tab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
|
||||
let nativeTab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
|
||||
|
||||
let active = true;
|
||||
if (createProperties.active !== null) {
|
||||
active = createProperties.active;
|
||||
}
|
||||
if (active) {
|
||||
window.gBrowser.selectedTab = tab;
|
||||
window.gBrowser.selectedTab = nativeTab;
|
||||
}
|
||||
|
||||
if (createProperties.index !== null) {
|
||||
window.gBrowser.moveTabTo(tab, createProperties.index);
|
||||
window.gBrowser.moveTabTo(nativeTab, createProperties.index);
|
||||
}
|
||||
|
||||
if (createProperties.pinned) {
|
||||
window.gBrowser.pinTab(tab);
|
||||
window.gBrowser.pinTab(nativeTab);
|
||||
}
|
||||
|
||||
if (active && !url) {
|
||||
@ -431,10 +432,10 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
// `executeScript` wait until the requested URL is loaded in
|
||||
// the tab before dispatching messages to the inner window
|
||||
// that contains the URL we're attempting to load.
|
||||
tabListener.initializingTabs.add(tab);
|
||||
tabListener.initializingTabs.add(nativeTab);
|
||||
}
|
||||
|
||||
return tabManager.convert(tab);
|
||||
return tabManager.convert(nativeTab);
|
||||
});
|
||||
},
|
||||
|
||||
@ -444,15 +445,15 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
}
|
||||
|
||||
for (let tabId of tabs) {
|
||||
let tab = tabTracker.getTab(tabId);
|
||||
tab.ownerGlobal.gBrowser.removeTab(tab);
|
||||
let nativeTab = tabTracker.getTab(tabId);
|
||||
nativeTab.ownerGlobal.gBrowser.removeTab(nativeTab);
|
||||
}
|
||||
},
|
||||
|
||||
async update(tabId, updateProperties) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = getTabOrActive(tabId);
|
||||
|
||||
let tabbrowser = tab.ownerGlobal.gBrowser;
|
||||
let tabbrowser = nativeTab.ownerGlobal.gBrowser;
|
||||
|
||||
if (updateProperties.url !== null) {
|
||||
let url = context.uri.resolve(updateProperties.url);
|
||||
@ -461,55 +462,53 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
return Promise.reject({message: `Illegal URL: ${url}`});
|
||||
}
|
||||
|
||||
tab.linkedBrowser.loadURI(url);
|
||||
nativeTab.linkedBrowser.loadURI(url);
|
||||
}
|
||||
|
||||
if (updateProperties.active !== null) {
|
||||
if (updateProperties.active) {
|
||||
tabbrowser.selectedTab = tab;
|
||||
tabbrowser.selectedTab = nativeTab;
|
||||
} else {
|
||||
// Not sure what to do here? Which tab should we select?
|
||||
}
|
||||
}
|
||||
if (updateProperties.muted !== null) {
|
||||
if (tab.muted != updateProperties.muted) {
|
||||
tab.toggleMuteAudio(extension.uuid);
|
||||
if (nativeTab.muted != updateProperties.muted) {
|
||||
nativeTab.toggleMuteAudio(extension.uuid);
|
||||
}
|
||||
}
|
||||
if (updateProperties.pinned !== null) {
|
||||
if (updateProperties.pinned) {
|
||||
tabbrowser.pinTab(tab);
|
||||
tabbrowser.pinTab(nativeTab);
|
||||
} else {
|
||||
tabbrowser.unpinTab(tab);
|
||||
tabbrowser.unpinTab(nativeTab);
|
||||
}
|
||||
}
|
||||
// FIXME: highlighted/selected, openerTabId
|
||||
|
||||
return tabManager.convert(tab);
|
||||
return tabManager.convert(nativeTab);
|
||||
},
|
||||
|
||||
async reload(tabId, reloadProperties) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = getTabOrActive(tabId);
|
||||
|
||||
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
if (reloadProperties && reloadProperties.bypassCache) {
|
||||
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
|
||||
}
|
||||
tab.linkedBrowser.reloadWithFlags(flags);
|
||||
nativeTab.linkedBrowser.reloadWithFlags(flags);
|
||||
},
|
||||
|
||||
async get(tabId) {
|
||||
let tab = tabTracker.getTab(tabId);
|
||||
|
||||
return tabManager.convert(tab);
|
||||
return tabManager.get(tabId).convert();
|
||||
},
|
||||
|
||||
getCurrent() {
|
||||
let tab;
|
||||
let tabData;
|
||||
if (context.tabId) {
|
||||
tab = tabManager.get(context.tabId).convert();
|
||||
tabData = tabManager.get(context.tabId).convert();
|
||||
}
|
||||
return Promise.resolve(tab);
|
||||
return Promise.resolve(tabData);
|
||||
},
|
||||
|
||||
async query(queryInfo) {
|
||||
@ -526,53 +525,21 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
tab => tab.convert());
|
||||
},
|
||||
|
||||
captureVisibleTab(windowId, options) {
|
||||
if (!extension.hasPermission("<all_urls>")) {
|
||||
return Promise.reject({message: "The <all_urls> permission is required to use the captureVisibleTab API"});
|
||||
}
|
||||
|
||||
async captureVisibleTab(windowId, options) {
|
||||
let window = windowId == null ?
|
||||
windowTracker.topWindow :
|
||||
windowTracker.getWindow(windowId, context);
|
||||
|
||||
let tab = window.gBrowser.selectedTab;
|
||||
return tabListener.awaitTabReady(tab).then(() => {
|
||||
let browser = tab.linkedBrowser;
|
||||
let recipient = {
|
||||
innerWindowID: browser.innerWindowID,
|
||||
};
|
||||
let tab = tabManager.wrapTab(window.gBrowser.selectedTab);
|
||||
await tabListener.awaitTabReady(tab.nativeTab);
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (options.format == null) {
|
||||
options.format = "png";
|
||||
}
|
||||
if (options.quality == null) {
|
||||
options.quality = 92;
|
||||
}
|
||||
|
||||
let message = {
|
||||
options,
|
||||
width: browser.clientWidth,
|
||||
height: browser.clientHeight,
|
||||
};
|
||||
|
||||
return context.sendMessage(browser.messageManager, "Extension:Capture",
|
||||
message, {recipient});
|
||||
});
|
||||
return tab.capture(context, options);
|
||||
},
|
||||
|
||||
async detectLanguage(tabId) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let tab = await promiseTabWhenReady(tabId);
|
||||
|
||||
return tabListener.awaitTabReady(tab).then(() => {
|
||||
let browser = tab.linkedBrowser;
|
||||
let recipient = {innerWindowID: browser.innerWindowID};
|
||||
|
||||
return context.sendMessage(browser.messageManager, "Extension:DetectLanguage",
|
||||
{}, {recipient});
|
||||
});
|
||||
return tab.sendMessage(context, "Extension:DetectLanguage");
|
||||
},
|
||||
|
||||
async executeScript(tabId, details) {
|
||||
@ -619,9 +586,9 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
let indexMap = new Map();
|
||||
|
||||
let tabs = tabIds.map(tabId => tabTracker.getTab(tabId));
|
||||
for (let tab of tabs) {
|
||||
for (let nativeTab of tabs) {
|
||||
// If the window is not specified, use the window from the tab.
|
||||
let window = destinationWindow || tab.ownerGlobal;
|
||||
let window = destinationWindow || nativeTab.ownerGlobal;
|
||||
let gBrowser = window.gBrowser;
|
||||
|
||||
let insertionPoint = indexMap.get(window) || index;
|
||||
@ -635,32 +602,32 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
// be moved to a position after the current set of pinned tabs.
|
||||
// Attempts to move a tab to an illegal position are ignored.
|
||||
let numPinned = gBrowser._numPinnedTabs;
|
||||
let ok = tab.pinned ? insertionPoint <= numPinned : insertionPoint >= numPinned;
|
||||
let ok = nativeTab.pinned ? insertionPoint <= numPinned : insertionPoint >= numPinned;
|
||||
if (!ok) {
|
||||
continue;
|
||||
}
|
||||
|
||||
indexMap.set(window, insertionPoint + 1);
|
||||
|
||||
if (tab.ownerGlobal != window) {
|
||||
if (nativeTab.ownerGlobal != window) {
|
||||
// If the window we are moving the tab in is different, then move the tab
|
||||
// to the new window.
|
||||
tab = gBrowser.adoptTab(tab, insertionPoint, false);
|
||||
nativeTab = gBrowser.adoptTab(nativeTab, insertionPoint, false);
|
||||
} else {
|
||||
// If the window we are moving is the same, just move the tab.
|
||||
gBrowser.moveTabTo(tab, insertionPoint);
|
||||
gBrowser.moveTabTo(nativeTab, insertionPoint);
|
||||
}
|
||||
tabsMoved.push(tab);
|
||||
tabsMoved.push(nativeTab);
|
||||
}
|
||||
|
||||
return tabsMoved.map(tab => tabManager.convert(tab));
|
||||
return tabsMoved.map(nativeTab => tabManager.convert(nativeTab));
|
||||
},
|
||||
|
||||
duplicate(tabId) {
|
||||
let tab = tabTracker.getTab(tabId);
|
||||
let nativeTab = tabTracker.getTab(tabId);
|
||||
|
||||
let gBrowser = tab.ownerGlobal.gBrowser;
|
||||
let newTab = gBrowser.duplicateTab(tab);
|
||||
let gBrowser = nativeTab.ownerGlobal.gBrowser;
|
||||
let newTab = gBrowser.duplicateTab(nativeTab);
|
||||
|
||||
return new Promise(resolve => {
|
||||
// We need to use SSTabRestoring because any attributes set before
|
||||
@ -671,10 +638,10 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
|
||||
// Pinned tabs that are duplicated are inserted
|
||||
// after the existing pinned tab and pinned.
|
||||
if (tab.pinned) {
|
||||
if (nativeTab.pinned) {
|
||||
gBrowser.pinTab(newTab);
|
||||
}
|
||||
gBrowser.moveTabTo(newTab, tab._tPos + 1);
|
||||
gBrowser.moveTabTo(newTab, nativeTab._tPos + 1);
|
||||
}, {once: true});
|
||||
|
||||
newTab.addEventListener("SSTabRestored", function() {
|
||||
@ -687,24 +654,24 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
},
|
||||
|
||||
getZoom(tabId) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = getTabOrActive(tabId);
|
||||
|
||||
let {ZoomManager} = tab.ownerGlobal;
|
||||
let zoom = ZoomManager.getZoomForBrowser(tab.linkedBrowser);
|
||||
let {ZoomManager} = nativeTab.ownerGlobal;
|
||||
let zoom = ZoomManager.getZoomForBrowser(nativeTab.linkedBrowser);
|
||||
|
||||
return Promise.resolve(zoom);
|
||||
},
|
||||
|
||||
setZoom(tabId, zoom) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = getTabOrActive(tabId);
|
||||
|
||||
let {FullZoom, ZoomManager} = tab.ownerGlobal;
|
||||
let {FullZoom, ZoomManager} = nativeTab.ownerGlobal;
|
||||
|
||||
if (zoom === 0) {
|
||||
// A value of zero means use the default zoom factor.
|
||||
return FullZoom.reset(tab.linkedBrowser);
|
||||
return FullZoom.reset(nativeTab.linkedBrowser);
|
||||
} else if (zoom >= ZoomManager.MIN && zoom <= ZoomManager.MAX) {
|
||||
FullZoom.setZoom(zoom, tab.linkedBrowser);
|
||||
FullZoom.setZoom(zoom, nativeTab.linkedBrowser);
|
||||
} else {
|
||||
return Promise.reject({
|
||||
message: `Zoom value ${zoom} out of range (must be between ${ZoomManager.MIN} and ${ZoomManager.MAX})`,
|
||||
@ -715,9 +682,9 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
},
|
||||
|
||||
_getZoomSettings(tabId) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = getTabOrActive(tabId);
|
||||
|
||||
let {FullZoom} = tab.ownerGlobal;
|
||||
let {FullZoom} = nativeTab.ownerGlobal;
|
||||
|
||||
return {
|
||||
mode: "automatic",
|
||||
@ -731,9 +698,9 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
},
|
||||
|
||||
setZoomSettings(tabId, settings) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = getTabOrActive(tabId);
|
||||
|
||||
let currentSettings = this._getZoomSettings(tab.id);
|
||||
let currentSettings = this._getZoomSettings(tabTracker.getId(nativeTab));
|
||||
|
||||
if (!Object.keys(settings).every(key => settings[key] === currentSettings[key])) {
|
||||
return Promise.reject(`Unsupported zoom settings: ${JSON.stringify(settings)}`);
|
||||
@ -754,14 +721,14 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
|
||||
// Store the zoom level for all existing tabs.
|
||||
for (let window of windowTracker.browserWindows()) {
|
||||
for (let tab of window.gBrowser.tabs) {
|
||||
let browser = tab.linkedBrowser;
|
||||
for (let nativeTab of window.gBrowser.tabs) {
|
||||
let browser = nativeTab.linkedBrowser;
|
||||
zoomLevels.set(browser, getZoomLevel(browser));
|
||||
}
|
||||
}
|
||||
|
||||
let tabCreated = (eventName, event) => {
|
||||
let browser = event.tab.linkedBrowser;
|
||||
let browser = event.nativeTab.linkedBrowser;
|
||||
zoomLevels.set(browser, getZoomLevel(browser));
|
||||
};
|
||||
|
||||
@ -778,8 +745,8 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
}
|
||||
|
||||
let {gBrowser} = browser.ownerGlobal;
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (!tab) {
|
||||
let nativeTab = gBrowser.getTabForBrowser(browser);
|
||||
if (!nativeTab) {
|
||||
// We only care about zoom events in the top-level browser of a tab.
|
||||
return;
|
||||
}
|
||||
@ -790,7 +757,7 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
if (oldZoomFactor != newZoomFactor) {
|
||||
zoomLevels.set(browser, newZoomFactor);
|
||||
|
||||
let tabId = tabTracker.getId(tab);
|
||||
let tabId = tabTracker.getId(nativeTab);
|
||||
fire.async({
|
||||
tabId,
|
||||
oldZoomFactor,
|
||||
|
@ -49,23 +49,23 @@ global.TabContext = function TabContext(getDefaults, extension) {
|
||||
};
|
||||
|
||||
TabContext.prototype = {
|
||||
get(tab) {
|
||||
if (!this.tabData.has(tab)) {
|
||||
this.tabData.set(tab, this.getDefaults(tab));
|
||||
get(nativeTab) {
|
||||
if (!this.tabData.has(nativeTab)) {
|
||||
this.tabData.set(nativeTab, this.getDefaults(nativeTab));
|
||||
}
|
||||
|
||||
return this.tabData.get(tab);
|
||||
return this.tabData.get(nativeTab);
|
||||
},
|
||||
|
||||
clear(tab) {
|
||||
this.tabData.delete(tab);
|
||||
clear(nativeTab) {
|
||||
this.tabData.delete(nativeTab);
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
if (event.type == "TabSelect") {
|
||||
let tab = event.target;
|
||||
this.emit("tab-select", tab);
|
||||
this.emit("location-change", tab);
|
||||
let nativeTab = event.target;
|
||||
this.emit("tab-select", nativeTab);
|
||||
this.emit("location-change", nativeTab);
|
||||
}
|
||||
},
|
||||
|
||||
@ -83,8 +83,8 @@ TabContext.prototype = {
|
||||
let lastLocation = this.lastLocation.get(browser);
|
||||
if (browser === gBrowser.selectedBrowser &&
|
||||
!(lastLocation && lastLocation.equalsExceptRef(browser.currentURI))) {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
this.emit("location-change", tab, true);
|
||||
let nativeTab = gBrowser.getTabForBrowser(browser);
|
||||
this.emit("location-change", nativeTab, true);
|
||||
}
|
||||
this.lastLocation.set(browser, browser.currentURI);
|
||||
},
|
||||
@ -106,6 +106,21 @@ class WindowTracker extends WindowTrackerBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 SingletonEventManager {
|
||||
constructor(context, name, event, listener) {
|
||||
super(context, name, fire => {
|
||||
@ -152,28 +167,28 @@ class TabTracker extends TabTrackerBase {
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
}
|
||||
|
||||
getId(tab) {
|
||||
if (this._tabs.has(tab)) {
|
||||
return this._tabs.get(tab);
|
||||
getId(nativeTab) {
|
||||
if (this._tabs.has(nativeTab)) {
|
||||
return this._tabs.get(nativeTab);
|
||||
}
|
||||
|
||||
this.init();
|
||||
|
||||
let id = this._nextId++;
|
||||
this.setId(tab, id);
|
||||
this.setId(nativeTab, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
setId(tab, id) {
|
||||
this._tabs.set(tab, id);
|
||||
this._tabIds.set(id, tab);
|
||||
setId(nativeTab, id) {
|
||||
this._tabs.set(nativeTab, id);
|
||||
this._tabIds.set(id, nativeTab);
|
||||
}
|
||||
|
||||
_handleTabDestroyed(event, {tab}) {
|
||||
let id = this._tabs.get(tab);
|
||||
_handleTabDestroyed(event, {nativeTab}) {
|
||||
let id = this._tabs.get(nativeTab);
|
||||
if (id) {
|
||||
this._tabs.delete(tab);
|
||||
if (this._tabIds.get(id) === tab) {
|
||||
this._tabs.delete(nativeTab);
|
||||
if (this._tabIds.get(id) === nativeTab) {
|
||||
this._tabIds.delete(id);
|
||||
}
|
||||
}
|
||||
@ -192,9 +207,9 @@ class TabTracker extends TabTrackerBase {
|
||||
* A XUL <tab> element.
|
||||
*/
|
||||
getTab(tabId, default_ = undefined) {
|
||||
let tab = this._tabIds.get(tabId);
|
||||
if (tab) {
|
||||
return tab;
|
||||
let nativeTab = this._tabIds.get(tabId);
|
||||
if (nativeTab) {
|
||||
return nativeTab;
|
||||
}
|
||||
if (default_ !== undefined) {
|
||||
return default_;
|
||||
@ -202,8 +217,13 @@ class TabTracker extends TabTrackerBase {
|
||||
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
* The DOM Event to handle.
|
||||
* @private
|
||||
*/
|
||||
handleEvent(event) {
|
||||
let tab = event.target;
|
||||
let nativeTab = event.target;
|
||||
|
||||
switch (event.type) {
|
||||
case "TabOpen":
|
||||
@ -213,10 +233,10 @@ class TabTracker extends TabTrackerBase {
|
||||
|
||||
// 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(tab, this.getId(adoptedTab));
|
||||
this.setId(nativeTab, this.getId(adoptedTab));
|
||||
|
||||
adoptedTab.linkedBrowser.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", {
|
||||
windowId: windowTracker.getId(tab.ownerGlobal),
|
||||
windowId: windowTracker.getId(nativeTab.ownerGlobal),
|
||||
});
|
||||
}
|
||||
|
||||
@ -238,16 +258,24 @@ class TabTracker extends TabTrackerBase {
|
||||
// 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(tab));
|
||||
this.setId(adoptedBy, this.getId(nativeTab));
|
||||
|
||||
this.emitDetached(tab, adoptedBy);
|
||||
this.emitDetached(nativeTab, adoptedBy);
|
||||
} else {
|
||||
this.emitRemoved(tab, false);
|
||||
this.emitRemoved(nativeTab, false);
|
||||
}
|
||||
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
|
||||
@ -259,16 +287,16 @@ class TabTracker extends TabTrackerBase {
|
||||
// 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 tab = window.arguments[0];
|
||||
let nativeTab = window.arguments[0];
|
||||
let adoptedBy = window.gBrowser.tabs[0];
|
||||
|
||||
this.adoptedTabs.set(tab, adoptedBy);
|
||||
this.setId(adoptedBy, this.getId(tab));
|
||||
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.tab === tab) {
|
||||
if (details.nativeTab === nativeTab) {
|
||||
this.off("tab-detached", listener);
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
@ -279,43 +307,85 @@ class TabTracker extends TabTrackerBase {
|
||||
|
||||
this.on("tab-detached", listener);
|
||||
} else {
|
||||
for (let tab of window.gBrowser.tabs) {
|
||||
this.emitCreated(tab);
|
||||
for (let nativeTab of window.gBrowser.tabs) {
|
||||
this.emitCreated(nativeTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 tab of window.gBrowser.tabs) {
|
||||
if (this.adoptedTabs.has(tab)) {
|
||||
this.emitDetached(tab, this.adoptedTabs.get(tab));
|
||||
for (let nativeTab of window.gBrowser.tabs) {
|
||||
if (this.adoptedTabs.has(nativeTab)) {
|
||||
this.emitDetached(nativeTab, this.adoptedTabs.get(nativeTab));
|
||||
} else {
|
||||
this.emitRemoved(tab, true);
|
||||
this.emitRemoved(nativeTab, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emitAttached(tab) {
|
||||
let newWindowId = windowTracker.getId(tab.ownerGlobal);
|
||||
let tabId = this.getId(tab);
|
||||
/**
|
||||
* 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", {tab, tabId, newWindowId, newPosition: tab._tPos});
|
||||
this.emit("tab-attached", {nativeTab, tabId, newWindowId, newPosition: nativeTab._tPos});
|
||||
}
|
||||
|
||||
emitDetached(tab, adoptedBy) {
|
||||
let oldWindowId = windowTracker.getId(tab.ownerGlobal);
|
||||
let tabId = this.getId(tab);
|
||||
/**
|
||||
* 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", {tab, adoptedBy, tabId, oldWindowId, oldPosition: tab._tPos});
|
||||
this.emit("tab-detached", {nativeTab, adoptedBy, tabId, oldWindowId, oldPosition: nativeTab._tPos});
|
||||
}
|
||||
|
||||
emitCreated(tab) {
|
||||
this.emit("tab-created", {tab});
|
||||
/**
|
||||
* Emits a "tab-created" event for the given tab element.
|
||||
*
|
||||
* @param {NativeTab} nativeTab
|
||||
* The tab element which is being created.
|
||||
* @private
|
||||
*/
|
||||
emitCreated(nativeTab) {
|
||||
this.emit("tab-created", {nativeTab});
|
||||
}
|
||||
|
||||
emitRemoved(tab, isWindowClosing) {
|
||||
let windowId = windowTracker.getId(tab.ownerGlobal);
|
||||
let tabId = this.getId(tab);
|
||||
/**
|
||||
* 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
|
||||
@ -327,7 +397,7 @@ class TabTracker extends TabTrackerBase {
|
||||
// event listener is registered. To make sure that the event listener is
|
||||
// notified, we dispatch `tabs.onRemoved` asynchronously.
|
||||
Services.tm.mainThread.dispatch(() => {
|
||||
this.emit("tab-removed", {tab, tabId, windowId, isWindowClosing});
|
||||
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
@ -351,9 +421,9 @@ class TabTracker extends TabTrackerBase {
|
||||
if (gBrowser && gBrowser.getTabForBrowser) {
|
||||
result.windowId = windowTracker.getId(browser.ownerGlobal);
|
||||
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (tab) {
|
||||
result.tabId = this.getId(tab);
|
||||
let nativeTab = gBrowser.getTabForBrowser(browser);
|
||||
if (nativeTab) {
|
||||
result.tabId = this.getId(nativeTab);
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,19 +446,19 @@ Object.assign(global, {tabTracker, windowTracker});
|
||||
|
||||
class Tab extends TabBase {
|
||||
get _favIconUrl() {
|
||||
return this.window.gBrowser.getIcon(this.tab);
|
||||
return this.window.gBrowser.getIcon(this.nativeTab);
|
||||
}
|
||||
|
||||
get audible() {
|
||||
return this.tab.soundPlaying;
|
||||
return this.nativeTab.soundPlaying;
|
||||
}
|
||||
|
||||
get browser() {
|
||||
return this.tab.linkedBrowser;
|
||||
return this.nativeTab.linkedBrowser;
|
||||
}
|
||||
|
||||
get cookieStoreId() {
|
||||
return getCookieStoreIdForTab(this, this.tab);
|
||||
return getCookieStoreIdForTab(this, this.nativeTab);
|
||||
}
|
||||
|
||||
get height() {
|
||||
@ -396,41 +466,37 @@ class Tab extends TabBase {
|
||||
}
|
||||
|
||||
get index() {
|
||||
return this.tab._tPos;
|
||||
}
|
||||
|
||||
get innerWindowID() {
|
||||
return this.browser.innerWindowID;
|
||||
return this.nativeTab._tPos;
|
||||
}
|
||||
|
||||
get mutedInfo() {
|
||||
let tab = this.tab;
|
||||
let {nativeTab} = this;
|
||||
|
||||
let mutedInfo = {muted: tab.muted};
|
||||
if (tab.muteReason === null) {
|
||||
let mutedInfo = {muted: nativeTab.muted};
|
||||
if (nativeTab.muteReason === null) {
|
||||
mutedInfo.reason = "user";
|
||||
} else if (tab.muteReason) {
|
||||
} else if (nativeTab.muteReason) {
|
||||
mutedInfo.reason = "extension";
|
||||
mutedInfo.extensionId = tab.muteReason;
|
||||
mutedInfo.extensionId = nativeTab.muteReason;
|
||||
}
|
||||
|
||||
return mutedInfo;
|
||||
}
|
||||
|
||||
get pinned() {
|
||||
return this.tab.pinned;
|
||||
return this.nativeTab.pinned;
|
||||
}
|
||||
|
||||
get active() {
|
||||
return this.tab.selected;
|
||||
return this.nativeTab.selected;
|
||||
}
|
||||
|
||||
get selected() {
|
||||
return this.tab.selected;
|
||||
return this.nativeTab.selected;
|
||||
}
|
||||
|
||||
get status() {
|
||||
if (this.tab.getAttribute("busy") === "true") {
|
||||
if (this.nativeTab.getAttribute("busy") === "true") {
|
||||
return "loading";
|
||||
}
|
||||
return "complete";
|
||||
@ -441,31 +507,47 @@ class Tab extends TabBase {
|
||||
}
|
||||
|
||||
get window() {
|
||||
return this.tab.ownerGlobal;
|
||||
return this.nativeTab.ownerGlobal;
|
||||
}
|
||||
|
||||
get windowId() {
|
||||
return windowTracker.getId(this.window);
|
||||
}
|
||||
|
||||
static convertFromSessionStoreClosedData(extension, tab, window = null) {
|
||||
/**
|
||||
* 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(tab.closedId),
|
||||
index: tab.pos ? tab.pos : 0,
|
||||
sessionId: String(tabData.closedId),
|
||||
index: tabData.pos ? tabData.pos : 0,
|
||||
windowId: window && windowTracker.getId(window),
|
||||
selected: false,
|
||||
highlighted: false,
|
||||
active: false,
|
||||
pinned: false,
|
||||
incognito: Boolean(tab.state && tab.state.isPrivate),
|
||||
incognito: Boolean(tabData.state && tabData.state.isPrivate),
|
||||
};
|
||||
|
||||
if (extension.tabManager.hasTabPermission(tab)) {
|
||||
let entries = tab.state ? tab.state.entries : tab.entries;
|
||||
if (extension.tabManager.hasTabPermission(tabData)) {
|
||||
let entries = tabData.state ? tabData.state.entries : tabData.entries;
|
||||
result.url = entries[0].url;
|
||||
result.title = entries[0].title;
|
||||
if (tab.image) {
|
||||
result.favIconUrl = tab.image;
|
||||
if (tabData.image) {
|
||||
result.favIconUrl = tabData.image;
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,6 +556,22 @@ class Tab extends TabBase {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -582,25 +680,38 @@ class Window extends WindowBase {
|
||||
* getTabs() {
|
||||
let {tabManager} = this.extension;
|
||||
|
||||
for (let tab of this.window.gBrowser.tabs) {
|
||||
yield tabManager.getWrapper(tab);
|
||||
for (let nativeTab of this.window.gBrowser.tabs) {
|
||||
yield tabManager.getWrapper(nativeTab);
|
||||
}
|
||||
}
|
||||
|
||||
static convertFromSessionStoreClosedData(extension, 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} windowData
|
||||
* Session store data for a closed window, as returned by
|
||||
* `SessionStore.getClosedWindowData()`.
|
||||
*
|
||||
* @returns {Object}
|
||||
* @static
|
||||
*/
|
||||
static convertFromSessionStoreClosedData(extension, windowData) {
|
||||
let result = {
|
||||
sessionId: String(window.closedId),
|
||||
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(window),
|
||||
state: this.getState(windowData),
|
||||
alwaysOnTop: false,
|
||||
};
|
||||
|
||||
if (window.tabs.length) {
|
||||
result.tabs = window.tabs.map(tab => {
|
||||
return Tab.convertFromSessionStoreClosedData(extension, tab);
|
||||
if (windowData.tabs.length) {
|
||||
result.tabs = windowData.tabs.map(tabData => {
|
||||
return Tab.convertFromSessionStoreClosedData(extension, tabData);
|
||||
});
|
||||
}
|
||||
|
||||
@ -612,24 +723,24 @@ Object.assign(global, {Tab, Window});
|
||||
|
||||
class TabManager extends TabManagerBase {
|
||||
get(tabId, default_ = undefined) {
|
||||
let tab = tabTracker.getTab(tabId, default_);
|
||||
let nativeTab = tabTracker.getTab(tabId, default_);
|
||||
|
||||
if (tab) {
|
||||
return this.getWrapper(tab);
|
||||
if (nativeTab) {
|
||||
return this.getWrapper(nativeTab);
|
||||
}
|
||||
return default_;
|
||||
}
|
||||
|
||||
addActiveTabPermission(tab = tabTracker.activeTab) {
|
||||
return super.addActiveTabPermission(tab);
|
||||
addActiveTabPermission(nativeTab = tabTracker.activeTab) {
|
||||
return super.addActiveTabPermission(nativeTab);
|
||||
}
|
||||
|
||||
revokeActiveTabPermission(tab = tabTracker.activeTab) {
|
||||
return super.revokeActiveTabPermission(tab);
|
||||
revokeActiveTabPermission(nativeTab = tabTracker.activeTab) {
|
||||
return super.revokeActiveTabPermission(nativeTab);
|
||||
}
|
||||
|
||||
wrapTab(tab) {
|
||||
return new Tab(this.extension, tab, tabTracker.getId(tab));
|
||||
wrapTab(nativeTab) {
|
||||
return new Tab(this.extension, nativeTab, tabTracker.getId(nativeTab));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>${url}</body></html>`;
|
||||
|
||||
add_task(function* testBrowserActionClickCanceled() {
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"browser_action": {
|
||||
@ -27,7 +29,6 @@ add_task(function* testBrowserActionClickCanceled() {
|
||||
let browserAction = browserActionFor(ext);
|
||||
|
||||
let widget = getBrowserActionWidget(extension).forWindow(window);
|
||||
let tab = window.gBrowser.selectedTab;
|
||||
|
||||
// Test canceled click.
|
||||
EventUtils.synthesizeMouseAtCenter(widget.node, {type: "mousedown", button: 0}, window);
|
||||
@ -76,6 +77,8 @@ add_task(function* testBrowserActionClickCanceled() {
|
||||
yield closeBrowserAction(extension);
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(function* testBrowserActionDisabled() {
|
||||
|
@ -109,6 +109,7 @@ def rust_triple_alias(host_or_target):
|
||||
# NetBSD
|
||||
('x86_64', 'NetBSD'): 'x86_64-unknown-netbsd',
|
||||
# OpenBSD
|
||||
('x86', 'OpenBSD'): 'i686-unknown-openbsd',
|
||||
('x86_64', 'OpenBSD'): 'x86_64-unknown-openbsd',
|
||||
# Linux
|
||||
('x86', 'Linux'): 'i686-unknown-linux-gnu',
|
||||
|
@ -139,7 +139,7 @@ CopyURIs(const InfallibleTArray<URIParams>& aDomains, nsIDomainSet* aSet)
|
||||
}
|
||||
|
||||
void
|
||||
DomainPolicy::ApplyClone(DomainPolicyClone* aClone)
|
||||
DomainPolicy::ApplyClone(const DomainPolicyClone* aClone)
|
||||
{
|
||||
CopyURIs(aClone->blacklist(), mBlacklist);
|
||||
CopyURIs(aClone->whitelist(), mWhitelist);
|
||||
|
@ -17,6 +17,7 @@ class DomainPolicyClone;
|
||||
%}
|
||||
|
||||
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
|
||||
[ptr] native DomainPolicyCloneConstPtr(const mozilla::dom::DomainPolicyClone);
|
||||
|
||||
/*
|
||||
* When a domain policy is instantiated by invoking activateDomainPolicy() on
|
||||
@ -41,7 +42,7 @@ interface nsIDomainPolicy : nsISupports
|
||||
void deactivate();
|
||||
|
||||
[noscript, notxpcom] void cloneDomainPolicy(in DomainPolicyClonePtr aClone);
|
||||
[noscript, notxpcom] void applyClone(in DomainPolicyClonePtr aClone);
|
||||
[noscript, notxpcom] void applyClone(in DomainPolicyCloneConstPtr aClone);
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(665c981b-0a0f-4229-ac06-a826e02d4f69)]
|
||||
|
@ -59,9 +59,9 @@ exports.viewSourceInDebugger = Task.async(function* (toolbox, sourceURL, sourceL
|
||||
|
||||
// New debugger frontend
|
||||
if (Services.prefs.getBoolPref("devtools.debugger.new-debugger-frontend")) {
|
||||
yield toolbox.selectTool("jsdebugger");
|
||||
const source = dbg._selectors().getSourceByURL(dbg._getState(), sourceURL);
|
||||
if (source) {
|
||||
yield toolbox.selectTool("jsdebugger");
|
||||
dbg._actions().selectSourceURL(sourceURL, { line: sourceLine });
|
||||
return true;
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
EXPORTS.mozilla.dom.battery += [
|
||||
'Constants.h',
|
||||
'Types.h',
|
||||
|
@ -15446,6 +15446,7 @@ class CGCallback(CGClass):
|
||||
|
||||
setupCall = fill(
|
||||
"""
|
||||
MOZ_ASSERT(!aRv.Failed(), "Don't pass an already-failed ErrorResult to a callback!");
|
||||
if (!aExecutionReason) {
|
||||
aExecutionReason = "${executionReason}";
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'BroadcastChannel.h',
|
||||
]
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'BrowserElementParent.h',
|
||||
]
|
||||
|
4
dom/cache/moz.build
vendored
4
dom/cache/moz.build
vendored
@ -4,6 +4,10 @@
|
||||
# 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/.
|
||||
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
EXPORTS.mozilla.dom.cache += [
|
||||
'Action.h',
|
||||
'ActorChild.h',
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "Embedding: APIs")
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsICommandManager.idl',
|
||||
'nsICommandParams.idl',
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIConsoleAPIStorage.idl',
|
||||
]
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Security")
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'CryptoBuffer.h',
|
||||
'CryptoKey.h',
|
||||
|
@ -4,6 +4,10 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
|
||||
EXPORTS += [
|
||||
'DeviceStorage.h',
|
||||
'DeviceStorageFileDescriptor.h',
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Flyweb")
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'FlyWebDiscoveryManager.h',
|
||||
'FlyWebPublishedServer.h',
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'ipc/GamepadEventTypes.ipdlh',
|
||||
'ipc/PGamepadEventChannel.ipdl',
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "Geolocation")
|
||||
|
||||
EXPORTS += [
|
||||
'nsGeoPosition.h',
|
||||
'nsGeoPositionIPCSerialiser.h',
|
||||
|
@ -502,10 +502,24 @@ NS_INTERFACE_MAP_BEGIN(ContentChild)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentChild)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvSetXPCOMProcessAttributes(const XPCOMInitData& aXPCOMInit,
|
||||
const StructuredCloneData& aInitialData,
|
||||
nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache)
|
||||
{
|
||||
mLookAndFeelCache = aLookAndFeelIntCache;
|
||||
InitXPCOM(aXPCOMInit, aInitialData);
|
||||
InitGraphicsDeviceData();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::Init(MessageLoop* aIOLoop,
|
||||
base::ProcessId aParentPid,
|
||||
IPC::Channel* aChannel)
|
||||
IPC::Channel* aChannel,
|
||||
uint64_t aChildID,
|
||||
bool aIsForBrowser)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
// We need to pass a display down to gtk_init because it's not going to
|
||||
@ -571,7 +585,8 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
||||
XRE_GetProcessType());
|
||||
#endif
|
||||
|
||||
SendGetProcessAttributes(&mID, &mIsForBrowser);
|
||||
mID = aChildID;
|
||||
mIsForBrowser = aIsForBrowser;
|
||||
|
||||
#ifdef NS_PRINTING
|
||||
// Force the creation of the nsPrintingProxy so that it's IPC counterpart,
|
||||
@ -933,8 +948,14 @@ ContentChild::InitGraphicsDeviceData()
|
||||
}
|
||||
|
||||
void
|
||||
ContentChild::InitXPCOM()
|
||||
ContentChild::InitXPCOM(const XPCOMInitData& aXPCOMInit,
|
||||
const mozilla::dom::ipc::StructuredCloneData& aInitialData)
|
||||
{
|
||||
SET_PREF_PHASE(pref_initPhase::BEGIN_ALL_PREFS);
|
||||
for (unsigned int i = 0; i < aXPCOMInit.prefs().Length(); i++) {
|
||||
Preferences::SetPreference(aXPCOMInit.prefs().ElementAt(i));
|
||||
}
|
||||
SET_PREF_PHASE(pref_initPhase::END_ALL_PREFS);
|
||||
// Do this as early as possible to get the parent process to initialize the
|
||||
// background thread since we'll likely need database information very soon.
|
||||
BackgroundChild::Startup();
|
||||
@ -957,42 +978,29 @@ ContentChild::InitXPCOM()
|
||||
if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
|
||||
NS_WARNING("Couldn't register console listener for child process");
|
||||
|
||||
bool isOffline, isLangRTL, haveBidiKeyboards;
|
||||
bool isConnected;
|
||||
int32_t captivePortalState;
|
||||
ClipboardCapabilities clipboardCaps;
|
||||
DomainPolicyClone domainPolicy;
|
||||
StructuredCloneData initialData;
|
||||
OptionalURIParams userContentSheetURL;
|
||||
mAvailableDictionaries = aXPCOMInit.dictionaries();
|
||||
|
||||
SendGetXPCOMProcessAttributes(&isOffline, &isConnected, &captivePortalState,
|
||||
&isLangRTL, &haveBidiKeyboards,
|
||||
&mAvailableDictionaries,
|
||||
&clipboardCaps, &domainPolicy, &initialData,
|
||||
&mFontFamilies, &userContentSheetURL,
|
||||
&mLookAndFeelCache);
|
||||
|
||||
RecvSetOffline(isOffline);
|
||||
RecvSetConnectivity(isConnected);
|
||||
RecvSetCaptivePortalState(captivePortalState);
|
||||
RecvBidiKeyboardNotify(isLangRTL, haveBidiKeyboards);
|
||||
RecvSetOffline(aXPCOMInit.isOffline());
|
||||
RecvSetConnectivity(aXPCOMInit.isConnected());
|
||||
RecvSetCaptivePortalState(aXPCOMInit.captivePortalState());
|
||||
RecvBidiKeyboardNotify(aXPCOMInit.isLangRTL(), aXPCOMInit.haveBidiKeyboards());
|
||||
|
||||
// Create the CPOW manager as soon as possible.
|
||||
SendPJavaScriptConstructor();
|
||||
|
||||
if (domainPolicy.active()) {
|
||||
if (aXPCOMInit.domainPolicy().active()) {
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
MOZ_ASSERT(ssm);
|
||||
ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
|
||||
if (!mPolicy) {
|
||||
MOZ_CRASH("Failed to activate domain policy.");
|
||||
}
|
||||
mPolicy->ApplyClone(&domainPolicy);
|
||||
mPolicy->ApplyClone(&aXPCOMInit.domainPolicy());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1"));
|
||||
if (nsCOMPtr<nsIClipboardProxy> clipboardProxy = do_QueryInterface(clipboard)) {
|
||||
clipboardProxy->SetCapabilities(clipboardCaps);
|
||||
clipboardProxy->SetCapabilities(aXPCOMInit.clipboardCaps());
|
||||
}
|
||||
|
||||
{
|
||||
@ -1002,7 +1010,9 @@ ContentChild::InitXPCOM()
|
||||
}
|
||||
ErrorResult rv;
|
||||
JS::RootedValue data(jsapi.cx());
|
||||
initialData.Read(jsapi.cx(), &data, rv);
|
||||
mozilla::dom::ipc::StructuredCloneData id;
|
||||
id.Copy(aInitialData);
|
||||
id.Read(jsapi.cx(), &data, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
@ -1011,7 +1021,7 @@ ContentChild::InitXPCOM()
|
||||
}
|
||||
|
||||
// The stylesheet cache is not ready yet. Store this URL for future use.
|
||||
nsCOMPtr<nsIURI> ucsURL = DeserializeURI(userContentSheetURL);
|
||||
nsCOMPtr<nsIURI> ucsURL = DeserializeURI(aXPCOMInit.userContentSheetURL());
|
||||
nsLayoutStylesheetCache::SetUserContentCSSURL(ucsURL);
|
||||
|
||||
// This will register cross-process observer.
|
||||
|
@ -96,9 +96,12 @@ public:
|
||||
|
||||
bool Init(MessageLoop* aIOLoop,
|
||||
base::ProcessId aParentPid,
|
||||
IPC::Channel* aChannel);
|
||||
IPC::Channel* aChannel,
|
||||
uint64_t aChildID,
|
||||
bool aIsForBrowser);
|
||||
|
||||
void InitXPCOM();
|
||||
void InitXPCOM(const XPCOMInitData& aXPCOMInit,
|
||||
const mozilla::dom::ipc::StructuredCloneData& aInitialData);
|
||||
|
||||
void InitGraphicsDeviceData();
|
||||
|
||||
@ -573,6 +576,11 @@ public:
|
||||
const bool& minimizeMemoryUsage,
|
||||
const MaybeFileDesc& DMDFile) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvSetXPCOMProcessAttributes(const XPCOMInitData& aXPCOMInit,
|
||||
const StructuredCloneData& aInitialData,
|
||||
nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;
|
||||
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
bool
|
||||
SendGetA11yContentId();
|
||||
|
@ -186,6 +186,8 @@
|
||||
|
||||
#include "nsLayoutStylesheetCache.h"
|
||||
|
||||
#include "ContentPrefs.h"
|
||||
|
||||
#ifdef MOZ_WEBRTC
|
||||
#include "signaling/src/peerconnection/WebrtcGlobalParent.h"
|
||||
#endif
|
||||
@ -1824,6 +1826,48 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
|
||||
PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
|
||||
|
||||
std::vector<std::string> extraArgs;
|
||||
extraArgs.push_back("-childID");
|
||||
char idStr[21];
|
||||
SprintfLiteral(idStr, "%" PRId64, static_cast<uint64_t>(mChildID));
|
||||
extraArgs.push_back(idStr);
|
||||
extraArgs.push_back(IsForBrowser() ? "-isForBrowser" : "-notForBrowser");
|
||||
|
||||
std::stringstream boolPrefs;
|
||||
std::stringstream intPrefs;
|
||||
std::stringstream stringPrefs;
|
||||
|
||||
size_t prefsLen;
|
||||
ContentPrefs::GetContentPrefs(&prefsLen);
|
||||
|
||||
for (unsigned int i = 0; i < prefsLen; i++) {
|
||||
MOZ_ASSERT(i == 0 || strcmp(ContentPrefs::GetContentPref(i), ContentPrefs::GetContentPref(i - 1)) > 0);
|
||||
switch (Preferences::GetType(ContentPrefs::GetContentPref(i))) {
|
||||
case nsIPrefBranch::PREF_INT:
|
||||
intPrefs << i << ':' << Preferences::GetInt(ContentPrefs::GetContentPref(i)) << '|';
|
||||
break;
|
||||
case nsIPrefBranch::PREF_BOOL:
|
||||
boolPrefs << i << ':' << Preferences::GetBool(ContentPrefs::GetContentPref(i)) << '|';
|
||||
break;
|
||||
case nsIPrefBranch::PREF_STRING: {
|
||||
std::string value(Preferences::GetCString(ContentPrefs::GetContentPref(i)).get());
|
||||
stringPrefs << i << ':' << value.length() << ':' << value << '|';
|
||||
}
|
||||
break;
|
||||
case nsIPrefBranch::PREF_INVALID:
|
||||
break;
|
||||
default:
|
||||
printf("preference type: %x\n", Preferences::GetType(ContentPrefs::GetContentPref(i)));
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
extraArgs.push_back("-intPrefs");
|
||||
extraArgs.push_back(intPrefs.str());
|
||||
extraArgs.push_back("-boolPrefs");
|
||||
extraArgs.push_back(boolPrefs.str());
|
||||
extraArgs.push_back("-stringPrefs");
|
||||
extraArgs.push_back(stringPrefs.str());
|
||||
|
||||
if (!mSubprocess->LaunchAndWaitForProcessHandle(extraArgs)) {
|
||||
MarkAsDead();
|
||||
return false;
|
||||
@ -1843,6 +1887,17 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
|
||||
// Set a reply timeout for CPOWs.
|
||||
SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 0));
|
||||
|
||||
Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_TIME_MS,
|
||||
static_cast<uint32_t>((TimeStamp::Now() - mLaunchTS)
|
||||
.ToMilliseconds()));
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
nsAutoString cpId;
|
||||
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
|
||||
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-initializing", cpId.get());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1900,6 +1955,90 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
||||
bool aSetupOffMainThreadCompositing,
|
||||
bool aSendRegisteredChrome)
|
||||
{
|
||||
Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_TIME_MS,
|
||||
static_cast<uint32_t>((TimeStamp::Now() - mLaunchTS)
|
||||
.ToMilliseconds()));
|
||||
|
||||
XPCOMInitData xpcomInit;
|
||||
|
||||
Preferences::GetPreferences(&xpcomInit.prefs());
|
||||
nsCOMPtr<nsIIOService> io(do_GetIOService());
|
||||
MOZ_ASSERT(io, "No IO service?");
|
||||
DebugOnly<nsresult> rv = io->GetOffline(&xpcomInit.isOffline());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
|
||||
|
||||
rv = io->GetConnectivity(&xpcomInit.isConnected());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
|
||||
|
||||
xpcomInit.captivePortalState() = nsICaptivePortalService::UNKNOWN;
|
||||
nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
|
||||
if (cps) {
|
||||
cps->GetState(&xpcomInit.captivePortalState());
|
||||
}
|
||||
|
||||
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
|
||||
|
||||
xpcomInit.isLangRTL() = false;
|
||||
xpcomInit.haveBidiKeyboards() = false;
|
||||
if (bidi) {
|
||||
bidi->IsLangRTL(&xpcomInit.isLangRTL());
|
||||
bidi->GetHaveBidiKeyboards(&xpcomInit.haveBidiKeyboards());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISpellChecker> spellChecker(do_GetService(NS_SPELLCHECKER_CONTRACTID));
|
||||
MOZ_ASSERT(spellChecker, "No spell checker?");
|
||||
|
||||
spellChecker->GetDictionaryList(&xpcomInit.dictionaries());
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1"));
|
||||
MOZ_ASSERT(clipboard, "No clipboard?");
|
||||
|
||||
rv = clipboard->SupportsSelectionClipboard(&xpcomInit.clipboardCaps().supportsSelectionClipboard());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
rv = clipboard->SupportsFindClipboard(&xpcomInit.clipboardCaps().supportsFindClipboard());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
// Let's copy the domain policy from the parent to the child (if it's active).
|
||||
StructuredCloneData initialData;
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
if (ssm) {
|
||||
ssm->CloneDomainPolicy(&xpcomInit.domainPolicy());
|
||||
|
||||
if (nsFrameMessageManager* mm = nsFrameMessageManager::sParentProcessManager) {
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
JS::RootedValue init(jsapi.cx());
|
||||
nsresult result = mm->GetInitialProcessData(jsapi.cx(), &init);
|
||||
if (NS_FAILED(result)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
initialData.Write(jsapi.cx(), init, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is only implemented (returns a non-empty list) by MacOSX at present.
|
||||
gfxPlatform::GetPlatform()->GetSystemFontFamilyList(&xpcomInit.fontFamilies());
|
||||
nsTArray<LookAndFeelInt> lnfCache = LookAndFeel::GetIntCache();
|
||||
|
||||
// Content processes have no permission to access profile directory, so we
|
||||
// send the file URL instead.
|
||||
StyleSheet* ucs = nsLayoutStylesheetCache::For(StyleBackendType::Gecko)->UserContentSheet();
|
||||
if (ucs) {
|
||||
SerializeURI(ucs->GetSheetURI(), xpcomInit.userContentSheetURL());
|
||||
} else {
|
||||
SerializeURI(nullptr, xpcomInit.userContentSheetURL());
|
||||
}
|
||||
|
||||
Unused << SendSetXPCOMProcessAttributes(xpcomInit, initialData, lnfCache);
|
||||
|
||||
if (aSendRegisteredChrome) {
|
||||
nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
|
||||
nsChromeRegistryChrome* chromeRegistry =
|
||||
@ -2071,13 +2210,6 @@ ContentParent::Pid() const
|
||||
return base::GetProcId(mSubprocess->GetChildProcessHandle());
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs)
|
||||
{
|
||||
Preferences::GetPreferences(aPrefs);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvGetGfxVars(InfallibleTArray<GfxVarUpdate>* aVars)
|
||||
{
|
||||
@ -2548,118 +2680,6 @@ ContentParent::RecvInitBackground(Endpoint<PBackgroundParent>&& aEndpoint)
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
|
||||
bool* aIsForBrowser)
|
||||
{
|
||||
*aCpId = mChildID;
|
||||
*aIsForBrowser = mIsForBrowser;
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
bool* aIsConnected,
|
||||
int32_t* aCaptivePortalState,
|
||||
bool* aIsLangRTL,
|
||||
bool* aHaveBidiKeyboards,
|
||||
InfallibleTArray<nsString>* dictionaries,
|
||||
ClipboardCapabilities* clipboardCaps,
|
||||
DomainPolicyClone* domainPolicy,
|
||||
StructuredCloneData* aInitialData,
|
||||
InfallibleTArray<FontFamilyListEntry>* fontFamilies,
|
||||
OptionalURIParams* aUserContentCSSURL,
|
||||
nsTArray<LookAndFeelInt>* aLookAndFeelIntCache)
|
||||
{
|
||||
Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_TIME_MS,
|
||||
static_cast<uint32_t>((TimeStamp::Now() - mLaunchTS)
|
||||
.ToMilliseconds()));
|
||||
|
||||
nsCOMPtr<nsIIOService> io(do_GetIOService());
|
||||
MOZ_ASSERT(io, "No IO service?");
|
||||
DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
|
||||
|
||||
rv = io->GetConnectivity(aIsConnected);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
|
||||
|
||||
*aCaptivePortalState = nsICaptivePortalService::UNKNOWN;
|
||||
nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
|
||||
if (cps) {
|
||||
cps->GetState(aCaptivePortalState);
|
||||
}
|
||||
|
||||
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
|
||||
|
||||
*aIsLangRTL = false;
|
||||
*aHaveBidiKeyboards = false;
|
||||
if (bidi) {
|
||||
bidi->IsLangRTL(aIsLangRTL);
|
||||
bidi->GetHaveBidiKeyboards(aHaveBidiKeyboards);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISpellChecker> spellChecker(do_GetService(NS_SPELLCHECKER_CONTRACTID));
|
||||
MOZ_ASSERT(spellChecker, "No spell checker?");
|
||||
|
||||
spellChecker->GetDictionaryList(dictionaries);
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1"));
|
||||
MOZ_ASSERT(clipboard, "No clipboard?");
|
||||
|
||||
rv = clipboard->SupportsSelectionClipboard(&clipboardCaps->supportsSelectionClipboard());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
rv = clipboard->SupportsFindClipboard(&clipboardCaps->supportsFindClipboard());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
// Let's copy the domain policy from the parent to the child (if it's active).
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
NS_ENSURE_TRUE(ssm, IPC_OK());
|
||||
ssm->CloneDomainPolicy(domainPolicy);
|
||||
|
||||
if (nsFrameMessageManager* mm = nsFrameMessageManager::sParentProcessManager) {
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
JS::RootedValue init(jsapi.cx());
|
||||
nsresult result = mm->GetInitialProcessData(jsapi.cx(), &init);
|
||||
if (NS_FAILED(result)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
aInitialData->Write(jsapi.cx(), init, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
}
|
||||
|
||||
// This is only implemented (returns a non-empty list) by MacOSX at present.
|
||||
gfxPlatform::GetPlatform()->GetSystemFontFamilyList(fontFamilies);
|
||||
*aLookAndFeelIntCache = LookAndFeel::GetIntCache();
|
||||
|
||||
// Content processes have no permission to access profile directory, so we
|
||||
// send the file URL instead.
|
||||
StyleSheet* ucs = nsLayoutStylesheetCache::For(StyleBackendType::Gecko)->UserContentSheet();
|
||||
if (ucs) {
|
||||
SerializeURI(ucs->GetSheetURI(), *aUserContentCSSURL);
|
||||
} else {
|
||||
SerializeURI(nullptr, *aUserContentCSSURL);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
nsAutoString cpId;
|
||||
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
|
||||
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-initializing", cpId.get());
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::jsipc::PJavaScriptParent *
|
||||
ContentParent::AllocPJavaScriptParent()
|
||||
{
|
||||
|
@ -746,24 +746,6 @@ private:
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvInitBackground(Endpoint<mozilla::ipc::PBackgroundParent>&& aEndpoint) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvGetProcessAttributes(ContentParentId* aCpId,
|
||||
bool* aIsForBrowser) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
bool* aIsConnected,
|
||||
int32_t* aCaptivePortalState,
|
||||
bool* aIsLangRTL,
|
||||
bool* aHaveBidiKeyboards,
|
||||
InfallibleTArray<nsString>* dictionaries,
|
||||
ClipboardCapabilities* clipboardCaps,
|
||||
DomainPolicyClone* domainPolicy,
|
||||
StructuredCloneData* initialData,
|
||||
InfallibleTArray<FontFamilyListEntry>* fontFamilies,
|
||||
OptionalURIParams* aUserContentSheetURL,
|
||||
nsTArray<LookAndFeelInt>* aLookAndFeelIntCache) override;
|
||||
|
||||
|
||||
mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport) override;
|
||||
mozilla::ipc::IPCResult RecvFinishMemoryReport(const uint32_t& aGeneration) override;
|
||||
|
||||
@ -898,7 +880,6 @@ private:
|
||||
virtual bool
|
||||
DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumentParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs) override;
|
||||
virtual mozilla::ipc::IPCResult RecvGetGfxVars(InfallibleTArray<GfxVarUpdate>* aVars) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvReadFontList(InfallibleTArray<FontListEntry>* retValue) override;
|
||||
|
276
dom/ipc/ContentPrefs.cpp
Normal file
276
dom/ipc/ContentPrefs.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "ContentPrefs.h"
|
||||
|
||||
const char* mozilla::dom::ContentPrefs::gInitPrefs[] = {
|
||||
"accessibility.monoaudio.enable",
|
||||
"accessibility.mouse_focuses_formcontrol",
|
||||
"accessibility.tabfocus_applies_to_xul",
|
||||
"app.update.channel",
|
||||
"browser.dom.window.dump.enabled",
|
||||
"browser.sessionhistory.max_entries",
|
||||
"browser.sessionhistory.max_total_viewers",
|
||||
"content.cors.disable",
|
||||
"content.cors.no_private_data",
|
||||
"content.notify.backoffcount",
|
||||
"content.notify.interval",
|
||||
"content.notify.ontimer",
|
||||
"content.sink.enable_perf_mode",
|
||||
"content.sink.event_probe_rate",
|
||||
"content.sink.initial_perf_time",
|
||||
"content.sink.interactive_deflect_count",
|
||||
"content.sink.interactive_parse_time",
|
||||
"content.sink.interactive_time",
|
||||
"content.sink.pending_event_mode",
|
||||
"content.sink.perf_deflect_count",
|
||||
"content.sink.perf_parse_time",
|
||||
"device.storage.prompt.testing",
|
||||
"device.storage.writable.name",
|
||||
"dom.allow_XUL_XBL_for_file",
|
||||
"dom.allow_cut_copy",
|
||||
"dom.enable_frame_timing",
|
||||
"dom.enable_performance",
|
||||
"dom.enable_resource_timing",
|
||||
"dom.event.handling-user-input-time-limit",
|
||||
"dom.event.touch.coalescing.enabled",
|
||||
"dom.forms.autocomplete.experimental",
|
||||
"dom.ipc.processPriorityManager.backgroundGracePeriodMS",
|
||||
"dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS",
|
||||
"dom.max_chrome_script_run_time",
|
||||
"dom.max_script_run_time",
|
||||
"dom.performance.enable_notify_performance_timing",
|
||||
"dom.performance.enable_user_timing_logging",
|
||||
"dom.storage.testing",
|
||||
"dom.url.encode_decode_hash",
|
||||
"dom.url.getters_decode_hash",
|
||||
"dom.use_watchdog",
|
||||
"dom.vibrator.enabled",
|
||||
"dom.vibrator.max_vibrate_list_len",
|
||||
"dom.vibrator.max_vibrate_ms",
|
||||
"focusmanager.testmode",
|
||||
"font.size.inflation.disabledInMasterProcess",
|
||||
"font.size.inflation.emPerLine",
|
||||
"font.size.inflation.forceEnabled",
|
||||
"font.size.inflation.lineThreshold",
|
||||
"font.size.inflation.mappingIntercept",
|
||||
"font.size.inflation.maxRatio",
|
||||
"font.size.inflation.minTwips",
|
||||
"full-screen-api.allow-trusted-requests-only",
|
||||
"full-screen-api.enabled",
|
||||
"full-screen-api.unprefix.enabled",
|
||||
"gfx.font_rendering.opentype_svg.enabled",
|
||||
"hangmonitor.timeout",
|
||||
"html5.flushtimer.initialdelay",
|
||||
"html5.flushtimer.subsequentdelay",
|
||||
"html5.offmainthread",
|
||||
"intl.charset.fallback.tld",
|
||||
"intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition",
|
||||
"javascript.enabled",
|
||||
"javascript.options.asmjs",
|
||||
"javascript.options.asyncstack",
|
||||
"javascript.options.baselinejit",
|
||||
"javascript.options.baselinejit.threshold",
|
||||
"javascript.options.baselinejit.unsafe_eager_compilation",
|
||||
"javascript.options.discardSystemSource",
|
||||
"javascript.options.dump_stack_on_debuggee_would_run",
|
||||
"javascript.options.gczeal",
|
||||
"javascript.options.gczeal.frequency",
|
||||
"javascript.options.ion",
|
||||
"javascript.options.ion.offthread_compilation",
|
||||
"javascript.options.ion.threshold",
|
||||
"javascript.options.ion.unsafe_eager_compilation",
|
||||
"javascript.options.jit.full_debug_checks",
|
||||
"javascript.options.native_regexp",
|
||||
"javascript.options.parallel_parsing",
|
||||
"javascript.options.shared_memory",
|
||||
"javascript.options.strict",
|
||||
"javascript.options.strict.debug",
|
||||
"javascript.options.throw_on_asmjs_validation_failure",
|
||||
"javascript.options.throw_on_debuggee_would_run",
|
||||
"javascript.options.wasm",
|
||||
"javascript.options.wasm_baselinejit",
|
||||
"javascript.options.werror",
|
||||
"javascript.use_us_english_locale",
|
||||
"jsloader.reuseGlobal",
|
||||
"layout.css.all-shorthand.enabled",
|
||||
"layout.css.background-blend-mode.enabled",
|
||||
"layout.css.background-clip-text.enabled",
|
||||
"layout.css.box-decoration-break.enabled",
|
||||
"layout.css.color-adjust.enabled",
|
||||
"layout.css.contain.enabled",
|
||||
"layout.css.control-characters.visible",
|
||||
"layout.css.display-flow-root.enabled",
|
||||
"layout.css.expensive-style-struct-assertions.enabled",
|
||||
"layout.css.float-logical-values.enabled",
|
||||
"layout.css.font-variations.enabled",
|
||||
"layout.css.grid.enabled",
|
||||
"layout.css.image-orientation.enabled",
|
||||
"layout.css.initial-letter.enabled",
|
||||
"layout.css.isolation.enabled",
|
||||
"layout.css.mix-blend-mode.enabled",
|
||||
"layout.css.object-fit-and-position.enabled",
|
||||
"layout.css.osx-font-smoothing.enabled",
|
||||
"layout.css.overflow-clip-box.enabled",
|
||||
"layout.css.prefixes.animations",
|
||||
"layout.css.prefixes.border-image",
|
||||
"layout.css.prefixes.box-sizing",
|
||||
"layout.css.prefixes.device-pixel-ratio-webkit",
|
||||
"layout.css.prefixes.font-features",
|
||||
"layout.css.prefixes.gradients",
|
||||
"layout.css.prefixes.transforms",
|
||||
"layout.css.prefixes.transitions",
|
||||
"layout.css.prefixes.webkit",
|
||||
"layout.css.scope-pseudo.enabled",
|
||||
"layout.css.scroll-behavior.property-enabled",
|
||||
"layout.css.scroll-snap.enabled",
|
||||
"layout.css.shape-outside.enabled",
|
||||
"layout.css.text-align-unsafe-value.enabled",
|
||||
"layout.css.text-combine-upright-digits.enabled",
|
||||
"layout.css.text-combine-upright.enabled",
|
||||
"layout.css.touch_action.enabled",
|
||||
"layout.css.unprefixing-service.enabled",
|
||||
"layout.css.unprefixing-service.globally-whitelisted",
|
||||
"layout.css.unprefixing-service.include-test-domains",
|
||||
"layout.css.variables.enabled",
|
||||
"layout.css.visited_links_enabled",
|
||||
"layout.idle_period.required_quiescent_frames",
|
||||
"layout.idle_period.time_limit",
|
||||
"layout.interruptible-reflow.enabled",
|
||||
"mathml.disabled",
|
||||
"media.apple.forcevda",
|
||||
"media.clearkey.persistent-license.enabled",
|
||||
"media.cubeb_latency_msg_frames",
|
||||
"media.cubeb_latency_playback_ms",
|
||||
"media.decoder-doctor.wmf-disabled-is-failure",
|
||||
"media.decoder.fuzzing.dont-delay-inputexhausted",
|
||||
"media.decoder.fuzzing.enabled",
|
||||
"media.decoder.fuzzing.video-output-minimum-interval-ms",
|
||||
"media.decoder.limit",
|
||||
"media.decoder.recycle.enabled",
|
||||
"media.dormant-on-pause-timeout-ms",
|
||||
"media.eme.audio.blank",
|
||||
"media.eme.enabled",
|
||||
"media.eme.video.blank",
|
||||
"media.ffmpeg.enabled",
|
||||
"media.ffvpx.enabled",
|
||||
"media.flac.enabled",
|
||||
"media.forcestereo.enabled",
|
||||
"media.gmp.async-shutdown-timeout",
|
||||
"media.gmp.decoder.aac",
|
||||
"media.gmp.decoder.enabled",
|
||||
"media.gmp.decoder.h264",
|
||||
"media.gmp.insecure.allow",
|
||||
"media.gpu-process-decoder",
|
||||
"media.libavcodec.allow-obsolete",
|
||||
"media.num-decode-threads",
|
||||
"media.ogg.enabled",
|
||||
"media.ogg.flac.enabled",
|
||||
"media.resampling.enabled",
|
||||
"media.resampling.rate",
|
||||
"media.ruin-av-sync.enabled",
|
||||
"media.rust.test_mode",
|
||||
"media.suspend-bkgnd-video.delay-ms",
|
||||
"media.suspend-bkgnd-video.enabled",
|
||||
"media.use-blank-decoder",
|
||||
"media.video_stats.enabled",
|
||||
"media.volume_scale",
|
||||
"media.webspeech.recognition.enable",
|
||||
"media.webspeech.recognition.force_enable",
|
||||
"media.webspeech.synth.force_global_queue",
|
||||
"media.webspeech.test.enable",
|
||||
"media.webspeech.test.fake_fsm_events",
|
||||
"media.webspeech.test.fake_recognition_service",
|
||||
"media.wmf.allow-unsupported-resolutions",
|
||||
"media.wmf.decoder.thread-count",
|
||||
"media.wmf.enabled",
|
||||
"media.wmf.skip-blacklist",
|
||||
"media.wmf.vp9.enabled",
|
||||
"memory.free_dirty_pages",
|
||||
"memory.low_commit_space_threshold_mb",
|
||||
"memory.low_memory_notification_interval_ms",
|
||||
"memory.low_physical_memory_threshold_mb",
|
||||
"memory.low_virtual_mem_threshold_mb",
|
||||
"network.IDN.blacklist_chars",
|
||||
"network.IDN.restriction_profile",
|
||||
"network.IDN.use_whitelist",
|
||||
"network.IDN_show_punycode",
|
||||
"network.buffer.cache.count",
|
||||
"network.buffer.cache.size",
|
||||
"network.captive-portal-service.enabled",
|
||||
"network.cookie.cookieBehavior",
|
||||
"network.cookie.lifetimePolicy",
|
||||
"network.dns.disablePrefetch",
|
||||
"network.dns.disablePrefetchFromHTTPS",
|
||||
"network.jar.block-remote-files",
|
||||
"network.loadinfo.skip_type_assertion",
|
||||
"network.notify.changed",
|
||||
"network.offline-mirrors-connectivity",
|
||||
"network.protocol-handler.external.jar",
|
||||
"network.proxy.type",
|
||||
"network.security.ports.banned",
|
||||
"network.security.ports.banned.override",
|
||||
"network.standard-url.enable-rust",
|
||||
"network.standard-url.max-length",
|
||||
"network.sts.max_time_for_events_between_two_polls",
|
||||
"network.sts.max_time_for_pr_close_during_shutdown",
|
||||
"network.tcp.keepalive.enabled",
|
||||
"network.tcp.keepalive.idle_time",
|
||||
"network.tcp.keepalive.probe_count",
|
||||
"network.tcp.keepalive.retry_interval",
|
||||
"network.tcp.sendbuffer",
|
||||
"nglayout.debug.invalidation",
|
||||
"privacy.donottrackheader.enabled",
|
||||
"privacy.firstparty.isolate",
|
||||
"privacy.firstparty.isolate.restrict_opener_access",
|
||||
"privacy.resistFingerprinting",
|
||||
"security.data_uri.inherit_security_context",
|
||||
"security.fileuri.strict_origin_policy",
|
||||
"security.sandbox.content.level",
|
||||
"security.sandbox.content.tempDirSuffix",
|
||||
"security.sandbox.logging.enabled",
|
||||
"security.sandbox.mac.track.violations",
|
||||
"security.sandbox.windows.log",
|
||||
"security.sandbox.windows.log.stackTraceDepth",
|
||||
"shutdown.watchdog.timeoutSecs",
|
||||
"signed.applets.codebase_principal_support",
|
||||
"svg.disabled",
|
||||
"svg.display-lists.hit-testing.enabled",
|
||||
"svg.display-lists.painting.enabled",
|
||||
"svg.new-getBBox.enabled",
|
||||
"svg.paint-order.enabled",
|
||||
"svg.path-caching.enabled",
|
||||
"svg.transform-box.enabled",
|
||||
"toolkit.asyncshutdown.crash_timeout",
|
||||
"toolkit.asyncshutdown.log",
|
||||
"toolkit.osfile.log",
|
||||
"toolkit.osfile.log.redirect",
|
||||
"toolkit.telemetry.enabled",
|
||||
"toolkit.telemetry.idleTimeout",
|
||||
"toolkit.telemetry.initDelay",
|
||||
"toolkit.telemetry.log.dump",
|
||||
"toolkit.telemetry.log.level",
|
||||
"toolkit.telemetry.minSubsessionLength",
|
||||
"toolkit.telemetry.scheduler.idleTickInterval",
|
||||
"toolkit.telemetry.scheduler.tickInterval",
|
||||
"toolkit.telemetry.unified",
|
||||
"ui.key.menuAccessKeyFocuses",
|
||||
"ui.popup.disable_autohide",
|
||||
"ui.use_activity_cursor",
|
||||
"view_source.editor.external"};
|
||||
|
||||
const char** mozilla::dom::ContentPrefs::GetContentPrefs(size_t* aCount)
|
||||
{
|
||||
*aCount = ArrayLength(ContentPrefs::gInitPrefs);
|
||||
return gInitPrefs;
|
||||
}
|
||||
|
||||
const char* mozilla::dom::ContentPrefs::GetContentPref(size_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(aIndex < ArrayLength(ContentPrefs::gInitPrefs));
|
||||
return gInitPrefs[aIndex];
|
||||
}
|
||||
|
25
dom/ipc/ContentPrefs.h
Normal file
25
dom/ipc/ContentPrefs.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 mozilla_dom_ContentPrefs_h
|
||||
#define mozilla_dom_ContentPrefs_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ContentPrefs {
|
||||
public:
|
||||
static const char** GetContentPrefs(size_t* aCount);
|
||||
static const char* GetContentPref(size_t aIndex);
|
||||
|
||||
private:
|
||||
static const char* gInitPrefs[];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/ipc/IOThreadChild.h"
|
||||
|
||||
#include "ContentProcess.h"
|
||||
#include "ContentPrefs.h"
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
#include <stdlib.h>
|
||||
@ -103,46 +104,143 @@ SetUpSandboxEnvironment()
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ContentProcess::SetAppDir(const nsACString& aPath)
|
||||
bool
|
||||
ContentProcess::Init(int aArgc, char* aArgv[])
|
||||
{
|
||||
mXREEmbed.SetAppDir(aPath);
|
||||
}
|
||||
// If passed in grab the application path for xpcom init
|
||||
bool foundAppdir = false;
|
||||
bool foundChildID = false;
|
||||
bool foundIsForBrowser = false;
|
||||
bool foundIntPrefs = false;
|
||||
bool foundBoolPrefs = false;
|
||||
bool foundStringPrefs = false;
|
||||
|
||||
uint64_t childID;
|
||||
bool isForBrowser;
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
void
|
||||
ContentProcess::SetProfile(const nsACString& aProfile)
|
||||
{
|
||||
bool flag;
|
||||
nsresult rv =
|
||||
XRE_GetFileFromPath(aProfile.BeginReading(), getter_AddRefs(mProfileDir));
|
||||
if (NS_FAILED(rv) ||
|
||||
NS_FAILED(mProfileDir->Exists(&flag)) || !flag) {
|
||||
NS_WARNING("Invalid profile directory passed to content process.");
|
||||
mProfileDir = nullptr;
|
||||
}
|
||||
}
|
||||
// If passed in grab the profile path for sandboxing
|
||||
bool foundProfile = false;
|
||||
nsCOMPtr<nsIFile> profileDir;
|
||||
#endif
|
||||
|
||||
bool
|
||||
ContentProcess::Init()
|
||||
{
|
||||
mContent.Init(IOThreadChild::message_loop(),
|
||||
ParentPid(),
|
||||
IOThreadChild::channel());
|
||||
mXREEmbed.Start();
|
||||
mContent.InitXPCOM();
|
||||
mContent.InitGraphicsDeviceData();
|
||||
InfallibleTArray<PrefSetting> prefsArray;
|
||||
for (int idx = aArgc; idx > 0; idx--) {
|
||||
if (!aArgv[idx]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(aArgv[idx], "-appdir")) {
|
||||
MOZ_ASSERT(!foundAppdir);
|
||||
if (foundAppdir) {
|
||||
continue;
|
||||
}
|
||||
nsCString appDir;
|
||||
appDir.Assign(nsDependentCString(aArgv[idx+1]));
|
||||
mXREEmbed.SetAppDir(appDir);
|
||||
foundAppdir = true;
|
||||
} else if (!strcmp(aArgv[idx], "-childID")) {
|
||||
MOZ_ASSERT(!foundChildID);
|
||||
if (foundChildID) {
|
||||
continue;
|
||||
}
|
||||
if (idx + 1 < aArgc) {
|
||||
childID = strtoull(aArgv[idx + 1], nullptr, 10);
|
||||
foundChildID = true;
|
||||
}
|
||||
} else if (!strcmp(aArgv[idx], "-isForBrowser") || !strcmp(aArgv[idx], "-notForBrowser")) {
|
||||
MOZ_ASSERT(!foundIsForBrowser);
|
||||
if (foundIsForBrowser) {
|
||||
continue;
|
||||
}
|
||||
isForBrowser = strcmp(aArgv[idx], "-notForBrowser");
|
||||
foundIsForBrowser = true;
|
||||
} else if (!strcmp(aArgv[idx], "-intPrefs")) {
|
||||
SET_PREF_PHASE(BEGIN_INIT_PREFS);
|
||||
char* str = aArgv[idx + 1];
|
||||
while (*str) {
|
||||
int32_t index = strtol(str, &str, 10);
|
||||
str++;
|
||||
MaybePrefValue value(PrefValue(static_cast<int32_t>(strtol(str, &str, 10))));
|
||||
str++;
|
||||
PrefSetting pref(nsCString(ContentPrefs::GetContentPref(index)), value, MaybePrefValue());
|
||||
prefsArray.AppendElement(pref);
|
||||
}
|
||||
SET_PREF_PHASE(END_INIT_PREFS);
|
||||
foundIntPrefs = true;
|
||||
} else if (!strcmp(aArgv[idx], "-boolPrefs")) {
|
||||
SET_PREF_PHASE(BEGIN_INIT_PREFS);
|
||||
char* str = aArgv[idx + 1];
|
||||
while (*str) {
|
||||
int32_t index = strtol(str, &str, 10);
|
||||
str++;
|
||||
MaybePrefValue value(PrefValue(!!strtol(str, &str, 10)));
|
||||
str++;
|
||||
PrefSetting pref(nsCString(ContentPrefs::GetContentPref(index)), value, MaybePrefValue());
|
||||
prefsArray.AppendElement(pref);
|
||||
}
|
||||
SET_PREF_PHASE(END_INIT_PREFS);
|
||||
foundBoolPrefs = true;
|
||||
} else if (!strcmp(aArgv[idx], "-stringPrefs")) {
|
||||
SET_PREF_PHASE(BEGIN_INIT_PREFS);
|
||||
char* str = aArgv[idx + 1];
|
||||
while (*str) {
|
||||
int32_t index = strtol(str, &str, 10);
|
||||
str++;
|
||||
int32_t length = strtol(str, &str, 10);
|
||||
str++;
|
||||
MaybePrefValue value(PrefValue(nsCString(str, length)));
|
||||
PrefSetting pref(nsCString(ContentPrefs::GetContentPref(index)), value, MaybePrefValue());
|
||||
prefsArray.AppendElement(pref);
|
||||
str += length + 1;
|
||||
}
|
||||
SET_PREF_PHASE(END_INIT_PREFS);
|
||||
foundStringPrefs = true;
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
else if (!strcmp(aArgv[idx], "-profile")) {
|
||||
MOZ_ASSERT(!foundProfile);
|
||||
if (foundProfile) {
|
||||
continue;
|
||||
}
|
||||
bool flag;
|
||||
nsresult rv = XRE_GetFileFromPath(aArgv[idx+1], getter_AddRefs(profileDir));
|
||||
if (NS_FAILED(rv) ||
|
||||
NS_FAILED(profileDir->Exists(&flag)) || !flag) {
|
||||
NS_WARNING("Invalid profile directory passed to content process.");
|
||||
profileDir = nullptr;
|
||||
}
|
||||
foundProfile = true;
|
||||
}
|
||||
#endif /* XP_MACOSX && MOZ_CONTENT_SANDBOX */
|
||||
|
||||
bool allFound = foundAppdir && foundChildID && foundIsForBrowser && foundIntPrefs && foundBoolPrefs && foundStringPrefs;
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
allFound &= foundProfile;
|
||||
#endif
|
||||
|
||||
if (allFound) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Preferences::SetInitPreferences(&prefsArray);
|
||||
mContent.Init(IOThreadChild::message_loop(),
|
||||
ParentPid(),
|
||||
IOThreadChild::channel(),
|
||||
childID,
|
||||
isForBrowser);
|
||||
mXREEmbed.Start();
|
||||
#if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
mContent.SetProfileDir(mProfileDir);
|
||||
mContent.SetProfileDir(profileDir);
|
||||
#endif
|
||||
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
SetUpSandboxEnvironment();
|
||||
SetUpSandboxEnvironment();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note: CleanUp() never gets called in non-debug builds because we exit early
|
||||
@ -150,7 +248,7 @@ ContentProcess::Init()
|
||||
void
|
||||
ContentProcess::CleanUp()
|
||||
{
|
||||
mXREEmbed.Stop();
|
||||
mXREEmbed.Stop();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -34,23 +34,13 @@ public:
|
||||
~ContentProcess()
|
||||
{ }
|
||||
|
||||
virtual bool Init() override;
|
||||
virtual bool Init(int aArgc, char* aArgv[]) override;
|
||||
virtual void CleanUp() override;
|
||||
|
||||
void SetAppDir(const nsACString& aPath);
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
void SetProfile(const nsACString& aProfile);
|
||||
#endif
|
||||
|
||||
private:
|
||||
ContentChild mContent;
|
||||
mozilla::ipc::ScopedXREEmbed mXREEmbed;
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
nsCOMPtr<nsIFile> mProfileDir;
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// This object initializes and configures COM.
|
||||
mozilla::mscom::MainThreadRuntime mCOMRuntime;
|
||||
|
@ -334,6 +334,22 @@ struct GMPCapabilityData
|
||||
GMPAPITags[] capabilities;
|
||||
};
|
||||
|
||||
struct XPCOMInitData
|
||||
{
|
||||
bool isOffline;
|
||||
bool isConnected;
|
||||
int32_t captivePortalState;
|
||||
bool isLangRTL;
|
||||
bool haveBidiKeyboards;
|
||||
nsString[] dictionaries;
|
||||
ClipboardCapabilities clipboardCaps;
|
||||
DomainPolicyClone domainPolicy;
|
||||
/* used on MacOSX only */
|
||||
FontFamilyListEntry[] fontFamilies;
|
||||
OptionalURIParams userContentSheetURL;
|
||||
PrefSetting[] prefs;
|
||||
};
|
||||
|
||||
struct GfxInfoFeatureStatus
|
||||
{
|
||||
int32_t feature;
|
||||
@ -527,6 +543,8 @@ child:
|
||||
*/
|
||||
async InitBlobURLs(BlobURLRegistrationData[] registrations);
|
||||
|
||||
async SetXPCOMProcessAttributes(XPCOMInitData xpcomInit, StructuredCloneData initialData, LookAndFeelInt[] lookAndFeelIntCache);
|
||||
|
||||
// Notify child that last-pb-context-exited notification was observed
|
||||
async LastPrivateDocShellDestroyed();
|
||||
|
||||
@ -650,30 +668,6 @@ child:
|
||||
parent:
|
||||
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
|
||||
|
||||
/**
|
||||
* Tell the content process some attributes of itself. This is
|
||||
* among the first information queried by content processes after
|
||||
* startup. (The message is sync to allow the content process to
|
||||
* control when it receives the information.)
|
||||
*
|
||||
* |id| is a unique ID among all subprocesses. When
|
||||
* |isForBrowser|, we're loading <browser> or <xul:browser remote>.
|
||||
*
|
||||
* Keep the return values in sync with PBrowser()!
|
||||
*/
|
||||
sync GetProcessAttributes()
|
||||
returns (ContentParentId cpId, bool isForBrowser);
|
||||
sync GetXPCOMProcessAttributes()
|
||||
returns (bool isOffline, bool isConnected, int32_t captivePortalState,
|
||||
bool isLangRTL,
|
||||
bool haveBidiKeyboards, nsString[] dictionaries,
|
||||
ClipboardCapabilities clipboardCaps,
|
||||
DomainPolicyClone domainPolicy,
|
||||
StructuredCloneData initialData,
|
||||
FontFamilyListEntry[] fontFamilies /* used on MacOSX only */,
|
||||
OptionalURIParams userContentSheetURL,
|
||||
LookAndFeelInt[] lookAndFeelIntCache);
|
||||
|
||||
sync CreateChildProcess(IPCTabContext context,
|
||||
ProcessPriority priority,
|
||||
TabId openerTabId)
|
||||
@ -817,7 +811,6 @@ parent:
|
||||
async ExtProtocolChannelConnectParent(uint32_t registrarId);
|
||||
|
||||
// PrefService message
|
||||
sync ReadPrefsArray() returns (PrefSetting[] prefs) verify;
|
||||
sync GetGfxVars() returns (GfxVarUpdate[] vars);
|
||||
|
||||
sync ReadFontList() returns (FontListEntry[] retValue);
|
||||
|
@ -119,6 +119,8 @@
|
||||
#include "GroupedSHistory.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#ifdef NS_PRINTING
|
||||
#include "nsIPrintSession.h"
|
||||
|
@ -20,6 +20,7 @@ EXPORTS.mozilla.dom += [
|
||||
'ContentBridgeParent.h',
|
||||
'ContentChild.h',
|
||||
'ContentParent.h',
|
||||
'ContentPrefs.h',
|
||||
'ContentProcess.h',
|
||||
'ContentProcessManager.h',
|
||||
'CPOWManagerGetter.h',
|
||||
@ -50,6 +51,7 @@ UNIFIED_SOURCES += [
|
||||
'ContentBridgeChild.cpp',
|
||||
'ContentBridgeParent.cpp',
|
||||
'ContentParent.cpp',
|
||||
'ContentPrefs.cpp',
|
||||
'ContentProcess.cpp',
|
||||
'ContentProcessManager.cpp',
|
||||
'CrashReporterParent.cpp',
|
||||
|
@ -25,7 +25,7 @@ GMPProcessChild::~GMPProcessChild()
|
||||
}
|
||||
|
||||
bool
|
||||
GMPProcessChild::Init()
|
||||
GMPProcessChild::Init(int aArgc, char* aArgv[])
|
||||
{
|
||||
nsAutoString pluginFilename;
|
||||
|
||||
|
@ -22,7 +22,7 @@ public:
|
||||
explicit GMPProcessChild(ProcessId aParentPid);
|
||||
~GMPProcessChild();
|
||||
|
||||
bool Init() override;
|
||||
bool Init(int aArgc, char* aArgv[]) override;
|
||||
void CleanUp() override;
|
||||
|
||||
private:
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Toolkit", "Notifications and Alerts")
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'NotificationStorage.js',
|
||||
'NotificationStorage.manifest',
|
||||
|
@ -40,7 +40,7 @@ namespace plugins {
|
||||
|
||||
|
||||
bool
|
||||
PluginProcessChild::Init()
|
||||
PluginProcessChild::Init(int aArgc, char* aArgv[])
|
||||
{
|
||||
nsDebugImpl::SetMultiprocessMode("NPAPI");
|
||||
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
virtual ~PluginProcessChild()
|
||||
{ }
|
||||
|
||||
virtual bool Init() override;
|
||||
virtual bool Init(int aArgc, char* aArgv[]) override;
|
||||
virtual void CleanUp() override;
|
||||
|
||||
protected:
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'Storage.h',
|
||||
'StorageIPC.h',
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'U2F.h',
|
||||
'U2FAuthenticator.h',
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'VRDisplay.h',
|
||||
'VRDisplayEvent.h',
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'NSSU2FTokenRemote.h',
|
||||
'ScopedCredential.h',
|
||||
|
@ -4,6 +4,369 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
with Files("APZTestData.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Panning and Zooming")
|
||||
|
||||
with Files("AccessibleNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Disability Access APIs")
|
||||
|
||||
with Files("Addon*"):
|
||||
BUG_COMPONENT = ("Toolkit", "Add-ons Manager")
|
||||
|
||||
with Files("AnalyserNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("Animat*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Animation")
|
||||
|
||||
with Files("*Audio*"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("Autocomplete*"):
|
||||
BUG_COMPONENT = ("Toolkit", "Autocomplete")
|
||||
|
||||
with Files("BaseKeyframeTypes.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Animation")
|
||||
|
||||
with Files("BatteryManager.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("BiquadFilterNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("BrowserElement*"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
with Files("CSP*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Security")
|
||||
|
||||
with Files("CSS*"):
|
||||
BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
|
||||
|
||||
with Files("Canvas*"):
|
||||
BUG_COMPONENT = ("Core", "Canvas: 2D")
|
||||
|
||||
with Files("Caret*"):
|
||||
BUG_COMPONENT = ("Core", "Editor")
|
||||
|
||||
with Files("Channel*"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("Client*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Service Workers")
|
||||
|
||||
with Files("ClipboardEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("ConstantSourceNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("ContainerBoxObject.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
with Files("ConvolverNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("Coordinates.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Geolocation")
|
||||
|
||||
with Files("Crypto.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Security")
|
||||
|
||||
with Files("Device*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("Directory.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("DataTransfer*"):
|
||||
BUG_COMPONENT = ("Core", "Drag and Drop")
|
||||
|
||||
with Files("DragEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Drag and Drop")
|
||||
|
||||
with Files("DecoderDoctorNotification.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video: Playback")
|
||||
|
||||
with Files("DelayNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("DynamicsCompressorNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("DesktopNotification.webidl"):
|
||||
BUG_COMPONENT = ("Toolkit", "Notification and Alerts")
|
||||
|
||||
with Files("FakePluginTagInit.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Plug-ins")
|
||||
|
||||
with Files("FlyWeb*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Flyweb")
|
||||
|
||||
with Files("FocusEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("Font*"):
|
||||
BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
|
||||
|
||||
with Files("FormData.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Core & HTML")
|
||||
|
||||
with Files("Geolocation.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Geolocation")
|
||||
|
||||
with Files("GainNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("Gamepad*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("GeometryUtils.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Layout")
|
||||
|
||||
with Files("GetUserMediaRequest.webidl"):
|
||||
BUG_COMPONENT = ("Core", "WebRTC")
|
||||
|
||||
with Files("Grid.webidl"):
|
||||
BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
|
||||
|
||||
with Files("GroupedHistoryEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Document Navigation")
|
||||
|
||||
with Files("HTML*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Core & HTML")
|
||||
|
||||
with Files("HashChangeEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("HeapSnapshot.webidl"):
|
||||
BUG_COMPONENT = ("Firefox", "Developer Tools: Memory")
|
||||
|
||||
with Files("HiddenPluginEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Plug-ins")
|
||||
|
||||
with Files("IDB*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: IndexedDB")
|
||||
|
||||
with Files("IIRFilterNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("Image*"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
with Files("ImageCapture*"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("InputEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("InstallTrigger.webidl"):
|
||||
BUG_COMPONENT = ("Toolkit", "Add-ons Manager")
|
||||
|
||||
with Files("InspectorUtils.webidl"):
|
||||
BUG_COMPONENT = ("Firefox", "Developer Tools: Inspector")
|
||||
|
||||
with Files("KeyAlgorithm.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Security")
|
||||
|
||||
with Files("Key*Event*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("KeyIdsInitData.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video: Playback")
|
||||
|
||||
with Files("Keyframe*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Animation")
|
||||
|
||||
with Files("LocalMediaStream.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("MediaDevice*"):
|
||||
BUG_COMPONENT = ("Core", "WebRTC")
|
||||
|
||||
with Files("Media*Source*"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("MediaStream*"):
|
||||
BUG_COMPONENT = ("Core", "WebRTC")
|
||||
|
||||
with Files("MediaStreamAudio*"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("MediaEncryptedEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("MediaKey*"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video: Playback")
|
||||
|
||||
with Files("Media*List*"):
|
||||
BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
|
||||
|
||||
with Files("MediaStreamList.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("*Record*"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video: Recording")
|
||||
|
||||
with Files("Media*Track*"):
|
||||
BUG_COMPONENT = ("Core", "WebRTC: Audio/Video")
|
||||
|
||||
with Files("Mouse*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("MozSelfSupport.webidl"):
|
||||
BUG_COMPONENT = ("Firefox Health Report", "Client: Desktop")
|
||||
|
||||
with Files("MozTimeManager.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("MutationEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("NativeOSFileInternals.webidl"):
|
||||
BUG_COMPONENT = ("Toolkit", "OS.File")
|
||||
|
||||
with Files("Net*"):
|
||||
BUG_COMPONENT = ("Core", "Networking")
|
||||
|
||||
with Files("OfflineAudio*"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("OffscreenCanvas.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Canvas 2D")
|
||||
|
||||
with Files("OscillatorNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("PannerNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("Peer*"):
|
||||
BUG_COMPONENT = ("Core", "WebRTC")
|
||||
|
||||
with Files("PeriodicWave.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("PointerEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("PopStateEvent.webidl*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("Position*"):
|
||||
BUG_COMPONENT = ("Core", "Geolocation")
|
||||
|
||||
with Files("ProfileTimelineMarker.webidl"):
|
||||
BUG_COMPONENT = ("Firefox", "Developer Tools: Performance Tools (profiler/timeline)")
|
||||
|
||||
with Files("ProgressEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("Push*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Push Notifications")
|
||||
|
||||
with Files("RTC*"):
|
||||
BUG_COMPONENT = ("Core", "WebRTC")
|
||||
|
||||
with Files("SVG*"):
|
||||
BUG_COMPONENT = ("Core", "SVG")
|
||||
|
||||
with Files("ScriptProcessorNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
# TODO: SecureElement*, SettingChangeNotification
|
||||
# are FirefoxOS::*, leaving as Core::DOM
|
||||
|
||||
with Files("Selection.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Selection")
|
||||
|
||||
with Files("ServiceWorker*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Service Workers")
|
||||
|
||||
with Files("SimpleGestureEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("SocketCommon.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("SourceBuffer*"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("StereoPannerNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("Style*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: CSS Object Model")
|
||||
|
||||
with Files("SubtleCrypto.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Security")
|
||||
|
||||
with Files("TCP*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("TextTrack*"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("ThreadSafeChromeUtils.webidl"):
|
||||
BUG_COMPONENT = ("Firefox", "Developer Tools: Memory")
|
||||
|
||||
with Files("TrackEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("U2F.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("UDP*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("UIEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("URL.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("UserProximityEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("VTT*"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("VRDisplay.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Graphics")
|
||||
|
||||
with Files("Video*"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
with Files("WaveShaperNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("WebAuthentication.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
|
||||
|
||||
with Files("WebGL*"):
|
||||
BUG_COMPONENT = ("Core", "Canvas: WebGL")
|
||||
|
||||
with Files("WebKitCSSMatrix.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: CSS Object Model")
|
||||
|
||||
with Files("Webrtc*"):
|
||||
BUG_COMPONENT = ("Core", "WebRTC")
|
||||
|
||||
with Files("WheelEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("WidevineCDMManifest.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video: Playback")
|
||||
|
||||
with Files("WindowOrWorkerGlobalScope.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Workers")
|
||||
|
||||
with Files("Worker*"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Workers")
|
||||
|
||||
GENERATED_WEBIDL_FILES = [
|
||||
'CSS2Properties.webidl',
|
||||
]
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "XBL")
|
||||
|
||||
DIRS += ['builtin']
|
||||
|
||||
EXPORTS += [
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIXMLHttpRequest.idl',
|
||||
]
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "XML")
|
||||
|
||||
DIRS += ['resources']
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "XSLT")
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIXSLTProcessor.idl',
|
||||
'nsIXSLTProcessorPrivate.idl',
|
||||
|
@ -818,18 +818,6 @@ nsPermissionManager::Init()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPermissionManager::RefreshPermission() {
|
||||
NS_ENSURE_TRUE(IsChildProcess(), NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = RemoveAllFromMemory();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = FetchPermissions();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPermissionManager::OpenDatabase(nsIFile* aPermissionsFile)
|
||||
{
|
||||
|
@ -692,6 +692,7 @@ gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getBufferStorage(BufferUs
|
||||
ANGLE_TRY(newStorage->resize(mSize, true));
|
||||
}
|
||||
|
||||
mIdleness[usage] = 0;
|
||||
ANGLE_TRY(updateBufferStorage(newStorage, 0, mSize));
|
||||
ANGLE_TRY(markBufferUsage(usage));
|
||||
|
||||
|
@ -22,7 +22,7 @@ GPUProcessImpl::~GPUProcessImpl()
|
||||
}
|
||||
|
||||
bool
|
||||
GPUProcessImpl::Init()
|
||||
GPUProcessImpl::Init(int aArgc, char* aArgv[])
|
||||
{
|
||||
return mGPU.Init(ParentPid(),
|
||||
IOThreadChild::message_loop(),
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
explicit GPUProcessImpl(ProcessId aParentPid);
|
||||
~GPUProcessImpl();
|
||||
|
||||
bool Init() override;
|
||||
bool Init(int aArgc, char* aArgv[]) override;
|
||||
void CleanUp() override;
|
||||
|
||||
private:
|
||||
|
@ -59,38 +59,6 @@ using namespace mozilla::media;
|
||||
typedef std::vector<CompositableOperation> OpVector;
|
||||
typedef nsTArray<OpDestroy> OpDestroyVector;
|
||||
|
||||
namespace {
|
||||
class ImageBridgeThread : public Thread {
|
||||
public:
|
||||
|
||||
ImageBridgeThread() : Thread("ImageBridgeChild") {
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
MOZ_IS_CLASS_INIT
|
||||
void Init() {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
mPseudoStackHack = profiler_get_pseudo_stack();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CleanUp() {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
mPseudoStackHack = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
// This is needed to avoid a spurious leak report. There's no other
|
||||
// use for it. See bug 1239504 and bug 1215265.
|
||||
MOZ_INIT_OUTSIDE_CTOR PseudoStack* mPseudoStackHack;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
struct CompositableTransaction
|
||||
{
|
||||
CompositableTransaction()
|
||||
@ -620,7 +588,7 @@ ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
|
||||
gfxPlatform::GetPlatform();
|
||||
|
||||
if (!sImageBridgeChildThread) {
|
||||
sImageBridgeChildThread = new ImageBridgeThread();
|
||||
sImageBridgeChildThread = new Thread("ImageBridgeChild");
|
||||
if (!sImageBridgeChildThread->Start()) {
|
||||
return false;
|
||||
}
|
||||
@ -747,7 +715,7 @@ ImageBridgeChild::InitSameProcess()
|
||||
MOZ_ASSERT(!sImageBridgeChildSingleton);
|
||||
MOZ_ASSERT(!sImageBridgeChildThread);
|
||||
|
||||
sImageBridgeChildThread = new ImageBridgeThread();
|
||||
sImageBridgeChildThread = new Thread("ImageBridgeChild");
|
||||
if (!sImageBridgeChildThread->IsRunning()) {
|
||||
sImageBridgeChildThread->Start();
|
||||
}
|
||||
@ -775,7 +743,7 @@ ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint)
|
||||
MOZ_ASSERT(!sImageBridgeChildSingleton);
|
||||
MOZ_ASSERT(!sImageBridgeChildThread);
|
||||
|
||||
sImageBridgeChildThread = new ImageBridgeThread();
|
||||
sImageBridgeChildThread = new Thread("ImageBridgeChild");
|
||||
if (!sImageBridgeChildThread->IsRunning()) {
|
||||
sImageBridgeChildThread->Start();
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
class nsWin32Locale {
|
||||
class nsWin32Locale final {
|
||||
public:
|
||||
static nsresult GetPlatformLocale(const nsAString& locale, LCID* winLCID);
|
||||
static void GetXPLocale(LCID winLCID, nsAString& locale);
|
||||
@ -18,15 +18,6 @@ public:
|
||||
private:
|
||||
// Static class - Don't allow instantiation.
|
||||
nsWin32Locale(void) {}
|
||||
|
||||
typedef LCID (WINAPI*LocaleNameToLCIDPtr)(LPCWSTR lpName, DWORD dwFlags);
|
||||
typedef int (WINAPI*LCIDToLocaleNamePtr)(LCID Locale, LPWSTR lpName,
|
||||
int cchName, DWORD dwFlags);
|
||||
|
||||
static LocaleNameToLCIDPtr localeNameToLCID;
|
||||
static LCIDToLocaleNamePtr lcidToLocaleName;
|
||||
|
||||
static void initFunctionPointers ();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -10,9 +10,7 @@
|
||||
#include "nsXPCOMStrings.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsWin32Locale.h"
|
||||
#include "prprf.h"
|
||||
#include <windows.h>
|
||||
#include "nsCRT.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -29,103 +27,6 @@ struct iso_map
|
||||
iso_pair sublang_list[20];
|
||||
};
|
||||
|
||||
nsWin32Locale::LocaleNameToLCIDPtr nsWin32Locale::localeNameToLCID = nullptr;
|
||||
nsWin32Locale::LCIDToLocaleNamePtr nsWin32Locale::lcidToLocaleName = nullptr;
|
||||
|
||||
// Older versions of VC++ and Win32 SDK and mingw don't have
|
||||
// macros for languages and sublanguages recently added to Win32.
|
||||
// see http://www.tug.org/ftp/tex/texinfo/intl/localename.c
|
||||
|
||||
#ifndef LANG_URDU
|
||||
#define LANG_URDU 0x20
|
||||
#endif
|
||||
#ifndef LANG_ARMENIAN
|
||||
#define LANG_ARMENIAN 0x2b
|
||||
#endif
|
||||
#ifndef LANG_AZERI
|
||||
#define LANG_AZERI 0x2c
|
||||
#endif
|
||||
#ifndef LANG_MACEDONIAN
|
||||
#define LANG_MACEDONIAN 0x2f
|
||||
#endif
|
||||
#ifndef LANG_GEORGIAN
|
||||
#define LANG_GEORGIAN 0x37
|
||||
#endif
|
||||
#ifndef LANG_HINDI
|
||||
#define LANG_HINDI 0x39
|
||||
#endif
|
||||
#ifndef LANG_MALAY
|
||||
#define LANG_MALAY 0x3e
|
||||
#endif
|
||||
#ifndef LANG_KAZAK
|
||||
#define LANG_KAZAK 0x3f
|
||||
#endif
|
||||
#ifndef LANG_KYRGYZ
|
||||
#define LANG_KYRGYZ 0x40
|
||||
#endif
|
||||
#ifndef LANG_SWAHILI
|
||||
#define LANG_SWAHILI 0x41
|
||||
#endif
|
||||
#ifndef LANG_UZBEK
|
||||
#define LANG_UZBEK 0x43
|
||||
#endif
|
||||
#ifndef LANG_TATAR
|
||||
#define LANG_TATAR 0x44
|
||||
#endif
|
||||
#ifndef LANG_PUNJABI
|
||||
#define LANG_PUNJABI 0x46
|
||||
#endif
|
||||
#ifndef LANG_GUJARAT
|
||||
#define LANG_GUJARAT 0x47
|
||||
#endif
|
||||
#ifndef LANG_TAMIL
|
||||
#define LANG_TAMIL 0x49
|
||||
#endif
|
||||
#ifndef LANG_TELUGU
|
||||
#define LANG_TELUGU 0x4a
|
||||
#endif
|
||||
#ifndef LANG_KANNADA
|
||||
#define LANG_KANNADA 0x4b
|
||||
#endif
|
||||
#ifndef LANG_MARATHI
|
||||
#define LANG_MARATHI 0x4e
|
||||
#endif
|
||||
#ifndef LANG_SANSKRIT
|
||||
#define LANG_SANSKRIT 0x4f
|
||||
#endif
|
||||
#ifndef LANG_MONGOLIAN
|
||||
#define LANG_MONGOLIAN 0x50
|
||||
#endif
|
||||
#ifndef LANG_GALICIAN
|
||||
#define LANG_GALICIAN 0x56
|
||||
#endif
|
||||
#ifndef LANG_KONKANI
|
||||
#define LANG_KONKANI 0x57
|
||||
#endif
|
||||
#ifndef LANG_DIVEHI
|
||||
#define LANG_DIVEHI 0x65
|
||||
#endif
|
||||
|
||||
#ifndef SUBLANG_MALAY_MALAYSIA
|
||||
#define SUBLANG_MALAY_MALAYSIA 0x01
|
||||
#endif
|
||||
#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
|
||||
#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
|
||||
#endif
|
||||
#ifndef SUBLANG_CHINESE_MACAU
|
||||
#define SUBLANG_CHINESE_MACAU 0x05
|
||||
#endif
|
||||
#ifndef SUBLANG_FRENCH_MONACO
|
||||
#define SUBLANG_FRENCH_MONACO 0x06
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_ZIMBABWE
|
||||
#define SUBLANG_ENGLISH_ZIMBABWE 0x0c
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_PHILIPPINES
|
||||
#define SUBLANG_ENGLISH_PHILIPPINES 0x0d
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// This list is used to map between ISO language
|
||||
// References :
|
||||
@ -574,21 +475,6 @@ iso_pair dbg_list[] =
|
||||
#define CROATIAN_ISO_CODE "hr"
|
||||
#define SERBIAN_ISO_CODE "sr"
|
||||
|
||||
void
|
||||
nsWin32Locale::initFunctionPointers(void)
|
||||
{
|
||||
static bool sInitialized = false;
|
||||
// We use the Vista and above functions if we have them
|
||||
if (!sInitialized) {
|
||||
HMODULE kernelDLL = GetModuleHandleW(L"kernel32.dll");
|
||||
if (kernelDLL) {
|
||||
localeNameToLCID = (LocaleNameToLCIDPtr) GetProcAddress(kernelDLL, "LocaleNameToLCID");
|
||||
lcidToLocaleName = (LCIDToLocaleNamePtr) GetProcAddress(kernelDLL, "LCIDToLocaleName");
|
||||
}
|
||||
sInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// the mapping routines are a first approximation to get us going on
|
||||
// the tier-1 languages. we are making an assumption that we can map
|
||||
@ -597,18 +483,12 @@ nsWin32Locale::initFunctionPointers(void)
|
||||
nsresult
|
||||
nsWin32Locale::GetPlatformLocale(const nsAString& locale, LCID* winLCID)
|
||||
{
|
||||
initFunctionPointers ();
|
||||
|
||||
if (localeNameToLCID) {
|
||||
nsAutoString locale_autostr(locale);
|
||||
LCID lcid = localeNameToLCID(locale_autostr.get(), 0);
|
||||
// The function returning 0 means that the locale name couldn't be matched,
|
||||
// so we fallback to the old function
|
||||
if (lcid != 0)
|
||||
{
|
||||
*winLCID = lcid;
|
||||
return NS_OK;
|
||||
}
|
||||
LCID lcid = LocaleNameToLCID(PromiseFlatString(locale).get(), 0);
|
||||
// The function returning 0 means that the locale name couldn't be matched,
|
||||
// so we fallback to the old function
|
||||
if (lcid != 0) {
|
||||
*winLCID = lcid;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
char locale_string[9] = {'\0','\0','\0','\0','\0','\0','\0','\0','\0'};
|
||||
@ -644,26 +524,19 @@ nsWin32Locale::GetPlatformLocale(const nsAString& locale, LCID* winLCID)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#ifndef LOCALE_NAME_MAX_LENGTH
|
||||
#define LOCALE_NAME_MAX_LENGTH 85
|
||||
#endif
|
||||
|
||||
void
|
||||
nsWin32Locale::GetXPLocale(LCID winLCID, nsAString& locale)
|
||||
{
|
||||
initFunctionPointers ();
|
||||
|
||||
if (lcidToLocaleName)
|
||||
{
|
||||
WCHAR ret_locale[LOCALE_NAME_MAX_LENGTH];
|
||||
int rv = lcidToLocaleName(winLCID, ret_locale, LOCALE_NAME_MAX_LENGTH, 0);
|
||||
// rv 0 means that the function failed to match up the LCID, so we fallback
|
||||
// to the old function
|
||||
if (rv != 0)
|
||||
{
|
||||
locale.Assign(ret_locale);
|
||||
return;
|
||||
}
|
||||
locale.SetCapacity(LOCALE_NAME_MAX_LENGTH);
|
||||
int length = LCIDToLocaleName(winLCID,
|
||||
reinterpret_cast<LPWSTR>(locale.BeginWriting()),
|
||||
LOCALE_NAME_MAX_LENGTH, 0);
|
||||
// 0 length means that the function failed to match up the LCID,
|
||||
// so we fallback to the old function
|
||||
if (length) {
|
||||
// length contains null terminate.
|
||||
locale.SetLength(length - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD lang_id, sublang_id;
|
||||
|
@ -109,8 +109,11 @@ public:
|
||||
int32_t processType = mProcessType;
|
||||
int32_t crashType = mCrashType;
|
||||
nsString childDumpID(mChildDumpID);
|
||||
nsCOMPtr<nsIAsyncShutdownBlocker> self(this);
|
||||
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([=] () -> void {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([
|
||||
self, processType, crashType, childDumpID
|
||||
] {
|
||||
nsCOMPtr<nsICrashService> crashService =
|
||||
do_GetService("@mozilla.org/crashservice;1");
|
||||
if (crashService) {
|
||||
@ -120,7 +123,7 @@ public:
|
||||
nsCOMPtr<nsIAsyncShutdownClient> barrier = GetShutdownBarrier();
|
||||
|
||||
if (barrier) {
|
||||
barrier->RemoveBlocker(this);
|
||||
barrier->RemoveBlocker(self);
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
explicit ProcessChild(ProcessId aParentPid);
|
||||
virtual ~ProcessChild();
|
||||
|
||||
virtual bool Init() = 0;
|
||||
virtual bool Init(int aArgc, char* aArgv[]) = 0;
|
||||
virtual void CleanUp()
|
||||
{ }
|
||||
|
||||
|
@ -259,14 +259,23 @@ DecommitPages(void* addr, size_t bytes)
|
||||
static void*
|
||||
ComputeRandomAllocationAddress()
|
||||
{
|
||||
// Return a random, page-aligned address. x64 CPUs have a 48-bit address
|
||||
// space and on some platforms the OS will give us access to 47 bits, so
|
||||
// to be safe we right shift by 18 to leave 46 bits.
|
||||
|
||||
uint64_t rand = js::GenerateRandomSeed();
|
||||
|
||||
# ifdef HAVE_64BIT_BUILD
|
||||
// x64 CPUs have a 48-bit address space and on some platforms the OS will
|
||||
// give us access to 47 bits, so to be safe we right shift by 18 to leave
|
||||
// 46 bits.
|
||||
rand >>= 18;
|
||||
# else
|
||||
// On 32-bit, right shift by 34 to leave 30 bits, range [0, 1GiB). Then add
|
||||
// 512MiB to get range [512MiB, 1.5GiB), or [0x20000000, 0x60000000). This
|
||||
// is based on V8 comments in platform-posix.cc saying this range is
|
||||
// relatively unpopulated across a variety of kernels.
|
||||
rand >>= 34;
|
||||
rand += 512 * 1024 * 1024;
|
||||
# endif
|
||||
|
||||
// Ensure page alignment.
|
||||
uintptr_t mask = ~uintptr_t(gc::SystemPageSize() - 1);
|
||||
return (void*) uintptr_t(rand & mask);
|
||||
}
|
||||
|
@ -5,6 +5,6 @@
|
||||
== box-sizing-content-box-001.xht box-sizing-content-box-001-ref.xht
|
||||
== box-sizing-content-box-002.xht box-sizing-content-box-002-ref.xht
|
||||
== box-sizing-content-box-003.xht box-sizing-content-box-003-ref.xht
|
||||
random-if(Android) fuzzy-if(skiaContent,15,50) fuzzy-if(OSX,255,1575) == box-sizing-replaced-001.xht box-sizing-replaced-001-ref.xht # bug 982547, Bug 1295466
|
||||
skip-if(Android||gtkWidget) fuzzy-if(skiaContent,15,50) fuzzy-if(OSX,255,1575) == box-sizing-replaced-001.xht box-sizing-replaced-001-ref.xht # bug 982547, Bug 1295466, Bug 1321707
|
||||
fuzzy-if(Android,27,874) fuzzy-if(gtkWidget,14,29) == box-sizing-replaced-002.xht box-sizing-replaced-002-ref.xht # Bug 1128229, Bug 1313772
|
||||
fuzzy-if(Android,27,925) fuzzy-if(gtkWidget,14,43) == box-sizing-replaced-003.xht box-sizing-replaced-003-ref.xht # Bug 1128229
|
||||
|
@ -728,7 +728,8 @@ nsXULTooltipListener::GetSourceTreeBoxObject(nsITreeBoxObject** aBoxObject)
|
||||
|
||||
nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
|
||||
if (mIsSourceTree && sourceNode) {
|
||||
RefPtr<nsXULElement> xulEl = nsXULElement::FromContent(sourceNode);
|
||||
RefPtr<nsXULElement> xulEl =
|
||||
nsXULElement::FromContentOrNull(sourceNode->GetParent());
|
||||
if (xulEl) {
|
||||
IgnoredErrorResult ignored;
|
||||
nsCOMPtr<nsIBoxObject> bx = xulEl->GetBoxObject(ignored);
|
||||
|
@ -58,9 +58,9 @@ extensions.on("page-shutdown", (type, context) => {
|
||||
}
|
||||
let {BrowserApp} = context.xulBrowser.ownerGlobal;
|
||||
if (BrowserApp) {
|
||||
let tab = BrowserApp.getTabForBrowser(context.xulBrowser);
|
||||
if (tab) {
|
||||
BrowserApp.closeTab(tab);
|
||||
let nativeTab = BrowserApp.getTabForBrowser(context.xulBrowser);
|
||||
if (nativeTab) {
|
||||
BrowserApp.closeTab(nativeTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,16 +89,16 @@ let tabListener = {
|
||||
onLocationChange(browser, webProgress, request, locationURI, flags) {
|
||||
if (webProgress.isTopLevel) {
|
||||
let {BrowserApp} = browser.ownerGlobal;
|
||||
let tab = BrowserApp.getTabForBrowser(browser);
|
||||
let nativeTab = BrowserApp.getTabForBrowser(browser);
|
||||
|
||||
// Now we are certain that the first page in the tab was loaded.
|
||||
this.initializingTabs.delete(tab);
|
||||
this.initializingTabs.delete(nativeTab);
|
||||
|
||||
// browser.innerWindowID is now set, resolve the promises if any.
|
||||
let deferred = this.tabReadyPromises.get(tab);
|
||||
let deferred = this.tabReadyPromises.get(nativeTab);
|
||||
if (deferred) {
|
||||
deferred.resolve(tab);
|
||||
this.tabReadyPromises.delete(tab);
|
||||
deferred.resolve(nativeTab);
|
||||
this.tabReadyPromises.delete(nativeTab);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -109,19 +109,20 @@ let tabListener = {
|
||||
* changes to the requested URL. Other tabs are assumed to be ready once their
|
||||
* inner window ID is known.
|
||||
*
|
||||
* @param {XULElement} tab The <tab> element.
|
||||
* @param {NativeTab} nativeTab The native tab object.
|
||||
* @returns {Promise} Resolves with the given tab once ready.
|
||||
*/
|
||||
awaitTabReady(tab) {
|
||||
let deferred = this.tabReadyPromises.get(tab);
|
||||
awaitTabReady(nativeTab) {
|
||||
let deferred = this.tabReadyPromises.get(nativeTab);
|
||||
if (!deferred) {
|
||||
deferred = PromiseUtils.defer();
|
||||
if (!this.initializingTabs.has(tab) && (tab.browser.innerWindowID ||
|
||||
tab.browser.currentURI.spec === "about:blank")) {
|
||||
deferred.resolve(tab);
|
||||
if (!this.initializingTabs.has(nativeTab) &&
|
||||
(nativeTab.browser.innerWindowID ||
|
||||
nativeTab.browser.currentURI.spec === "about:blank")) {
|
||||
deferred.resolve(nativeTab);
|
||||
} else {
|
||||
this.initTabReady();
|
||||
this.tabReadyPromises.set(tab, deferred);
|
||||
this.tabReadyPromises.set(nativeTab, deferred);
|
||||
}
|
||||
}
|
||||
return deferred.promise;
|
||||
@ -148,7 +149,7 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
tab = tabManager.getWrapper(tabTracker.activeTab);
|
||||
}
|
||||
|
||||
await tabListener.awaitTabReady(tab.tab);
|
||||
await tabListener.awaitTabReady(tab.nativeTab);
|
||||
|
||||
return tab;
|
||||
}
|
||||
@ -163,7 +164,7 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
|
||||
onCreated: new SingletonEventManager(context, "tabs.onCreated", fire => {
|
||||
let listener = (eventName, event) => {
|
||||
fire.async(tabManager.convert(event.tab));
|
||||
fire.async(tabManager.convert(event.nativeTab));
|
||||
};
|
||||
|
||||
tabTracker.on("tab-created", listener);
|
||||
@ -233,12 +234,12 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
|
||||
let listener = event => {
|
||||
let needed = [];
|
||||
let tab;
|
||||
let nativeTab;
|
||||
switch (event.type) {
|
||||
case "DOMTitleChanged": {
|
||||
let {BrowserApp} = getBrowserWindow(event.target.ownerGlobal);
|
||||
|
||||
tab = BrowserApp.getTabForWindow(event.target.ownerGlobal);
|
||||
nativeTab = BrowserApp.getTabForWindow(event.target.ownerGlobal);
|
||||
needed.push("title");
|
||||
break;
|
||||
}
|
||||
@ -246,17 +247,17 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
case "DOMAudioPlaybackStarted":
|
||||
case "DOMAudioPlaybackStopped": {
|
||||
let {BrowserApp} = event.target.ownerGlobal;
|
||||
tab = BrowserApp.getTabForBrowser(event.originalTarget);
|
||||
nativeTab = BrowserApp.getTabForBrowser(event.originalTarget);
|
||||
needed.push("audible");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tab) {
|
||||
if (!nativeTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
tab = tabManager.getWrapper(tab);
|
||||
let tab = tabManager.getWrapper(nativeTab);
|
||||
let changeInfo = {};
|
||||
for (let prop of needed) {
|
||||
changeInfo[prop] = tab[prop];
|
||||
@ -267,14 +268,14 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
|
||||
let statusListener = ({browser, status, url}) => {
|
||||
let {BrowserApp} = browser.ownerGlobal;
|
||||
let tab = BrowserApp.getTabForBrowser(browser);
|
||||
if (tab) {
|
||||
let nativeTab = BrowserApp.getTabForBrowser(browser);
|
||||
if (nativeTab) {
|
||||
let changed = {status};
|
||||
if (url) {
|
||||
changed.url = url;
|
||||
}
|
||||
|
||||
fireForTab(tabManager.wrapTab(tab), changed);
|
||||
fireForTab(tabManager.wrapTab(nativeTab), changed);
|
||||
}
|
||||
};
|
||||
|
||||
@ -319,13 +320,13 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
options.disallowInheritPrincipal = true;
|
||||
|
||||
tabListener.initTabReady();
|
||||
let tab = BrowserApp.addTab(url, options);
|
||||
let nativeTab = BrowserApp.addTab(url, options);
|
||||
|
||||
if (createProperties.url) {
|
||||
tabListener.initializingTabs.add(tab);
|
||||
tabListener.initializingTabs.add(nativeTab);
|
||||
}
|
||||
|
||||
return tabManager.convert(tab);
|
||||
return tabManager.convert(nativeTab);
|
||||
},
|
||||
|
||||
async remove(tabs) {
|
||||
@ -334,15 +335,15 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
}
|
||||
|
||||
for (let tabId of tabs) {
|
||||
let tab = tabTracker.getTab(tabId);
|
||||
tab.browser.ownerGlobal.BrowserApp.closeTab(tab);
|
||||
let nativeTab = tabTracker.getTab(tabId);
|
||||
nativeTab.browser.ownerGlobal.BrowserApp.closeTab(nativeTab);
|
||||
}
|
||||
},
|
||||
|
||||
async update(tabId, updateProperties) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = getTabOrActive(tabId);
|
||||
|
||||
let {BrowserApp} = tab.browser.ownerGlobal;
|
||||
let {BrowserApp} = nativeTab.browser.ownerGlobal;
|
||||
|
||||
if (updateProperties.url !== null) {
|
||||
let url = context.uri.resolve(updateProperties.url);
|
||||
@ -351,29 +352,29 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
return Promise.reject({message: `Illegal URL: ${url}`});
|
||||
}
|
||||
|
||||
tab.browser.loadURI(url);
|
||||
nativeTab.browser.loadURI(url);
|
||||
}
|
||||
|
||||
if (updateProperties.active !== null) {
|
||||
if (updateProperties.active) {
|
||||
BrowserApp.selectTab(tab);
|
||||
BrowserApp.selectTab(nativeTab);
|
||||
} else {
|
||||
// Not sure what to do here? Which tab should we select?
|
||||
}
|
||||
}
|
||||
// FIXME: highlighted/selected, muted, pinned, openerTabId
|
||||
|
||||
return tabManager.convert(tab);
|
||||
return tabManager.convert(nativeTab);
|
||||
},
|
||||
|
||||
async reload(tabId, reloadProperties) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = getTabOrActive(tabId);
|
||||
|
||||
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
if (reloadProperties && reloadProperties.bypassCache) {
|
||||
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
|
||||
}
|
||||
tab.browser.reloadWithFlags(flags);
|
||||
nativeTab.browser.reloadWithFlags(flags);
|
||||
},
|
||||
|
||||
async get(tabId) {
|
||||
@ -400,41 +401,15 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||
tab => tab.convert());
|
||||
},
|
||||
|
||||
captureVisibleTab(windowId, options) {
|
||||
if (!extension.hasPermission("<all_urls>")) {
|
||||
return Promise.reject({message: "The <all_urls> permission is required to use the captureVisibleTab API"});
|
||||
}
|
||||
|
||||
async captureVisibleTab(windowId, options) {
|
||||
let window = windowId == null ?
|
||||
windowTracker.topWindow :
|
||||
windowTracker.getWindow(windowId, context);
|
||||
|
||||
let tab = window.BrowserApp.selectedTab;
|
||||
return tabListener.awaitTabReady(tab).then(() => {
|
||||
let {browser} = tab;
|
||||
let recipient = {
|
||||
innerWindowID: browser.innerWindowID,
|
||||
};
|
||||
let tab = tabManager.wrapTab(window.BrowserApp.selectedTab);
|
||||
await tabListener.awaitTabReady(tab.nativeTab);
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (options.format == null) {
|
||||
options.format = "png";
|
||||
}
|
||||
if (options.quality == null) {
|
||||
options.quality = 92;
|
||||
}
|
||||
|
||||
let message = {
|
||||
options,
|
||||
width: browser.clientWidth,
|
||||
height: browser.clientHeight,
|
||||
};
|
||||
|
||||
return context.sendMessage(browser.messageManager, "Extension:Capture",
|
||||
message, {recipient});
|
||||
});
|
||||
return tab.capture(context, options);
|
||||
},
|
||||
|
||||
async executeScript(tabId, details) {
|
||||
|
@ -28,17 +28,46 @@ const BrowserStatusFilter = Components.Constructor(
|
||||
let tabTracker;
|
||||
let windowTracker;
|
||||
|
||||
/**
|
||||
* A nsIWebProgressListener for a specific XUL browser, which delegates the
|
||||
* events that it receives to a tab progress listener, and prepends the browser
|
||||
* to their arguments list.
|
||||
*
|
||||
* @param {XULElement} browser
|
||||
* A XUL browser element.
|
||||
* @param {object} listener
|
||||
* A tab progress listener object.
|
||||
* @param {integer} flags
|
||||
* The web progress notification flags with which to filter events.
|
||||
*/
|
||||
class BrowserProgressListener {
|
||||
constructor(browser, listener, flags) {
|
||||
this.listener = listener;
|
||||
this.browser = browser;
|
||||
this.filter = new BrowserStatusFilter(this, flags);
|
||||
this.browser.addProgressListener(this.filter, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the listener, and perform any necessary cleanup.
|
||||
*/
|
||||
destroy() {
|
||||
this.browser.removeProgressListener(this.filter);
|
||||
this.filter.removeProgressListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the appropriate listener in the wrapped tab progress listener, with
|
||||
* the wrapped XUL browser object as its first argument, and the additional
|
||||
* arguments in `args`.
|
||||
*
|
||||
* @param {string} method
|
||||
* The name of the nsIWebProgressListener method which is being
|
||||
* delegated.
|
||||
* @param {*} args
|
||||
* The arguments to pass to the delegated listener.
|
||||
* @private
|
||||
*/
|
||||
delegate(method, ...args) {
|
||||
if (this.listener[method]) {
|
||||
this.listener[method](this.browser, ...args);
|
||||
@ -57,6 +86,16 @@ class BrowserProgressListener {
|
||||
onSecurityChange(webProgress, request, state) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles wrapping a tab progress listener in browser-specific
|
||||
* BrowserProgressListener instances, an attaching them to each tab in a given
|
||||
* browser window.
|
||||
*
|
||||
* @param {DOMWindow} window
|
||||
* The browser window to which to attach the listeners.
|
||||
* @param {object} listener
|
||||
* The tab progress listener to wrap.
|
||||
*/
|
||||
class ProgressListenerWrapper {
|
||||
constructor(window, listener) {
|
||||
this.window = window;
|
||||
@ -66,39 +105,61 @@ class ProgressListenerWrapper {
|
||||
this.flags = Ci.nsIWebProgress.NOTIFY_STATE_ALL |
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION;
|
||||
|
||||
for (let tab of this.window.BrowserApp.tabs) {
|
||||
this.addBrowserProgressListener(tab.browser);
|
||||
for (let nativeTab of this.window.BrowserApp.tabs) {
|
||||
this.addBrowserProgressListener(nativeTab.browser);
|
||||
}
|
||||
|
||||
this.window.BrowserApp.deck.addEventListener("TabOpen", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the wrapper, removing any remaining listeners it has added.
|
||||
*/
|
||||
destroy() {
|
||||
this.window.BrowserApp.deck.removeEventListener("TabOpen", this);
|
||||
|
||||
for (let tab of this.window.BrowserApp.tabs) {
|
||||
this.removeProgressListener(tab.browser);
|
||||
for (let nativeTab of this.window.BrowserApp.tabs) {
|
||||
this.removeProgressListener(nativeTab.browser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a progress listener to the given XUL browser element.
|
||||
*
|
||||
* @param {XULElement} browser
|
||||
* The XUL browser to add the listener to.
|
||||
* @private
|
||||
*/
|
||||
addBrowserProgressListener(browser) {
|
||||
this.removeProgressListener(browser);
|
||||
|
||||
let listener = new BrowserProgressListener(browser, this.listener, this.flags);
|
||||
this.listeners.set(browser, listener);
|
||||
|
||||
browser.addProgressListener(listener.filter, this.flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a progress listener from the given XUL browser element.
|
||||
*
|
||||
* @param {XULElement} browser
|
||||
* The XUL browser to remove the listener from.
|
||||
* @private
|
||||
*/
|
||||
removeProgressListener(browser) {
|
||||
let listener = this.listeners.get(browser);
|
||||
if (listener) {
|
||||
browser.removeProgressListener(listener.filter);
|
||||
listener.destroy();
|
||||
this.listeners.delete(browser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles tab open events, and adds the necessary progress listeners to the
|
||||
* new tabs.
|
||||
*
|
||||
* @param {Event} event
|
||||
* The DOM event to handle.
|
||||
* @private
|
||||
*/
|
||||
handleEvent(event) {
|
||||
if (event.type === "TabOpen") {
|
||||
this.addBrowserProgressListener(event.originalTarget);
|
||||
@ -107,7 +168,6 @@ class ProgressListenerWrapper {
|
||||
|
||||
}
|
||||
|
||||
|
||||
class WindowTracker extends WindowTrackerBase {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
@ -132,6 +192,24 @@ class WindowTracker extends WindowTrackerBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event manager API provider which listens for an event in the Android
|
||||
* global EventDispatcher, 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 an object detailing the
|
||||
* EventDispatcher event that was received.
|
||||
*
|
||||
* @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 EventDispatcher event to listen for.
|
||||
* @param {function} listener
|
||||
* The listener function to call when an EventDispatcher event is
|
||||
* recieved.
|
||||
*/
|
||||
global.GlobalEventManager = class extends SingletonEventManager {
|
||||
constructor(context, name, event, listener) {
|
||||
super(context, name, fire => {
|
||||
@ -149,6 +227,21 @@ global.GlobalEventManager = class extends SingletonEventManager {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 SingletonEventManager {
|
||||
constructor(context, name, event, listener) {
|
||||
super(context, name, fire => {
|
||||
@ -173,16 +266,16 @@ class TabTracker extends TabTrackerBase {
|
||||
windowTracker.addListener("TabOpen", this);
|
||||
}
|
||||
|
||||
getId(tab) {
|
||||
return tab.id;
|
||||
getId(nativeTab) {
|
||||
return nativeTab.id;
|
||||
}
|
||||
|
||||
getTab(id, default_ = undefined) {
|
||||
let win = windowTracker.topWindow;
|
||||
if (win) {
|
||||
let tab = win.BrowserApp.getTabForId(id);
|
||||
if (tab) {
|
||||
return tab;
|
||||
let nativeTab = win.BrowserApp.getTabForId(id);
|
||||
if (nativeTab) {
|
||||
return nativeTab;
|
||||
}
|
||||
}
|
||||
if (default_ !== undefined) {
|
||||
@ -191,31 +284,56 @@ class TabTracker extends TabTrackerBase {
|
||||
throw new ExtensionError(`Invalid tab ID: ${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles tab open and close events, and emits the appropriate internal
|
||||
* events for them.
|
||||
*
|
||||
* @param {Event} event
|
||||
* A DOM event to handle.
|
||||
* @private
|
||||
*/
|
||||
handleEvent(event) {
|
||||
const {BrowserApp} = event.target.ownerGlobal;
|
||||
let tab = BrowserApp.getTabForBrowser(event.target);
|
||||
let nativeTab = BrowserApp.getTabForBrowser(event.target);
|
||||
|
||||
switch (event.type) {
|
||||
case "TabOpen":
|
||||
this.emitCreated(tab);
|
||||
this.emitCreated(nativeTab);
|
||||
break;
|
||||
|
||||
case "TabClose":
|
||||
this.emitRemoved(tab, false);
|
||||
this.emitRemoved(nativeTab, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emitCreated(tab) {
|
||||
this.emit("tab-created", {tab});
|
||||
/**
|
||||
* Emits a "tab-created" event for the given tab element.
|
||||
*
|
||||
* @param {NativeTab} nativeTab
|
||||
* The tab element which is being created.
|
||||
* @private
|
||||
*/
|
||||
emitCreated(nativeTab) {
|
||||
this.emit("tab-created", {nativeTab});
|
||||
}
|
||||
|
||||
emitRemoved(tab, isWindowClosing) {
|
||||
let windowId = windowTracker.getId(tab.browser.ownerGlobal);
|
||||
let tabId = this.getId(tab);
|
||||
/**
|
||||
* 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.browser.ownerGlobal);
|
||||
let tabId = this.getId(nativeTab);
|
||||
|
||||
Services.tm.mainThread.dispatch(() => {
|
||||
this.emit("tab-removed", {tab, tabId, windowId, isWindowClosing});
|
||||
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
@ -229,9 +347,9 @@ class TabTracker extends TabTrackerBase {
|
||||
if (BrowserApp) {
|
||||
result.windowId = windowTracker.getId(browser.ownerGlobal);
|
||||
|
||||
let tab = BrowserApp.getTabForBrowser(browser);
|
||||
if (tab) {
|
||||
result.tabId = this.getId(tab);
|
||||
let nativeTab = BrowserApp.getTabForBrowser(browser);
|
||||
if (nativeTab) {
|
||||
result.tabId = this.getId(nativeTab);
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,15 +376,15 @@ class Tab extends TabBase {
|
||||
}
|
||||
|
||||
get audible() {
|
||||
return this.tab.playingAudio;
|
||||
return this.nativeTab.playingAudio;
|
||||
}
|
||||
|
||||
get browser() {
|
||||
return this.tab.browser;
|
||||
return this.nativeTab.browser;
|
||||
}
|
||||
|
||||
get cookieStoreId() {
|
||||
return getCookieStoreIdForTab(this, this.tab);
|
||||
return getCookieStoreIdForTab(this, this.nativeTab);
|
||||
}
|
||||
|
||||
get height() {
|
||||
@ -278,7 +396,7 @@ class Tab extends TabBase {
|
||||
}
|
||||
|
||||
get index() {
|
||||
return this.window.BrowserApp.tabs.indexOf(this.tab);
|
||||
return this.window.BrowserApp.tabs.indexOf(this.nativeTab);
|
||||
}
|
||||
|
||||
get mutedInfo() {
|
||||
@ -290,11 +408,11 @@ class Tab extends TabBase {
|
||||
}
|
||||
|
||||
get active() {
|
||||
return this.tab.getActive();
|
||||
return this.nativeTab.getActive();
|
||||
}
|
||||
|
||||
get selected() {
|
||||
return this.tab.getActive();
|
||||
return this.nativeTab.getActive();
|
||||
}
|
||||
|
||||
get status() {
|
||||
@ -357,8 +475,8 @@ class Window extends WindowBase {
|
||||
* getTabs() {
|
||||
let {tabManager} = this.extension;
|
||||
|
||||
for (let tab of this.window.BrowserApp.tabs) {
|
||||
yield tabManager.getWrapper(tab);
|
||||
for (let nativeTab of this.window.BrowserApp.tabs) {
|
||||
yield tabManager.getWrapper(nativeTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -367,24 +485,24 @@ Object.assign(global, {Tab, Window});
|
||||
|
||||
class TabManager extends TabManagerBase {
|
||||
get(tabId, default_ = undefined) {
|
||||
let tab = tabTracker.getTab(tabId, default_);
|
||||
let nativeTab = tabTracker.getTab(tabId, default_);
|
||||
|
||||
if (tab) {
|
||||
return this.getWrapper(tab);
|
||||
if (nativeTab) {
|
||||
return this.getWrapper(nativeTab);
|
||||
}
|
||||
return default_;
|
||||
}
|
||||
|
||||
addActiveTabPermission(tab = tabTracker.activeTab) {
|
||||
return super.addActiveTabPermission(tab);
|
||||
addActiveTabPermission(nativeTab = tabTracker.activeTab) {
|
||||
return super.addActiveTabPermission(nativeTab);
|
||||
}
|
||||
|
||||
revokeActiveTabPermission(tab = tabTracker.activeTab) {
|
||||
return super.revokeActiveTabPermission(tab);
|
||||
revokeActiveTabPermission(nativeTab = tabTracker.activeTab) {
|
||||
return super.revokeActiveTabPermission(nativeTab);
|
||||
}
|
||||
|
||||
wrapTab(tab) {
|
||||
return new Tab(this.extension, tab, tab.id);
|
||||
wrapTab(nativeTab) {
|
||||
return new Tab(this.extension, nativeTab, nativeTab.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
@ -546,6 +546,14 @@ NS_INTERFACE_MAP_END
|
||||
* nsIPrefService Implementation
|
||||
*/
|
||||
|
||||
InfallibleTArray<Preferences::PrefSetting>* gInitPrefs;
|
||||
|
||||
/*static*/
|
||||
void
|
||||
Preferences::SetInitPreferences(nsTArray<PrefSetting>* aPrefs) {
|
||||
gInitPrefs = new InfallibleTArray<PrefSetting>(mozilla::Move(*aPrefs));
|
||||
}
|
||||
|
||||
nsresult
|
||||
Preferences::Init()
|
||||
{
|
||||
@ -557,15 +565,13 @@ Preferences::Init()
|
||||
rv = pref_InitInitialObjects();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
using mozilla::dom::ContentChild;
|
||||
if (XRE_IsContentProcess()) {
|
||||
InfallibleTArray<PrefSetting> prefs;
|
||||
ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
|
||||
|
||||
// Store the array
|
||||
for (uint32_t i = 0; i < prefs.Length(); ++i) {
|
||||
pref_SetPref(prefs[i]);
|
||||
MOZ_ASSERT(gInitPrefs);
|
||||
for (unsigned int i = 0; i < gInitPrefs->Length(); i++) {
|
||||
Preferences::SetPreference(gInitPrefs->ElementAt(i));
|
||||
}
|
||||
delete gInitPrefs;
|
||||
gInitPrefs = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -780,6 +786,14 @@ Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
Preferences::SetInitPhase(pref_initPhase phase)
|
||||
{
|
||||
pref_SetInitPhase(phase);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
|
||||
{
|
||||
|
@ -28,6 +28,20 @@ typedef void (*PrefChangedFunc)(const char *, void *);
|
||||
#define have_PrefChangedFunc_typedef
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
enum pref_initPhase {
|
||||
START,
|
||||
BEGIN_INIT_PREFS,
|
||||
END_INIT_PREFS,
|
||||
BEGIN_ALL_PREFS,
|
||||
END_ALL_PREFS
|
||||
};
|
||||
|
||||
#define SET_PREF_PHASE(p) Preferences::SetInitPhase(p)
|
||||
#else
|
||||
#define SET_PREF_PHASE(p) do { } while (0)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
@ -366,6 +380,12 @@ public:
|
||||
static void GetPreference(PrefSetting* aPref);
|
||||
static void SetPreference(const PrefSetting& aPref);
|
||||
|
||||
static void SetInitPreferences(nsTArray<PrefSetting>* aPrefs);
|
||||
|
||||
#ifdef DEBUG
|
||||
static void SetInitPhase(pref_initPhase phase);
|
||||
#endif
|
||||
|
||||
static int64_t SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf);
|
||||
|
||||
static void DirtyCallback();
|
||||
|
@ -4533,13 +4533,7 @@ pref("webgl.max-acceptable-fb-status-invals", 0);
|
||||
|
||||
pref("webgl.enable-webgl2", true);
|
||||
|
||||
#ifdef RELEASE_OR_BETA
|
||||
// Keep this disabled on Release and Beta for now. (see bug 1171228)
|
||||
pref("webgl.enable-debug-renderer-info", false);
|
||||
#else
|
||||
pref("webgl.enable-debug-renderer-info", true);
|
||||
#endif
|
||||
|
||||
pref("webgl.renderer-string-override", "");
|
||||
pref("webgl.vendor-string-override", "");
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "prprf.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/ContentPrefs.h"
|
||||
#include "nsQuickSort.h"
|
||||
#include "nsString.h"
|
||||
#include "nsPrintfCString.h"
|
||||
@ -736,13 +737,48 @@ static PrefTypeFlags pref_SetValue(PrefValue* existingValue, PrefTypeFlags flags
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
static pref_initPhase gPhase = START;
|
||||
|
||||
void
|
||||
pref_SetInitPhase(pref_initPhase phase)
|
||||
{
|
||||
gPhase = phase;
|
||||
}
|
||||
|
||||
struct StringComparator
|
||||
{
|
||||
const char* mKey;
|
||||
explicit StringComparator(const char* aKey) : mKey(aKey) {}
|
||||
int operator()(const char* string) const {
|
||||
return strcmp(mKey, string);
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
inInitArray(const char* key)
|
||||
{
|
||||
size_t prefsLen;
|
||||
size_t found;
|
||||
const char** list = mozilla::dom::ContentPrefs::GetContentPrefs(&prefsLen);
|
||||
return BinarySearchIf(list, 0, prefsLen,
|
||||
StringComparator(key), &found);
|
||||
}
|
||||
#endif
|
||||
|
||||
PrefHashEntry* pref_HashTableLookup(const char *key)
|
||||
{
|
||||
#ifndef MOZ_B2G
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT((!XRE_IsContentProcess() || gPhase != START),
|
||||
"pref access before commandline prefs set");
|
||||
/* If you're hitting this assertion, you've added a pref access to start up.
|
||||
* Consider moving it later or add it to the whitelist in ContentPrefs.cpp
|
||||
* and get review from a DOM peer
|
||||
*/
|
||||
MOZ_ASSERT((!XRE_IsContentProcess() || gPhase > END_INIT_PREFS || inInitArray(key)),
|
||||
"accessing non-init pref before the rest of the prefs are sent");
|
||||
return static_cast<PrefHashEntry*>(gHashTable->Search(key));
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "Preferences.h"
|
||||
|
||||
extern PLDHashTable* gHashTable;
|
||||
|
||||
@ -25,6 +26,11 @@ pref_savePrefs(PLDHashTable* aTable, uint32_t* aPrefCount);
|
||||
nsresult
|
||||
pref_SetPref(const mozilla::dom::PrefSetting& aPref);
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
pref_SetInitPhase(pref_initPhase phase);
|
||||
#endif
|
||||
|
||||
int pref_CompareStrings(const void *v1, const void *v2, void* unused);
|
||||
PrefHashEntry* pref_HashTableLookup(const char *key);
|
||||
|
||||
|
@ -40,13 +40,8 @@ namespace net {
|
||||
|
||||
/**
|
||||
* Class that provides an nsILoadInfo implementation.
|
||||
*
|
||||
* Note that there is no reason why this class should be MOZ_EXPORT, but
|
||||
* Thunderbird relies on some insane hacks which require this, so we'll leave it
|
||||
* as is for now, but hopefully we'll be able to remove the MOZ_EXPORT keyword
|
||||
* from this class at some point. See bug 1149127 for the discussion.
|
||||
*/
|
||||
class MOZ_EXPORT LoadInfo final : public nsILoadInfo
|
||||
class LoadInfo final : public nsILoadInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -273,12 +273,6 @@ interface nsIPermissionManager : nsISupports
|
||||
in boolean exactHost,
|
||||
in uint64_t sessionExpireTime,
|
||||
in uint64_t persistentExpireTime);
|
||||
|
||||
/**
|
||||
* Remove all current permission settings and get permission settings from
|
||||
* chrome process.
|
||||
*/
|
||||
void refreshPermission();
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
@ -0,0 +1 @@
|
||||
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1332564
|
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/../macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
|
||||
iconv -f UTF-8 -t UTF-16 > $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings
|
||||
$(NSINSTALL) -D $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS/updater-xpcshell
|
||||
$(NSINSTALL) updater-xpcshell $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS
|
||||
$(NSINSTALL) $(FINAL_TARGET)/updater-xpcshell $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS
|
||||
rm -Rf $(XPCSHELLTESTROOT)/data/updater.app
|
||||
mv $(XPCSHELLTESTROOT)/data/updater-xpcshell.app $(XPCSHELLTESTROOT)/data/updater.app
|
||||
mv $(XPCSHELLTESTROOT)/data/updater.app/Contents/MacOS/updater-xpcshell $(XPCSHELLTESTROOT)/data/updater.app/Contents/MacOS/org.mozilla.updater
|
||||
@ -35,7 +35,7 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
# Copy for mochitest chrome tests
|
||||
rsync -a -C $(XPCSHELLTESTROOT)/data/updater.app $(MOCHITESTROOT)/data/
|
||||
else
|
||||
cp $(PROGRAM) $(XPCSHELLTESTROOT)/data/updater$(BIN_SUFFIX)
|
||||
cp $(PROGRAM) $(MOCHITESTROOT)/data/updater$(BIN_SUFFIX)
|
||||
cp $(FINAL_TARGET)/updater-xpcshell$(BIN_SUFFIX) $(XPCSHELLTESTROOT)/data/updater$(BIN_SUFFIX)
|
||||
cp $(FINAL_TARGET)/updater-xpcshell$(BIN_SUFFIX) $(MOCHITESTROOT)/data/updater$(BIN_SUFFIX)
|
||||
endif
|
||||
endif # COMPILE_ENVIRONMENT
|
||||
|
@ -4,10 +4,11 @@
|
||||
# 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/.
|
||||
|
||||
FINAL_TARGET = '_tests/xpcshell/toolkit/mozapps/update/tests'
|
||||
|
||||
Program('updater-xpcshell')
|
||||
|
||||
updater_rel_path = '../'
|
||||
DIST_INSTALL = False
|
||||
DEFINES['TEST_UPDATER'] = True
|
||||
include('../updater-common.build')
|
||||
|
||||
|
@ -3501,10 +3501,25 @@ int NS_main(int argc, NS_tchar **argv)
|
||||
*d = NS_T('\0');
|
||||
++d;
|
||||
|
||||
const size_t callbackBackupPathBufSize =
|
||||
sizeof(gCallbackBackupPath)/sizeof(gCallbackBackupPath[0]);
|
||||
const int callbackBackupPathLen =
|
||||
NS_tsnprintf(gCallbackBackupPath, callbackBackupPathBufSize,
|
||||
NS_T("%s" CALLBACK_BACKUP_EXT), argv[callbackIndex]);
|
||||
|
||||
if (callbackBackupPathLen < 0 ||
|
||||
callbackBackupPathLen >= static_cast<int>(callbackBackupPathBufSize)) {
|
||||
LOG(("NS_main: callback backup path truncated"));
|
||||
LogFinish();
|
||||
WriteStatusFile(USAGE_ERROR);
|
||||
|
||||
// Don't attempt to launch the callback when the callback path is
|
||||
// longer than expected.
|
||||
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Make a copy of the callback executable so it can be read when patching.
|
||||
NS_tsnprintf(gCallbackBackupPath,
|
||||
sizeof(gCallbackBackupPath)/sizeof(gCallbackBackupPath[0]),
|
||||
NS_T("%s" CALLBACK_BACKUP_EXT), argv[callbackIndex]);
|
||||
NS_tremove(gCallbackBackupPath);
|
||||
if(!CopyFileW(argv[callbackIndex], gCallbackBackupPath, true)) {
|
||||
DWORD copyFileError = GetLastError();
|
||||
|
@ -625,49 +625,8 @@ XRE_InitChildProcess(int aArgc,
|
||||
process = new PluginProcessChild(parentPID);
|
||||
break;
|
||||
|
||||
case GeckoProcessType_Content: {
|
||||
process = new ContentProcess(parentPID);
|
||||
// If passed in grab the application path for xpcom init
|
||||
bool foundAppdir = false;
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
// If passed in grab the profile path for sandboxing
|
||||
bool foundProfile = false;
|
||||
#endif
|
||||
|
||||
for (int idx = aArgc; idx > 0; idx--) {
|
||||
if (aArgv[idx] && !strcmp(aArgv[idx], "-appdir")) {
|
||||
MOZ_ASSERT(!foundAppdir);
|
||||
if (foundAppdir) {
|
||||
continue;
|
||||
}
|
||||
nsCString appDir;
|
||||
appDir.Assign(nsDependentCString(aArgv[idx+1]));
|
||||
static_cast<ContentProcess*>(process.get())->SetAppDir(appDir);
|
||||
foundAppdir = true;
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
if (aArgv[idx] && !strcmp(aArgv[idx], "-profile")) {
|
||||
MOZ_ASSERT(!foundProfile);
|
||||
if (foundProfile) {
|
||||
continue;
|
||||
}
|
||||
nsCString profile;
|
||||
profile.Assign(nsDependentCString(aArgv[idx+1]));
|
||||
static_cast<ContentProcess*>(process.get())->SetProfile(profile);
|
||||
foundProfile = true;
|
||||
}
|
||||
if (foundProfile && foundAppdir) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if (foundAppdir) {
|
||||
break;
|
||||
}
|
||||
#endif /* XP_MACOSX && MOZ_CONTENT_SANDBOX */
|
||||
}
|
||||
}
|
||||
case GeckoProcessType_Content:
|
||||
process = new ContentProcess(parentPID);
|
||||
break;
|
||||
|
||||
case GeckoProcessType_IPDLUnitTest:
|
||||
@ -690,7 +649,7 @@ XRE_InitChildProcess(int aArgc,
|
||||
MOZ_CRASH("Unknown main thread class");
|
||||
}
|
||||
|
||||
if (!process->Init()) {
|
||||
if (!process->Init(aArgc, aArgv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
195
xpcom/ds/IncrementalTokenizer.cpp
Normal file
195
xpcom/ds/IncrementalTokenizer.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "mozilla/IncrementalTokenizer.h"
|
||||
|
||||
#include "mozilla/AutoRestore.h"
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
#include "IncrementalTokenizer.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
IncrementalTokenizer::IncrementalTokenizer(Consumer aConsumer,
|
||||
const char * aWhitespaces,
|
||||
const char * aAdditionalWordChars,
|
||||
uint32_t aRawMinBuffered)
|
||||
: TokenizerBase(aWhitespaces, aAdditionalWordChars)
|
||||
#ifdef DEBUG
|
||||
, mConsuming(false)
|
||||
#endif
|
||||
, mNeedMoreInput(false)
|
||||
, mRollback(false)
|
||||
, mInputCursor(0)
|
||||
, mConsumer(aConsumer)
|
||||
{
|
||||
mInputFinished = false;
|
||||
mMinRawDelivery = aRawMinBuffered;
|
||||
}
|
||||
|
||||
nsresult IncrementalTokenizer::FeedInput(const nsACString & aInput)
|
||||
{
|
||||
NS_ENSURE_TRUE(mConsumer, NS_ERROR_NOT_INITIALIZED);
|
||||
MOZ_ASSERT(!mInputFinished);
|
||||
|
||||
mInput.Cut(0, mInputCursor);
|
||||
mInputCursor = 0;
|
||||
|
||||
mInput.Append(aInput);
|
||||
|
||||
return Process();
|
||||
}
|
||||
|
||||
nsresult IncrementalTokenizer::FeedInput(nsIInputStream * aInput, uint32_t aCount)
|
||||
{
|
||||
NS_ENSURE_TRUE(mConsumer, NS_ERROR_NOT_INITIALIZED);
|
||||
MOZ_ASSERT(!mInputFinished);
|
||||
MOZ_ASSERT(!mConsuming);
|
||||
|
||||
mInput.Cut(0, mInputCursor);
|
||||
mInputCursor = 0;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
while (NS_SUCCEEDED(rv) && aCount) {
|
||||
nsCString::index_type remainder = mInput.Length();
|
||||
nsCString::index_type load =
|
||||
std::min<nsCString::index_type>(aCount, PR_UINT32_MAX - remainder);
|
||||
|
||||
if (!load) {
|
||||
// To keep the API simple, we fail if the input data buffer if filled.
|
||||
// It's highly unlikely there will ever be such amout of data cumulated
|
||||
// unless a logic fault in the consumer code.
|
||||
NS_ERROR("IncrementalTokenizer consumer not reading data?");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (!mInput.SetLength(remainder + load, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsCString::char_iterator buffer = mInput.BeginWriting() + remainder;
|
||||
|
||||
uint32_t read;
|
||||
rv = aInput->Read(buffer, load, &read);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// remainder + load fits the uint32_t size, so must remainder + read.
|
||||
mInput.SetLength(remainder + read);
|
||||
aCount -= read;
|
||||
|
||||
rv = Process();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult IncrementalTokenizer::FinishInput()
|
||||
{
|
||||
NS_ENSURE_TRUE(mConsumer, NS_ERROR_NOT_INITIALIZED);
|
||||
MOZ_ASSERT(!mInputFinished);
|
||||
MOZ_ASSERT(!mConsuming);
|
||||
|
||||
mInput.Cut(0, mInputCursor);
|
||||
mInputCursor = 0;
|
||||
|
||||
mInputFinished = true;
|
||||
nsresult rv = Process();
|
||||
mConsumer = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool IncrementalTokenizer::Next(Token & aToken)
|
||||
{
|
||||
// Assert we are called only from the consumer callback
|
||||
MOZ_ASSERT(mConsuming);
|
||||
|
||||
if (mPastEof) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsACString::const_char_iterator next = Parse(aToken);
|
||||
mPastEof = aToken.Type() == TOKEN_EOF;
|
||||
if (next == mCursor && !mPastEof) {
|
||||
// Not enough input to make a deterministic decision.
|
||||
return false;
|
||||
}
|
||||
|
||||
AssignFragment(aToken, mCursor, next);
|
||||
mCursor = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IncrementalTokenizer::NeedMoreInput()
|
||||
{
|
||||
// Assert we are called only from the consumer callback
|
||||
MOZ_ASSERT(mConsuming);
|
||||
|
||||
// When the input has been finished, we can't set the flag to prevent
|
||||
// indefinite wait for more input (that will never come)
|
||||
mNeedMoreInput = !mInputFinished;
|
||||
}
|
||||
|
||||
void IncrementalTokenizer::Rollback()
|
||||
{
|
||||
// Assert we are called only from the consumer callback
|
||||
MOZ_ASSERT(mConsuming);
|
||||
|
||||
mRollback = true;
|
||||
}
|
||||
|
||||
nsresult IncrementalTokenizer::Process()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// Assert we are not re-entered
|
||||
MOZ_ASSERT(!mConsuming);
|
||||
|
||||
AutoRestore<bool> consuming(mConsuming);
|
||||
mConsuming = true;
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(!mPastEof);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
mInput.BeginReading(mCursor);
|
||||
mCursor += mInputCursor;
|
||||
mInput.EndReading(mEnd);
|
||||
|
||||
while (NS_SUCCEEDED(rv) && !mPastEof) {
|
||||
Token token;
|
||||
nsACString::const_char_iterator next = Parse(token);
|
||||
mPastEof = token.Type() == TOKEN_EOF;
|
||||
if (next == mCursor && !mPastEof) {
|
||||
// Not enough input to make a deterministic decision.
|
||||
break;
|
||||
}
|
||||
|
||||
AssignFragment(token, mCursor, next);
|
||||
|
||||
nsACString::const_char_iterator rollback = mCursor;
|
||||
mCursor = next;
|
||||
|
||||
mNeedMoreInput = mRollback = false;
|
||||
|
||||
rv = mConsumer(token, *this);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
if (mNeedMoreInput || mRollback) {
|
||||
mCursor = rollback;
|
||||
mPastEof = false;
|
||||
if (mNeedMoreInput) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mInputCursor = mCursor - mInput.BeginReading();
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // mozilla
|
122
xpcom/ds/IncrementalTokenizer.h
Normal file
122
xpcom/ds/IncrementalTokenizer.h
Normal file
@ -0,0 +1,122 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 INCREMENTAL_TOKENIZER_H__
|
||||
#define INCREMENTAL_TOKENIZER_H__
|
||||
|
||||
#include "mozilla/Tokenizer.h"
|
||||
|
||||
#include "nsError.h"
|
||||
#include <functional>
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class IncrementalTokenizer : public TokenizerBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The consumer callback. The function is called for every single token
|
||||
* as found in the input. Failure result returned by this callback stops
|
||||
* the tokenization immediately and bubbles to result of Feed/FinishInput.
|
||||
*
|
||||
* Fragment()s of consumed tokens are ensured to remain valid until next call to
|
||||
* Feed/FinishInput and are pointing to a single linear buffer. Hence, those can
|
||||
* be safely used to accumulate the data for processing after Feed/FinishInput
|
||||
* returned.
|
||||
*/
|
||||
typedef std::function<nsresult(Token const&, IncrementalTokenizer& i)> Consumer;
|
||||
|
||||
/**
|
||||
* For aWhitespaces and aAdditionalWordChars arguments see TokenizerBase.
|
||||
*
|
||||
* @param aConsumer
|
||||
* A mandatory non-null argument, a function that consumes the tokens as they
|
||||
* come when the tokenizer is fed.
|
||||
* @param aRawMinBuffered
|
||||
* When we have buffered at least aRawMinBuffered data, but there was no custom
|
||||
* token found so far because of too small incremental feed chunks, deliver
|
||||
* the raw data to preserve streaming and to save memory. This only has effect
|
||||
* in OnlyCustomTokenizing mode.
|
||||
*/
|
||||
explicit IncrementalTokenizer(Consumer aConsumer,
|
||||
const char* aWhitespaces = nullptr,
|
||||
const char* aAdditionalWordChars = nullptr,
|
||||
uint32_t aRawMinBuffered = 1024);
|
||||
|
||||
/**
|
||||
* Pushes the input to be tokenized. These directly call the Consumer callback
|
||||
* on every found token. Result of the Consumer callback is returned here.
|
||||
*
|
||||
* The tokenizer must be initialized with a valid consumer prior call to these
|
||||
* methods. It's not allowed to call Feed/FinishInput from inside the Consumer
|
||||
* callback.
|
||||
*/
|
||||
nsresult FeedInput(const nsACString& aInput);
|
||||
nsresult FeedInput(nsIInputStream* aInput, uint32_t aCount);
|
||||
nsresult FinishInput();
|
||||
|
||||
/**
|
||||
* Can only be called from inside the consumer callback.
|
||||
*
|
||||
* When there is still anything to read from the input, tokenize it, store
|
||||
* the token type and value to aToken result and shift the cursor past this
|
||||
* just parsed token. Each call to Next() reads another token from
|
||||
* the input and shifts the cursor.
|
||||
*
|
||||
* Returns false if there is not enough data to deterministically recognize
|
||||
* tokens or when the last returned token was EOF.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool Next(Token& aToken);
|
||||
|
||||
/**
|
||||
* Can only be called from inside the consumer callback.
|
||||
*
|
||||
* Tells the tokenizer to revert the cursor and stop the async parsing until
|
||||
* next feed of the input. This is useful when more than one token is needed
|
||||
* to decide on the syntax but there is not enough input to get a next token
|
||||
* (Next() returned false.)
|
||||
*/
|
||||
void NeedMoreInput();
|
||||
|
||||
/**
|
||||
* Can only be called from inside the consumer callback.
|
||||
*
|
||||
* This makes the consumer callback be called again while parsing
|
||||
* the input at the previous cursor position again. This is useful when
|
||||
* the tokenizer state (custom tokens, tokenization mode) has changed and
|
||||
* we want to re-parse the input again.
|
||||
*/
|
||||
void Rollback();
|
||||
|
||||
private:
|
||||
// Loops over the input with TokenizerBase::Parse and calls the Consumer callback.
|
||||
nsresult Process();
|
||||
|
||||
#ifdef DEBUG
|
||||
// True when inside the consumer callback, used only for assertions.
|
||||
bool mConsuming;
|
||||
#endif // DEBUG
|
||||
// Modifyable only from the Consumer callback, tells the parser to break, rollback
|
||||
// and wait for more input.
|
||||
bool mNeedMoreInput;
|
||||
// Modifyable only from the Consumer callback, tells the parser to rollback and
|
||||
// parse the input again, with (if modified) new settings of the tokenizer.
|
||||
bool mRollback;
|
||||
// The input buffer. Updated with each call to Feed/FinishInput.
|
||||
nsCString mInput;
|
||||
// Numerical index pointing at the current cursor position. We don't keep direct
|
||||
// reference to the string buffer since the buffer gets often reallocated.
|
||||
nsCString::index_type mInputCursor;
|
||||
// Refernce to the consumer function.
|
||||
Consumer mConsumer;
|
||||
};
|
||||
|
||||
} // mozilla
|
||||
|
||||
#endif
|
@ -7,6 +7,7 @@
|
||||
#include "Tokenizer.h"
|
||||
|
||||
#include "nsUnicharUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -15,11 +16,9 @@ static const char sWhitespaces[] = " \t";
|
||||
Tokenizer::Tokenizer(const nsACString& aSource,
|
||||
const char* aWhitespaces,
|
||||
const char* aAdditionalWordChars)
|
||||
: mPastEof(false)
|
||||
, mHasFailed(false)
|
||||
, mWhitespaces(aWhitespaces ? aWhitespaces : sWhitespaces)
|
||||
, mAdditionalWordChars(aAdditionalWordChars)
|
||||
: TokenizerBase(aWhitespaces, aAdditionalWordChars)
|
||||
{
|
||||
mInputFinished = true;
|
||||
aSource.BeginReading(mCursor);
|
||||
mRecord = mRollback = mCursor;
|
||||
aSource.EndReading(mEnd);
|
||||
@ -43,7 +42,7 @@ Tokenizer::Next(Token& aToken)
|
||||
mRollback = mCursor;
|
||||
mCursor = Parse(aToken);
|
||||
|
||||
aToken.AssignFragment(mRollback, mCursor);
|
||||
AssignFragment(aToken, mRollback, mCursor);
|
||||
|
||||
mPastEof = aToken.Type() == TOKEN_EOF;
|
||||
mHasFailed = false;
|
||||
@ -67,7 +66,7 @@ Tokenizer::Check(const TokenType aTokenType, Token& aResult)
|
||||
mRollback = mCursor;
|
||||
mCursor = next;
|
||||
|
||||
aResult.AssignFragment(mRollback, mCursor);
|
||||
AssignFragment(aResult, mRollback, mCursor);
|
||||
|
||||
mPastEof = aResult.Type() == TOKEN_EOF;
|
||||
mHasFailed = false;
|
||||
@ -96,12 +95,6 @@ Tokenizer::Check(const Token& aToken)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::HasFailed() const
|
||||
{
|
||||
return mHasFailed;
|
||||
}
|
||||
|
||||
void
|
||||
Tokenizer::SkipWhites(WhiteSkipping aIncludeNewLines)
|
||||
{
|
||||
@ -275,24 +268,156 @@ Tokenizer::Claim(nsDependentCSubstring& aResult, ClaimInclusion aInclusion)
|
||||
aResult.Rebind(mRecord, close - mRecord);
|
||||
}
|
||||
|
||||
// protected
|
||||
// TokenizerBase
|
||||
|
||||
TokenizerBase::TokenizerBase(const char* aWhitespaces,
|
||||
const char* aAdditionalWordChars)
|
||||
: mPastEof(false)
|
||||
, mHasFailed(false)
|
||||
, mInputFinished(true)
|
||||
, mMode(Mode::FULL)
|
||||
, mMinRawDelivery(1024)
|
||||
, mWhitespaces(aWhitespaces ? aWhitespaces : sWhitespaces)
|
||||
, mAdditionalWordChars(aAdditionalWordChars)
|
||||
, mCursor(nullptr)
|
||||
, mEnd(nullptr)
|
||||
, mNextCustomTokenID(TOKEN_CUSTOM0)
|
||||
{
|
||||
}
|
||||
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::AddCustomToken(const nsACString & aValue,
|
||||
ECaseSensitivity aCaseInsensitivity, bool aEnabled)
|
||||
{
|
||||
MOZ_ASSERT(!aValue.IsEmpty());
|
||||
|
||||
UniquePtr<Token>& t = *mCustomTokens.AppendElement();
|
||||
t = MakeUnique<Token>();
|
||||
|
||||
t->mType = static_cast<TokenType>(++mNextCustomTokenID);
|
||||
t->mCustomCaseInsensitivity = aCaseInsensitivity;
|
||||
t->mCustomEnabled = aEnabled;
|
||||
t->mCustom.Assign(aValue);
|
||||
return *t;
|
||||
}
|
||||
|
||||
void
|
||||
TokenizerBase::RemoveCustomToken(Token& aToken)
|
||||
{
|
||||
if (aToken.mType == TOKEN_UNKNOWN) {
|
||||
// Already removed
|
||||
return;
|
||||
}
|
||||
|
||||
for (UniquePtr<Token> const& custom : mCustomTokens) {
|
||||
if (custom->mType == aToken.mType) {
|
||||
mCustomTokens.RemoveElement(custom);
|
||||
aToken.mType = TOKEN_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Token to remove not found");
|
||||
}
|
||||
|
||||
void
|
||||
TokenizerBase::EnableCustomToken(Token const& aToken, bool aEnabled)
|
||||
{
|
||||
if (aToken.mType == TOKEN_UNKNOWN) {
|
||||
// Already removed
|
||||
return;
|
||||
}
|
||||
|
||||
for (UniquePtr<Token> const& custom : mCustomTokens) {
|
||||
if (custom->Type() == aToken.Type()) {
|
||||
// This effectively destroys the token instance.
|
||||
custom->mCustomEnabled = aEnabled;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Token to change not found");
|
||||
}
|
||||
|
||||
void
|
||||
TokenizerBase::SetTokenizingMode(Mode aMode)
|
||||
{
|
||||
mMode = aMode;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::HasInput() const
|
||||
TokenizerBase::HasFailed() const
|
||||
{
|
||||
return mHasFailed;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::HasInput() const
|
||||
{
|
||||
return !mPastEof;
|
||||
}
|
||||
|
||||
nsACString::const_char_iterator
|
||||
Tokenizer::Parse(Token& aToken) const
|
||||
TokenizerBase::Parse(Token& aToken) const
|
||||
{
|
||||
if (mCursor == mEnd) {
|
||||
if (!mInputFinished) {
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
aToken = Token::EndOfFile();
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
nsACString::size_type available = mEnd - mCursor;
|
||||
|
||||
uint32_t longestCustom = 0;
|
||||
for (UniquePtr<Token> const& custom : mCustomTokens) {
|
||||
if (IsCustom(mCursor, *custom, &longestCustom)) {
|
||||
aToken = *custom;
|
||||
return mCursor + custom->mCustom.Length();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mInputFinished && available < longestCustom) {
|
||||
// Not enough data to deterministically decide.
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
nsACString::const_char_iterator next = mCursor;
|
||||
|
||||
if (mMode == Mode::CUSTOM_ONLY) {
|
||||
// We have to do a brute-force search for all of the enabled custom
|
||||
// tokens.
|
||||
while (next < mEnd) {
|
||||
++next;
|
||||
for (UniquePtr<Token> const& custom : mCustomTokens) {
|
||||
if (IsCustom(next, *custom)) {
|
||||
aToken = Token::Raw();
|
||||
return next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mInputFinished) {
|
||||
// End of the data reached.
|
||||
aToken = Token::Raw();
|
||||
return next;
|
||||
}
|
||||
|
||||
if (longestCustom < available && available > mMinRawDelivery) {
|
||||
// We can return some data w/o waiting for either a custom token
|
||||
// or call to FinishData() when we leave the tail where all the
|
||||
// custom tokens potentially fit, so we can't lose only partially
|
||||
// delivered tokens. This preserves reasonable granularity.
|
||||
aToken = Token::Raw();
|
||||
return mEnd - longestCustom + 1;
|
||||
}
|
||||
|
||||
// Not enough data to deterministically decide.
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
enum State {
|
||||
PARSE_INTEGER,
|
||||
PARSE_WORD,
|
||||
@ -326,6 +451,9 @@ Tokenizer::Parse(Token& aToken) const
|
||||
resultingNumber += static_cast<uint64_t>(*next - '0');
|
||||
|
||||
++next;
|
||||
if (IsPending(next)) {
|
||||
break;
|
||||
}
|
||||
if (IsEnd(next) || !IsNumber(*next)) {
|
||||
if (!resultingNumber.isValid()) {
|
||||
aToken = Token::Error();
|
||||
@ -338,6 +466,9 @@ Tokenizer::Parse(Token& aToken) const
|
||||
|
||||
case PARSE_WORD:
|
||||
++next;
|
||||
if (IsPending(next)) {
|
||||
break;
|
||||
}
|
||||
if (IsEnd(next) || !IsWord(*next)) {
|
||||
aToken = Token::Word(Substring(mCursor, next));
|
||||
return next;
|
||||
@ -346,6 +477,9 @@ Tokenizer::Parse(Token& aToken) const
|
||||
|
||||
case PARSE_CRLF:
|
||||
++next;
|
||||
if (IsPending(next)) {
|
||||
break;
|
||||
}
|
||||
if (!IsEnd(next) && *next == '\n') { // LF is optional
|
||||
++next;
|
||||
}
|
||||
@ -369,17 +503,24 @@ Tokenizer::Parse(Token& aToken) const
|
||||
} // switch (state)
|
||||
} // while (next < end)
|
||||
|
||||
return next;
|
||||
MOZ_ASSERT(!mInputFinished);
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::IsEnd(const nsACString::const_char_iterator& caret) const
|
||||
TokenizerBase::IsEnd(const nsACString::const_char_iterator& caret) const
|
||||
{
|
||||
return caret == mEnd;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::IsWordFirst(const char aInput) const
|
||||
TokenizerBase::IsPending(const nsACString::const_char_iterator& caret) const
|
||||
{
|
||||
return IsEnd(caret) && !mInputFinished;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::IsWordFirst(const char aInput) const
|
||||
{
|
||||
// TODO: make this fully work with unicode
|
||||
return (ToLowerCase(static_cast<uint32_t>(aInput)) !=
|
||||
@ -389,50 +530,107 @@ Tokenizer::IsWordFirst(const char aInput) const
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::IsWord(const char aInput) const
|
||||
TokenizerBase::IsWord(const char aInput) const
|
||||
{
|
||||
return IsWordFirst(aInput) || IsNumber(aInput);
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::IsNumber(const char aInput) const
|
||||
TokenizerBase::IsNumber(const char aInput) const
|
||||
{
|
||||
// TODO: are there unicode numbers?
|
||||
return aInput >= '0' && aInput <= '9';
|
||||
}
|
||||
|
||||
// Tokenizer::Token
|
||||
bool
|
||||
TokenizerBase::IsCustom(const nsACString::const_char_iterator & caret,
|
||||
const Token & aCustomToken,
|
||||
uint32_t * aLongest) const
|
||||
{
|
||||
MOZ_ASSERT(aCustomToken.mType > TOKEN_CUSTOM0);
|
||||
if (!aCustomToken.mCustomEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Tokenizer::Token::Token(const Token& aOther)
|
||||
if (aLongest) {
|
||||
*aLongest = std::max(*aLongest, aCustomToken.mCustom.Length());
|
||||
}
|
||||
|
||||
uint32_t inputLength = mEnd - caret;
|
||||
if (aCustomToken.mCustom.Length() > inputLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDependentCSubstring inputFragment(caret, aCustomToken.mCustom.Length());
|
||||
if (aCustomToken.mCustomCaseInsensitivity == CASE_INSENSITIVE) {
|
||||
return inputFragment.Equals(aCustomToken.mCustom, nsCaseInsensitiveUTF8StringComparator());
|
||||
}
|
||||
return inputFragment.Equals(aCustomToken.mCustom);
|
||||
}
|
||||
|
||||
void TokenizerBase::AssignFragment(Token& aToken,
|
||||
nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end)
|
||||
{
|
||||
aToken.AssignFragment(begin, end);
|
||||
}
|
||||
|
||||
// TokenizerBase::Token
|
||||
|
||||
TokenizerBase::Token::Token()
|
||||
: mType(TOKEN_UNKNOWN)
|
||||
, mChar(0)
|
||||
, mInteger(0)
|
||||
, mCustomCaseInsensitivity(CASE_SENSITIVE)
|
||||
, mCustomEnabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
TokenizerBase::Token::Token(const Token& aOther)
|
||||
: mType(aOther.mType)
|
||||
, mCustom(aOther.mCustom)
|
||||
, mChar(aOther.mChar)
|
||||
, mInteger(aOther.mInteger)
|
||||
, mCustomCaseInsensitivity(aOther.mCustomCaseInsensitivity)
|
||||
, mCustomEnabled(aOther.mCustomEnabled)
|
||||
{
|
||||
if (mType == TOKEN_WORD) {
|
||||
if (mType == TOKEN_WORD || mType > TOKEN_CUSTOM0) {
|
||||
mWord.Rebind(aOther.mWord.BeginReading(), aOther.mWord.Length());
|
||||
}
|
||||
}
|
||||
|
||||
Tokenizer::Token&
|
||||
Tokenizer::Token::operator=(const Token& aOther)
|
||||
TokenizerBase::Token&
|
||||
TokenizerBase::Token::operator=(const Token& aOther)
|
||||
{
|
||||
mType = aOther.mType;
|
||||
mCustom = aOther.mCustom;
|
||||
mChar = aOther.mChar;
|
||||
mWord.Rebind(aOther.mWord.BeginReading(), aOther.mWord.Length());
|
||||
mInteger = aOther.mInteger;
|
||||
mCustomCaseInsensitivity = aOther.mCustomCaseInsensitivity;
|
||||
mCustomEnabled = aOther.mCustomEnabled;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
Tokenizer::Token::AssignFragment(nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end)
|
||||
TokenizerBase::Token::AssignFragment(nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end)
|
||||
{
|
||||
mFragment.Rebind(begin, end - begin);
|
||||
}
|
||||
|
||||
// static
|
||||
Tokenizer::Token
|
||||
Tokenizer::Token::Word(const nsACString& aValue)
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Raw()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_RAW;
|
||||
return t;
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Word(const nsACString& aValue)
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_WORD;
|
||||
@ -441,8 +639,8 @@ Tokenizer::Token::Word(const nsACString& aValue)
|
||||
}
|
||||
|
||||
// static
|
||||
Tokenizer::Token
|
||||
Tokenizer::Token::Char(const char aValue)
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Char(const char aValue)
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_CHAR;
|
||||
@ -451,8 +649,8 @@ Tokenizer::Token::Char(const char aValue)
|
||||
}
|
||||
|
||||
// static
|
||||
Tokenizer::Token
|
||||
Tokenizer::Token::Number(const uint64_t aValue)
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Number(const uint64_t aValue)
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_INTEGER;
|
||||
@ -461,8 +659,8 @@ Tokenizer::Token::Number(const uint64_t aValue)
|
||||
}
|
||||
|
||||
// static
|
||||
Tokenizer::Token
|
||||
Tokenizer::Token::Whitespace()
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Whitespace()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_WS;
|
||||
@ -471,8 +669,8 @@ Tokenizer::Token::Whitespace()
|
||||
}
|
||||
|
||||
// static
|
||||
Tokenizer::Token
|
||||
Tokenizer::Token::NewLine()
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::NewLine()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_EOL;
|
||||
@ -480,8 +678,8 @@ Tokenizer::Token::NewLine()
|
||||
}
|
||||
|
||||
// static
|
||||
Tokenizer::Token
|
||||
Tokenizer::Token::EndOfFile()
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::EndOfFile()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_EOF;
|
||||
@ -489,8 +687,8 @@ Tokenizer::Token::EndOfFile()
|
||||
}
|
||||
|
||||
// static
|
||||
Tokenizer::Token
|
||||
Tokenizer::Token::Error()
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Error()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_ERROR;
|
||||
@ -498,7 +696,7 @@ Tokenizer::Token::Error()
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::Token::Equals(const Token& aOther) const
|
||||
TokenizerBase::Token::Equals(const Token& aOther) const
|
||||
{
|
||||
if (mType != aOther.mType) {
|
||||
return false;
|
||||
@ -517,21 +715,21 @@ Tokenizer::Token::Equals(const Token& aOther) const
|
||||
}
|
||||
|
||||
char
|
||||
Tokenizer::Token::AsChar() const
|
||||
TokenizerBase::Token::AsChar() const
|
||||
{
|
||||
MOZ_ASSERT(mType == TOKEN_CHAR || mType == TOKEN_WS);
|
||||
return mChar;
|
||||
}
|
||||
|
||||
nsDependentCSubstring
|
||||
Tokenizer::Token::AsString() const
|
||||
TokenizerBase::Token::AsString() const
|
||||
{
|
||||
MOZ_ASSERT(mType == TOKEN_WORD);
|
||||
return mWord;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Tokenizer::Token::AsInteger() const
|
||||
TokenizerBase::Token::AsInteger() const
|
||||
{
|
||||
MOZ_ASSERT(mType == TOKEN_INTEGER);
|
||||
return mInteger;
|
||||
|
@ -9,32 +9,36 @@
|
||||
|
||||
#include "nsString.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* This is a simple implementation of a lexical analyzer or maybe better
|
||||
* called a tokenizer. It doesn't allow any user dictionaries or
|
||||
* user define token types.
|
||||
*
|
||||
* It is limited only to ASCII input for now. UTF-8 or any other input
|
||||
* encoding must yet be implemented.
|
||||
*/
|
||||
class Tokenizer {
|
||||
class TokenizerBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The analyzer works with elements in the input cut to a sequence of token
|
||||
* where each token has an elementary type
|
||||
*/
|
||||
enum TokenType {
|
||||
enum TokenType : uint32_t
|
||||
{
|
||||
TOKEN_UNKNOWN,
|
||||
TOKEN_RAW,
|
||||
TOKEN_ERROR,
|
||||
TOKEN_INTEGER,
|
||||
TOKEN_WORD,
|
||||
TOKEN_CHAR,
|
||||
TOKEN_WS,
|
||||
TOKEN_EOL,
|
||||
TOKEN_EOF
|
||||
TOKEN_EOF,
|
||||
TOKEN_CUSTOM0 = 1000
|
||||
};
|
||||
|
||||
enum ECaseSensitivity
|
||||
{
|
||||
CASE_SENSITIVE,
|
||||
CASE_INSENSITIVE
|
||||
};
|
||||
|
||||
/**
|
||||
@ -42,23 +46,29 @@ public:
|
||||
* to allow checks against it via methods of Tokenizer or are results of some of
|
||||
* the Tokenizer's methods.
|
||||
*/
|
||||
class Token {
|
||||
class Token
|
||||
{
|
||||
TokenType mType;
|
||||
nsDependentCSubstring mWord;
|
||||
nsCString mCustom;
|
||||
char mChar;
|
||||
uint64_t mInteger;
|
||||
ECaseSensitivity mCustomCaseInsensitivity;
|
||||
bool mCustomEnabled;
|
||||
|
||||
// If this token is a result of the parsing process, this member is referencing
|
||||
// a sub-string in the input buffer. If this is externally created Token this
|
||||
// member is left an empty string.
|
||||
nsDependentCSubstring mFragment;
|
||||
|
||||
friend class Tokenizer;
|
||||
friend class TokenizerBase;
|
||||
void AssignFragment(nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end);
|
||||
|
||||
static Token Raw();
|
||||
|
||||
public:
|
||||
Token() : mType(TOKEN_UNKNOWN), mChar(0), mInteger(0) {}
|
||||
Token();
|
||||
Token(const Token& aOther);
|
||||
Token& operator=(const Token& aOther);
|
||||
|
||||
@ -83,6 +93,120 @@ public:
|
||||
nsDependentCSubstring Fragment() const { return mFragment; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Consumers may register a custom string that, when found in the input, is considered
|
||||
* a token and returned by Next*() and accepted by Check*() methods.
|
||||
* AddCustomToken() returns a reference to a token that can then be comapred using
|
||||
* Token::Equals() againts the output from Next*() or be passed to Check*().
|
||||
*/
|
||||
Token AddCustomToken(const nsACString& aValue, ECaseSensitivity aCaseInsensitivity, bool aEnabled = true);
|
||||
template <uint32_t N>
|
||||
Token AddCustomToken(const char(&aValue)[N], ECaseSensitivity aCaseInsensitivity, bool aEnabled = true)
|
||||
{
|
||||
return AddCustomToken(nsDependentCSubstring(aValue, N - 1), aCaseInsensitivity, aEnabled);
|
||||
}
|
||||
void RemoveCustomToken(Token& aToken);
|
||||
/**
|
||||
* Only applies to a custom type of a Token (see AddCustomToken above.)
|
||||
* This turns on and off token recognition. When a custom token is disabled,
|
||||
* it's ignored as never added as a custom token.
|
||||
*/
|
||||
void EnableCustomToken(Token const& aToken, bool aEnable);
|
||||
|
||||
/**
|
||||
* Mode of tokenization.
|
||||
* FULL tokenization, the default, recognizes built-in tokens and any custom tokens,
|
||||
* if added.
|
||||
* CUSTOM_ONLY will only recognize custom tokens, the rest is seen as 'raw'.
|
||||
* This mode can be understood as a 'binary' mode.
|
||||
*/
|
||||
enum class Mode
|
||||
{
|
||||
FULL,
|
||||
CUSTOM_ONLY
|
||||
};
|
||||
void SetTokenizingMode(Mode aMode);
|
||||
|
||||
/**
|
||||
* Return false iff the last Check*() call has returned false or when we've read past
|
||||
* the end of the input string.
|
||||
*/
|
||||
MOZ_MUST_USE bool HasFailed() const;
|
||||
|
||||
protected:
|
||||
explicit TokenizerBase(const char* aWhitespaces = nullptr,
|
||||
const char* aAdditionalWordChars = nullptr);
|
||||
|
||||
// false if we have already read the EOF token.
|
||||
bool HasInput() const;
|
||||
// Main parsing function, it doesn't shift the read cursor, just returns the next
|
||||
// token position.
|
||||
nsACString::const_char_iterator Parse(Token& aToken) const;
|
||||
// Is read cursor at the end?
|
||||
bool IsEnd(const nsACString::const_char_iterator& caret) const;
|
||||
// True, when we are at the end of the input data, but it has not been marked
|
||||
// as complete yet. In that case we cannot proceed with providing a multi-char token.
|
||||
bool IsPending(const nsACString::const_char_iterator & caret) const;
|
||||
// Is read cursor on a character that is a word start?
|
||||
bool IsWordFirst(const char aInput) const;
|
||||
// Is read cursor on a character that is an in-word letter?
|
||||
bool IsWord(const char aInput) const;
|
||||
// Is read cursor on a character that is a valid number?
|
||||
// TODO - support multiple radix
|
||||
bool IsNumber(const char aInput) const;
|
||||
// Is equal to the given custom token?
|
||||
bool IsCustom(const nsACString::const_char_iterator& caret,
|
||||
const Token& aCustomToken, uint32_t* aLongest = nullptr) const;
|
||||
|
||||
// Friendly helper to assign a fragment on a Token
|
||||
static void AssignFragment(Token& aToken,
|
||||
nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end);
|
||||
|
||||
// true iff we have already read the EOF token
|
||||
bool mPastEof;
|
||||
// true iff the last Check*() call has returned false, reverts to true on Rollback() call
|
||||
bool mHasFailed;
|
||||
// true if the input string is final (finished), false when we expect more data
|
||||
// yet to be fed to the tokenizer (see IncrementalTokenizer derived class).
|
||||
bool mInputFinished;
|
||||
// custom only vs full tokenizing mode, see the Parse() method
|
||||
Mode mMode;
|
||||
// minimal raw data chunked delivery during incremental feed
|
||||
uint32_t mMinRawDelivery;
|
||||
|
||||
// Customizable list of whitespaces
|
||||
const char* mWhitespaces;
|
||||
// Additinal custom word characters
|
||||
const char* mAdditionalWordChars;
|
||||
|
||||
// All these point to the original buffer passed to the constructor or to the incremental
|
||||
// buffer after FeedInput.
|
||||
nsACString::const_char_iterator mCursor; // Position of the current (actually next to read) token start
|
||||
nsACString::const_char_iterator mEnd; // End of the input position
|
||||
|
||||
// This is the list of tokens user has registered with AddCustomToken()
|
||||
nsTArray<UniquePtr<Token>> mCustomTokens;
|
||||
uint32_t mNextCustomTokenID;
|
||||
|
||||
private:
|
||||
TokenizerBase() = delete;
|
||||
TokenizerBase(const TokenizerBase&) = delete;
|
||||
TokenizerBase(TokenizerBase&&) = delete;
|
||||
TokenizerBase(const TokenizerBase&&) = delete;
|
||||
TokenizerBase &operator=(const TokenizerBase&) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a simple implementation of a lexical analyzer or maybe better
|
||||
* called a tokenizer. It doesn't allow any user dictionaries or
|
||||
* user define token types.
|
||||
*
|
||||
* It is limited only to ASCII input for now. UTF-8 or any other input
|
||||
* encoding must yet be implemented.
|
||||
*/
|
||||
class Tokenizer : public TokenizerBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param aSource
|
||||
@ -133,13 +257,6 @@ public:
|
||||
MOZ_MUST_USE
|
||||
bool Check(const Token& aToken);
|
||||
|
||||
/**
|
||||
* Return false iff the last Check*() call has returned false or when we've read past
|
||||
* the end of the input string.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool HasFailed() const;
|
||||
|
||||
/**
|
||||
* SkipWhites method (below) may also skip new line characters automatically.
|
||||
*/
|
||||
@ -312,36 +429,9 @@ public:
|
||||
ClaimInclusion aInclude = EXCLUDE_LAST);
|
||||
|
||||
protected:
|
||||
// false if we have already read the EOF token.
|
||||
bool HasInput() const;
|
||||
// Main parsing function, it doesn't shift the read cursor, just returns the next
|
||||
// token position.
|
||||
nsACString::const_char_iterator Parse(Token& aToken) const;
|
||||
// Is read cursor at the end?
|
||||
bool IsEnd(const nsACString::const_char_iterator& caret) const;
|
||||
// Is read cursor on a character that is a word start?
|
||||
bool IsWordFirst(const char aInput) const;
|
||||
// Is read cursor on a character that is an in-word letter?
|
||||
bool IsWord(const char aInput) const;
|
||||
// Is read cursor on a character that is a valid number?
|
||||
// TODO - support multiple radix
|
||||
bool IsNumber(const char aInput) const;
|
||||
|
||||
// true iff we have already read the EOF token
|
||||
bool mPastEof;
|
||||
// true iff the last Check*() call has returned false, reverts to true on Rollback() call
|
||||
bool mHasFailed;
|
||||
|
||||
// Customizable list of whitespaces
|
||||
const char* mWhitespaces;
|
||||
// Additinal custom word characters
|
||||
const char* mAdditionalWordChars;
|
||||
|
||||
// All these point to the original buffer passed to the Tokenizer
|
||||
// All these point to the original buffer passed to the Tokenizer's constructor
|
||||
nsACString::const_char_iterator mRecord; // Position where the recorded sub-string for Claim() is
|
||||
nsACString::const_char_iterator mRollback; // Position of the previous token start
|
||||
nsACString::const_char_iterator mCursor; // Position of the current (actually next to read) token start
|
||||
nsACString::const_char_iterator mEnd; // End of the input position
|
||||
|
||||
private:
|
||||
Tokenizer() = delete;
|
||||
|
@ -83,12 +83,14 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'IncrementalTokenizer.h',
|
||||
'Observer.h',
|
||||
'StickyTimeDuration.h',
|
||||
'Tokenizer.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'IncrementalTokenizer.cpp',
|
||||
'nsArray.cpp',
|
||||
'nsArrayEnumerator.cpp',
|
||||
'nsArrayUtils.cpp',
|
||||
|
@ -5,6 +5,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Tokenizer.h"
|
||||
#include "mozilla/IncrementalTokenizer.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -732,3 +734,401 @@ TEST(Tokenizer, SkipUntil)
|
||||
EXPECT_TRUE(p.CheckEOF());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Tokenizer, Custom)
|
||||
{
|
||||
Tokenizer p("aaaaaacustom-1\r,custom-1,Custom-1,Custom-1,00custom-2xxxx,CUSTOM-2");
|
||||
|
||||
Tokenizer::Token c1 = p.AddCustomToken("custom-1", Tokenizer::CASE_INSENSITIVE);
|
||||
Tokenizer::Token c2 = p.AddCustomToken("custom-2", Tokenizer::CASE_SENSITIVE);
|
||||
|
||||
// It's expected to NOT FIND the custom token if it's not on an edge
|
||||
// between other recognizable tokens.
|
||||
EXPECT_TRUE(p.CheckWord("aaaaaacustom"));
|
||||
EXPECT_TRUE(p.CheckChar('-'));
|
||||
EXPECT_TRUE(p.Check(Tokenizer::Token::Number(1)));
|
||||
EXPECT_TRUE(p.CheckEOL());
|
||||
EXPECT_TRUE(p.CheckChar(','));
|
||||
|
||||
EXPECT_TRUE(p.Check(c1));
|
||||
EXPECT_TRUE(p.CheckChar(','));
|
||||
|
||||
EXPECT_TRUE(p.Check(c1));
|
||||
EXPECT_TRUE(p.CheckChar(','));
|
||||
|
||||
p.EnableCustomToken(c1, false);
|
||||
EXPECT_TRUE(p.CheckWord("Custom"));
|
||||
EXPECT_TRUE(p.CheckChar('-'));
|
||||
EXPECT_TRUE(p.Check(Tokenizer::Token::Number(1)));
|
||||
EXPECT_TRUE(p.CheckChar(','));
|
||||
|
||||
EXPECT_TRUE(p.Check(Tokenizer::Token::Number(0)));
|
||||
EXPECT_TRUE(p.Check(c2));
|
||||
EXPECT_TRUE(p.CheckWord("xxxx"));
|
||||
EXPECT_TRUE(p.CheckChar(','));
|
||||
|
||||
EXPECT_TRUE(p.CheckWord("CUSTOM"));
|
||||
EXPECT_TRUE(p.CheckChar('-'));
|
||||
EXPECT_TRUE(p.Check(Tokenizer::Token::Number(2)));
|
||||
|
||||
EXPECT_TRUE(p.CheckEOF());
|
||||
}
|
||||
|
||||
TEST(Tokenizer, CustomRaw)
|
||||
{
|
||||
Tokenizer p("aaaaaacustom-1\r,custom-1,Custom-1,Custom-1,00custom-2xxxx,CUSTOM-2");
|
||||
|
||||
Tokenizer::Token c1 = p.AddCustomToken("custom-1", Tokenizer::CASE_INSENSITIVE);
|
||||
Tokenizer::Token c2 = p.AddCustomToken("custom-2", Tokenizer::CASE_SENSITIVE);
|
||||
|
||||
// In this mode it's expected to find all custom tokens among any kind of input.
|
||||
p.SetTokenizingMode(Tokenizer::Mode::CUSTOM_ONLY);
|
||||
|
||||
Tokenizer::Token t;
|
||||
|
||||
EXPECT_TRUE(p.Next(t));
|
||||
EXPECT_TRUE(t.Type() == Tokenizer::TOKEN_RAW);
|
||||
EXPECT_TRUE(t.Fragment().EqualsLiteral("aaaaaa"));
|
||||
|
||||
EXPECT_TRUE(p.Check(c1));
|
||||
|
||||
EXPECT_TRUE(p.Next(t));
|
||||
EXPECT_TRUE(t.Type() == Tokenizer::TOKEN_RAW);
|
||||
EXPECT_TRUE(t.Fragment().EqualsLiteral("\r,"));
|
||||
|
||||
EXPECT_TRUE(p.Check(c1));
|
||||
|
||||
EXPECT_TRUE(p.Next(t));
|
||||
EXPECT_TRUE(t.Type() == Tokenizer::TOKEN_RAW);
|
||||
EXPECT_TRUE(t.Fragment().EqualsLiteral(","));
|
||||
|
||||
EXPECT_TRUE(p.Check(c1));
|
||||
|
||||
EXPECT_TRUE(p.Next(t));
|
||||
EXPECT_TRUE(t.Type() == Tokenizer::TOKEN_RAW);
|
||||
EXPECT_TRUE(t.Fragment().EqualsLiteral(","));
|
||||
|
||||
EXPECT_TRUE(p.Check(c1));
|
||||
|
||||
EXPECT_TRUE(p.Next(t));
|
||||
EXPECT_TRUE(t.Type() == Tokenizer::TOKEN_RAW);
|
||||
EXPECT_TRUE(t.Fragment().EqualsLiteral(",00"));
|
||||
|
||||
EXPECT_TRUE(p.Check(c2));
|
||||
|
||||
EXPECT_TRUE(p.Next(t));
|
||||
EXPECT_TRUE(t.Type() == Tokenizer::TOKEN_RAW);
|
||||
EXPECT_TRUE(t.Fragment().EqualsLiteral("xxxx,CUSTOM-2"));
|
||||
|
||||
EXPECT_TRUE(p.CheckEOF());
|
||||
}
|
||||
|
||||
TEST(Tokenizer, Incremental)
|
||||
{
|
||||
typedef TokenizerBase::Token Token;
|
||||
|
||||
int test = 0;
|
||||
IncrementalTokenizer i([&](Token const& t, IncrementalTokenizer& i) -> nsresult
|
||||
{
|
||||
switch (++test) {
|
||||
case 1: EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("test1")))); break;
|
||||
case 2: EXPECT_TRUE(t.Equals(Token::Char(','))); break;
|
||||
case 3: EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("test2")))); break;
|
||||
case 4: EXPECT_TRUE(t.Equals(Token::Char(','))); break;
|
||||
case 5: EXPECT_TRUE(t.Equals(Token::Char(','))); break;
|
||||
case 6: EXPECT_TRUE(t.Equals(Token::Char(','))); break;
|
||||
case 7: EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("test3")))); break;
|
||||
case 8: EXPECT_TRUE(t.Equals(Token::EndOfFile())); break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
});
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(input, "test1,test2,,,test3");
|
||||
auto cur = input.BeginReading();
|
||||
auto end = input.EndReading();
|
||||
for (; cur < end; ++cur) {
|
||||
i.FeedInput(nsDependentCSubstring(cur, 1));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(test == 6);
|
||||
i.FinishInput();
|
||||
EXPECT_TRUE(test == 8);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, IncrementalRollback)
|
||||
{
|
||||
typedef TokenizerBase::Token Token;
|
||||
|
||||
int test = 0;
|
||||
IncrementalTokenizer i([&](Token const& t, IncrementalTokenizer& i) -> nsresult
|
||||
{
|
||||
switch (++test) {
|
||||
case 1: EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("test1")))); break;
|
||||
case 2: EXPECT_TRUE(t.Equals(Token::Char(','))); break;
|
||||
case 3: EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("test2"))));
|
||||
i.Rollback(); // so that we get the token again
|
||||
break;
|
||||
case 4: EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("test2")))); break;
|
||||
case 5: EXPECT_TRUE(t.Equals(Token::Char(','))); break;
|
||||
case 6: EXPECT_TRUE(t.Equals(Token::Char(','))); break;
|
||||
case 7: EXPECT_TRUE(t.Equals(Token::Char(','))); break;
|
||||
case 8: EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("test3")))); break;
|
||||
case 9: EXPECT_TRUE(t.Equals(Token::EndOfFile())); break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
});
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(input, "test1,test2,,,test3");
|
||||
auto cur = input.BeginReading();
|
||||
auto end = input.EndReading();
|
||||
for (; cur < end; ++cur) {
|
||||
i.FeedInput(nsDependentCSubstring(cur, 1));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(test == 7);
|
||||
i.FinishInput();
|
||||
EXPECT_TRUE(test == 9);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, IncrementalNeedMoreInput)
|
||||
{
|
||||
typedef TokenizerBase::Token Token;
|
||||
|
||||
int test = 0;
|
||||
IncrementalTokenizer i([&](Token const& t, IncrementalTokenizer& i) -> nsresult
|
||||
{
|
||||
Token t2;
|
||||
switch (++test) {
|
||||
case 1:
|
||||
EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("a"))));
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
EXPECT_TRUE(t.Equals(Token::Whitespace()));
|
||||
if (i.Next(t2)) {
|
||||
EXPECT_TRUE(test == 5);
|
||||
EXPECT_TRUE(t2.Equals(Token::Word(NS_LITERAL_CSTRING("bb"))));
|
||||
} else {
|
||||
EXPECT_TRUE(test < 5);
|
||||
i.NeedMoreInput();
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
EXPECT_TRUE(t.Equals(Token::Char(',')));
|
||||
break;
|
||||
case 7:
|
||||
EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("c"))));
|
||||
return NS_ERROR_FAILURE;
|
||||
default:
|
||||
EXPECT_TRUE(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
});
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(input, "a bb,c");
|
||||
auto cur = input.BeginReading();
|
||||
auto end = input.EndReading();
|
||||
|
||||
nsresult rv;
|
||||
for (; cur < end; ++cur) {
|
||||
rv = i.FeedInput(nsDependentCSubstring(cur, 1));
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(rv == NS_OK);
|
||||
EXPECT_TRUE(test == 6);
|
||||
|
||||
rv = i.FinishInput();
|
||||
EXPECT_TRUE(rv == NS_ERROR_FAILURE);
|
||||
EXPECT_TRUE(test == 7);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, IncrementalCustom)
|
||||
{
|
||||
typedef TokenizerBase::Token Token;
|
||||
|
||||
int test = 0;
|
||||
Token custom;
|
||||
IncrementalTokenizer i([&](Token const& t, IncrementalTokenizer& i) -> nsresult
|
||||
{
|
||||
switch (++test) {
|
||||
case 1: EXPECT_TRUE(t.Equals(custom)); break;
|
||||
case 2: EXPECT_TRUE(t.Equals(Token::Word(NS_LITERAL_CSTRING("bla")))); break;
|
||||
case 3: EXPECT_TRUE(t.Equals(Token::EndOfFile())); break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}, nullptr, "-");
|
||||
|
||||
custom = i.AddCustomToken("some-test", Tokenizer::CASE_SENSITIVE);
|
||||
i.FeedInput(NS_LITERAL_CSTRING("some-"));
|
||||
EXPECT_TRUE(test == 0);
|
||||
i.FeedInput(NS_LITERAL_CSTRING("tes"));
|
||||
EXPECT_TRUE(test == 0);
|
||||
i.FeedInput(NS_LITERAL_CSTRING("tbla"));
|
||||
EXPECT_TRUE(test == 1);
|
||||
i.FinishInput();
|
||||
EXPECT_TRUE(test == 3);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, IncrementalCustomRaw)
|
||||
{
|
||||
typedef TokenizerBase::Token Token;
|
||||
|
||||
int test = 0;
|
||||
Token custom;
|
||||
IncrementalTokenizer i([&](Token const& t, IncrementalTokenizer& i) -> nsresult
|
||||
{
|
||||
switch (++test) {
|
||||
case 1: EXPECT_TRUE(t.Fragment().EqualsLiteral("test1,")); break;
|
||||
case 2: EXPECT_TRUE(t.Equals(custom)); break;
|
||||
case 3: EXPECT_TRUE(t.Fragment().EqualsLiteral("!,,test3"));
|
||||
i.Rollback();
|
||||
i.SetTokenizingMode(Tokenizer::Mode::FULL);
|
||||
break;
|
||||
case 4: EXPECT_TRUE(t.Equals(Token::Char('!')));
|
||||
i.SetTokenizingMode(Tokenizer::Mode::CUSTOM_ONLY);
|
||||
break;
|
||||
case 5: EXPECT_TRUE(t.Fragment().EqualsLiteral(",,test3")); break;
|
||||
case 6: EXPECT_TRUE(t.Equals(custom)); break;
|
||||
case 7: EXPECT_TRUE(t.Fragment().EqualsLiteral("tes")); break;
|
||||
case 8: EXPECT_TRUE(t.Equals(Token::EndOfFile())); break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
});
|
||||
|
||||
custom = i.AddCustomToken("test2", Tokenizer::CASE_SENSITIVE);
|
||||
i.SetTokenizingMode(Tokenizer::Mode::CUSTOM_ONLY);
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(input, "test1,test2!,,test3test2tes");
|
||||
auto cur = input.BeginReading();
|
||||
auto end = input.EndReading();
|
||||
for (; cur < end; ++cur) {
|
||||
i.FeedInput(nsDependentCSubstring(cur, 1));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(test == 6);
|
||||
i.FinishInput();
|
||||
EXPECT_TRUE(test == 8);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, IncrementalCustomRemove)
|
||||
{
|
||||
typedef TokenizerBase::Token Token;
|
||||
|
||||
int test = 0;
|
||||
Token custom;
|
||||
IncrementalTokenizer i([&](Token const& t, IncrementalTokenizer& i) -> nsresult
|
||||
{
|
||||
switch (++test) {
|
||||
case 1: EXPECT_TRUE(t.Equals(custom));
|
||||
i.RemoveCustomToken(custom);
|
||||
break;
|
||||
case 2: EXPECT_FALSE(t.Equals(custom)); break;
|
||||
case 3: EXPECT_TRUE(t.Equals(Token::EndOfFile())); break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
});
|
||||
|
||||
custom = i.AddCustomToken("custom1", Tokenizer::CASE_SENSITIVE);
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(input, "custom1custom1");
|
||||
i.FeedInput(input);
|
||||
EXPECT_TRUE(test == 1);
|
||||
i.FinishInput();
|
||||
EXPECT_TRUE(test == 3);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, IncrementalBuffering1)
|
||||
{
|
||||
typedef TokenizerBase::Token Token;
|
||||
|
||||
int test = 0;
|
||||
Token custom;
|
||||
nsDependentCSubstring observedFragment;
|
||||
IncrementalTokenizer i([&](Token const& t, IncrementalTokenizer& i) -> nsresult
|
||||
{
|
||||
switch (++test) {
|
||||
case 1: EXPECT_TRUE(t.Fragment().EqualsLiteral("012")); break;
|
||||
case 2: EXPECT_TRUE(t.Fragment().EqualsLiteral("3456789")); break;
|
||||
case 3: EXPECT_TRUE(t.Equals(custom)); break;
|
||||
case 4: EXPECT_TRUE(t.Fragment().EqualsLiteral("qwe")); break;
|
||||
case 5: EXPECT_TRUE(t.Fragment().EqualsLiteral("rt")); break;
|
||||
case 6: EXPECT_TRUE(t.Equals(Token::EndOfFile())); break;
|
||||
}
|
||||
|
||||
observedFragment.Rebind(t.Fragment().BeginReading(),
|
||||
t.Fragment().Length());
|
||||
return NS_OK;
|
||||
}, nullptr, nullptr, 3);
|
||||
|
||||
custom = i.AddCustomToken("aaa", Tokenizer::CASE_SENSITIVE);
|
||||
// This externally unused token is added only to check the internal algorithm
|
||||
// does work correctly as expected when there are two different length tokens.
|
||||
Unused << i.AddCustomToken("bb", Tokenizer::CASE_SENSITIVE);
|
||||
i.SetTokenizingMode(Tokenizer::Mode::CUSTOM_ONLY);
|
||||
|
||||
i.FeedInput(NS_LITERAL_CSTRING("01234"));
|
||||
EXPECT_TRUE(test == 1);
|
||||
EXPECT_TRUE(observedFragment.EqualsLiteral("012"));
|
||||
|
||||
i.FeedInput(NS_LITERAL_CSTRING("5"));
|
||||
EXPECT_TRUE(test == 1);
|
||||
i.FeedInput(NS_LITERAL_CSTRING("6789aa"));
|
||||
EXPECT_TRUE(test == 2);
|
||||
EXPECT_TRUE(observedFragment.EqualsLiteral("3456789"));
|
||||
|
||||
i.FeedInput(NS_LITERAL_CSTRING("aqwert"));
|
||||
EXPECT_TRUE(test == 4);
|
||||
EXPECT_TRUE(observedFragment.EqualsLiteral("qwe"));
|
||||
|
||||
i.FinishInput();
|
||||
EXPECT_TRUE(test == 6);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, IncrementalBuffering2)
|
||||
{
|
||||
typedef TokenizerBase::Token Token;
|
||||
|
||||
int test = 0;
|
||||
Token custom;
|
||||
IncrementalTokenizer i([&](Token const& t, IncrementalTokenizer& i) -> nsresult
|
||||
{
|
||||
switch (++test) {
|
||||
case 1: EXPECT_TRUE(t.Fragment().EqualsLiteral("01")); break;
|
||||
case 2: EXPECT_TRUE(t.Fragment().EqualsLiteral("234567")); break;
|
||||
case 3: EXPECT_TRUE(t.Fragment().EqualsLiteral("89")); break;
|
||||
case 4: EXPECT_TRUE(t.Equals(custom)); break;
|
||||
case 5: EXPECT_TRUE(t.Fragment().EqualsLiteral("qwert")); break;
|
||||
case 6: EXPECT_TRUE(t.Equals(Token::EndOfFile())); break;
|
||||
}
|
||||
return NS_OK;
|
||||
}, nullptr, nullptr, 3);
|
||||
|
||||
custom = i.AddCustomToken("aaa", Tokenizer::CASE_SENSITIVE);
|
||||
// This externally unused token is added only to check the internal algorithm
|
||||
// does work correctly as expected when there are two different length tokens.
|
||||
Unused << i.AddCustomToken("bbbbb", Tokenizer::CASE_SENSITIVE);
|
||||
i.SetTokenizingMode(Tokenizer::Mode::CUSTOM_ONLY);
|
||||
|
||||
i.FeedInput(NS_LITERAL_CSTRING("01234"));
|
||||
EXPECT_TRUE(test == 0);
|
||||
i.FeedInput(NS_LITERAL_CSTRING("5"));
|
||||
EXPECT_TRUE(test == 1);
|
||||
i.FeedInput(NS_LITERAL_CSTRING("6789aa"));
|
||||
EXPECT_TRUE(test == 2);
|
||||
i.FeedInput(NS_LITERAL_CSTRING("aqwert"));
|
||||
EXPECT_TRUE(test == 4);
|
||||
i.FinishInput();
|
||||
EXPECT_TRUE(test == 6);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user