This commit is contained in:
Nick Alexander 2013-11-14 22:41:14 -08:00
Родитель 003967689a 56e157765f
Коммит 512ba56709
277 изменённых файлов: 9957 добавлений и 2869 удалений

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

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/ # Modifying this file will now automatically clobber the buildbot machines \o/
# #
Another Windows WebIDL clobber needed due to bug 928195 Another Windows WebIDL clobber needed due to bug 674741

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

@ -1,4 +1,4 @@
{ {
"revision": "d9e07db2d0512169f304985a070eade8e81e6ba7", "revision": "88cc9854d6daff8c577e3867b95a1e523e429112",
"repo_path": "/integration/gaia-central" "repo_path": "/integration/gaia-central"
} }

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

@ -189,6 +189,9 @@
@BINPATH@/components/dom_geolocation.xpt @BINPATH@/components/dom_geolocation.xpt
@BINPATH@/components/dom_media.xpt @BINPATH@/components/dom_media.xpt
@BINPATH@/components/dom_network.xpt @BINPATH@/components/dom_network.xpt
#ifdef MOZ_NFC
@BINPATH@/components/dom_nfc.xpt
#endif
@BINPATH@/components/dom_notification.xpt @BINPATH@/components/dom_notification.xpt
@BINPATH@/components/dom_html.xpt @BINPATH@/components/dom_html.xpt
@BINPATH@/components/dom_indexeddb.xpt @BINPATH@/components/dom_indexeddb.xpt
@ -494,6 +497,13 @@
@BINPATH@/components/webvtt.xpt @BINPATH@/components/webvtt.xpt
@BINPATH@/components/WebVTT.manifest @BINPATH@/components/WebVTT.manifest
@BINPATH@/components/WebVTTParserWrapper.js @BINPATH@/components/WebVTTParserWrapper.js
#ifdef MOZ_NFC
@BINPATH@/components/nsNfc.manifest
@BINPATH@/components/nsNfc.js
@BINPATH@/components/Nfc.manifest
@BINPATH@/components/Nfc.js
@BINPATH@/components/NfcContentHelper.js
#endif
#ifdef MOZ_ENABLE_DBUS #ifdef MOZ_ENABLE_DBUS
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@ @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
#endif #endif

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

@ -1210,6 +1210,11 @@ pref("devtools.webconsole.fontSize", 0);
// be cleared each time page navigation happens. // be cleared each time page navigation happens.
pref("devtools.webconsole.persistlog", false); pref("devtools.webconsole.persistlog", false);
// Web Console timestamp: |true| if you want the logs and instructions
// in the Web Console to display a timestamp, or |false| to not display
// any timestamps.
pref("devtools.webconsole.timestampMessages", false);
// The number of lines that are displayed in the web console for the Net, // The number of lines that are displayed in the web console for the Net,
// CSS, JS and Web Developer categories. // CSS, JS and Web Developer categories.
pref("devtools.hud.loglimit.network", 200); pref("devtools.hud.loglimit.network", 200);

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

@ -731,10 +731,6 @@ var gPluginHandler = {
let principal = contentWindow.document.nodePrincipal; let principal = contentWindow.document.nodePrincipal;
Services.perms.addFromPrincipal(principal, aPluginInfo.permissionString, Services.perms.addFromPrincipal(principal, aPluginInfo.permissionString,
permission, expireType, expireTime); permission, expireType, expireTime);
if (aNewState == "block") {
return;
}
} }
// Manually activate the plugins that would have been automatically // Manually activate the plugins that would have been automatically
@ -752,19 +748,23 @@ var gPluginHandler = {
} }
if (aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) { if (aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
pluginFound = true; pluginFound = true;
if (gPluginHandler.canActivatePlugin(plugin)) { if (aNewState == "block") {
let overlay = this.getPluginUI(plugin, "main"); plugin.reload(true);
if (overlay) { } else {
overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true); if (gPluginHandler.canActivatePlugin(plugin)) {
let overlay = this.getPluginUI(plugin, "main");
if (overlay) {
overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
}
plugin.playPlugin();
} }
plugin.playPlugin();
} }
} }
} }
// If there are no instances of the plugin on the page any more, what the // If there are no instances of the plugin on the page any more, what the
// user probably needs is for us to allow and then refresh. // user probably needs is for us to allow and then refresh.
if (!pluginFound) { if (aNewState != "block" && !pluginFound) {
browser.reload(); browser.reload();
} }
}, },

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

@ -1514,6 +1514,7 @@ SocialStatus = {
"class": "social-panel-frame", "class": "social-panel-frame",
"id": notificationFrameId, "id": notificationFrameId,
"tooltip": "aHTMLTooltip", "tooltip": "aHTMLTooltip",
"context": "contentAreaContextMenu",
// work around bug 793057 - by making the panel roughly the final size // work around bug 793057 - by making the panel roughly the final size
// we are more likely to have the anchor in the correct position. // we are more likely to have the anchor in the correct position.

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

@ -8,52 +8,6 @@ var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Co
Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Services.jsm");
// This listens for the next opened tab and checks it is of the right url.
// opencallback is called when the new tab is fully loaded
// closecallback is called when the tab is closed
function TabOpenListener(url, opencallback, closecallback) {
this.url = url;
this.opencallback = opencallback;
this.closecallback = closecallback;
gBrowser.tabContainer.addEventListener("TabOpen", this, false);
}
TabOpenListener.prototype = {
url: null,
opencallback: null,
closecallback: null,
tab: null,
browser: null,
handleEvent: function(event) {
if (event.type == "TabOpen") {
gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
this.tab = event.originalTarget;
this.browser = this.tab.linkedBrowser;
gBrowser.addEventListener("pageshow", this, false);
} else if (event.type == "pageshow") {
if (event.target.location.href != this.url)
return;
gBrowser.removeEventListener("pageshow", this, false);
this.tab.addEventListener("TabClose", this, false);
var url = this.browser.contentDocument.location.href;
is(url, this.url, "Should have opened the correct tab");
this.opencallback(this.tab, this.browser.contentWindow);
} else if (event.type == "TabClose") {
if (event.originalTarget != this.tab)
return;
this.tab.removeEventListener("TabClose", this, false);
this.opencallback = null;
this.tab = null;
this.browser = null;
// Let the window close complete
executeSoon(this.closecallback);
this.closecallback = null;
}
}
};
function test() { function test() {
waitForExplicitFinish(); waitForExplicitFinish();
registerCleanupFunction(function() { registerCleanupFunction(function() {

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

@ -9,52 +9,6 @@ var gRunNextTestAfterPluginRemoved = false;
Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Services.jsm");
// This listens for the next opened tab and checks it is of the right url.
// opencallback is called when the new tab is fully loaded
// closecallback is called when the tab is closed
function TabOpenListener(url, opencallback, closecallback) {
this.url = url;
this.opencallback = opencallback;
this.closecallback = closecallback;
gBrowser.tabContainer.addEventListener("TabOpen", this, false);
}
TabOpenListener.prototype = {
url: null,
opencallback: null,
closecallback: null,
tab: null,
browser: null,
handleEvent: function(event) {
if (event.type == "TabOpen") {
gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
this.tab = event.originalTarget;
this.browser = this.tab.linkedBrowser;
gBrowser.addEventListener("pageshow", this, false);
} else if (event.type == "pageshow") {
if (event.target.location.href != this.url)
return;
gBrowser.removeEventListener("pageshow", this, false);
this.tab.addEventListener("TabClose", this, false);
var url = this.browser.contentDocument.location.href;
is(url, this.url, "Should have opened the correct tab");
this.opencallback(this.tab, this.browser.contentWindow);
} else if (event.type == "TabClose") {
if (event.originalTarget != this.tab)
return;
this.tab.removeEventListener("TabClose", this, false);
this.opencallback = null;
this.tab = null;
this.browser = null;
// Let the window close complete
executeSoon(this.closecallback);
this.closecallback = null;
}
}
};
function test() { function test() {
waitForExplicitFinish(); waitForExplicitFinish();
registerCleanupFunction(function() { registerCleanupFunction(function() {

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

@ -8,52 +8,6 @@ var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Co
Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Services.jsm");
// This listens for the next opened tab and checks it is of the right url.
// opencallback is called when the new tab is fully loaded
// closecallback is called when the tab is closed
function TabOpenListener(url, opencallback, closecallback) {
this.url = url;
this.opencallback = opencallback;
this.closecallback = closecallback;
gBrowser.tabContainer.addEventListener("TabOpen", this, false);
}
TabOpenListener.prototype = {
url: null,
opencallback: null,
closecallback: null,
tab: null,
browser: null,
handleEvent: function(event) {
if (event.type == "TabOpen") {
gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
this.tab = event.originalTarget;
this.browser = this.tab.linkedBrowser;
gBrowser.addEventListener("pageshow", this, false);
} else if (event.type == "pageshow") {
if (event.target.location.href != this.url)
return;
gBrowser.removeEventListener("pageshow", this, false);
this.tab.addEventListener("TabClose", this, false);
var url = this.browser.contentDocument.location.href;
is(url, this.url, "Should have opened the correct tab");
this.opencallback(this.tab, this.browser.contentWindow);
} else if (event.type == "TabClose") {
if (event.originalTarget != this.tab)
return;
this.tab.removeEventListener("TabClose", this, false);
this.opencallback = null;
this.tab = null;
this.browser = null;
// Let the window close complete
executeSoon(this.closecallback);
this.closecallback = null;
}
}
};
function test() { function test() {
waitForExplicitFinish(); waitForExplicitFinish();
registerCleanupFunction(function() { registerCleanupFunction(function() {

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

@ -90,8 +90,12 @@ function test() {
function doTest(aIsPrivateMode, aWindow, aCallback) { function doTest(aIsPrivateMode, aWindow, aCallback) {
aWindow.gBrowser.addEventListener("pageshow", function pageShown(event) { aWindow.gBrowser.addEventListener("pageshow", function pageShown(event) {
if (event.target.location == "about:blank") // If data: -url PAC file isn't loaded soon enough, we may get about:privatebrowsing loaded
if (event.target.location == "about:blank" ||
event.target.location == "about:privatebrowsing") {
aWindow.gBrowser.selectedBrowser.loadURI(testURI);
return; return;
}
aWindow.gBrowser.removeEventListener("pageshow", pageShown); aWindow.gBrowser.removeEventListener("pageshow", pageShown);
executeSoon(function () { executeSoon(function () {

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

@ -93,7 +93,7 @@ let MessageListener = {
receiveMessage: function ({name, data: {id}}) { receiveMessage: function ({name, data: {id}}) {
switch (name) { switch (name) {
case "SessionStore:collectSessionHistory": case "SessionStore:collectSessionHistory":
let history = SessionHistory.read(docShell); let history = SessionHistory.collect(docShell);
if ("index" in history) { if ("index" in history) {
let tabIndex = history.index - 1; let tabIndex = history.index - 1;
// Don't include private data. It's only needed when duplicating // Don't include private data. It's only needed when duplicating
@ -141,7 +141,7 @@ let SyncHandler = {
}, },
collectSessionHistory: function (includePrivateData) { collectSessionHistory: function (includePrivateData) {
let history = SessionHistory.read(docShell); let history = SessionHistory.collect(docShell);
if ("index" in history) { if ("index" in history) {
let tabIndex = history.index - 1; let tabIndex = history.index - 1;
TextAndScrollData.updateFrame(history.entries[tabIndex], TextAndScrollData.updateFrame(history.entries[tabIndex],

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

@ -15,6 +15,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivacyLevel", XPCOMUtils.defineLazyModuleGetter(this, "PrivacyLevel",
"resource:///modules/sessionstore/PrivacyLevel.jsm"); "resource:///modules/sessionstore/PrivacyLevel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Utils",
"resource:///modules/sessionstore/Utils.jsm");
function debug(msg) { function debug(msg) {
Services.console.logStringMessage("SessionHistory: " + msg); Services.console.logStringMessage("SessionHistory: " + msg);
@ -36,8 +38,12 @@ XPCOMUtils.defineLazyGetter(this, "gPostData", function () {
* The external API exported by this module. * The external API exported by this module.
*/ */
this.SessionHistory = Object.freeze({ this.SessionHistory = Object.freeze({
read: function (docShell, includePrivateData) { collect: function (docShell, includePrivateData) {
return SessionHistoryInternal.read(docShell, includePrivateData); return SessionHistoryInternal.collect(docShell, includePrivateData);
},
restore: function (docShell, tabData) {
SessionHistoryInternal.restore(docShell, tabData);
} }
}); });
@ -53,7 +59,7 @@ let SessionHistoryInternal = {
* @param includePrivateData (optional) * @param includePrivateData (optional)
* True to always include private data and skip any privacy checks. * True to always include private data and skip any privacy checks.
*/ */
read: function (docShell, includePrivateData = false) { collect: function (docShell, includePrivateData = false) {
let data = {entries: []}; let data = {entries: []};
let isPinned = docShell.isAppTab; let isPinned = docShell.isAppTab;
let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation); let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
@ -63,7 +69,7 @@ let SessionHistoryInternal = {
try { try {
for (let i = 0; i < history.count; i++) { for (let i = 0; i < history.count; i++) {
let shEntry = history.getEntryAtIndex(i, false); let shEntry = history.getEntryAtIndex(i, false);
let entry = this._serializeEntry(shEntry, includePrivateData, isPinned); let entry = this.serializeEntry(shEntry, includePrivateData, isPinned);
data.entries.push(entry); data.entries.push(entry);
} }
} catch (ex) { } catch (ex) {
@ -109,7 +115,7 @@ let SessionHistoryInternal = {
* The tab is pinned and should be treated differently for privacy. * The tab is pinned and should be treated differently for privacy.
* @return object * @return object
*/ */
_serializeEntry: function (shEntry, includePrivateData, isPinned) { serializeEntry: function (shEntry, includePrivateData, isPinned) {
let entry = { url: shEntry.URI.spec }; let entry = { url: shEntry.URI.spec };
// Save some bytes and don't include the title property // Save some bytes and don't include the title property
@ -152,7 +158,7 @@ let SessionHistoryInternal = {
// Collect post data for the current history entry. // Collect post data for the current history entry.
try { try {
let postdata = this._serializePostData(shEntry, isPinned); let postdata = this.serializePostData(shEntry, isPinned);
if (postdata) { if (postdata) {
entry.postdata_b64 = postdata; entry.postdata_b64 = postdata;
} }
@ -163,7 +169,7 @@ let SessionHistoryInternal = {
// Collect owner data for the current history entry. // Collect owner data for the current history entry.
try { try {
let owner = this._serializeOwner(shEntry); let owner = this.serializeOwner(shEntry);
if (owner) { if (owner) {
entry.owner_b64 = owner; entry.owner_b64 = owner;
} }
@ -197,7 +203,7 @@ let SessionHistoryInternal = {
break; break;
} }
children.push(this._serializeEntry(child, includePrivateData, isPinned)); children.push(this.serializeEntry(child, includePrivateData, isPinned));
} }
} }
@ -218,7 +224,7 @@ let SessionHistoryInternal = {
* Whether the docShell is owned by a pinned tab. * Whether the docShell is owned by a pinned tab.
* @return The base64 encoded post data. * @return The base64 encoded post data.
*/ */
_serializePostData: function (shEntry, isPinned) { serializePostData: function (shEntry, isPinned) {
let isHttps = shEntry.URI.schemeIs("https"); let isHttps = shEntry.URI.schemeIs("https");
if (!shEntry.postData || !gPostData || if (!shEntry.postData || !gPostData ||
!PrivacyLevel.canSave({isHttps: isHttps, isPinned: isPinned})) { !PrivacyLevel.canSave({isHttps: isHttps, isPinned: isPinned})) {
@ -250,7 +256,7 @@ let SessionHistoryInternal = {
* The session history entry. * The session history entry.
* @return The base64 encoded owner data. * @return The base64 encoded owner data.
*/ */
_serializeOwner: function (shEntry) { serializeOwner: function (shEntry) {
if (!shEntry.owner) { if (!shEntry.owner) {
return null; return null;
} }
@ -274,5 +280,166 @@ let SessionHistoryInternal = {
// is guaranteed to handle all chars in strings, including embedded // is guaranteed to handle all chars in strings, including embedded
// nulls. // nulls.
return btoa(String.fromCharCode.apply(null, ownerBytes)); return btoa(String.fromCharCode.apply(null, ownerBytes));
} },
/**
* Restores session history data for a given docShell.
*
* @param docShell
* The docShell that owns the session history.
* @param tabData
* The tabdata including all history entries.
*/
restore: function (docShell, tabData) {
let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
let history = webNavigation.sessionHistory;
if (history.count > 0) {
history.PurgeHistory(history.count);
}
history.QueryInterface(Ci.nsISHistoryInternal);
let idMap = { used: {} };
let docIdentMap = {};
for (let i = 0; i < tabData.entries.length; i++) {
//XXXzpao Wallpaper patch for bug 514751
if (!tabData.entries[i].url)
continue;
history.addEntry(this.deserializeEntry(tabData.entries[i],
idMap, docIdentMap), true);
}
},
/**
* Expands serialized history data into a session-history-entry instance.
*
* @param entry
* Object containing serialized history data for a URL
* @param idMap
* Hash for ensuring unique frame IDs
* @param docIdentMap
* Hash to ensure reuse of BFCache entries
* @returns nsISHEntry
*/
deserializeEntry: function (entry, idMap, docIdentMap) {
var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
createInstance(Ci.nsISHEntry);
shEntry.setURI(Utils.makeURI(entry.url));
shEntry.setTitle(entry.title || entry.url);
if (entry.subframe)
shEntry.setIsSubFrame(entry.subframe || false);
shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
if (entry.contentType)
shEntry.contentType = entry.contentType;
if (entry.referrer)
shEntry.referrerURI = Utils.makeURI(entry.referrer);
if (entry.isSrcdocEntry)
shEntry.srcdocData = entry.srcdocData;
if (entry.cacheKey) {
var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
createInstance(Ci.nsISupportsPRUint32);
cacheKey.data = entry.cacheKey;
shEntry.cacheKey = cacheKey;
}
if (entry.ID) {
// get a new unique ID for this frame (since the one from the last
// start might already be in use)
var id = idMap[entry.ID] || 0;
if (!id) {
for (id = Date.now(); id in idMap.used; id++);
idMap[entry.ID] = id;
idMap.used[id] = true;
}
shEntry.ID = id;
}
if (entry.docshellID)
shEntry.docshellID = entry.docshellID;
if (entry.structuredCloneState && entry.structuredCloneVersion) {
shEntry.stateData =
Cc["@mozilla.org/docshell/structured-clone-container;1"].
createInstance(Ci.nsIStructuredCloneContainer);
shEntry.stateData.initFromBase64(entry.structuredCloneState,
entry.structuredCloneVersion);
}
if (entry.scroll) {
var scrollPos = (entry.scroll || "0,0").split(",");
scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
}
if (entry.postdata_b64) {
var postdata = atob(entry.postdata_b64);
var stream = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
stream.setData(postdata, postdata.length);
shEntry.postData = stream;
}
let childDocIdents = {};
if (entry.docIdentifier) {
// If we have a serialized document identifier, try to find an SHEntry
// which matches that doc identifier and adopt that SHEntry's
// BFCacheEntry. If we don't find a match, insert shEntry as the match
// for the document identifier.
let matchingEntry = docIdentMap[entry.docIdentifier];
if (!matchingEntry) {
matchingEntry = {shEntry: shEntry, childDocIdents: childDocIdents};
docIdentMap[entry.docIdentifier] = matchingEntry;
}
else {
shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
childDocIdents = matchingEntry.childDocIdents;
}
}
if (entry.owner_b64) {
var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
var binaryData = atob(entry.owner_b64);
ownerInput.setData(binaryData, binaryData.length);
var binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
createInstance(Ci.nsIObjectInputStream);
binaryStream.setInputStream(ownerInput);
try { // Catch possible deserialization exceptions
shEntry.owner = binaryStream.readObject(true);
} catch (ex) { debug(ex); }
}
if (entry.children && shEntry instanceof Ci.nsISHContainer) {
for (var i = 0; i < entry.children.length; i++) {
//XXXzpao Wallpaper patch for bug 514751
if (!entry.children[i].url)
continue;
// We're getting sessionrestore.js files with a cycle in the
// doc-identifier graph, likely due to bug 698656. (That is, we have
// an entry where doc identifier A is an ancestor of doc identifier B,
// and another entry where doc identifier B is an ancestor of A.)
//
// If we were to respect these doc identifiers, we'd create a cycle in
// the SHEntries themselves, which causes the docshell to loop forever
// when it looks for the root SHEntry.
//
// So as a hack to fix this, we restrict the scope of a doc identifier
// to be a node's siblings and cousins, and pass childDocIdents, not
// aDocIdents, to _deserializeHistoryEntry. That is, we say that two
// SHEntries with the same doc identifier have the same document iff
// they have the same parent or their parents have the same document.
shEntry.AddChild(this.deserializeEntry(entry.children[i], idMap,
childDocIdents), i);
}
}
return shEntry;
},
}; };

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

@ -117,6 +117,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "TextAndScrollData",
"resource:///modules/sessionstore/TextAndScrollData.jsm"); "resource:///modules/sessionstore/TextAndScrollData.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionFile", XPCOMUtils.defineLazyModuleGetter(this, "SessionFile",
"resource:///modules/sessionstore/SessionFile.jsm"); "resource:///modules/sessionstore/SessionFile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
"resource:///modules/sessionstore/SessionHistory.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TabAttributes", XPCOMUtils.defineLazyModuleGetter(this, "TabAttributes",
"resource:///modules/sessionstore/TabAttributes.jsm"); "resource:///modules/sessionstore/TabAttributes.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TabState", XPCOMUtils.defineLazyModuleGetter(this, "TabState",
@ -1346,10 +1348,10 @@ let SessionStoreInternal = {
let tab = aWindow.gBrowser.selectedTab; let tab = aWindow.gBrowser.selectedTab;
// If __SS_restoreState is still on the browser and it is // If __SS_restoreState is still on the browser and it is
// TAB_STATE_NEEDS_RESTORE, then then we haven't restored // TAB_STATE_NEEDS_RESTORE, then then we haven't restored
// this tab yet. Explicitly call restoreTab to kick off the restore. // this tab yet. Explicitly call restoreTabContent to kick off the restore.
if (tab.linkedBrowser.__SS_restoreState && if (tab.linkedBrowser.__SS_restoreState &&
tab.linkedBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) tab.linkedBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
this.restoreTab(tab); this.restoreTabContent(tab);
// attempt to update the current URL we send in a crash report // attempt to update the current URL we send in a crash report
this._updateCrashReportURL(aWindow); this._updateCrashReportURL(aWindow);
@ -1477,7 +1479,7 @@ let SessionStoreInternal = {
// Remove the tab state from the cache. // Remove the tab state from the cache.
// Note that we cannot simply replace the contents of the cache // Note that we cannot simply replace the contents of the cache
// as |aState| can be an incomplete state that will be completed // as |aState| can be an incomplete state that will be completed
// by |restoreHistoryPrecursor|. // by |restoreTabs|.
let tabState = JSON.parse(aState); let tabState = JSON.parse(aState);
if (!tabState) { if (!tabState) {
debug("Empty state argument"); debug("Empty state argument");
@ -1508,7 +1510,7 @@ let SessionStoreInternal = {
TabStateCache.delete(aTab); TabStateCache.delete(aTab);
this._setWindowStateBusy(window); this._setWindowStateBusy(window);
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0); this.restoreTabs(window, [aTab], [tabState], 0);
}, },
duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) { duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
@ -1528,8 +1530,8 @@ let SessionStoreInternal = {
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) : aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
aWindow.gBrowser.addTab(); aWindow.gBrowser.addTab();
this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0, this.restoreTabs(aWindow, [newTab], [tabState], 0,
true /* Load this tab right away. */); true /* Load this tab right away. */);
return newTab; return newTab;
}, },
@ -1608,7 +1610,7 @@ let SessionStoreInternal = {
let tab = tabbrowser.addTab(); let tab = tabbrowser.addTab();
// restore tab content // restore tab content
this.restoreHistoryPrecursor(aWindow, [tab], [closedTabState], 1); this.restoreTabs(aWindow, [tab], [closedTabState], 1);
// restore the tab's position // restore the tab's position
tabbrowser.moveTabTo(tab, closedTab.pos); tabbrowser.moveTabTo(tab, closedTab.pos);
@ -2227,7 +2229,7 @@ let SessionStoreInternal = {
TelemetryStopwatch.start("FX_SESSION_RESTORE_RESTORE_WINDOW_MS"); TelemetryStopwatch.start("FX_SESSION_RESTORE_RESTORE_WINDOW_MS");
// We're not returning from this before we end up calling restoreHistoryPrecursor // We're not returning from this before we end up calling restoreTabs
// for this window, so make sure we send the SSWindowStateBusy event. // for this window, so make sure we send the SSWindowStateBusy event.
this._setWindowStateBusy(aWindow); this._setWindowStateBusy(aWindow);
@ -2325,7 +2327,7 @@ let SessionStoreInternal = {
// If overwriting tabs, we want to reset each tab's "restoring" state. Since // If overwriting tabs, we want to reset each tab's "restoring" state. Since
// we're overwriting those tabs, they should no longer be restoring. The // we're overwriting those tabs, they should no longer be restoring. The
// tabs will be rebuilt and marked if they need to be restored after loading // tabs will be rebuilt and marked if they need to be restored after loading
// state (in restoreHistoryPrecursor). // state (in restoreTabs).
// We also want to invalidate any cached information on the tab state. // We also want to invalidate any cached information on the tab state.
if (overwriteTabs) { if (overwriteTabs) {
for (let i = 0; i < tabbrowser.tabs.length; i++) { for (let i = 0; i < tabbrowser.tabs.length; i++) {
@ -2380,7 +2382,7 @@ let SessionStoreInternal = {
this._windows[aWindow.__SSi]._closedTabs = winData._closedTabs || []; this._windows[aWindow.__SSi]._closedTabs = winData._closedTabs || [];
} }
this.restoreHistoryPrecursor(aWindow, tabs, winData.tabs, this.restoreTabs(aWindow, tabs, winData.tabs,
(overwriteTabs ? (parseInt(winData.selected) || 1) : 0)); (overwriteTabs ? (parseInt(winData.selected) || 1) : 0));
if (aState.scratchpads) { if (aState.scratchpads) {
@ -2474,7 +2476,7 @@ let SessionStoreInternal = {
return [aTabs, aTabData]; return [aTabs, aTabData];
}, },
/** /**
* Manage history restoration for a window * Manage history restoration for a window
* @param aWindow * @param aWindow
@ -2489,9 +2491,8 @@ let SessionStoreInternal = {
* Flag to indicate whether the given set of tabs aTabs should be * Flag to indicate whether the given set of tabs aTabs should be
* restored/loaded immediately even if restore_on_demand = true * restored/loaded immediately even if restore_on_demand = true
*/ */
restoreHistoryPrecursor: restoreTabs: function (aWindow, aTabs, aTabData, aSelectTab,
function ssi_restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab, aRestoreImmediately = false)
aRestoreImmediately = false)
{ {
var tabbrowser = aWindow.gBrowser; var tabbrowser = aWindow.gBrowser;
@ -2553,6 +2554,17 @@ let SessionStoreInternal = {
// out of date now that we're restoring it. // out of date now that we're restoring it.
TabState.dropPendingCollections(tab); TabState.dropPendingCollections(tab);
if (!tabData.entries) {
tabData.entries = [];
}
if (tabData.extData) {
tab.__SS_extdata = {};
for (let key in tabData.extData)
tab.__SS_extdata[key] = tabData.extData[key];
} else {
delete tab.__SS_extdata;
}
browser.__SS_tabStillLoading = true; browser.__SS_tabStillLoading = true;
// keep the data around to prevent dataloss in case // keep the data around to prevent dataloss in case
@ -2562,11 +2574,7 @@ let SessionStoreInternal = {
browser.setAttribute("pending", "true"); browser.setAttribute("pending", "true");
tab.setAttribute("pending", "true"); tab.setAttribute("pending", "true");
// Make sure that set/getTabValue will set/read the correct data by if (tabData.entries.length == 0) {
// wiping out any current value in tab.__SS_extdata.
delete tab.__SS_extdata;
if (!tabData.entries || tabData.entries.length == 0) {
// make sure to blank out this tab's content // make sure to blank out this tab's content
// (just purging the tab's history won't be enough) // (just purging the tab's history won't be enough)
browser.loadURIWithFlags("about:blank", browser.loadURIWithFlags("about:blank",
@ -2601,114 +2609,84 @@ let SessionStoreInternal = {
tab.crop = "center"; tab.crop = "center";
} }
} }
// Restore tab attributes.
if ("attributes" in tabData) {
TabAttributes.set(tab, tabData.attributes);
}
// Restore the tab icon.
if ("image" in tabData) {
tabbrowser.setIcon(tab, tabData.image);
}
} }
// helper hashes for ensuring unique frame IDs and unique document function restoreNextHistory() {
// identifiers. if (aWindow.closed) {
let idMap = { used: {} }; return;
let docIdentMap = {}; }
this.restoreHistory(aWindow, aTabs, aTabData, idMap, docIdentMap,
aRestoreImmediately); // if the tab got removed before being completely restored, then skip it
while (aTabs.length > 0 && !this._canRestoreTabHistory(aTabs[0])) {
aTabs.shift();
aTabData.shift();
}
if (aTabs.length == 0) {
// At this point we're essentially ready for consumers to read/write data
// via the sessionstore API so we'll send the SSWindowStateReady event.
this._setWindowStateReady(aWindow);
return; // no more tabs to restore
}
let tab = aTabs.shift();
let tabData = aTabData.shift();
this.restoreHistory(aWindow, tab, tabData, aRestoreImmediately);
// Restore the history in the next tab
aWindow.setTimeout(restoreNextHistory.bind(this), 0);
}
restoreNextHistory.call(this);
}, },
/** /**
* Restore history for a list of tabs. * Restore history for a list of tabs.
* @param aWindow * @param window
* Window reference * Window reference
* @param aTabs * @param tab
* Array of tab references * Tab to be restored
* @param aTabData * @param tabData
* Array of tab data * Tab data to restore
* @param aIdMap * @param restoreImmediately
* Hash for ensuring unique frame IDs
* @param aRestoreImmediately
* Flag to indicate whether the given set of tabs aTabs should be * Flag to indicate whether the given set of tabs aTabs should be
* restored/loaded immediately even if restore_on_demand = true * restored/loaded immediately even if restore_on_demand = true
*/ */
restoreHistory: restoreHistory: function (window, tab, tabData, restoreImmediately) {
function ssi_restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap, let browser = tab.linkedBrowser;
aRestoreImmediately) let history = browser.webNavigation.sessionHistory;
{
// if the tab got removed before being completely restored, then skip it
while (aTabs.length > 0 && !(this._canRestoreTabHistory(aTabs[0]))) {
aTabs.shift();
aTabData.shift();
}
if (aTabs.length == 0) {
// At this point we're essentially ready for consumers to read/write data
// via the sessionstore API so we'll send the SSWindowStateReady event.
this._setWindowStateReady(aWindow);
return; // no more tabs to restore
}
var tab = aTabs.shift();
var tabData = aTabData.shift();
var browser = aWindow.gBrowser.getBrowserForTab(tab);
var history = browser.webNavigation.sessionHistory;
if (history.count > 0) {
history.PurgeHistory(history.count);
}
history.QueryInterface(Ci.nsISHistoryInternal);
browser.__SS_shistoryListener = new SessionStoreSHistoryListener(tab); browser.__SS_shistoryListener = new SessionStoreSHistoryListener(tab);
history.addSHistoryListener(browser.__SS_shistoryListener); history.addSHistoryListener(browser.__SS_shistoryListener);
if (!tabData.entries) { SessionHistory.restore(browser.docShell, tabData);
tabData.entries = [];
}
if (tabData.extData) {
tab.__SS_extdata = {};
for (let key in tabData.extData)
tab.__SS_extdata[key] = tabData.extData[key];
}
else
delete tab.__SS_extdata;
for (var i = 0; i < tabData.entries.length; i++) {
//XXXzpao Wallpaper patch for bug 514751
if (!tabData.entries[i].url)
continue;
history.addEntry(this._deserializeHistoryEntry(tabData.entries[i],
aIdMap, aDocIdentMap), true);
}
// make sure to reset the capabilities and attributes, in case this tab gets reused // make sure to reset the capabilities and attributes, in case this tab gets reused
let disallow = new Set(tabData.disallow && tabData.disallow.split(",")); let disallow = new Set(tabData.disallow && tabData.disallow.split(","));
DocShellCapabilities.restore(browser.docShell, disallow); DocShellCapabilities.restore(browser.docShell, disallow);
// Restore tab attributes.
if ("attributes" in tabData) {
TabAttributes.set(tab, tabData.attributes);
}
// Restore the tab icon.
if ("image" in tabData) {
aWindow.gBrowser.setIcon(tab, tabData.image);
}
if (tabData.storage && browser.docShell instanceof Ci.nsIDocShell) if (tabData.storage && browser.docShell instanceof Ci.nsIDocShell)
SessionStorage.deserialize(browser.docShell, tabData.storage); SessionStorage.deserialize(browser.docShell, tabData.storage);
// notify the tabbrowser that the tab chrome has been restored // notify the tabbrowser that the tab chrome has been restored
var event = aWindow.document.createEvent("Events"); var event = window.document.createEvent("Events");
event.initEvent("SSTabRestoring", true, false); event.initEvent("SSTabRestoring", true, false);
tab.dispatchEvent(event); tab.dispatchEvent(event);
// Restore the history in the next tab
aWindow.setTimeout(() => {
if (!aWindow.closed) {
this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
aRestoreImmediately);
}
}, 0);
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but // This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
// it ensures each window will have its selected tab loaded. // it ensures each window will have its selected tab loaded.
if (aRestoreImmediately || aWindow.gBrowser.selectedBrowser == browser) { if (restoreImmediately || window.gBrowser.selectedBrowser == browser) {
this.restoreTab(tab); this.restoreTabContent(tab);
} } else {
else {
TabRestoreQueue.add(tab); TabRestoreQueue.add(tab);
this.restoreNextTab(); this.restoreNextTab();
} }
@ -2731,7 +2709,7 @@ let SessionStoreInternal = {
* *
* @returns true/false indicating whether or not a load actually happened * @returns true/false indicating whether or not a load actually happened
*/ */
restoreTab: function ssi_restoreTab(aTab) { restoreTabContent: function (aTab) {
let window = aTab.ownerDocument.defaultView; let window = aTab.ownerDocument.defaultView;
let browser = aTab.linkedBrowser; let browser = aTab.linkedBrowser;
let tabData = browser.__SS_data; let tabData = browser.__SS_data;
@ -2834,7 +2812,7 @@ let SessionStoreInternal = {
let tab = TabRestoreQueue.shift(); let tab = TabRestoreQueue.shift();
if (tab) { if (tab) {
let didStartLoad = this.restoreTab(tab); let didStartLoad = this.restoreTabContent(tab);
// If we don't start a load in the restored tab (eg, no entries) then we // If we don't start a load in the restored tab (eg, no entries) then we
// want to attempt to restore the next tab. // want to attempt to restore the next tab.
if (!didStartLoad) if (!didStartLoad)
@ -2842,136 +2820,6 @@ let SessionStoreInternal = {
} }
}, },
/**
* expands serialized history data into a session-history-entry instance
* @param aEntry
* Object containing serialized history data for a URL
* @param aIdMap
* Hash for ensuring unique frame IDs
* @returns nsISHEntry
*/
_deserializeHistoryEntry:
function ssi_deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) {
var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
createInstance(Ci.nsISHEntry);
shEntry.setURI(Utils.makeURI(aEntry.url));
shEntry.setTitle(aEntry.title || aEntry.url);
if (aEntry.subframe)
shEntry.setIsSubFrame(aEntry.subframe || false);
shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
if (aEntry.contentType)
shEntry.contentType = aEntry.contentType;
if (aEntry.referrer)
shEntry.referrerURI = Utils.makeURI(aEntry.referrer);
if (aEntry.isSrcdocEntry)
shEntry.srcdocData = aEntry.srcdocData;
if (aEntry.cacheKey) {
var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
createInstance(Ci.nsISupportsPRUint32);
cacheKey.data = aEntry.cacheKey;
shEntry.cacheKey = cacheKey;
}
if (aEntry.ID) {
// get a new unique ID for this frame (since the one from the last
// start might already be in use)
var id = aIdMap[aEntry.ID] || 0;
if (!id) {
for (id = Date.now(); id in aIdMap.used; id++);
aIdMap[aEntry.ID] = id;
aIdMap.used[id] = true;
}
shEntry.ID = id;
}
if (aEntry.docshellID)
shEntry.docshellID = aEntry.docshellID;
if (aEntry.structuredCloneState && aEntry.structuredCloneVersion) {
shEntry.stateData =
Cc["@mozilla.org/docshell/structured-clone-container;1"].
createInstance(Ci.nsIStructuredCloneContainer);
shEntry.stateData.initFromBase64(aEntry.structuredCloneState,
aEntry.structuredCloneVersion);
}
if (aEntry.scroll) {
var scrollPos = (aEntry.scroll || "0,0").split(",");
scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
}
if (aEntry.postdata_b64) {
var postdata = atob(aEntry.postdata_b64);
var stream = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
stream.setData(postdata, postdata.length);
shEntry.postData = stream;
}
let childDocIdents = {};
if (aEntry.docIdentifier) {
// If we have a serialized document identifier, try to find an SHEntry
// which matches that doc identifier and adopt that SHEntry's
// BFCacheEntry. If we don't find a match, insert shEntry as the match
// for the document identifier.
let matchingEntry = aDocIdentMap[aEntry.docIdentifier];
if (!matchingEntry) {
matchingEntry = {shEntry: shEntry, childDocIdents: childDocIdents};
aDocIdentMap[aEntry.docIdentifier] = matchingEntry;
}
else {
shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
childDocIdents = matchingEntry.childDocIdents;
}
}
if (aEntry.owner_b64) {
var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
var binaryData = atob(aEntry.owner_b64);
ownerInput.setData(binaryData, binaryData.length);
var binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
createInstance(Ci.nsIObjectInputStream);
binaryStream.setInputStream(ownerInput);
try { // Catch possible deserialization exceptions
shEntry.owner = binaryStream.readObject(true);
} catch (ex) { debug(ex); }
}
if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
for (var i = 0; i < aEntry.children.length; i++) {
//XXXzpao Wallpaper patch for bug 514751
if (!aEntry.children[i].url)
continue;
// We're getting sessionrestore.js files with a cycle in the
// doc-identifier graph, likely due to bug 698656. (That is, we have
// an entry where doc identifier A is an ancestor of doc identifier B,
// and another entry where doc identifier B is an ancestor of A.)
//
// If we were to respect these doc identifiers, we'd create a cycle in
// the SHEntries themselves, which causes the docshell to loop forever
// when it looks for the root SHEntry.
//
// So as a hack to fix this, we restrict the scope of a doc identifier
// to be a node's siblings and cousins, and pass childDocIdents, not
// aDocIdents, to _deserializeHistoryEntry. That is, we say that two
// SHEntries with the same doc identifier have the same document iff
// they have the same parent or their parents have the same document.
shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap,
childDocIdents), i);
}
}
return shEntry;
},
/** /**
* Accumulates a list of frames that need to be restored for the * Accumulates a list of frames that need to be restored for the
* given browser element. A frame is only restored if its current * given browser element. A frame is only restored if its current
@ -3508,7 +3356,7 @@ let SessionStoreInternal = {
/** /**
* Determine if we can restore history into this tab. * Determine if we can restore history into this tab.
* This will be false when a tab has been removed (usually between * This will be false when a tab has been removed (usually between
* restoreHistoryPrecursor && restoreHistory) or if the tab is still marked * restoreTabs && restoreHistory) or if the tab is still marked
* as loading. * as loading.
* *
* @param aTab * @param aTab
@ -3835,11 +3683,11 @@ let SessionStoreInternal = {
} }
else if (previousState == TAB_STATE_NEEDS_RESTORE) { else if (previousState == TAB_STATE_NEEDS_RESTORE) {
// Make sure the session history listener is removed. This is normally // Make sure the session history listener is removed. This is normally
// done in restoreTab, but this tab is being removed before that gets called. // done in restoreTabContent, but this tab is being removed before that gets called.
this._removeSHistoryListener(aTab); this._removeSHistoryListener(aTab);
// Make sure that the tab is removed from the list of tabs to restore. // Make sure that the tab is removed from the list of tabs to restore.
// Again, this is normally done in restoreTab, but that isn't being called // Again, this is normally done in restoreTabContent, but that isn't being called
// for this tab. // for this tab.
TabRestoreQueue.remove(aTab); TabRestoreQueue.remove(aTab);
} }
@ -4129,9 +3977,9 @@ SessionStoreSHistoryListener.prototype = {
}, },
OnHistoryReload: function(aReloadURI, aReloadFlags) { OnHistoryReload: function(aReloadURI, aReloadFlags) {
// On reload, we want to make sure that session history loads the right // On reload, we want to make sure that session history loads the right
// URI. In order to do that, we will juet call restoreTab. That will remove // URI. In order to do that, we will juet call restoreTabContent. That will remove
// the history listener and load the right URI. // the history listener and load the right URI.
SessionStoreInternal.restoreTab(this.tab); SessionStoreInternal.restoreTabContent(this.tab);
// Returning false will stop the load that docshell is attempting. // Returning false will stop the load that docshell is attempting.
return false; return false;
} }

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

@ -404,7 +404,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
DebuggerController.SourceScripts.togglePrettyPrint(source) DebuggerController.SourceScripts.togglePrettyPrint(source)
.then(resetEditor, printError) .then(resetEditor, printError)
.then(DebuggerView.showEditor); .then(DebuggerView.showEditor)
.then(this.updateToolbarButtonsState);
}, },
/** /**

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

@ -128,6 +128,7 @@ skip-if = true
[browser_dbg_pretty-print-09.js] [browser_dbg_pretty-print-09.js]
[browser_dbg_pretty-print-10.js] [browser_dbg_pretty-print-10.js]
[browser_dbg_pretty-print-11.js] [browser_dbg_pretty-print-11.js]
[browser_dbg_pretty-print-12.js]
[browser_dbg_progress-listener-bug.js] [browser_dbg_progress-listener-bug.js]
[browser_dbg_reload-preferred-script-01.js] [browser_dbg_reload-preferred-script-01.js]
[browser_dbg_reload-preferred-script-02.js] [browser_dbg_reload-preferred-script-02.js]

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

@ -0,0 +1,54 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that we don't leave the pretty print button checked when we fail to
* pretty print a source (because it isn't a JS file, for example).
*/
const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
waitForSourceShown(gPanel, "")
.then(() => {
let shown = ensureSourceIs(gPanel, TAB_URL, true)
gSources.selectedValue = TAB_URL;
return shown;
})
.then(clickPrettyPrintButton)
.then(testButtonIsntChecked)
.then(() => closeDebuggerAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
});
});
}
function clickPrettyPrintButton() {
gDebugger.document.getElementById("pretty-print").click();
}
function testButtonIsntChecked() {
is(gDebugger.document.getElementById("pretty-print").checked, false,
"The button shouldn't be checked after trying to pretty print a non-js file.");
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;
gSources = null;
});

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

@ -54,6 +54,10 @@
<checkbox label="&options.enablePersistentLogging.label;" <checkbox label="&options.enablePersistentLogging.label;"
tooltiptext="&options.enablePersistentLogging.tooltip;" tooltiptext="&options.enablePersistentLogging.tooltip;"
data-pref="devtools.webconsole.persistlog"/> data-pref="devtools.webconsole.persistlog"/>
<checkbox id="webconsole-timestamp-messages"
label="&options.timestampMessages.label;"
tooltiptext="&options.timestampMessages.tooltip;"
data-pref="devtools.webconsole.timestampMessages"/>
</vbox> </vbox>
<label value="&options.profiler.label;"/> <label value="&options.profiler.label;"/>
<vbox id="profiler-options" class="options-groupbox"> <vbox id="profiler-options" class="options-groupbox">

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

@ -239,3 +239,4 @@ skip-if = os == "linux"
[browser_webconsole_view_source.js] [browser_webconsole_view_source.js]
[browser_webconsole_reflow.js] [browser_webconsole_reflow.js]
[browser_webconsole_log_file_filter.js] [browser_webconsole_log_file_filter.js]
[browser_webconsole_expandable_timestamps.js]

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

@ -22,6 +22,13 @@ function testFilterButtons(aHud) {
testMenuFilterButton("css"); testMenuFilterButton("css");
testMenuFilterButton("js"); testMenuFilterButton("js");
testMenuFilterButton("logging"); testMenuFilterButton("logging");
testMenuFilterButton("security");
testIsolateFilterButton("net");
testIsolateFilterButton("css");
testIsolateFilterButton("js");
testIsolateFilterButton("logging");
testIsolateFilterButton("security");
finishTest(); finishTest();
} }
@ -72,15 +79,7 @@ function testMenuFilterButton(aCategory) {
"checked after turning off its first menu item"); "checked after turning off its first menu item");
// Turn all the filters off by clicking the main part of the button. // Turn all the filters off by clicking the main part of the button.
let anonymousNodes = hud.ui.document.getAnonymousNodes(button); let subbutton = getMainButton(button);
let subbutton;
for (let i = 0; i < anonymousNodes.length; i++) {
let node = anonymousNodes[i];
if (node.classList.contains("toolbarbutton-menubutton-button")) {
subbutton = node;
break;
}
}
ok(subbutton, "we have the subbutton for category " + aCategory); ok(subbutton, "we have the subbutton for category " + aCategory);
clickButton(subbutton); clickButton(subbutton);
@ -129,10 +128,81 @@ function testMenuFilterButton(aCategory) {
clickButton(subbutton); clickButton(subbutton);
} }
function testIsolateFilterButton(aCategory) {
let selector = ".webconsole-filter-button[category=\"" + aCategory + "\"]";
let targetButton = hudBox.querySelector(selector);
ok(targetButton, "we have the \"" + aCategory + "\" button");
// Get the main part of the filter button.
let subbutton = getMainButton(targetButton);
ok(subbutton, "we have the subbutton for category " + aCategory);
// Turn on all the filters by alt clicking the main part of the button.
altClickButton(subbutton);
ok(isChecked(targetButton), "the button for category " + aCategory +
" is checked after isolating for filter");
// Check if all the filters for the target button are on.
let menuItems = targetButton.querySelectorAll("menuitem");
Array.forEach(menuItems, (item) => {
let prefKey = item.getAttribute("prefKey");
ok(isChecked(item), "menu item " + prefKey + " for category " +
aCategory + " is checked after isolating for " + aCategory);
ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
"turned on after isolating for " + aCategory);
});
// Ensure all other filter buttons are toggled off and their
// associated filters are turned off
let buttons = hudBox.querySelectorAll(".webconsole-filter-button[category]");
Array.forEach(buttons, (filterButton) => {
if (filterButton !== targetButton) {
let category = filterButton.getAttribute("category");
ok(!isChecked(filterButton), "the button for category " +
category + " is unchecked after isolating for " + aCategory);
menuItems = filterButton.querySelectorAll("menuitem");
Array.forEach(menuItems, (item) => {
let prefKey = item.getAttribute("prefKey");
ok(!isChecked(item), "menu item " + prefKey + " for category " +
aCategory + " is unchecked after isolating for " + aCategory);
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
"turned off after isolating for " + aCategory);
});
// Turn all the filters on again by clicking the button.
let mainButton = getMainButton(filterButton);
clickButton(mainButton);
}
});
}
/**
* Return the main part of the target filter button.
*/
function getMainButton(aTargetButton) {
let anonymousNodes = hud.ui.document.getAnonymousNodes(aTargetButton);
let subbutton;
for (let i = 0; i < anonymousNodes.length; i++) {
let node = anonymousNodes[i];
if (node.classList.contains("toolbarbutton-menubutton-button")) {
subbutton = node;
break;
}
}
return subbutton;
}
function clickButton(aNode) { function clickButton(aNode) {
EventUtils.sendMouseEvent({ type: "click" }, aNode); EventUtils.sendMouseEvent({ type: "click" }, aNode);
} }
function altClickButton(aNode) {
EventUtils.sendMouseEvent({ type: "click", altKey: true }, aNode);
}
function chooseMenuItem(aNode) { function chooseMenuItem(aNode) {
let event = document.createEvent("XULCommandEvent"); let event = document.createEvent("XULCommandEvent");
event.initCommandEvent("command", true, true, window, 0, false, false, false, event.initCommandEvent("command", true, true, window, 0, false, false, false,

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

@ -0,0 +1,57 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test for the message timestamps option: check if the preference toggles the
// display of messages in the console output. See bug 722267.
function test()
{
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
let hud;
registerCleanupFunction(() => {
Services.prefs.clearUserPref(PREF_MESSAGE_TIMESTAMP);
});
addTab("data:text/html;charset=utf-8,Web Console test for bug 722267 - " +
"preference for toggling timestamps in messages");
browser.addEventListener("load", function tabLoad() {
browser.removeEventListener("load", tabLoad, true);
openConsole(null, consoleOpened);
}, true);
function consoleOpened(aHud)
{
hud = aHud;
info("console opened");
let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP);
ok(!prefValue, "messages have no timestamp by default (pref check)");
ok(hud.outputNode.classList.contains("hideTimestamps"),
"messages have no timestamp (class name check)");
let toolbox = gDevTools.getToolbox(hud.target);
toolbox.selectTool("options").then(onOptionsPanelSelected);
}
function onOptionsPanelSelected(panel)
{
info("options panel opened");
gDevTools.once("pref-changed", onPrefChanged);
let checkbox = panel.panelDoc.getElementById("webconsole-timestamp-messages");
checkbox.click();
}
function onPrefChanged()
{
info("pref changed");
let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP);
ok(prefValue, "messages have timestamps (pref check)");
ok(!hud.outputNode.classList.contains("hideTimestamps"),
"messages have timestamps (class name check)");
finishTest();
}
}

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

@ -171,6 +171,7 @@ const MAX_LONG_STRING_LENGTH = 200000;
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout"; const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
const PREF_PERSISTLOG = "devtools.webconsole.persistlog"; const PREF_PERSISTLOG = "devtools.webconsole.persistlog";
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
/** /**
* A WebConsoleFrame instance is an interactive console initialized *per target* * A WebConsoleFrame instance is an interactive console initialized *per target*
@ -201,6 +202,7 @@ function WebConsoleFrame(aWebConsoleOwner)
this._toggleFilter = this._toggleFilter.bind(this); this._toggleFilter = this._toggleFilter.bind(this);
this._onPanelSelected = this._onPanelSelected.bind(this); this._onPanelSelected = this._onPanelSelected.bind(this);
this._flushMessageQueue = this._flushMessageQueue.bind(this); this._flushMessageQueue = this._flushMessageQueue.bind(this);
this._onToolboxPrefChanged = this._onToolboxPrefChanged.bind(this);
this._outputTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); this._outputTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._outputTimerInitialized = false; this._outputTimerInitialized = false;
@ -571,6 +573,13 @@ WebConsoleFrame.prototype = {
if (toolbox) { if (toolbox) {
toolbox.on("webconsole-selected", this._onPanelSelected); toolbox.on("webconsole-selected", this._onPanelSelected);
} }
// Toggle the timestamp on preference change
gDevTools.on("pref-changed", this._onToolboxPrefChanged);
this._onToolboxPrefChanged("pref-changed", {
pref: PREF_MESSAGE_TIMESTAMP,
newValue: Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP),
});
}, },
/** /**
@ -801,18 +810,26 @@ WebConsoleFrame.prototype = {
break; break;
} }
// Toggle on the targeted filter button, and if the user alt clicked,
// toggle off all other filter buttons and their associated filters.
let state = target.getAttribute("checked") !== "true"; let state = target.getAttribute("checked") !== "true";
if (aEvent.getModifierState("Alt")) {
let buttons = this.document
.querySelectorAll(".webconsole-filter-button");
Array.forEach(buttons, (button) => {
if (button !== target) {
button.setAttribute("checked", false);
this._setMenuState(button, false);
}
});
state = true;
}
target.setAttribute("checked", state); target.setAttribute("checked", state);
// This is a filter button with a drop-down, and the user clicked the // This is a filter button with a drop-down, and the user clicked the
// main part of the button. Go through all the severities and toggle // main part of the button. Go through all the severities and toggle
// their associated filters. // their associated filters.
let menuItems = target.querySelectorAll("menuitem"); this._setMenuState(target, state);
for (let i = 0; i < menuItems.length; i++) {
menuItems[i].setAttribute("checked", state);
let prefKey = menuItems[i].getAttribute("prefKey");
this.setFilterState(prefKey, state);
}
break; break;
} }
@ -851,6 +868,25 @@ WebConsoleFrame.prototype = {
} }
}, },
/**
* Set the menu attributes for a specific toggle button.
*
* @private
* @param XULElement aTarget
* Button with drop down items to be toggled.
* @param boolean aState
* True if the menu item is being toggled on, and false otherwise.
*/
_setMenuState: function WCF__setMenuState(aTarget, aState)
{
let menuItems = aTarget.querySelectorAll("menuitem");
Array.forEach(menuItems, (item) => {
item.setAttribute("checked", aState);
let prefKey = item.getAttribute("prefKey");
this.setFilterState(prefKey, aState);
});
},
/** /**
* Set the filter state for a specific toggle button. * Set the filter state for a specific toggle button.
* *
@ -2775,6 +2811,29 @@ WebConsoleFrame.prototype = {
}, false); }, false);
}, },
/**
* Handler for the pref-changed event coming from the toolbox.
* Currently this function only handles the timestamps preferences.
*
* @private
* @param object aEvent
* This parameter is a string that holds the event name
* pref-changed in this case.
* @param object aData
* This is the pref-changed data object.
*/
_onToolboxPrefChanged: function WCF__onToolboxPrefChanged(aEvent, aData)
{
if (aData.pref == PREF_MESSAGE_TIMESTAMP) {
if (aData.newValue) {
this.outputNode.classList.remove("hideTimestamps");
}
else {
this.outputNode.classList.add("hideTimestamps");
}
}
},
/** /**
* Copies the selected items to the system clipboard. * Copies the selected items to the system clipboard.
* *
@ -2885,6 +2944,8 @@ WebConsoleFrame.prototype = {
toolbox.off("webconsole-selected", this._onPanelSelected); toolbox.off("webconsole-selected", this._onPanelSelected);
} }
gDevTools.off("pref-changed", this._onToolboxPrefChanged);
this._repeatNodes = {}; this._repeatNodes = {};
this._outputQueue = []; this._outputQueue = [];
this._pruneCategoriesQueue = {}; this._pruneCategoriesQueue = {};

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

@ -48,8 +48,8 @@ function goUpdateConsoleCommands() {
<command id="cmd_close" oncommand="goDoCommand('cmd_close');" disabled="true"/> <command id="cmd_close" oncommand="goDoCommand('cmd_close');" disabled="true"/>
</commandset> </commandset>
<keyset id="consoleKeys"> <keyset id="consoleKeys">
<key id="key_fullZoomReduce" key="&fullZoomReduceCmd.commandkey;" command="cmd_fullZoomReduce" modifiers="accel"/> <key id="key_fullZoomReduce" key="&fullZoomReduceCmd.commandkey;" command="cmd_fullZoomReduce" modifiers="accel"/>
<key key="&fullZoomReduceCmd.commandkey2;" command="cmd_fullZoomReduce" modifiers="accel"/> <key key="&fullZoomReduceCmd.commandkey2;" command="cmd_fullZoomReduce" modifiers="accel"/>
<key id="key_fullZoomEnlarge" key="&fullZoomEnlargeCmd.commandkey;" command="cmd_fullZoomEnlarge" modifiers="accel"/> <key id="key_fullZoomEnlarge" key="&fullZoomEnlargeCmd.commandkey;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
<key key="&fullZoomEnlargeCmd.commandkey2;" command="cmd_fullZoomEnlarge" modifiers="accel"/> <key key="&fullZoomEnlargeCmd.commandkey2;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
<key key="&fullZoomEnlargeCmd.commandkey3;" command="cmd_fullZoomEnlarge" modifiers="accel"/> <key key="&fullZoomEnlargeCmd.commandkey3;" command="cmd_fullZoomEnlarge" modifiers="accel"/>

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

@ -109,6 +109,11 @@
<!ENTITY options.enablePersistentLogging.label "Enable persistent logs"> <!ENTITY options.enablePersistentLogging.label "Enable persistent logs">
<!ENTITY options.enablePersistentLogging.tooltip "If you enable this option the Web Console will not clear the output each time you navigate to a new page"> <!ENTITY options.enablePersistentLogging.tooltip "If you enable this option the Web Console will not clear the output each time you navigate to a new page">
<!-- LOCALIZATION NOTE (options.timestampMessages.label): This is the
- label for the checkbox that toggles timestamps in the Web Console -->
<!ENTITY options.timestampMessages.label "Enable timestamps">
<!ENTITY options.timestampMessages.tooltip "If you enable this option commands and output in the Web Console will display a timestamp">
<!-- LOCALIZATION NOTE (options.profiler.label): This is the label for the <!-- LOCALIZATION NOTE (options.profiler.label): This is the label for the
- heading of the group of JavaScript Profiler preferences in the options - heading of the group of JavaScript Profiler preferences in the options
- panel. --> - panel. -->

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

@ -170,9 +170,8 @@ var ContextCommands = {
// Link specific // Link specific
openLinkInNewTab: function cc_openLinkInNewTab() { openLinkInNewTab: function cc_openLinkInNewTab() {
let tab = Browser.addTab(ContextMenuUI.popupState.linkURL, false, Browser.selectedTab); let url = ContextMenuUI.popupState.linkURL;
ContextUI.peekTabs(kOpenInNewTabAnimationDelayMsec); BrowserUI.openLinkInNewTab(url, false, Browser.selectedTab);
Elements.tabList.strip.ensureElementIsVisible(tab.chromeTab);
}, },
copyLink: function cc_copyLink() { copyLink: function cc_copyLink() {

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

@ -161,7 +161,7 @@ var ContextUI = {
* Dismiss tab bar after a delay. Fires context ui events. * Dismiss tab bar after a delay. Fires context ui events.
*/ */
dismissTabsWithDelay: function (aDelay) { dismissTabsWithDelay: function (aDelay) {
aDelay = aDelay || kNewTabAnimationDelayMsec; aDelay = aDelay || kForegroundTabAnimationDelay;
this._clearDelayedTimeout(); this._clearDelayedTimeout();
this._hidingId = setTimeout(function () { this._hidingId = setTimeout(function () {
ContextUI.dismissTabs(); ContextUI.dismissTabs();

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

@ -39,6 +39,9 @@ var APZCObserver = {
handleEvent: function APZC_handleEvent(aEvent) { handleEvent: function APZC_handleEvent(aEvent) {
switch (aEvent.type) { switch (aEvent.type) {
case 'pageshow': case 'pageshow':
if (aEvent.target != Browser.selectedBrowser.contentDocument)
break;
// fall through to TabSelect:
case 'TabSelect': case 'TabSelect':
// ROOT_ID doesn't really identify the view we want. When we call // ROOT_ID doesn't really identify the view we want. When we call
// this on a content document (tab), findElementWithViewId will // this on a content document (tab), findElementWithViewId will

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

@ -66,6 +66,9 @@ XPCOMUtils.defineLazyServiceGetter(window, "gFaviconService",
XPCOMUtils.defineLazyServiceGetter(window, "gFocusManager", XPCOMUtils.defineLazyServiceGetter(window, "gFocusManager",
"@mozilla.org/focus-manager;1", "@mozilla.org/focus-manager;1",
"nsIFocusManager"); "nsIFocusManager");
XPCOMUtils.defineLazyServiceGetter(window, "gEventListenerService",
"@mozilla.org/eventlistenerservice;1",
"nsIEventListenerService");
#ifdef MOZ_CRASHREPORTER #ifdef MOZ_CRASHREPORTER
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
"@mozilla.org/xre/app-info;1", "@mozilla.org/xre/app-info;1",

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

@ -14,12 +14,12 @@ Cu.import("resource://gre/modules/devtools/dbg-server.jsm")
const debugServerStateChanged = "devtools.debugger.remote-enabled"; const debugServerStateChanged = "devtools.debugger.remote-enabled";
const debugServerPortChanged = "devtools.debugger.remote-port"; const debugServerPortChanged = "devtools.debugger.remote-port";
// delay when showing the tab bar briefly after a new (empty) tab opens // delay when showing the tab bar briefly after a new foreground tab opens
const kNewTabAnimationDelayMsec = 1000; const kForegroundTabAnimationDelay = 1000;
// delay when showing the tab bar after opening a link on a new tab // delay when showing the tab bar after opening a new background tab opens
const kOpenInNewTabAnimationDelayMsec = 3000; const kBackgroundTabAnimationDelay = 3000;
// delay before closing tab bar after selecting another tab // delay before closing tab bar after closing or selecting a tab
const kSelectTabAnimationDelayMsec = 500; const kChangeTabAnimationDelay = 500;
/** /**
* Cache of commonly used elements. * Cache of commonly used elements.
@ -173,6 +173,14 @@ var BrowserUI = {
}, },
uninit: function() { uninit: function() {
messageManager.removeMessageListener("DOMTitleChanged", this);
messageManager.removeMessageListener("DOMWillOpenModalDialog", this);
messageManager.removeMessageListener("DOMWindowClose", this);
messageManager.removeMessageListener("Browser:OpenURI", this);
messageManager.removeMessageListener("Browser:SaveAs:Return", this);
messageManager.removeMessageListener("Content:StateChange", this);
messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps); messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps);
Services.obs.removeObserver(this, "handle-xul-text-link"); Services.obs.removeObserver(this, "handle-xul-text-link");
@ -180,7 +188,6 @@ var BrowserUI = {
FlyoutPanelsUI.uninit(); FlyoutPanelsUI.uninit();
MetroDownloadsView.uninit(); MetroDownloadsView.uninit();
SettingsCharm.uninit(); SettingsCharm.uninit();
messageManager.removeMessageListener("Content:StateChange", this);
PageThumbs.uninit(); PageThumbs.uninit();
this.stopDebugServer(); this.stopDebugServer();
}, },
@ -436,10 +443,25 @@ var BrowserUI = {
* See Browser.addTab for more documentation. * See Browser.addTab for more documentation.
*/ */
addAndShowTab: function (aURI, aOwner) { addAndShowTab: function (aURI, aOwner) {
ContextUI.peekTabs(kNewTabAnimationDelayMsec); ContextUI.peekTabs(kForegroundTabAnimationDelay);
return Browser.addTab(aURI || kStartURI, true, aOwner); return Browser.addTab(aURI || kStartURI, true, aOwner);
}, },
/**
* Open a new tab in response to clicking a link in an existing tab.
* See Browser.addTab for more documentation.
*/
openLinkInNewTab: function (aURI, aBringFront, aOwner) {
ContextUI.peekTabs(aBringFront ? kForegroundTabAnimationDelay
: kBackgroundTabAnimationDelay);
let tab = Browser.addTab(aURI, aBringFront, aOwner, {
referrerURI: aOwner.browser.documentURI,
charset: aOwner.browser.characterSet,
});
Elements.tabList.strip.ensureElementIsVisible(tab.chromeTab);
return tab;
},
setOnTabAnimationEnd: function setOnTabAnimationEnd(aCallback) { setOnTabAnimationEnd: function setOnTabAnimationEnd(aCallback) {
Elements.tabs.addEventListener("animationend", function onAnimationEnd() { Elements.tabs.addEventListener("animationend", function onAnimationEnd() {
Elements.tabs.removeEventListener("animationend", onAnimationEnd); Elements.tabs.removeEventListener("animationend", onAnimationEnd);
@ -464,7 +486,7 @@ var BrowserUI = {
this.setOnTabAnimationEnd(function() { this.setOnTabAnimationEnd(function() {
Browser.closeTab(tabToClose, { forceClose: true } ); Browser.closeTab(tabToClose, { forceClose: true } );
if (wasCollapsed) if (wasCollapsed)
ContextUI.dismissTabsWithDelay(kNewTabAnimationDelayMsec); ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay);
}); });
}, },
@ -506,7 +528,7 @@ var BrowserUI = {
selectTabAndDismiss: function selectTabAndDismiss(aTab) { selectTabAndDismiss: function selectTabAndDismiss(aTab) {
this.selectTab(aTab); this.selectTab(aTab);
ContextUI.dismissTabsWithDelay(kSelectTabAnimationDelayMsec); ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay);
}, },
selectTabAtIndex: function selectTabAtIndex(aIndex) { selectTabAtIndex: function selectTabAtIndex(aIndex) {

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

@ -79,6 +79,7 @@ var Browser = {
// Call InputSourceHelper first so global listeners get called before // Call InputSourceHelper first so global listeners get called before
// we start processing input in TouchModule. // we start processing input in TouchModule.
InputSourceHelper.init(); InputSourceHelper.init();
ClickEventHandler.init();
TouchModule.init(); TouchModule.init();
GestureModule.init(); GestureModule.init();
@ -213,6 +214,7 @@ var Browser = {
shutdown: function shutdown() { shutdown: function shutdown() {
APZCObserver.shutdown(); APZCObserver.shutdown();
BrowserUI.uninit(); BrowserUI.uninit();
ClickEventHandler.uninit();
ContentAreaObserver.shutdown(); ContentAreaObserver.shutdown();
Appbar.shutdown(); Appbar.shutdown();
@ -485,7 +487,7 @@ var Browser = {
if (aBringFront) if (aBringFront)
this.selectedTab = newTab; this.selectedTab = newTab;
this._announceNewTab(newTab, params, aBringFront); this._announceNewTab(newTab);
return newTab; return newTab;
}, },
@ -511,7 +513,7 @@ var Browser = {
* helper for addTab related methods. Fires events related to * helper for addTab related methods. Fires events related to
* new tab creation. * new tab creation.
*/ */
_announceNewTab: function _announceNewTab(aTab, aParams, aBringFront) { _announceNewTab: function (aTab) {
let event = document.createEvent("UIEvents"); let event = document.createEvent("UIEvents");
event.initUIEvent("TabOpen", true, false, window, 0); event.initUIEvent("TabOpen", true, false, window, 0);
aTab.chromeTab.dispatchEvent(event); aTab.chromeTab.dispatchEvent(event);
@ -1020,9 +1022,6 @@ Browser.MainDragger.prototype = {
}; };
const OPEN_APPTAB = 100; // Hack until we get a real API
function nsBrowserAccess() { } function nsBrowserAccess() { }
nsBrowserAccess.prototype = { nsBrowserAccess.prototype = {
@ -1032,56 +1031,54 @@ nsBrowserAccess.prototype = {
throw Cr.NS_NOINTERFACE; throw Cr.NS_NOINTERFACE;
}, },
_getOpenAction: function _getOpenAction(aURI, aOpener, aWhere, aContext) {
let where = aWhere;
/*
* aWhere:
* OPEN_DEFAULTWINDOW: default action
* OPEN_CURRENTWINDOW: current window/tab
* OPEN_NEWWINDOW: not allowed, converted to newtab below
* OPEN_NEWTAB: open a new tab
* OPEN_SWITCHTAB: open in an existing tab if it matches, otherwise open
* a new tab. afaict we always open these in the current tab.
*/
if (where == Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
// query standard browser prefs indicating what to do for default action
switch (aContext) {
// indicates this is an open request from a 3rd party app.
case Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL :
where = Services.prefs.getIntPref("browser.link.open_external");
break;
// internal request
default :
where = Services.prefs.getIntPref("browser.link.open_newwindow");
}
}
if (where == Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW) {
Util.dumpLn("Invalid request - we can't open links in new windows.");
where = Ci.nsIBrowserDOMWindow.OPEN_NEWTAB;
}
return where;
},
_getBrowser: function _getBrowser(aURI, aOpener, aWhere, aContext) { _getBrowser: function _getBrowser(aURI, aOpener, aWhere, aContext) {
let isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL); let isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
// We don't allow externals apps opening chrome docs
if (isExternal && aURI && aURI.schemeIs("chrome")) if (isExternal && aURI && aURI.schemeIs("chrome"))
return null; return null;
let location;
let browser;
let loadflags = isExternal ? let loadflags = isExternal ?
Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL : Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
Ci.nsIWebNavigation.LOAD_FLAGS_NONE; Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
let location; let openAction = this._getOpenAction(aURI, aOpener, aWhere, aContext);
if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
switch (aContext) {
case Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL :
aWhere = Services.prefs.getIntPref("browser.link.open_external");
break;
default : // OPEN_NEW or an illegal value
aWhere = Services.prefs.getIntPref("browser.link.open_newwindow");
}
}
let browser; if (openAction == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW) {
let url = aURI ? aURI.spec : "about:blank";
let newWindow = openDialog("chrome://browser/content/browser.xul", "_blank",
"all,dialog=no", url, null, null, null);
// since newWindow.Browser doesn't exist yet, just return null
return null;
} else if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
let owner = isExternal ? null : Browser.selectedTab; let owner = isExternal ? null : Browser.selectedTab;
let tab = Browser.addTab("about:blank", true, owner); let tab = BrowserUI.openLinkInNewTab("about:blank", true, owner);
if (isExternal)
tab.closeOnExit = true;
browser = tab.browser; browser = tab.browser;
} else if (aWhere == OPEN_APPTAB) { } else {
Browser.tabs.forEach(function(aTab) {
if ("appURI" in aTab.browser && aTab.browser.appURI.spec == aURI.spec) {
Browser.selectedTab = aTab;
browser = aTab.browser;
}
});
if (!browser) {
// Make a new tab to hold the app
let tab = Browser.addTab("about:blank", true);
browser = tab.browser;
browser.appURI = aURI;
} else {
// Just use the existing browser, but return null to keep the system from trying to load the URI again
browser = null;
}
} else { // OPEN_CURRENTWINDOW and illegal values
browser = Browser.selectedBrowser; browser = Browser.selectedBrowser;
} }
@ -1097,10 +1094,6 @@ nsBrowserAccess.prototype = {
browser.focus(); browser.focus();
} catch(e) { } } catch(e) { }
// We are loading web content into this window, so make sure content is visible
// XXX Can we remove this? It seems to be reproduced in BrowserUI already.
BrowserUI.showContent();
return browser; return browser;
}, },
@ -1584,3 +1577,68 @@ function rendererFactory(aBrowser, aCanvas) {
return wrapper; return wrapper;
}; };
// Based on ClickEventHandler from /browser/base/content/content.js
let ClickEventHandler = {
init: function () {
gEventListenerService.addSystemEventListener(Elements.browsers, "click", this, true);
},
uninit: function () {
gEventListenerService.removeSystemEventListener(Elements.browsers, "click", this, true);
},
handleEvent: function (aEvent) {
if (!aEvent.isTrusted || aEvent.defaultPrevented) {
return;
}
let [href, node] = this._hrefAndLinkNodeForClickEvent(aEvent);
if (href && (aEvent.button == 1 || aEvent.ctrlKey)) {
// Open link in a new tab for middle-click or ctrl-click
BrowserUI.openLinkInNewTab(href, aEvent.shiftKey, Browser.selectedTab);
}
},
/**
* Extracts linkNode and href for the current click target.
*
* @param event
* The click event.
* @return [href, linkNode].
*
* @note linkNode will be null if the click wasn't on an anchor
* element (or XLink).
*/
_hrefAndLinkNodeForClickEvent: function(event) {
function isHTMLLink(aNode) {
return ((aNode instanceof content.HTMLAnchorElement && aNode.href) ||
(aNode instanceof content.HTMLAreaElement && aNode.href) ||
aNode instanceof content.HTMLLinkElement);
}
let node = event.target;
while (node && !isHTMLLink(node)) {
node = node.parentNode;
}
if (node)
return [node.href, node];
// If there is no linkNode, try simple XLink.
let href, baseURI;
node = event.target;
while (node && !href) {
if (node.nodeType == content.Node.ELEMENT_NODE) {
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href)
baseURI = node.ownerDocument.baseURIObject;
}
node = node.parentNode;
}
// In case of XLink, we don't return the node we got href from since
// callers expect <a>-like elements.
// Note: makeURI() will throw if aUri is not a valid URI.
return [href ? Services.io.newURI(href, null, baseURI).spec : null, null];
}
};

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

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>link click test</title>
</head>
<body>
<a id="link" href="about:blank">link</a>
</body>
</html>

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

@ -0,0 +1,97 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function test() {
waitForExplicitFinish();
runTests();
}
gTests.push({
desc: "regular link click",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabCount = Browser.tabs.length;
EventUtils.sendMouseEvent({type: "click"}, "link", tab.browser.contentWindow);
yield waitForCondition(() => tab.browser.currentURI.spec == "about:blank");
is(Browser.tabs.length, tabCount, "link loaded in the same tab");
}
});
gTests.push({
desc: "middle-click opens link in background tab",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabOpen = waitForEvent(window, "TabOpen");
EventUtils.sendMouseEvent({type: "click", button: 1}, "link", tab.browser.contentWindow);
let event = yield tabOpen;
let newTab = Browser.getTabFromChrome(event.originalTarget);
yield waitForEvent(newTab.browser, "pageshow");
is(newTab.browser.currentURI.spec, "about:blank");
ok(newTab != Browser.selectedTab, "new tab is in the background");
Browser.closeTab(newTab, { forceClose: true });
}
});
gTests.push({
desc: "shift-middle-click opens link in background tab",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabOpen = waitForEvent(window, "TabOpen");
EventUtils.sendMouseEvent({type: "click", button: 1, shiftKey: true}, "link", tab.browser.contentWindow);
let event = yield tabOpen;
let newTab = Browser.getTabFromChrome(event.originalTarget);
yield waitForEvent(newTab.browser, "pageshow");
is(newTab.browser.currentURI.spec, "about:blank");
ok(newTab == Browser.selectedTab, "new tab is in the foreground");
Browser.closeTab(newTab, { forceClose: true });
}
});
gTests.push({
desc: "ctrl-click opens link in background tab",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabOpen = waitForEvent(window, "TabOpen");
EventUtils.sendMouseEvent({type: "click", ctrlKey: true}, "link", tab.browser.contentWindow);
let event = yield tabOpen;
let newTab = Browser.getTabFromChrome(event.originalTarget);
yield waitForEvent(newTab.browser, "pageshow");
is(newTab.browser.currentURI.spec, "about:blank");
ok(newTab != Browser.selectedTab, "new tab is in the background");
Browser.closeTab(newTab, { forceClose: true });
}
});
gTests.push({
desc: "shift-ctrl-click opens link in background tab",
run: function () {
let tab = yield addTab(chromeRoot + "browser_link_click.html");
let tabOpen = waitForEvent(window, "TabOpen");
EventUtils.sendMouseEvent({type: "click", ctrlKey: true, shiftKey: true}, "link", tab.browser.contentWindow);
let event = yield tabOpen;
let newTab = Browser.getTabFromChrome(event.originalTarget);
yield waitForEvent(newTab.browser, "pageshow");
is(newTab.browser.currentURI.spec, "about:blank");
ok(newTab == Browser.selectedTab, "new tab is in the foreground");
Browser.closeTab(newTab, { forceClose: true });
}
});

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

@ -6,6 +6,7 @@ support-files =
browser_context_menu_tests_04.html browser_context_menu_tests_04.html
browser_findbar.html browser_findbar.html
browser_form_auto_complete.html browser_form_auto_complete.html
browser_link_click.html
browser_onscreen_keyboard.html browser_onscreen_keyboard.html
browser_progress_indicator.xul browser_progress_indicator.xul
browser_selection_basic.html browser_selection_basic.html
@ -42,6 +43,7 @@ support-files =
[browser_form_auto_complete.js] [browser_form_auto_complete.js]
[browser_history.js] [browser_history.js]
[browser_inputsource.js] [browser_inputsource.js]
[browser_link_click.js]
[browser_onscreen_keyboard.js] [browser_onscreen_keyboard.js]
[browser_prefs_ui.js] [browser_prefs_ui.js]
[browser_remotetabs.js] [browser_remotetabs.js]

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

@ -112,6 +112,10 @@ a {
align-items: flex-start; align-items: flex-start;
} }
#output-container.hideTimestamps > .message > .timestamp {
display: none;
}
.filtered-by-type, .filtered-by-type,
.filtered-by-string { .filtered-by-string {
display: none; display: none;

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

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [ XPIDL_SOURCES += [
'nsIDomainPolicy.idl',
'nsIPrincipal.idl', 'nsIPrincipal.idl',
'nsIScriptSecurityManager.idl', 'nsIScriptSecurityManager.idl',
'nsISecurityCheckedComponent.idl', 'nsISecurityCheckedComponent.idl',

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

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIURI;
interface nsIDomainSet;
/*
* When a domain policy is instantiated by invoking activateDomainPolicy() on
* nsIScriptSecurityManager, these domain sets are consulted when each new
* global is created (they have no effect on already-created globals).
* If javascript is globally enabled with |javascript.enabled|, the blacklists
* are consulted. If globally disabled, the whitelists are consulted. Lookups
* on blacklist and whitelist happen with contains(), and lookups on
* superBlacklist and superWhitelist happen with containsSuperDomain().
*
* When deactivate() is invoked, the domain sets are emptied, and the
* nsIDomainPolicy ceases to have any effect on the system.
*/
[scriptable, builtinclass, uuid(27b10f54-f34b-42b7-8594-4348d3ad7953)]
interface nsIDomainPolicy : nsISupports
{
readonly attribute nsIDomainSet blacklist;
readonly attribute nsIDomainSet superBlacklist;
readonly attribute nsIDomainSet whitelist;
readonly attribute nsIDomainSet superWhitelist;
void deactivate();
};
[scriptable, builtinclass, uuid(946a01ff-6525-4007-a2c2-447ebe1875d3)]
interface nsIDomainSet : nsISupports
{
/*
* Add a domain to the set. No-op if it already exists.
*/
void add(in nsIURI aDomain);
/*
* Remove a domain from the set. No-op if it doesn't exist.
*/
void remove(in nsIURI aDomain);
/*
* Remove all entries from the set.
*/
void clear();
/*
* Returns true if a given domain is in the set.
*/
bool contains(in nsIURI aDomain);
/*
* Returns true if a given domain is a subdomain of one of the entries in
* the set.
*/
bool containsSuperDomain(in nsIURI aDomain);
};

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

@ -9,8 +9,9 @@
interface nsIURI; interface nsIURI;
interface nsIChannel; interface nsIChannel;
interface nsIDocShell; interface nsIDocShell;
interface nsIDomainPolicy;
[scriptable, uuid(d6475e53-9ece-4dc0-940c-095ac3d85363)] [scriptable, uuid(2911ae60-1b5f-47e6-941e-1bb7b53a167d)]
interface nsIScriptSecurityManager : nsIXPCSecurityManager interface nsIScriptSecurityManager : nsIXPCSecurityManager
{ {
///////////////// Security Checks ////////////////// ///////////////// Security Checks //////////////////
@ -103,24 +104,9 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
in unsigned long flags); in unsigned long flags);
/** /**
* Check that the function 'funObj' is allowed to run on 'targetObj' * Return true if scripts may be executed in the scope of the given global.
*
* Will return error code NS_ERROR_DOM_SECURITY_ERR if the function
* should not run
*
* @param cx The current active JavaScript context.
* @param funObj The function trying to run..
* @param targetObj The object the function will run on.
*/ */
[noscript] void checkFunctionAccess(in JSContextPtr cx, in voidPtr funObj, [noscript,notxpcom] boolean scriptAllowed(in JSObjectPtr aGlobal);
in voidPtr targetObj);
/**
* Return true if content from the given principal is allowed to
* execute scripts.
*/
[noscript] boolean canExecuteScripts(in JSContextPtr cx,
in nsIPrincipal principal);
///////////////// Principals /////////////////////// ///////////////// Principals ///////////////////////
/** /**
@ -216,6 +202,13 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
* script to check whether a given principal is system. * script to check whether a given principal is system.
*/ */
boolean isSystemPrincipal(in nsIPrincipal aPrincipal); boolean isSystemPrincipal(in nsIPrincipal aPrincipal);
%{C++
bool IsSystemPrincipal(nsIPrincipal* aPrincipal) {
bool isSystem = false;
IsSystemPrincipal(aPrincipal, &isSystem);
return isSystem;
}
%}
/** /**
* Same as getSubjectPrincipal(), only faster. cx must *never* be * Same as getSubjectPrincipal(), only faster. cx must *never* be
@ -236,6 +229,29 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
* inMozBrowser has to be true if the app is inside a mozbrowser iframe. * inMozBrowser has to be true if the app is inside a mozbrowser iframe.
*/ */
AUTF8String getJarPrefix(in unsigned long appId, in boolean inMozBrowser); AUTF8String getJarPrefix(in unsigned long appId, in boolean inMozBrowser);
/**
* Per-domain controls to enable and disable script. This system is designed
* to be used by at most one consumer, and enforces this with its semantics.
*
* Initially, domainPolicyActive is false. When activateDomainPolicy() is
* invoked, domainPolicyActive becomes true, and subsequent calls to
* activateDomainPolicy() will fail until deactivate() is invoked on the
* nsIDomainPolicy returned from activateDomainPolicy(). At this point,
* domainPolicyActive becomes false again, and a new consumer may acquire
* control of the system by invoking activateDomainPolicy().
*/
nsIDomainPolicy activateDomainPolicy();
readonly attribute boolean domainPolicyActive;
/**
* Query mechanism for the above policy.
*
* If domainPolicyEnabled is false, this simply returns the current value
* of javascript.enabled. Otherwise, it returns the same value, but taking
* the various blacklist/whitelist exceptions into account.
*/
bool policyAllowsScript(in nsIURI aDomain);
}; };
%{C++ %{C++

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

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 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 DomainPolicy_h__
#define DomainPolicy_h__
#include "nsIDomainPolicy.h"
#include "nsTHashtable.h"
#include "nsURIHashKey.h"
namespace mozilla {
// The name "DomainPolicy" conflicts with some of the old-style policy machinery
// in nsScriptSecurityManager.cpp, which needs to #include this file. So we
// temporarily use a sub-namespace until that machinery goes away in bug 913734.
namespace hotness {
class DomainPolicy : public nsIDomainPolicy
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINPOLICY
DomainPolicy();
virtual ~DomainPolicy();
private:
nsCOMPtr<nsIDomainSet> mBlacklist;
nsCOMPtr<nsIDomainSet> mSuperBlacklist;
nsCOMPtr<nsIDomainSet> mWhitelist;
nsCOMPtr<nsIDomainSet> mSuperWhitelist;
};
class DomainSet : public nsIDomainSet
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINSET
DomainSet() {}
virtual ~DomainSet() {}
protected:
nsTHashtable<nsURIHashKey> mHashTable;
};
} /* namespace hotness */
} /* namespace mozilla */
#endif /* DomainPolicy_h__ */

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

@ -362,6 +362,8 @@ public:
AppAttributesEqual(nsIPrincipal* aFirst, AppAttributesEqual(nsIPrincipal* aFirst,
nsIPrincipal* aSecond); nsIPrincipal* aSecond);
void DeactivateDomainPolicy();
private: private:
// GetScriptSecurityManager is the only call that can make one // GetScriptSecurityManager is the only call that can make one
@ -381,7 +383,7 @@ private:
// Returns null if a principal cannot be found; generally callers // Returns null if a principal cannot be found; generally callers
// should error out at that point. // should error out at that point.
static nsIPrincipal* doGetObjectPrincipal(JS::Handle<JSObject*> obj); static nsIPrincipal* doGetObjectPrincipal(JSObject* obj);
// Returns null if a principal cannot be found. Note that rv can be NS_OK // Returns null if a principal cannot be found. Note that rv can be NS_OK
// when this happens -- this means that there was no JS running. // when this happens -- this means that there was no JS running.
@ -462,15 +464,6 @@ private:
nsIPrincipal* aSubjectPrincipal, nsIPrincipal* aSubjectPrincipal,
const char* aObjectSecurityLevel); const char* aObjectSecurityLevel);
/**
* Helper for CanExecuteScripts that allows the caller to specify
* whether execution should be allowed if cx has no
* nsIScriptContext.
*/
nsresult
CanExecuteScripts(JSContext* cx, nsIPrincipal *aPrincipal,
bool aAllowIfNoScriptContext, bool *result);
nsresult nsresult
Init(); Init();
@ -496,6 +489,10 @@ private:
bool mIsJavaScriptEnabled; bool mIsJavaScriptEnabled;
bool mPolicyPrefsChanged; bool mPolicyPrefsChanged;
// This machinery controls new-style domain policies. The old-style
// policy machinery will be removed soon.
nsCOMPtr<nsIDomainPolicy> mDomainPolicy;
static bool sStrictFileOriginPolicy; static bool sStrictFileOriginPolicy;
static nsIIOService *sIOService; static nsIIOService *sIOService;

165
caps/src/DomainPolicy.cpp Normal file
Просмотреть файл

@ -0,0 +1,165 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=4 et sw=4 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 "DomainPolicy.h"
#include "nsScriptSecurityManager.h"
namespace mozilla {
namespace hotness {
NS_IMPL_ISUPPORTS1(DomainPolicy, nsIDomainPolicy)
DomainPolicy::DomainPolicy() : mBlacklist(new DomainSet())
, mSuperBlacklist(new DomainSet())
, mWhitelist(new DomainSet())
, mSuperWhitelist(new DomainSet())
{}
DomainPolicy::~DomainPolicy()
{
// The SSM holds a strong ref to the DomainPolicy until Deactivate() is
// invoked, so we should never hit the destructor until that happens.
MOZ_ASSERT(!mBlacklist && !mSuperBlacklist &&
!mWhitelist && !mSuperWhitelist);
}
NS_IMETHODIMP
DomainPolicy::GetBlacklist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mBlacklist;
set.forget(aSet);
return NS_OK;
}
NS_IMETHODIMP
DomainPolicy::GetSuperBlacklist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mSuperBlacklist;
set.forget(aSet);
return NS_OK;
}
NS_IMETHODIMP
DomainPolicy::GetWhitelist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mWhitelist;
set.forget(aSet);
return NS_OK;
}
NS_IMETHODIMP
DomainPolicy::GetSuperWhitelist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mSuperWhitelist;
set.forget(aSet);
return NS_OK;
}
NS_IMETHODIMP
DomainPolicy::Deactivate()
{
// Clear the hashtables first to free up memory, since script might
// hold the doomed sets alive indefinitely.
mBlacklist->Clear();
mSuperBlacklist->Clear();
mWhitelist->Clear();
mSuperWhitelist->Clear();
// Null them out.
mBlacklist = nullptr;
mSuperBlacklist = nullptr;
mWhitelist = nullptr;
mSuperWhitelist = nullptr;
// Inform the SSM.
nsScriptSecurityManager::GetScriptSecurityManager()->DeactivateDomainPolicy();
return NS_OK;
}
static already_AddRefed<nsIURI>
GetCanonicalClone(nsIURI* aURI)
{
nsCOMPtr<nsIURI> clone;
nsresult rv = aURI->Clone(getter_AddRefs(clone));
NS_ENSURE_SUCCESS(rv, nullptr);
rv = clone->SetUserPass(EmptyCString());
NS_ENSURE_SUCCESS(rv, nullptr);
rv = clone->SetPath(EmptyCString());
NS_ENSURE_SUCCESS(rv, nullptr);
return clone.forget();
}
NS_IMPL_ISUPPORTS1(DomainSet, nsIDomainSet)
NS_IMETHODIMP
DomainSet::Add(nsIURI* aDomain)
{
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
mHashTable.PutEntry(clone);
return NS_OK;
}
NS_IMETHODIMP
DomainSet::Remove(nsIURI* aDomain)
{
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
mHashTable.RemoveEntry(clone);
return NS_OK;
}
NS_IMETHODIMP
DomainSet::Clear()
{
mHashTable.Clear();
return NS_OK;
}
NS_IMETHODIMP
DomainSet::Contains(nsIURI* aDomain, bool* aContains)
{
*aContains = false;
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
*aContains = mHashTable.Contains(clone);
return NS_OK;
}
NS_IMETHODIMP
DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains)
{
*aContains = false;
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
nsAutoCString domain;
nsresult rv = clone->GetHost(domain);
NS_ENSURE_SUCCESS(rv, rv);
while (true) {
// Check the current domain.
if (mHashTable.Contains(clone)) {
*aContains = true;
return NS_OK;
}
// Chop off everything before the first dot, or break if there are no
// dots left.
int32_t index = domain.Find(".");
if (index == kNotFound)
break;
domain.Assign(Substring(domain, index + 1));
rv = clone->SetHost(domain);
NS_ENSURE_SUCCESS(rv, rv);
}
// No match.
return NS_OK;
}
} /* namespace hotness */
} /* namespace mozilla */

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

@ -7,6 +7,7 @@
MODULE = 'caps' MODULE = 'caps'
SOURCES += [ SOURCES += [
'DomainPolicy.cpp',
'nsJSPrincipals.cpp', 'nsJSPrincipals.cpp',
'nsNullPrincipal.cpp', 'nsNullPrincipal.cpp',
'nsNullPrincipalURI.cpp', 'nsNullPrincipalURI.cpp',

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

@ -21,6 +21,7 @@
#include "nsSystemPrincipal.h" #include "nsSystemPrincipal.h"
#include "nsPrincipal.h" #include "nsPrincipal.h"
#include "nsNullPrincipal.h" #include "nsNullPrincipal.h"
#include "DomainPolicy.h"
#include "nsXPIDLString.h" #include "nsXPIDLString.h"
#include "nsCRT.h" #include "nsCRT.h"
#include "nsCRTGlue.h" #include "nsCRTGlue.h"
@ -63,6 +64,7 @@
#include "mozilla/StaticPtr.h" #include "mozilla/StaticPtr.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsCxPusher.h" #include "nsCxPusher.h"
#include "nsJSUtils.h"
// This should be probably defined on some other place... but I couldn't find it // This should be probably defined on some other place... but I couldn't find it
#define WEBAPPS_PERM_NAME "webapps-manage" #define WEBAPPS_PERM_NAME "webapps-manage"
@ -183,12 +185,6 @@ GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
return GetOriginFromURI(uri, aOrigin); return GetOriginFromURI(uri, aOrigin);
} }
static nsIScriptContext *
GetScriptContext(JSContext *cx)
{
return GetScriptContextFromJSContext(cx);
}
inline void SetPendingException(JSContext *cx, const char *aMsg) inline void SetPendingException(JSContext *cx, const char *aMsg)
{ {
JS_ReportError(cx, "%s", aMsg); JS_ReportError(cx, "%s", aMsg);
@ -1601,173 +1597,38 @@ nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
return rv; return rv;
} }
NS_IMETHODIMP bool
nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj, nsScriptSecurityManager::ScriptAllowed(JSObject *aGlobal)
void *aTargetObj)
{ {
// This check is called for event handlers MOZ_ASSERT(aGlobal);
nsresult rv; MOZ_ASSERT(JS_IsGlobalObject(aGlobal) || js::IsOuterObject(aGlobal));
JS::Rooted<JSObject*> rootedFunObj(aCx, static_cast<JSObject*>(aFunObj)); AutoJSContext cx;
nsIPrincipal* subject = doGetObjectPrincipal(rootedFunObj); JS::RootedObject global(cx, js::UncheckedUnwrap(aGlobal, /* stopAtOuter = */ false));
if (!subject)
return NS_ERROR_FAILURE;
if (subject == mSystemPrincipal) // Check the bits on the compartment private.
// This is the system principal: just allow access xpc::Scriptability& scriptability = xpc::Scriptability::Get(aGlobal);
return NS_OK; if (!scriptability.Allowed()) {
return false;
// Check if the principal the function was compiled under is
// allowed to execute scripts.
bool result;
rv = CanExecuteScripts(aCx, subject, true, &result);
if (NS_FAILED(rv))
return rv;
if (!result)
return NS_ERROR_DOM_SECURITY_ERR;
if (!aTargetObj) {
// We're done here
return NS_OK;
} }
/* // If the compartment is immune to script policy, we're done.
** Get origin of subject and object and compare. if (scriptability.IsImmuneToScriptPolicy()) {
*/ return true;
JS::Rooted<JSObject*> obj(aCx, (JSObject*)aTargetObj);
nsIPrincipal* object = doGetObjectPrincipal(obj);
if (!object)
return NS_ERROR_FAILURE;
bool subsumes;
rv = subject->Subsumes(object, &subsumes);
if (NS_SUCCEEDED(rv) && !subsumes) {
rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
return rv;
}
NS_IMETHODIMP
nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
nsIPrincipal *aPrincipal,
bool *result)
{
return CanExecuteScripts(cx, aPrincipal, false, result);
}
nsresult
nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
nsIPrincipal *aPrincipal,
bool aAllowIfNoScriptContext,
bool *result)
{
*result = false;
if (aPrincipal == mSystemPrincipal)
{
// Even if JavaScript is disabled, we must still execute system scripts
*result = true;
return NS_OK;
} }
// Same thing for nsExpandedPrincipal, which is pseudo-privileged. // Check for a per-site policy.
nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal);
if (ep)
{
*result = true;
return NS_OK;
}
//-- See if the current window allows JS execution
nsIScriptContext *scriptContext = GetScriptContext(cx);
if (!scriptContext) {
if (aAllowIfNoScriptContext) {
*result = true;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
if (!scriptContext->GetScriptsEnabled()) {
// No scripting on this context, folks
*result = false;
return NS_OK;
}
nsIScriptGlobalObject *sgo = scriptContext->GetGlobalObject();
if (!sgo) {
return NS_ERROR_FAILURE;
}
// window can be null here if we're running with a non-DOM window
// as the script global (i.e. a XUL prototype document).
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
nsCOMPtr<nsIDocShell> docshell;
nsresult rv;
if (window) {
docshell = window->GetDocShell();
}
if (docshell) {
rv = docshell->GetCanExecuteScripts(result);
if (NS_FAILED(rv)) return rv;
if (!*result) return NS_OK;
}
// OK, the docshell doesn't have script execution explicitly disabled.
// Check whether our URI is an "about:" URI that allows scripts. If it is,
// we need to allow JS to run. In this case, don't apply the JS enabled
// pref or policies. On failures, just press on and don't do this special
// case.
nsCOMPtr<nsIURI> principalURI;
aPrincipal->GetURI(getter_AddRefs(principalURI));
if (!principalURI) {
// Broken principal of some sort. Disallow.
*result = false;
return NS_ERROR_UNEXPECTED;
}
bool isAbout;
rv = principalURI->SchemeIs("about", &isAbout);
if (NS_SUCCEEDED(rv) && isAbout) {
nsCOMPtr<nsIAboutModule> module;
rv = NS_GetAboutModule(principalURI, getter_AddRefs(module));
if (NS_SUCCEEDED(rv)) {
uint32_t flags;
rv = module->GetURIFlags(principalURI, &flags);
if (NS_SUCCEEDED(rv) &&
(flags & nsIAboutModule::ALLOW_SCRIPT)) {
*result = true;
return NS_OK;
}
}
}
*result = mIsJavaScriptEnabled;
if (!*result)
return NS_OK; // Do not run scripts
//-- Check for a per-site policy
static const char jsPrefGroupName[] = "javascript"; static const char jsPrefGroupName[] = "javascript";
ClassInfoData nameData(nullptr, jsPrefGroupName); ClassInfoData nameData(nullptr, jsPrefGroupName);
SecurityLevel secLevel; SecurityLevel secLevel;
rv = LookupPolicy(aPrincipal, nameData, EnabledID(), nsresult rv = LookupPolicy(doGetObjectPrincipal(global), nameData,
nsIXPCSecurityManager::ACCESS_GET_PROPERTY, EnabledID(),
nullptr, &secLevel); nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS) nullptr, &secLevel);
{ if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS) {
*result = false; return false;
return rv;
} }
//-- Nobody vetoed, so allow the JS to run. return true;
*result = true;
return NS_OK;
} }
///////////////// Principals /////////////////////// ///////////////// Principals ///////////////////////
@ -1964,7 +1825,7 @@ nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
// static // static
nsIPrincipal* nsIPrincipal*
nsScriptSecurityManager::doGetObjectPrincipal(JS::Handle<JSObject*> aObj) nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
{ {
JSCompartment *compartment = js::GetObjectCompartment(aObj); JSCompartment *compartment = js::GetObjectCompartment(aObj);
JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment); JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
@ -2291,6 +2152,9 @@ nsScriptSecurityManager::~nsScriptSecurityManager(void)
if(mDefaultPolicy) if(mDefaultPolicy)
mDefaultPolicy->Drop(); mDefaultPolicy->Drop();
delete mCapabilities; delete mCapabilities;
if (mDomainPolicy)
mDomainPolicy->Deactivate();
MOZ_ASSERT(!mDomainPolicy);
} }
void void
@ -2716,3 +2580,74 @@ nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId,
mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix); mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv)
{
*aRv = !!mDomainPolicy;
return NS_OK;
}
NS_IMETHODIMP
nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv)
{
// We only allow one domain policy at a time. The holder of the previous
// policy must explicitly deactivate it first.
if (mDomainPolicy) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
mDomainPolicy = new mozilla::hotness::DomainPolicy();
nsCOMPtr<nsIDomainPolicy> ptr = mDomainPolicy;
ptr.forget(aRv);
return NS_OK;
}
// Intentionally non-scriptable. Script must have a reference to the
// nsIDomainPolicy to deactivate it.
void
nsScriptSecurityManager::DeactivateDomainPolicy()
{
mDomainPolicy = nullptr;
}
NS_IMETHODIMP
nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
{
nsresult rv;
// Compute our rule. If we don't have any domain policy set up that might
// provide exceptions to this rule, we're done.
*aRv = mIsJavaScriptEnabled;
if (!mDomainPolicy) {
return NS_OK;
}
// We have a domain policy. Grab the appropriate set of exceptions to the
// rule (either the blacklist or the whitelist, depending on whether script
// is enabled or disabled by default).
nsCOMPtr<nsIDomainSet> exceptions;
nsCOMPtr<nsIDomainSet> superExceptions;
if (*aRv) {
mDomainPolicy->GetBlacklist(getter_AddRefs(exceptions));
mDomainPolicy->GetSuperBlacklist(getter_AddRefs(superExceptions));
} else {
mDomainPolicy->GetWhitelist(getter_AddRefs(exceptions));
mDomainPolicy->GetSuperWhitelist(getter_AddRefs(superExceptions));
}
bool contains;
rv = exceptions->Contains(aURI, &contains);
NS_ENSURE_SUCCESS(rv, rv);
if (contains) {
*aRv = !*aRv;
return NS_OK;
}
rv = superExceptions->ContainsSuperDomain(aURI, &contains);
NS_ENSURE_SUCCESS(rv, rv);
if (contains) {
*aRv = !*aRv;
}
return NS_OK;
}

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

@ -1,10 +0,0 @@
#
# 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/.
# jarPrefix test doesn't work on Windows, see bug 776296.
ifneq ($(OS_ARCH),WINNT)
MOCHITEST_CHROME_FILES = test_principal_jarprefix_origin_appid_appstatus.html \
$(NULL)
endif

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

@ -0,0 +1,4 @@
[test_disableScript.xul]
[test_principal_jarprefix_origin_appid_appstatus.html]
# jarPrefix test doesn't work on Windows, see bug 776296.
skip-if = os == "win"

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

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<script>
var gFiredOnload = false;
var gFiredOnclick = false;
</script>
</head>
<body onload="gFiredOnload = true;" onclick="gFiredOnclick = true;">
</body>
</html>

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

@ -1,4 +1,6 @@
[DEFAULT] [DEFAULT]
support-files =
file_disableScript.html
[test_app_principal_equality.html] [test_app_principal_equality.html]
[test_bug246699.html] [test_bug246699.html]

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

@ -5,4 +5,5 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
MOCHITEST_MANIFESTS += ['mochitest.ini'] MOCHITEST_MANIFESTS += ['mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']

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

@ -0,0 +1,321 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=840488
-->
<window title="Mozilla Bug 840488"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=840488"
target="_blank">Mozilla Bug 840488</a>
</body>
<iframe id="root" name="root" onload="go();" type="content"/>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for all the different ways that script can be disabled for a given global. **/
SimpleTest.waitForExplicitFinish();
const Cu = Components.utils;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const ssm = Services.scriptSecurityManager;
function makeURI(uri) { return Services.io.newURI(uri, null, null); }
const path = "/tests/caps/tests/mochitest/file_disableScript.html";
const uri = "http://www.example.com" + path;
var rootFrame = document.getElementById('root');
rootFrame.setAttribute('src', uri + "?name=rootframe");
function navigateFrame(ifr, src) {
let deferred = Promise.defer();
function onload() {
ifr.removeEventListener('load', onload);
deferred.resolve();
}
ifr.addEventListener('load', onload, false);
ifr.setAttribute('src', src);
return deferred.promise;
}
function navigateBack(ifr) {
let deferred = Promise.defer();
// pageshow events don't fire on the iframe element, so we need to use the
// chrome event handler for the docshell.
var browser = ifr.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
function onpageshow(evt) {
info("Navigated back. Persisted: " + evt.persisted);
browser.removeEventListener('pageshow', onpageshow);
deferred.resolve();
}
browser.addEventListener('pageshow', onpageshow, false);
ifr.contentWindow.history.back();
return deferred.promise;
}
function addFrame(parentWin, name, expectOnload) {
let ifr = parentWin.document.createElement('iframe');
parentWin.document.body.appendChild(ifr);
ifr.setAttribute('name', name);
let deferred = Promise.defer();
// We need to append 'name' to avoid running afoul of recursive frame detection.
let frameURI = uri + "?name=" + name;
navigateFrame(ifr, frameURI).then(function() {
is(ifr.contentWindow.location, frameURI, "Successful load");
is(!!ifr.contentWindow.wrappedJSObject.gFiredOnload, expectOnload,
"onload should only fire when scripts are enabled");
deferred.resolve();
});
return deferred.promise;
}
function checkScriptEnabled(win, expectEnabled) {
win.wrappedJSObject.gFiredOnclick = false;
win.document.body.dispatchEvent(new win.Event('click'));
is(win.wrappedJSObject.gFiredOnclick, expectEnabled, "Checking script-enabled for " + win.name + " (" + win.location + ")");
}
function setScriptEnabledForDocShell(win, enabled) {
win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.allowJavascript = enabled;
}
function testList(expectEnabled, win, list, idx) {
let idx = idx || 0;
let deferred = Promise.defer();
let target = list[idx] + path;
info("Testing scriptability for: " + target + ". expecting " + expectEnabled);
navigateFrame(win.frameElement, target).then(function() {
checkScriptEnabled(win, expectEnabled);
if (idx == list.length - 1)
deferred.resolve();
else
testList(expectEnabled, win, list, idx + 1).then(function() { deferred.resolve(); });
});
return deferred.promise;
}
function testDomainPolicy(defaultScriptability, exceptions, superExceptions,
exempt, notExempt, set, superSet, win) {
// Populate our sets.
for (var e of exceptions)
set.add(makeURI(e));
for (var e of superExceptions)
superSet.add(makeURI(e));
return testList(defaultScriptability, win, notExempt).then(function() {
return testList(!defaultScriptability, win, exempt);
});
}
function setScriptEnabledForBrowser(enabled) {
var prefname = "javascript.enabled";
Services.prefs.setBoolPref(prefname, enabled);
}
function reloadFrame(frame) {
let deferred = Promise.defer();
frame.addEventListener('load', function onload() {
deferred.resolve();
frame.removeEventListener('load', onload);
}, false);
frame.contentWindow.location.reload(true);
return deferred.promise;
}
function go() {
rootFrame.setAttribute('onload', null);
// Test simple docshell enable/disable.
var rootWin = rootFrame.contentWindow;
checkScriptEnabled(rootWin, true);
setScriptEnabledForDocShell(rootWin, false);
checkScriptEnabled(rootWin, false);
setScriptEnabledForDocShell(rootWin, true);
checkScriptEnabled(rootWin, true);
// Play around with the docshell tree and make sure everything works as
// we expect.
addFrame(rootWin, 'parent', true).then(function() {
checkScriptEnabled(rootWin[0], true);
return addFrame(rootWin[0], 'childA', true);
}).then(function() {
checkScriptEnabled(rootWin[0][0], true);
setScriptEnabledForDocShell(rootWin[0], false);
checkScriptEnabled(rootWin, true);
checkScriptEnabled(rootWin[0], false);
checkScriptEnabled(rootWin[0][0], false);
return addFrame(rootWin[0], 'childB', false);
}).then(function() {
checkScriptEnabled(rootWin[0][1], false);
setScriptEnabledForDocShell(rootWin[0][0], false);
setScriptEnabledForDocShell(rootWin[0], true);
checkScriptEnabled(rootWin[0], true);
checkScriptEnabled(rootWin[0][0], false);
setScriptEnabledForDocShell(rootWin[0][0], true);
// Flags are inherited from the parent docshell at attach time. Note that
// the flag itself is inherited, regardless of whether or not scripts are
// currently allowed on the parent (which could depend on the parent's
// parent). Check that.
checkScriptEnabled(rootWin[0][1], false);
setScriptEnabledForDocShell(rootWin[0], false);
setScriptEnabledForDocShell(rootWin[0][1], true);
return addFrame(rootWin[0][1], 'grandchild', false);
}).then(function() {
checkScriptEnabled(rootWin[0], false);
checkScriptEnabled(rootWin[0][1], false);
checkScriptEnabled(rootWin[0][1][0], false);
setScriptEnabledForDocShell(rootWin[0], true);
checkScriptEnabled(rootWin[0], true);
checkScriptEnabled(rootWin[0][1], true);
checkScriptEnabled(rootWin[0][1][0], true);
// Try navigating two frames, then munging docshell scriptability, then
// pulling the frames out of the bfcache to make sure that flags are
// properly propagated to inactive inner windows. We do this both for an
// 'own' docshell, as well as for an ancestor docshell.
return navigateFrame(rootWin[0][0].frameElement, rootWin[0][0].location + '-navigated');
}).then(function() { return navigateFrame(rootWin[0][1][0].frameElement, rootWin[0][1][0].location + '-navigated'); })
.then(function() {
checkScriptEnabled(rootWin[0][0], true);
checkScriptEnabled(rootWin[0][1][0], true);
setScriptEnabledForDocShell(rootWin[0][0], false);
setScriptEnabledForDocShell(rootWin[0][1], false);
checkScriptEnabled(rootWin[0][0], false);
checkScriptEnabled(rootWin[0][1][0], false);
return navigateBack(rootWin[0][0].frameElement);
}).then(function() { return navigateBack(rootWin[0][1][0].frameElement); })
.then(function() {
checkScriptEnabled(rootWin[0][0], false);
checkScriptEnabled(rootWin[0][1][0], false);
// Disable JS via the global pref pref. This is only guaranteed to have an effect
// for subsequent loads.
setScriptEnabledForBrowser(false);
return reloadFrame(rootFrame);
}).then(function() {
checkScriptEnabled(rootWin, false);
setScriptEnabledForBrowser(true);
return reloadFrame(rootFrame);
}).then(function() {
checkScriptEnabled(rootWin, true);
// Play around with dynamically blocking script for a given global.
// This takes effect immediately.
Cu.blockScriptForGlobal(rootWin);
Cu.blockScriptForGlobal(rootWin);
Cu.unblockScriptForGlobal(rootWin);
checkScriptEnabled(rootWin, false);
Cu.unblockScriptForGlobal(rootWin);
checkScriptEnabled(rootWin, true);
Cu.blockScriptForGlobal(rootWin);
return reloadFrame(rootFrame);
}).then(function() {
checkScriptEnabled(rootWin, true);
// Test system-wide domain policy. This only takes effect for subsequently-
// loaded globals.
// Check the basic semantics of the sets.
is(ssm.domainPolicyActive, false, "not enabled");
window.policy = ssm.activateDomainPolicy();
ok(policy instanceof Ci.nsIDomainPolicy, "Got a policy");
try {
ssm.activateDomainPolicy();
ok(false, "Should have thrown");
} catch (e) {
ok(true, "can't have two live domain policies");
}
var sbRef = policy.superBlacklist;
isnot(sbRef, null, "superBlacklist non-null");
ok(!sbRef.contains(makeURI('http://www.example.com')));
sbRef.add(makeURI('http://www.example.com/foopy'));
ok(sbRef.contains(makeURI('http://www.example.com')));
sbRef.remove(makeURI('http://www.example.com'));
ok(!sbRef.contains(makeURI('http://www.example.com')));
sbRef.add(makeURI('http://www.example.com/foopy/this.that/'));
ok(sbRef.contains(makeURI('http://www.example.com/baz')));
ok(!sbRef.contains(makeURI('https://www.example.com')));
ok(!sbRef.contains(makeURI('https://www.example.com:88')));
ok(!sbRef.contains(makeURI('http://foo.www.example.com')));
ok(sbRef.containsSuperDomain(makeURI('http://foo.www.example.com')));
ok(sbRef.containsSuperDomain(makeURI('http://foo.bar.www.example.com')));
ok(!sbRef.containsSuperDomain(makeURI('http://foo.bar.www.exxample.com')));
ok(!sbRef.containsSuperDomain(makeURI('http://example.com')));
ok(!sbRef.containsSuperDomain(makeURI('http://com/this.that/')));
ok(!sbRef.containsSuperDomain(makeURI('https://foo.www.example.com')));
ok(sbRef.contains(makeURI('http://www.example.com')));
policy.deactivate();
is(ssm.domainPolicyActive, false, "back to inactive");
ok(!sbRef.contains(makeURI('http://www.example.com')),
"Disabling domain policy clears the set");
policy = ssm.activateDomainPolicy();
ok(policy.superBlacklist);
isnot(sbRef, policy.superBlacklist, "Mint new sets each time!");
policy.deactivate();
is(policy.blacklist, null, "blacklist nulled out");
policy = ssm.activateDomainPolicy();
isnot(policy.blacklist, null, "non-null again");
isnot(policy.blacklist, sbRef, "freshly minted");
policy.deactivate();
//
// Now, create and apply a mock-policy. We check the same policy both as
// a blacklist and as a whitelist.
//
window.testPolicy = {
// The policy.
exceptions: ['http://test1.example.com', 'http://example.com'],
superExceptions: ['http://test2.example.org', 'https://test1.example.com'],
// The testcases.
exempt: ['http://test1.example.com', 'http://example.com',
'http://test2.example.org', 'http://sub1.test2.example.org',
'https://sub1.test1.example.com'],
notExempt: ['http://test2.example.com', 'http://sub1.test1.example.com',
'http://www.example.com', 'https://test2.example.com',
'https://example.com', 'http://test1.example.org'],
};
policy = ssm.activateDomainPolicy();
info("Testing Blacklist-style Domain Policy");
return testDomainPolicy(true, testPolicy.exceptions,
testPolicy.superExceptions, testPolicy.exempt,
testPolicy.notExempt, policy.blacklist,
policy.superBlacklist, rootWin);
}).then(function() {
policy.deactivate();
policy = ssm.activateDomainPolicy();
info("Testing Whitelist-style Domain Policy");
setScriptEnabledForBrowser(false);
return testDomainPolicy(false, testPolicy.exceptions,
testPolicy.superExceptions, testPolicy.exempt,
testPolicy.notExempt, policy.whitelist,
policy.superWhitelist, rootWin);
}).then(function() {
setScriptEnabledForBrowser(true);
policy.deactivate();
SimpleTest.finish();
});
}
]]>
</script>
</window>

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

@ -223,6 +223,7 @@ if test -n "$gonkdir" ; then
GONK_INCLUDES="-I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/frameworks/base/include -I$gonkdir/frameworks/base/services/camera -I$gonkdir/frameworks/base/include/media/stagefright -I$gonkdir/frameworks/base/include/media/stagefright/openmax -I$gonkdir/frameworks/base/media/libstagefright/rtsp -I$gonkdir/frameworks/base/media/libstagefright/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib -I$gonkdir/dalvik/libnativehelper/include/nativehelper" GONK_INCLUDES="-I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/frameworks/base/include -I$gonkdir/frameworks/base/services/camera -I$gonkdir/frameworks/base/include/media/stagefright -I$gonkdir/frameworks/base/include/media/stagefright/openmax -I$gonkdir/frameworks/base/media/libstagefright/rtsp -I$gonkdir/frameworks/base/media/libstagefright/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib -I$gonkdir/dalvik/libnativehelper/include/nativehelper"
MOZ_B2G_BT=1 MOZ_B2G_BT=1
MOZ_B2G_BT_BLUEZ=1 MOZ_B2G_BT_BLUEZ=1
MOZ_NFC=1
MOZ_B2G_CAMERA=1 MOZ_B2G_CAMERA=1
MOZ_OMX_DECODER=1 MOZ_OMX_DECODER=1
AC_SUBST(MOZ_OMX_DECODER) AC_SUBST(MOZ_OMX_DECODER)
@ -239,6 +240,7 @@ if test -n "$gonkdir" ; then
MOZ_B2G_BT_BLUEDROID=1 MOZ_B2G_BT_BLUEDROID=1
fi fi
MOZ_NFC=1
MOZ_B2G_CAMERA=1 MOZ_B2G_CAMERA=1
MOZ_OMX_DECODER=1 MOZ_OMX_DECODER=1
AC_SUBST(MOZ_OMX_DECODER) AC_SUBST(MOZ_OMX_DECODER)
@ -7306,6 +7308,18 @@ AC_SUBST(MOZ_B2G_BT)
AC_SUBST(MOZ_B2G_BT_BLUEZ) AC_SUBST(MOZ_B2G_BT_BLUEZ)
AC_SUBST(MOZ_B2G_BT_BLUEDROID) AC_SUBST(MOZ_B2G_BT_BLUEDROID)
dnl ========================================================
dnl = Enable NFC Interface for B2G (Gonk usually)
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(b2g-nfc,
[ --enable-nfc Set compile flags necessary for compiling NFC API ],
MOZ_NFC=1,
MOZ_NFC= )
if test -n "$MOZ_NFC"; then
AC_DEFINE(MOZ_NFC)
fi
AC_SUBST(MOZ_NFC)
dnl ======================================================== dnl ========================================================
dnl = Enable Pico Speech Synthesis (Gonk usually) dnl = Enable Pico Speech Synthesis (Gonk usually)
dnl ======================================================== dnl ========================================================

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

@ -10,10 +10,10 @@
#include "nsAttrAndChildArray.h" #include "nsAttrAndChildArray.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "nsMappedAttributeElement.h" #include "nsMappedAttributeElement.h"
#include "prbit.h"
#include "nsString.h" #include "nsString.h"
#include "nsHTMLStyleSheet.h" #include "nsHTMLStyleSheet.h"
#include "nsRuleWalker.h" #include "nsRuleWalker.h"
@ -772,7 +772,7 @@ nsAttrAndChildArray::GrowBy(uint32_t aGrowSize)
} while (size < minSize); } while (size < minSize);
} }
else { else {
size = 1u << PR_CeilingLog2(minSize); size = 1u << mozilla::CeilingLog2(minSize);
} }
bool needToInitialize = !mImpl; bool needToInitialize = !mImpl;

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

@ -253,8 +253,14 @@ public:
// nsWrapperCache // nsWrapperCache
using nsWrapperCache::GetWrapperPreserveColor; using nsWrapperCache::GetWrapperPreserveColor;
virtual JSObject* WrapObject(JSContext *cx, virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE; JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return nsWrapperCache::GetWrapperPreserveColor();
}
public:
// nsIDOMHTMLCollection // nsIDOMHTMLCollection
NS_DECL_NSIDOMHTMLCOLLECTION NS_DECL_NSIDOMHTMLCOLLECTION

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

@ -7206,19 +7206,10 @@ nsDocument::IsScriptEnabled()
nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
NS_ENSURE_TRUE(sm, false); NS_ENSURE_TRUE(sm, false);
nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetWindow()); nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetInnerWindow());
NS_ENSURE_TRUE(globalObject, false); NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), false);
nsIScriptContext *scriptContext = globalObject->GetContext(); return sm->ScriptAllowed(globalObject->GetGlobalJSObject());
NS_ENSURE_TRUE(scriptContext, false);
AutoPushJSContext cx(scriptContext->GetNativeContext());
NS_ENSURE_TRUE(cx, false);
bool enabled;
nsresult rv = sm->CanExecuteScripts(cx, NodePrincipal(), &enabled);
NS_ENSURE_SUCCESS(rv, false);
return enabled;
} }
nsRadioGroupStruct* nsRadioGroupStruct*

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

@ -498,28 +498,6 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
return false; return false;
} }
// Script evaluation can also be disabled in the current script
// context even though it's enabled in the document.
// XXX - still hard-coded for JS here, even though another language
// may be specified. Should this check be made *after* we examine
// the attributes to locate the script-type?
// For now though, if JS is disabled we assume every language is
// disabled.
// XXX is this different from the mDocument->IsScriptEnabled() call?
nsCOMPtr<nsIScriptGlobalObject> globalObject =
do_QueryInterface(mDocument->GetWindow());
if (!globalObject) {
return false;
}
nsIScriptContext *context = globalObject->GetScriptContext();
// If scripts aren't enabled in the current context, there's no
// point in going on.
if (!context || !context->GetScriptsEnabled()) {
return false;
}
JSVersion version = JSVERSION_DEFAULT; JSVersion version = JSVERSION_DEFAULT;
// Check the type attribute to determine language and version. // Check the type attribute to determine language and version.

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

@ -1084,9 +1084,9 @@ CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
const PRUnichar *aEncoderOptions, const PRUnichar *aEncoderOptions,
nsIInputStream **aStream) nsIInputStream **aStream)
{ {
uint8_t* imageBuffer = nullptr; nsAutoArrayPtr<uint8_t> imageBuffer;
int32_t format = 0; int32_t format = 0;
GetImageBuffer(&imageBuffer, &format); GetImageBuffer(getter_Transfers(imageBuffer), &format);
if (!imageBuffer) { if (!imageBuffer) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }

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

@ -794,9 +794,9 @@ WebGLContext::GetInputStream(const char* aMimeType,
if (!gl) if (!gl)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
uint8_t* imageBuffer = nullptr; nsAutoArrayPtr<uint8_t> imageBuffer;
int32_t format = 0; int32_t format = 0;
GetImageBuffer(&imageBuffer, &format); GetImageBuffer(getter_Transfers(imageBuffer), &format);
if (!imageBuffer) { if (!imageBuffer) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }

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

@ -24,8 +24,8 @@ class Element;
// IID for the nsIHTMLCollection interface // IID for the nsIHTMLCollection interface
#define NS_IHTMLCOLLECTION_IID \ #define NS_IHTMLCOLLECTION_IID \
{ 0x5643235d, 0x9a72, 0x4b6a, \ { 0x4e169191, 0x5196, 0x4e17, \
{ 0xa6, 0x0c, 0x64, 0x63, 0x72, 0xb7, 0x53, 0x4a } } { 0xa4, 0x79, 0xd5, 0x35, 0x0b, 0x5b, 0x0a, 0xcd } }
/** /**
* An internal interface * An internal interface
@ -76,11 +76,11 @@ public:
JSObject* GetWrapperPreserveColor() JSObject* GetWrapperPreserveColor()
{ {
nsWrapperCache* cache; return GetWrapperPreserveColorInternal();
CallQueryInterface(this, &cache);
return cache->GetWrapperPreserveColor();
} }
virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) = 0; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) = 0;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() = 0;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLCollection, NS_IHTMLCOLLECTION_IID) NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLCollection, NS_IHTMLCOLLECTION_IID)

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

@ -79,8 +79,15 @@ public:
nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const; nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
// nsWrapperCache // nsWrapperCache
virtual JSObject* using nsWrapperCache::GetWrapperPreserveColor;
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE; virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return nsWrapperCache::GetWrapperPreserveColor();
}
public:
static bool ShouldBeInElements(nsIFormControl* aFormControl); static bool ShouldBeInElements(nsIFormControl* aFormControl);

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

@ -42,8 +42,14 @@ public:
// nsWrapperCache // nsWrapperCache
using nsWrapperCache::GetWrapperPreserveColor; using nsWrapperCache::GetWrapperPreserveColor;
virtual JSObject* WrapObject(JSContext* cx, virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE; JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return nsWrapperCache::GetWrapperPreserveColor();
}
public:
// nsIDOMHTMLOptionsCollection interface // nsIDOMHTMLOptionsCollection interface
NS_DECL_NSIDOMHTMLOPTIONSCOLLECTION NS_DECL_NSIDOMHTMLOPTIONSCOLLECTION

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

@ -55,9 +55,16 @@ public:
HTMLPropertiesCollection(nsGenericHTMLElement* aRoot); HTMLPropertiesCollection(nsGenericHTMLElement* aRoot);
virtual ~HTMLPropertiesCollection(); virtual ~HTMLPropertiesCollection();
// nsWrapperCache
using nsWrapperCache::GetWrapperPreserveColor; using nsWrapperCache::GetWrapperPreserveColor;
virtual JSObject* WrapObject(JSContext *cx, virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE; JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{
return nsWrapperCache::GetWrapperPreserveColor();
}
public:
virtual Element* GetElementAt(uint32_t aIndex); virtual Element* GetElementAt(uint32_t aIndex);

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

@ -50,13 +50,15 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TableRowsCollection) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TableRowsCollection)
// nsWrapperCache // nsWrapperCache
virtual JSObject* WrapObject(JSContext *cx, using nsWrapperCache::GetWrapperPreserveColor;
JS::Handle<JSObject*> scope) MOZ_OVERRIDE virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
{ {
return mozilla::dom::HTMLCollectionBinding::Wrap(cx, scope, this); return nsWrapperCache::GetWrapperPreserveColor();
} }
protected:
// Those rows that are not in table sections // Those rows that are not in table sections
HTMLTableElement* mParent; HTMLTableElement* mParent;
nsRefPtr<nsContentList> mOrphanRows; nsRefPtr<nsContentList> mOrphanRows;
@ -82,6 +84,13 @@ TableRowsCollection::~TableRowsCollection()
// reference for us. // reference for us.
} }
JSObject*
TableRowsCollection::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope)
{
return HTMLCollectionBinding::Wrap(aCx, aScope, this);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TableRowsCollection, mOrphanRows) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TableRowsCollection, mOrphanRows)
NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection) NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection) NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection)

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

@ -706,24 +706,17 @@ IsScriptEnabled(nsIDocument *aDoc, nsIDocShell *aContainer)
NS_ENSURE_TRUE(aDoc && aContainer, true); NS_ENSURE_TRUE(aDoc && aContainer, true);
nsCOMPtr<nsIScriptGlobalObject> globalObject = nsCOMPtr<nsIScriptGlobalObject> globalObject =
do_QueryInterface(aDoc->GetWindow()); do_QueryInterface(aDoc->GetInnerWindow());
// Getting context is tricky if the document hasn't had its // Getting context is tricky if the document hasn't had its
// GlobalObject set yet // GlobalObject set yet
if (!globalObject) { if (!globalObject) {
globalObject = aContainer->GetScriptGlobalObject(); globalObject = aContainer->GetScriptGlobalObject();
NS_ENSURE_TRUE(globalObject, true);
} }
nsIScriptContext *scriptContext = globalObject->GetContext(); NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), true);
NS_ENSURE_TRUE(scriptContext, true); return nsContentUtils::GetSecurityManager()->
JSContext *cx = scriptContext->GetNativeContext(); ScriptAllowed(globalObject->GetGlobalJSObject());
NS_ENSURE_TRUE(cx, true);
bool enabled = true;
nsContentUtils::GetSecurityManager()->
CanExecuteScripts(cx, aDoc->NodePrincipal(), &enabled);
return enabled;
} }
nsresult nsresult

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

@ -1080,24 +1080,12 @@ nsXBLBinding::AllowScripts()
return false; return false;
} }
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(doc->GetWindow()); nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(doc->GetInnerWindow());
if (!global) { if (!global || !global->GetGlobalJSObject()) {
return false; return false;
} }
nsCOMPtr<nsIScriptContext> context = global->GetContext(); return mgr->ScriptAllowed(global->GetGlobalJSObject());
if (!context) {
return false;
}
AutoPushJSContext cx(context->GetNativeContext());
nsCOMPtr<nsIDocument> ourDocument =
mPrototypeBinding->XBLDocumentInfo()->GetDocument();
bool canExecute;
nsresult rv =
mgr->CanExecuteScripts(cx, ourDocument->NodePrincipal(), &canExecute);
return NS_SUCCEEDED(rv) && canExecute;
} }
nsXBLBinding* nsXBLBinding*

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

@ -328,12 +328,12 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
// Now call the method // Now call the method
// Check whether it's OK to call the method. // Check whether script is enabled.
rv = nsContentUtils::GetSecurityManager()->CheckFunctionAccess(cx, method, bool scriptAllowed = nsContentUtils::GetSecurityManager()->
thisObject); ScriptAllowed(js::GetGlobalForObjectCrossCompartment(method));
bool ok = true; bool ok = true;
if (NS_SUCCEEDED(rv)) { if (scriptAllowed) {
JS::Rooted<JS::Value> retval(cx); JS::Rooted<JS::Value> retval(cx);
ok = ::JS_CallFunctionValue(cx, thisObject, OBJECT_TO_JSVAL(method), ok = ::JS_CallFunctionValue(cx, thisObject, OBJECT_TO_JSVAL(method),
0 /* argc */, nullptr /* argv */, retval.address()); 0 /* argc */, nullptr /* argv */, retval.address());

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

@ -3660,18 +3660,14 @@ XULDocument::ExecuteScript(nsIScriptContext * aContext,
NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
if (!aContext->GetScriptsEnabled())
return NS_OK;
// Execute the precompiled script with the given version // Execute the precompiled script with the given version
nsAutoMicroTask mt; nsAutoMicroTask mt;
JSContext *cx = aContext->GetNativeContext(); JSContext *cx = aContext->GetNativeContext();
AutoCxPusher pusher(cx); AutoCxPusher pusher(cx);
JS::Rooted<JSObject*> global(cx, mScriptGlobalObject->GetGlobalJSObject()); JS::Rooted<JSObject*> global(cx, mScriptGlobalObject->GetGlobalJSObject());
// XXXkhuey can this ever be null? NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
if (global) { NS_ENSURE_TRUE(nsContentUtils::GetSecurityManager()->ScriptAllowed(global), NS_OK);
JS::ExposeObjectToActiveJS(global); JS::ExposeObjectToActiveJS(global);
}
xpc_UnmarkGrayScript(aScriptObject); xpc_UnmarkGrayScript(aScriptObject);
JSAutoCompartment ac(cx, global); JSAutoCompartment ac(cx, global);
JS::Rooted<JS::Value> unused(cx); JS::Rooted<JS::Value> unused(cx);

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

@ -762,6 +762,7 @@ nsDocShell::nsDocShell():
mUseGlobalHistory(false), mUseGlobalHistory(false),
mInPrivateBrowsing(false), mInPrivateBrowsing(false),
mDeviceSizeIsPageSize(false), mDeviceSizeIsPageSize(false),
mCanExecuteScripts(false),
mFiredUnloadEvent(false), mFiredUnloadEvent(false),
mEODForCurrentDocument(false), mEODForCurrentDocument(false),
mURIResultedInDocument(false), mURIResultedInDocument(false),
@ -2077,12 +2078,6 @@ nsDocShell::GetAllowJavascript(bool * aAllowJavascript)
NS_ENSURE_ARG_POINTER(aAllowJavascript); NS_ENSURE_ARG_POINTER(aAllowJavascript);
*aAllowJavascript = mAllowJavascript; *aAllowJavascript = mAllowJavascript;
if (!mAllowJavascript) {
return NS_OK;
}
bool unsafe;
*aAllowJavascript = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
return NS_OK; return NS_OK;
} }
@ -2090,6 +2085,7 @@ NS_IMETHODIMP
nsDocShell::SetAllowJavascript(bool aAllowJavascript) nsDocShell::SetAllowJavascript(bool aAllowJavascript)
{ {
mAllowJavascript = aAllowJavascript; mAllowJavascript = aAllowJavascript;
RecomputeCanExecuteScripts();
return NS_OK; return NS_OK;
} }
@ -2823,6 +2819,48 @@ nsDocShell::GetParentDocshell()
return docshell.forget().downcast<nsDocShell>(); return docshell.forget().downcast<nsDocShell>();
} }
void
nsDocShell::RecomputeCanExecuteScripts()
{
bool old = mCanExecuteScripts;
nsRefPtr<nsDocShell> parent = GetParentDocshell();
// If we have no tree owner, that means that we've been detached from the
// docshell tree (this is distinct from having no parent dochshell, which
// is the case for root docshells). In that case, don't allow script.
if (!mTreeOwner) {
mCanExecuteScripts = false;
// If scripting has been explicitly disabled on our docshell, we're done.
} else if (!mAllowJavascript) {
mCanExecuteScripts = false;
// If we have a parent, inherit.
} else if (parent) {
mCanExecuteScripts = parent->mCanExecuteScripts;
// Otherwise, we're the root of the tree, and we haven't explicitly disabled
// script. Allow.
} else {
mCanExecuteScripts = true;
}
// Inform our active DOM window.
//
// This will pass the outer, which will be in the scope of the active inner.
if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
xpc::Scriptability& scriptability =
xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
}
// If our value has changed, our children might be affected. Recompute their
// value as well.
if (old != mCanExecuteScripts) {
nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
while (iter.HasMore()) {
static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
}
}
}
nsresult nsresult
nsDocShell::SetDocLoaderParent(nsDocLoader * aParent) nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
{ {
@ -2892,6 +2930,10 @@ nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent)); nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
if (parentURIListener) if (parentURIListener)
mContentListener->SetParentContentListener(parentURIListener); mContentListener->SetParentContentListener(parentURIListener);
// Our parent has changed. Recompute scriptability.
RecomputeCanExecuteScripts();
return NS_OK; return NS_OK;
} }
@ -3446,6 +3488,16 @@ nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)
child->SetTreeOwner(aTreeOwner); child->SetTreeOwner(aTreeOwner);
} }
// Our tree owner has changed. Recompute scriptability.
//
// Note that this is near-redundant with the recomputation in
// SetDocLoaderParent(), but not so for the root DocShell, where the call to
// SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
// and we never set another parent. Given that this is neither expensive nor
// performance-critical, let's be safe and unconditionally recompute this
// state whenever dependent state changes.
RecomputeCanExecuteScripts();
return NS_OK; return NS_OK;
} }
@ -12657,20 +12709,7 @@ unsigned long nsDocShell::gNumberOfDocShells = 0;
NS_IMETHODIMP NS_IMETHODIMP
nsDocShell::GetCanExecuteScripts(bool *aResult) nsDocShell::GetCanExecuteScripts(bool *aResult)
{ {
NS_ENSURE_ARG_POINTER(aResult); *aResult = mCanExecuteScripts;
*aResult = false; // disallow by default
nsRefPtr<nsDocShell> docshell = this;
do {
nsresult rv = docshell->GetAllowJavascript(aResult);
if (NS_FAILED(rv)) return rv;
if (!*aResult) {
return NS_OK;
}
docshell = docshell->GetParentDocshell();
} while (docshell);
return NS_OK; return NS_OK;
} }

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

@ -813,6 +813,12 @@ protected:
bool mInPrivateBrowsing; bool mInPrivateBrowsing;
bool mDeviceSizeIsPageSize; bool mDeviceSizeIsPageSize;
// Because scriptability depends on the mAllowJavascript values of our
// ancestors, we cache the effective scriptability and recompute it when
// it might have changed;
bool mCanExecuteScripts;
void RecomputeCanExecuteScripts();
// This boolean is set to true right before we fire pagehide and generally // This boolean is set to true right before we fire pagehide and generally
// unset when we embed a new content viewer. While it's true no navigation // unset when we embed a new content viewer. While it's true no navigation
// is allowed in this docshell. // is allowed in this docshell.

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

@ -570,7 +570,7 @@ interface nsIDocShell : nsIDocShellTreeItem
* The rule of thumb here is that we disable js if this docshell or any * The rule of thumb here is that we disable js if this docshell or any
* of its parents disallow scripting. * of its parents disallow scripting.
*/ */
readonly attribute boolean canExecuteScripts; [infallible] readonly attribute boolean canExecuteScripts;
/** /**
* Sets whether a docshell is active. An active docshell is one that is * Sets whether a docshell is active. An active docshell is one that is

Двоичные данные
docshell/test/bug369814.zip

Двоичный файл не отображается.

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

@ -302,6 +302,17 @@ this.PermissionsTable = { geolocation: {
privileged: PROMPT_ACTION, privileged: PROMPT_ACTION,
certified: PROMPT_ACTION certified: PROMPT_ACTION
}, },
"nfc": {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION,
access: ["read", "write"]
},
"nfc-manager": {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
}; };
/** /**

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

@ -1793,6 +1793,18 @@ Navigator::HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal)
} }
#endif // MOZ_B2G_FM #endif // MOZ_B2G_FM
#ifdef MOZ_NFC
/* static */
bool
Navigator::HasNfcSupport(JSContext* /* unused */, JSObject* aGlobal)
{
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
return win && (CheckPermission(win, "nfc-read") ||
CheckPermission(win, "nfc-write"));
}
#endif // MOZ_NFC
#ifdef MOZ_TIME_MANAGER #ifdef MOZ_TIME_MANAGER
/* static */ /* static */
bool bool

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

@ -287,6 +287,9 @@ public:
#ifdef MOZ_B2G_FM #ifdef MOZ_B2G_FM
static bool HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal); static bool HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal);
#endif // MOZ_B2G_FM #endif // MOZ_B2G_FM
#ifdef MOZ_NFC
static bool HasNfcSupport(JSContext* /* unused */, JSObject* aGlobal);
#endif // MOZ_NFC
#ifdef MOZ_TIME_MANAGER #ifdef MOZ_TIME_MANAGER
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal); static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
#endif // MOZ_TIME_MANAGER #endif // MOZ_TIME_MANAGER

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

@ -139,6 +139,7 @@
#endif #endif
#include "nsIDOMCustomEvent.h" #include "nsIDOMCustomEvent.h"
#include "nsIFrameRequestCallback.h" #include "nsIFrameRequestCallback.h"
#include "nsIJARChannel.h"
#include "xpcprivate.h" #include "xpcprivate.h"
@ -2061,6 +2062,9 @@ WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
mInnerWindowHolder = aHolder; mInnerWindowHolder = aHolder;
aWindow->SuspendTimeouts(); aWindow->SuspendTimeouts();
// When a global goes into the bfcache, we disable script.
xpc::Scriptability::Get(aWindow->mJSObject).SetDocShellAllowsScript(false);
} }
WindowStateHolder::~WindowStateHolder() WindowStateHolder::~WindowStateHolder()
@ -2459,6 +2463,10 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// Enter the new global's compartment. // Enter the new global's compartment.
JSAutoCompartment ac(cx, mJSObject); JSAutoCompartment ac(cx, mJSObject);
// Set scriptability based on the state of the docshell.
bool allow = GetDocShell()->GetCanExecuteScripts();
xpc::Scriptability::Get(mJSObject).SetDocShellAllowsScript(allow);
// If we created a new inner window above, we need to do the last little bit // If we created a new inner window above, we need to do the last little bit
// of initialization now that the dust has settled. // of initialization now that the dust has settled.
if (createdInnerWindow) { if (createdInnerWindow) {
@ -2541,6 +2549,14 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
// If the document comes from a JAR, check if the channel was determined
// to be unsafe. If so, permanently disable script on the compartment by
// calling Block() and throwing away the key.
nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel());
if (jarChannel && jarChannel->GetIsUnsafe()) {
xpc::Scriptability::Get(newInnerWindow->mJSObject).Block();
}
if (mArguments) { if (mArguments) {
newInnerWindow->DefineArgumentsProperty(mArguments); newInnerWindow->DefineArgumentsProperty(mArguments);
mArguments = nullptr; mArguments = nullptr;
@ -3174,19 +3190,6 @@ nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject)
} }
} }
void
nsGlobalWindow::SetScriptsEnabled(bool aEnabled, bool aFireTimeouts)
{
FORWARD_TO_INNER_VOID(SetScriptsEnabled, (aEnabled, aFireTimeouts));
if (aEnabled && aFireTimeouts) {
// Scripts are enabled (again?) on this context, run timeouts that
// fired on this context while scripts were disabled.
void (nsGlobalWindow::*run)() = &nsGlobalWindow::RunTimeout;
NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, run));
}
}
nsresult nsresult
nsGlobalWindow::SetArguments(nsIArray *aArguments) nsGlobalWindow::SetArguments(nsIArray *aArguments)
{ {
@ -8942,11 +8945,14 @@ NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
NS_IMETHODIMP NS_IMETHODIMP
nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal) nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
{ {
MOZ_ASSERT(!IsInnerWindow() || IsCurrentInnerWindow(),
"We should only fire events on the current inner window.");
FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK); FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK);
if (!IsCurrentInnerWindow()) {
NS_WARNING("DispatchEvent called on non-current inner window, dropping. "
"Please check the window in the caller instead.");
return NS_ERROR_FAILURE;
}
if (!mDoc) { if (!mDoc) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -11824,20 +11830,6 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
continue; continue;
} }
// The "scripts disabled" concept is still a little vague wrt
// multiple languages. Prepare for the day when languages can be
// disabled independently of the other languages...
if (!scx->GetScriptsEnabled()) {
// Scripts were enabled once in this window (unless aTimeout ==
// nullptr) but now scripts are disabled (we might be in
// print-preview, for instance), this means we shouldn't run any
// timeouts at this point.
//
// If scripts are enabled for this language in this window again
// we'll fire the timeouts that are due at that point.
continue;
}
// This timeout is good to run // This timeout is good to run
++timeoutsRan; ++timeoutsRan;
bool timeout_was_cleared = RunTimeoutHandler(timeout, scx); bool timeout_was_cleared = RunTimeoutHandler(timeout, scx);

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

@ -354,7 +354,6 @@ public:
void PoisonOuterWindowProxy(JSObject *aObject); void PoisonOuterWindowProxy(JSObject *aObject);
virtual void OnFinalize(JSObject* aObject); virtual void OnFinalize(JSObject* aObject);
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts);
virtual bool IsBlackForCC(); virtual bool IsBlackForCC();

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

@ -27,8 +27,8 @@ class nsIDOMWindow;
class nsIURI; class nsIURI;
#define NS_ISCRIPTCONTEXT_IID \ #define NS_ISCRIPTCONTEXT_IID \
{ 0xf3859ce7, 0x7551, 0x4760, \ { 0x513c2c1a, 0xf4f1, 0x44da, \
{ 0x84, 0x29, 0x64, 0x4f, 0x26, 0x1e, 0xdb, 0x91 } } { 0x8e, 0x38, 0xf4, 0x0c, 0x30, 0x9a, 0x5d, 0xef } }
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't /* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
know what language we have is a little silly... */ know what language we have is a little silly... */
@ -128,12 +128,6 @@ public:
*/ */
virtual void GC(JS::gcreason::Reason aReason) = 0; virtual void GC(JS::gcreason::Reason aReason) = 0;
/**
* Called to disable/enable script execution in this context.
*/
virtual bool GetScriptsEnabled() = 0;
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts) = 0;
// SetProperty is suspect and jst believes should not be needed. Currenly // SetProperty is suspect and jst believes should not be needed. Currenly
// used only for "arguments". // used only for "arguments".
virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget, virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget,

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

@ -27,8 +27,8 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
#define NS_ISCRIPTGLOBALOBJECT_IID \ #define NS_ISCRIPTGLOBALOBJECT_IID \
{ 0x214fa2f6, 0xcc0c, 0x42cf, \ { 0xa6c0bfae, 0x8be4, 0x4747, \
{ 0x98, 0x4b, 0x45, 0xf5, 0x73, 0x9c, 0x6b, 0x73 } } { 0xaf, 0x1a, 0xe3, 0xf0, 0x3f, 0xb6, 0x0e, 0xb8 } }
/** /**
* The global object which keeps a script context for each supported script * The global object which keeps a script context for each supported script
@ -70,11 +70,6 @@ public:
*/ */
virtual void OnFinalize(JSObject* aObject) = 0; virtual void OnFinalize(JSObject* aObject) = 0;
/**
* Called to enable/disable scripts.
*/
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts) = 0;
/** /**
* Handle a script error. Generally called by a script context. * Handle a script error. Generally called by a script context.
*/ */

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

@ -839,7 +839,6 @@ nsJSContext::nsJSContext(bool aGCOnDestruction,
js_options_dot_str, this); js_options_dot_str, this);
} }
mIsInitialized = false; mIsInitialized = false;
mScriptsEnabled = true;
mProcessingScriptTag = false; mProcessingScriptTag = false;
HoldJSObjects(this); HoldJSObjects(this);
} }
@ -950,10 +949,6 @@ nsJSContext::EvaluateString(const nsAString& aScript,
void **aOffThreadToken) void **aOffThreadToken)
{ {
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
if (!mScriptsEnabled) {
return NS_OK;
}
AutoCxPusher pusher(mContext); AutoCxPusher pusher(mContext);
nsJSUtils::EvaluateOptions evalOptions; nsJSUtils::EvaluateOptions evalOptions;
evalOptions.setCoerceToString(aCoerceToString); evalOptions.setCoerceToString(aCoerceToString);
@ -1863,27 +1858,6 @@ nsJSContext::IsContextInitialized()
return mIsInitialized; return mIsInitialized;
} }
bool
nsJSContext::GetScriptsEnabled()
{
return mScriptsEnabled;
}
void
nsJSContext::SetScriptsEnabled(bool aEnabled, bool aFireTimeouts)
{
// eeek - this seems the wrong way around - the global should callback
// into each context, so every language is disabled.
mScriptsEnabled = aEnabled;
nsIScriptGlobalObject *global = GetGlobalObject();
if (global) {
global->SetScriptsEnabled(aEnabled, aFireTimeouts);
}
}
bool bool
nsJSContext::GetProcessingScriptTag() nsJSContext::GetProcessingScriptTag()
{ {

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

@ -59,9 +59,6 @@ public:
virtual nsresult InitContext() MOZ_OVERRIDE; virtual nsresult InitContext() MOZ_OVERRIDE;
virtual bool IsContextInitialized() MOZ_OVERRIDE; virtual bool IsContextInitialized() MOZ_OVERRIDE;
virtual bool GetScriptsEnabled() MOZ_OVERRIDE;
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts) MOZ_OVERRIDE;
virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget, const char* aPropName, nsISupports* aVal) MOZ_OVERRIDE; virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget, const char* aPropName, nsISupports* aVal) MOZ_OVERRIDE;
virtual bool GetProcessingScriptTag() MOZ_OVERRIDE; virtual bool GetProcessingScriptTag() MOZ_OVERRIDE;
@ -166,7 +163,6 @@ private:
JS::Heap<JSObject*> mWindowProxy; JS::Heap<JSObject*> mWindowProxy;
bool mIsInitialized; bool mIsInitialized;
bool mScriptsEnabled;
bool mGCOnDestruction; bool mGCOnDestruction;
bool mProcessingScriptTag; bool mProcessingScriptTag;

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

@ -241,15 +241,14 @@ nsJSUtils::EvaluateString(JSContext* aCx,
JS::ExposeObjectToActiveJS(aScopeObject); JS::ExposeObjectToActiveJS(aScopeObject);
nsAutoMicroTask mt; nsAutoMicroTask mt;
nsresult rv = NS_OK;
JSPrincipals* p = JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject)); JSPrincipals* p = JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject));
aCompileOptions.setPrincipals(p); aCompileOptions.setPrincipals(p);
bool ok = false; bool ok = false;
nsresult rv = nsContentUtils::GetSecurityManager()-> nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
CanExecuteScripts(aCx, nsJSPrincipals::get(p), &ok); NS_ENSURE_TRUE(ssm->ScriptAllowed(js::GetGlobalForObjectCrossCompartment(aScopeObject)), NS_OK);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(ok, NS_OK);
mozilla::Maybe<AutoDontReportUncaught> dontReport; mozilla::Maybe<AutoDontReportUncaught> dontReport;
if (!aEvaluateOptions.reportUncaught) { if (!aEvaluateOptions.reportUncaught) {

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

@ -120,14 +120,12 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
if (mIsMainThread) { if (mIsMainThread) {
// Check that it's ok to run this callback at all. // Check that it's ok to run this callback at all.
// FIXME: Bug 807371: we want a less silly check here. // Make sure to unwrap aCallback before passing it in to get the global of
// Make sure to unwrap aCallback before passing it in, because // the callback object, not the wrapper.
// getting principals from wrappers is silly. bool allowed = nsContentUtils::GetSecurityManager()->
nsresult rv = nsContentUtils::GetSecurityManager()-> ScriptAllowed(js::GetGlobalForObjectCrossCompartment(js::UncheckedUnwrap(aCallback)));
CheckFunctionAccess(cx, js::UncheckedUnwrap(aCallback), nullptr);
if (NS_FAILED(rv)) { if (!allowed) {
// Security check failed. We're done here.
return; return;
} }
} }

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

@ -249,7 +249,14 @@ AdapterPropertiesChangeCallback(bt_status_t aStatus, int aNumProperties,
propertiesArray.AppendElement( propertiesArray.AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue)); BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
} else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) { } else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) {
propertyValue = sAdapterDiscoverable = *(uint32_t*)p.val; bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val;
if (newMode == BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
propertyValue = sAdapterDiscoverable = true;
} else {
propertyValue = sAdapterDiscoverable = false;
}
propertiesArray.AppendElement( propertiesArray.AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"), propertyValue)); BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"), propertyValue));
} else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) { } else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) {
@ -637,9 +644,12 @@ ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable,
int aStatusCode, const nsAString& aCustomMsg) int aStatusCode, const nsAString& aCustomMsg)
{ {
MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr"); MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr");
nsAutoString replyError;
BT_LOGR("%s: error code(%d)", __FUNCTION__, aStatusCode);
nsAutoString replyError;
replyError.Assign(aCustomMsg); replyError.Assign(aCustomMsg);
if (aStatusCode == BT_STATUS_BUSY) { if (aStatusCode == BT_STATUS_BUSY) {
replyError.AppendLiteral(":BT_STATUS_BUSY"); replyError.AppendLiteral(":BT_STATUS_BUSY");
} else if (aStatusCode == BT_STATUS_NOT_READY) { } else if (aStatusCode == BT_STATUS_NOT_READY) {
@ -840,6 +850,7 @@ BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
const nsString propName = aValue.name(); const nsString propName = aValue.name();
bt_property_t prop; bt_property_t prop;
bt_scan_mode_t scanMode;
nsString str; nsString str;
// For Bluedroid, it's necessary to check property name for SetProperty // For Bluedroid, it's necessary to check property name for SetProperty
@ -863,22 +874,23 @@ BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
prop.val = (void*)name; prop.val = (void*)name;
prop.len = strlen(name); prop.len = strlen(name);
} else if (aValue.value().type() == BluetoothValue::Tbool) { } else if (aValue.value().type() == BluetoothValue::Tbool) {
bt_scan_mode_t mode = aValue.value().get_bool() ? scanMode = aValue.value().get_bool() ?
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE : BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE :
BT_SCAN_MODE_CONNECTABLE; BT_SCAN_MODE_CONNECTABLE;
bt_scan_mode_t* sss = &mode;
prop.val = (void*)sss; prop.val = (void*)&scanMode;
prop.len = sizeof(sss); prop.len = sizeof(scanMode);
} else { } else {
BT_LOGR("SetProperty but the property cannot be recognized correctly."); BT_LOGR("SetProperty but the property cannot be recognized correctly.");
return NS_OK; return NS_OK;
} }
sSetPropertyRunnableArray.AppendElement(aRunnable); sSetPropertyRunnableArray.AppendElement(aRunnable);
int ret = sBtInterface->set_adapter_property(&prop);
if (ret != BT_STATUS_SUCCESS) int ret = sBtInterface->set_adapter_property(&prop);
if (ret != BT_STATUS_SUCCESS) {
ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetProperty")); ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetProperty"));
}
return NS_OK; return NS_OK;
} }

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

@ -29,6 +29,11 @@ const browserElementTestHelpers = {
} }
}, },
_setPrefs: function() {
this.lockTestReady();
SpecialPowers.pushPrefEnv({'set': Array.slice(arguments)}, this.unlockTestReady.bind(this));
},
_testReadyLockCount: 0, _testReadyLockCount: 0,
_firedTestReady: false, _firedTestReady: false,
lockTestReady: function() { lockTestReady: function() {
@ -44,9 +49,11 @@ const browserElementTestHelpers = {
}, },
enableProcessPriorityManager: function() { enableProcessPriorityManager: function() {
this._setPref('dom.ipc.processPriorityManager.testMode', true); this._setPrefs(
this._setPref('dom.ipc.processPriorityManager.enabled', true); ['dom.ipc.processPriorityManager.testMode', true],
this._setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2); ['dom.ipc.processPriorityManager.enabled', true],
['dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2]
);
}, },
setEnabledPref: function(value) { setEnabledPref: function(value) {

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

@ -289,11 +289,12 @@ parent:
ContentReceivedTouch(ScrollableLayerGuid aGuid, bool aPreventDefault); ContentReceivedTouch(ScrollableLayerGuid aGuid, bool aPreventDefault);
/** /**
* Updates the parent's zoom constraints for this tab. The zoom controller * Updates the zoom constraints for a scrollable frame in this tab.
* code lives on the parent side and so this allows it to have up-to-date * The zoom controller code lives on the parent side and so this allows it to
* zoom constraints. * have up-to-date zoom constraints.
*/ */
UpdateZoomConstraints(bool aAllowZoom, CSSToScreenScale aMinZoom, CSSToScreenScale aMaxZoom); UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId,
bool aAllowZoom, CSSToScreenScale aMinZoom, CSSToScreenScale aMaxZoom);
/** /**
* Notifies the parent about a scroll event. The pres shell ID and * Notifies the parent about a scroll event. The pres shell ID and

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

@ -537,8 +537,17 @@ TabChild::HandlePossibleViewportChange()
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils()); nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
uint32_t presShellId;
ViewID viewId;
if (!APZCCallbackHelper::GetScrollIdentifiers(document->GetDocumentElement(),
&presShellId, &viewId)) {
return;
}
nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize); nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize);
SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(), SendUpdateZoomConstraints(presShellId,
viewId,
viewportInfo.IsZoomAllowed(),
viewportInfo.GetMinZoom(), viewportInfo.GetMinZoom(),
viewportInfo.GetMaxZoom()); viewportInfo.GetMaxZoom());

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

@ -1626,12 +1626,14 @@ TabParent::RecvZoomToRect(const uint32_t& aPresShellId,
} }
bool bool
TabParent::RecvUpdateZoomConstraints(const bool& aAllowZoom, TabParent::RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
const ViewID& aViewId,
const bool& aAllowZoom,
const CSSToScreenScale& aMinZoom, const CSSToScreenScale& aMinZoom,
const CSSToScreenScale& aMaxZoom) const CSSToScreenScale& aMaxZoom)
{ {
if (RenderFrameParent* rfp = GetRenderFrame()) { if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom); rfp->UpdateZoomConstraints(aPresShellId, aViewId, aAllowZoom, aMinZoom, aMaxZoom);
} }
return true; return true;
} }

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

@ -165,7 +165,9 @@ public:
virtual bool RecvZoomToRect(const uint32_t& aPresShellId, virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
const ViewID& aViewId, const ViewID& aViewId,
const CSSRect& aRect); const CSSRect& aRect);
virtual bool RecvUpdateZoomConstraints(const bool& aAllowZoom, virtual bool RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
const ViewID& aViewId,
const bool& aAllowZoom,
const CSSToScreenScale& aMinZoom, const CSSToScreenScale& aMinZoom,
const CSSToScreenScale& aMaxZoom); const CSSToScreenScale& aMaxZoom);
virtual bool RecvUpdateScrollOffset(const uint32_t& aPresShellId, const ViewID& aViewId, const CSSIntPoint& aScrollOffset); virtual bool RecvUpdateScrollOffset(const uint32_t& aPresShellId, const ViewID& aViewId, const CSSIntPoint& aScrollOffset);

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

@ -95,6 +95,15 @@ this.SystemMessagePermissionsTable = {
"cdma-info-rec-received": { "cdma-info-rec-received": {
"mobileconnection": [] "mobileconnection": []
}, },
"nfc-manager-tech-discovered": {
"nfc-manager": []
},
"nfc-manager-tech-lost": {
"nfc-manager": []
},
"nfc-powerlevel-change": {
"settings": ["read", "write"]
}
}; };
this.SystemMessagePermissionsChecker = { this.SystemMessagePermissionsChecker = {

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

@ -97,6 +97,9 @@ if CONFIG['MOZ_PAY']:
if CONFIG['MOZ_GAMEPAD']: if CONFIG['MOZ_GAMEPAD']:
PARALLEL_DIRS += ['gamepad'] PARALLEL_DIRS += ['gamepad']
if CONFIG['MOZ_NFC']:
PARALLEL_DIRS += ['nfc']
# bindings/test is here, because it needs to build after bindings/, and # bindings/test is here, because it needs to build after bindings/, and
# we build subdirectories before ourselves. # we build subdirectories before ourselves.
TEST_DIRS += [ TEST_DIRS += [

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

@ -211,11 +211,12 @@ interface nsIDOMTCPSocket : nsISupports
}; };
/* /*
* Internal interfaces for use in cross-process socket implementation. * This interface is implemented in TCPSocket.js as an internal interfaces
* for use in cross-process socket implementation.
* Needed to account for multiple possible types that can be provided to * Needed to account for multiple possible types that can be provided to
* the socket callbacks as arguments. * the socket callbacks as arguments.
*/ */
[scriptable, uuid(234c664c-3d6c-4859-b45c-4e9a98cb5bdc)] [scriptable, uuid(017f130f-2477-4215-8783-57eada957699)]
interface nsITCPSocketInternal : nsISupports { interface nsITCPSocketInternal : nsISupports {
// Trigger the callback for |type| and provide a DOMError() object with the given data // Trigger the callback for |type| and provide a DOMError() object with the given data
void callListenerError(in DOMString type, in DOMString name); void callListenerError(in DOMString type, in DOMString name);
@ -229,8 +230,20 @@ interface nsITCPSocketInternal : nsISupports {
// Trigger the callback for |type| with no argument // Trigger the callback for |type| with no argument
void callListenerVoid(in DOMString type); void callListenerVoid(in DOMString type);
// Update the DOM object's readyState and bufferedAmount values with the provided data // Update the DOM object's readyState.
void updateReadyStateAndBuffered(in DOMString readyState, in uint32_t bufferedAmount); // @param readyState
// new ready state to be set to TCPSocket.
void updateReadyState(in DOMString readyState);
// Update the DOM object's bufferedAmount value with a tracking number to
// ensure the update request is sent after child's send() invocation.
// @param bufferedAmount
// TCPSocket parent's bufferedAmount.
// @param trackingNumber
// A number to ensure the bufferedAmount is updated after data
// from child are sent to parent.
void updateBufferedAmount(in uint32_t bufferedAmount,
in uint32_t trackingNumber);
// Create a socket object on the parent side. // Create a socket object on the parent side.
// This is called in accepting any open request on the parent side. // This is called in accepting any open request on the parent side.
@ -259,6 +272,18 @@ interface nsITCPSocketInternal : nsISupports {
// Set App ID. // Set App ID.
void setAppId(in unsigned long appId); void setAppId(in unsigned long appId);
// Set a callback that handles the request from a TCP socket parent when that
// socket parent wants to notify that its bufferedAmount is updated.
void setOnUpdateBufferedAmountHandler(in jsval handler);
// Providing child process with ability to pass more arguments to parent's
// send() function.
// @param trackingNumber
// To ensure the request to update bufferedAmount in child is after
// lastest send() invocation from child.
void onRecvSendFromChild(in jsval data, in unsigned long byteOffset,
in unsigned long byteLength, in unsigned long trackingNumber);
}; };
/** /**

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

@ -8,22 +8,26 @@ interface nsITCPSocketInternal;
interface nsIDOMWindow; interface nsIDOMWindow;
// Interface to allow the content process socket to reach the IPC bridge. // Interface to allow the content process socket to reach the IPC bridge.
[scriptable, uuid(ada5342d-6d45-4ff1-a7d3-6a4b150d0385)] // Implemented in C++ as TCPSocketChild, referenced as _socketBridge in TCPSocket.js
[scriptable, uuid(292ebb3a-beac-4e06-88b0-b5b4e88ebd1c)]
interface nsITCPSocketChild : nsISupports interface nsITCPSocketChild : nsISupports
{ {
// Tell the chrome process to open a corresponding connection with the given parameters // Tell the chrome process to open a corresponding connection with the given parameters
[implicit_jscontext] [implicit_jscontext]
void open(in nsITCPSocketInternal socket, in DOMString host, void sendOpen(in nsITCPSocketInternal socket, in DOMString host,
in unsigned short port, in boolean ssl, in DOMString binaryType, in unsigned short port, in boolean ssl, in DOMString binaryType,
in nsIDOMWindow window, in jsval windowVal); in nsIDOMWindow window, in jsval windowVal);
// Tell the chrome process to perform send and update the tracking number.
[implicit_jscontext]
void sendSend(in jsval data, in unsigned long byteOffset,
in unsigned long byteLength, in unsigned long trackingNumber);
// Tell the chrome process to perform equivalent operations to all following methods // Tell the chrome process to perform equivalent operations to all following methods
[implicit_jscontext] void sendResume();
void send(in jsval data, in unsigned long byteOffset, in unsigned long byteLength); void sendSuspend();
void resume(); void sendClose();
void suspend(); void sendStartTLS();
void close();
void startTLS();
/** /**
* Initialize the TCP socket on the child side for IPC. It is called from the child side, * Initialize the TCP socket on the child side for IPC. It is called from the child side,

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

@ -9,20 +9,28 @@ interface nsIDOMTCPServerSocket;
interface nsITCPServerSocketParent; interface nsITCPServerSocketParent;
interface nsITCPSocketIntermediary; interface nsITCPSocketIntermediary;
// Interface required to allow the TCP socket object in the parent process // Interface required to allow the TCP socket object (TCPSocket.js) in the
// to talk to the parent IPC actor // parent process to talk to the parent IPC actor, TCPSocketParent, which
[scriptable, uuid(123f654b-4435-43c8-8447-db1b5420a1c2)] // is written in C++.
[scriptable, uuid(868662a4-681c-4b89-9f02-6fe5b7ace265)]
interface nsITCPSocketParent : nsISupports interface nsITCPSocketParent : nsISupports
{ {
[implicit_jscontext] void initJS(in jsval intermediary); [implicit_jscontext] void initJS(in jsval intermediary);
// Trigger a callback in the content process for |type|, providing a serialized // Trigger a callback in the content process for |type|, providing a serialized
// argument of |data|, and update the child's readyState and bufferedAmount values // argument of |data|, and update the child's readyState value with the given
// with the given values. // values.
[implicit_jscontext] void sendCallback(in DOMString type, //
in jsval data, // @param type
in DOMString readyState, // Event type: 'onopen', 'ondata', 'onerror' or 'onclose'. 'odrain' is
in uint32_t bufferedAmount); // controlled by child.
// @param data
// Serialized data that is passed to event handler.
// @param readyState
// Current ready state.
[implicit_jscontext] void sendEvent(in DOMString type,
in jsval data,
in DOMString readyState);
// Initialize a parent socket object. It is called from the parent side socket, // Initialize a parent socket object. It is called from the parent side socket,
// which is generated in accepting any open request on the parent side. // which is generated in accepting any open request on the parent side.
@ -34,11 +42,27 @@ interface nsITCPSocketParent : nsISupports
// Intermediate class object. See nsITCPSocketIntermediary. // Intermediate class object. See nsITCPSocketIntermediary.
[implicit_jscontext] void setSocketAndIntermediary(in nsIDOMTCPSocket socket, [implicit_jscontext] void setSocketAndIntermediary(in nsIDOMTCPSocket socket,
in nsITCPSocketIntermediary intermediary); in nsITCPSocketIntermediary intermediary);
// When parent's buffered amount is updated and it wants to inform child to
// update the bufferedAmount as well.
//
// @param bufferedAmount
// The new value of bufferedAmount that is going to be set to child's
// bufferedAmount.
// @param trackingNumber
// Parent's current tracking number, reflecting the number of calls to
// send() on the child process. This number is sent back to the child
// to make sure the bufferedAmount updated on the child will correspond
// to the latest call of send().
void sendUpdateBufferedAmount(in uint32_t bufferedAmount, in uint32_t trackingNumber);
}; };
// Intermediate class to handle sending multiple possible data types // Intermediate class to handle sending multiple possible data types
// and kicking off the chrome process socket object's connection. // and kicking off the chrome process socket object's connection.
[scriptable, uuid(be67b1b8-03b0-4171-a791-d004458021b6)] // This interface is the bridge of TCPSocketParent, which is written in C++,
// and TCPSocket, which is written in Javascript. TCPSocketParentIntermediary
// implements nsITCPSocketIntermediary in Javascript.
[scriptable, uuid(c434224a-dbb7-4869-8b2b-e49cee990e85)]
interface nsITCPSocketIntermediary : nsISupports { interface nsITCPSocketIntermediary : nsISupports {
// Open the connection to the server with the given parameters // Open the connection to the server with the given parameters
nsIDOMTCPSocket open(in nsITCPSocketParent parent, nsIDOMTCPSocket open(in nsITCPSocketParent parent,
@ -51,9 +75,9 @@ interface nsITCPSocketIntermediary : nsISupports {
in unsigned short port, in unsigned short backlog, in unsigned short port, in unsigned short backlog,
in DOMString binaryType); in DOMString binaryType);
// Send a basic string along the connection // Called when received a child request to send a string.
void sendString(in DOMString data); void onRecvSendString(in DOMString data, in uint32_t trackingNumber);
// Send a typed array // Called when received a child request to send an array buffer.
void sendArrayBuffer(in jsval data); void onRecvSendArrayBuffer(in jsval data, in uint32_t trackingNumber);
}; };

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

@ -362,6 +362,7 @@ this.NetworkStatsService = {
this.updateQueue.push({netId: aNetId, callbacks: [aCallback]}); this.updateQueue.push({netId: aNetId, callbacks: [aCallback]});
} else { } else {
this.updateQueue[index].callbacks.push(aCallback); this.updateQueue[index].callbacks.push(aCallback);
return;
} }
// Call the function that process the elements of the queue. // Call the function that process the elements of the queue.

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

@ -35,16 +35,35 @@ protocol PTCPSocket
manager PNecko; manager PNecko;
parent: parent:
// Forward calling to child's open() method to parent, expect TCPOptions
// is expanded to |useSSL| (from TCPOptions.useSecureTransport) and
// |binaryType| (from TCPOption.binaryType).
Open(nsString host, uint16_t port, bool useSSL, nsString binaryType); Open(nsString host, uint16_t port, bool useSSL, nsString binaryType);
Data(SendableData data);
// When child's send() is called, this message requrests parent to send
// data and update it's trackingNumber.
Data(SendableData data, uint32_t trackingNumber);
// Forward calling to child's upgradeToSecure() method to parent.
StartTLS(); StartTLS();
// Forward calling to child's send() method to parent.
Suspend(); Suspend();
// Forward calling to child's resume() method to parent.
Resume(); Resume();
// Forward calling to child's close() method to parent.
Close(); Close();
child: child:
Callback(nsString type, CallbackData data, // Forward events that are dispatched by parent.
nsString readyState, uint32_t bufferedAmount); Callback(nsString type, CallbackData data, nsString readyState);
// Update child's bufferedAmount when parent's bufferedAmount is updated.
// trackingNumber is also passed back to child to ensure the bufferedAmount
// is corresponding the last call to send().
UpdateBufferedAmount(uint32_t bufferedAmount, uint32_t trackingNumber);
both: both:
RequestDelete(); RequestDelete();

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

@ -162,6 +162,10 @@ TCPSocket.prototype = {
_waitingForStartTLS: false, _waitingForStartTLS: false,
_pendingDataAfterStartTLS: [], _pendingDataAfterStartTLS: [],
// Used to notify when update bufferedAmount is updated.
_onUpdateBufferedAmount: null,
_trackingNumber: 0,
#ifdef MOZ_WIDGET_GONK #ifdef MOZ_WIDGET_GONK
// Network statistics (Gonk-specific feature) // Network statistics (Gonk-specific feature)
_txBytes: 0, _txBytes: 0,
@ -242,6 +246,12 @@ TCPSocket.prototype = {
.createTransport(options, 1, host, port, null); .createTransport(options, 1, host, port, null);
}, },
_sendBufferedAmount: function ts_sendBufferedAmount() {
if (this._onUpdateBufferedAmount) {
this._onUpdateBufferedAmount(this.bufferedAmount, this._trackingNumber);
}
},
_ensureCopying: function ts_ensureCopying() { _ensureCopying: function ts_ensureCopying() {
let self = this; let self = this;
if (this._asyncCopierActive) { if (this._asyncCopierActive) {
@ -254,6 +264,7 @@ TCPSocket.prototype = {
onStopRequest: function ts_output_onStopRequest(request, context, status) { onStopRequest: function ts_output_onStopRequest(request, context, status) {
self._asyncCopierActive = false; self._asyncCopierActive = false;
self._multiplexStream.removeStream(0); self._multiplexStream.removeStream(0);
self._sendBufferedAmount();
if (!Components.isSuccessCode(status)) { if (!Components.isSuccessCode(status)) {
// Note that we can/will get an error here as well as in the // Note that we can/will get an error here as well as in the
@ -280,7 +291,9 @@ TCPSocket.prototype = {
} }
} }
if (self._waitingForDrain) { // If we have a callback to update bufferedAmount, we let child to
// decide whether ondrain should be dispatched.
if (self._waitingForDrain && !self._onUpdateBufferedAmount) {
self._waitingForDrain = false; self._waitingForDrain = false;
self.callListener("drain"); self.callListener("drain");
} }
@ -382,9 +395,36 @@ TCPSocket.prototype = {
this.callListener(type); this.callListener(type);
}, },
updateReadyStateAndBuffered: function ts_setReadyState(readyState, bufferedAmount) { /**
* This method is expected to be called by TCPSocketChild to update child's
* readyState.
*/
updateReadyState: function ts_updateReadyState(readyState) {
if (!this._inChild) {
LOG("Calling updateReadyState in parent, which should only be called " +
"in child");
return;
}
this._readyState = readyState; this._readyState = readyState;
},
updateBufferedAmount: function ts_updateBufferedAmount(bufferedAmount, trackingNumber) {
if (trackingNumber != this._trackingNumber) {
LOG("updateBufferedAmount is called but trackingNumber is not matched " +
"parent's trackingNumber: " + trackingNumber + ", child's trackingNumber: " +
this._trackingNumber);
return;
}
this._bufferedAmount = bufferedAmount; this._bufferedAmount = bufferedAmount;
if (bufferedAmount == 0) {
if (this._waitingForDrain) {
this._waitingForDrain = false;
this.callListener("drain");
}
} else {
LOG("bufferedAmount is updated but haven't reaches zero. bufferedAmount: " +
bufferedAmount);
}
}, },
createAcceptedParent: function ts_createAcceptedParent(transport, binaryType) { createAcceptedParent: function ts_createAcceptedParent(transport, binaryType) {
@ -420,6 +460,25 @@ TCPSocket.prototype = {
#endif #endif
}, },
setOnUpdateBufferedAmountHandler: function(aFunction) {
if (typeof(aFunction) == 'function') {
this._onUpdateBufferedAmount = aFunction;
} else {
throw new Error("only function can be passed to " +
"setOnUpdateBufferedAmountHandler");
}
},
/**
* Handle the requst of sending data and update trackingNumber from
* child.
* This function is expected to be called by TCPSocketChild.
*/
onRecvSendFromChild: function(data, byteOffset, byteLength, trackingNumber) {
this._trackingNumber = trackingNumber;
this.send(data, byteOffset, byteLength);
},
/* end nsITCPSocketInternal methods */ /* end nsITCPSocketInternal methods */
initWindowless: function ts_initWindowless() { initWindowless: function ts_initWindowless() {
@ -517,8 +576,8 @@ TCPSocket.prototype = {
if (this._inChild) { if (this._inChild) {
that._socketBridge = Cc["@mozilla.org/tcp-socket-child;1"] that._socketBridge = Cc["@mozilla.org/tcp-socket-child;1"]
.createInstance(Ci.nsITCPSocketChild); .createInstance(Ci.nsITCPSocketChild);
that._socketBridge.open(that, host, port, !!that._ssl, that._socketBridge.sendOpen(that, host, port, !!that._ssl,
that._binaryType, this.useWin, this.useWin || this); that._binaryType, this.useWin, this.useWin || this);
return that; return that;
} }
@ -551,7 +610,7 @@ TCPSocket.prototype = {
this._ssl = 'ssl'; this._ssl = 'ssl';
if (this._inChild) { if (this._inChild) {
this._socketBridge.startTLS(); this._socketBridge.sendStartTLS();
return; return;
} }
@ -585,7 +644,7 @@ TCPSocket.prototype = {
this._readyState = kCLOSING; this._readyState = kCLOSING;
if (this._inChild) { if (this._inChild) {
this._socketBridge.close(); this._socketBridge.sendClose();
return; return;
} }
@ -605,15 +664,27 @@ TCPSocket.prototype = {
} }
if (this._inChild) { if (this._inChild) {
this._socketBridge.send(data, byteOffset, byteLength); this._socketBridge.sendSend(data, byteOffset, byteLength, ++this._trackingNumber);
} }
let length = this._binaryType === "arraybuffer" ? byteLength : data.length; let length = this._binaryType === "arraybuffer" ? byteLength : data.length;
let newBufferedAmount = this.bufferedAmount + length;
let bufferFull = newBufferedAmount >= BUFFER_SIZE;
if (bufferFull) {
// If we buffered more than some arbitrary amount of data,
// (65535 right now) we should tell the caller so they can
// wait until ondrain is called if they so desire. Once all the
// buffered data has been written to the socket, ondrain is
// called.
this._waitingForDrain = true;
}
var newBufferedAmount = this.bufferedAmount + length;
var bufferNotFull = newBufferedAmount < BUFFER_SIZE;
if (this._inChild) { if (this._inChild) {
return bufferNotFull; // In child, we just add buffer length to our bufferedAmount and let
// parent to update our bufferedAmount when data have been sent.
this._bufferedAmount = newBufferedAmount;
return !bufferFull;
} }
let new_stream; let new_stream;
@ -633,15 +704,6 @@ TCPSocket.prototype = {
this._multiplexStream.appendStream(new_stream); this._multiplexStream.appendStream(new_stream);
} }
if (newBufferedAmount >= BUFFER_SIZE) {
// If we buffered more than some arbitrary amount of data,
// (65535 right now) we should tell the caller so they can
// wait until ondrain is called if they so desire. Once all the
//buffered data has been written to the socket, ondrain is
// called.
this._waitingForDrain = true;
}
this._ensureCopying(); this._ensureCopying();
#ifdef MOZ_WIDGET_GONK #ifdef MOZ_WIDGET_GONK
@ -650,12 +712,12 @@ TCPSocket.prototype = {
this._saveNetworkStats(false); this._saveNetworkStats(false);
#endif #endif
return bufferNotFull; return !bufferFull;
}, },
suspend: function ts_suspend() { suspend: function ts_suspend() {
if (this._inChild) { if (this._inChild) {
this._socketBridge.suspend(); this._socketBridge.sendSuspend();
return; return;
} }
@ -668,7 +730,7 @@ TCPSocket.prototype = {
resume: function ts_resume() { resume: function ts_resume() {
if (this._inChild) { if (this._inChild) {
this._socketBridge.resume(); this._socketBridge.sendResume();
return; return;
} }

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

@ -77,10 +77,11 @@ TCPSocketChild::TCPSocketChild()
} }
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketChild::Open(nsITCPSocketInternal* aSocket, const nsAString& aHost, TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
uint16_t aPort, bool aUseSSL, const nsAString& aBinaryType, const nsAString& aHost, uint16_t aPort,
nsIDOMWindow* aWindow, const JS::Value& aWindowObj, bool aUseSSL, const nsAString& aBinaryType,
JSContext* aCx) nsIDOMWindow* aWindow, const JS::Value& aWindowObj,
JSContext* aCx)
{ {
mSocket = aSocket; mSocket = aSocket;
@ -91,7 +92,8 @@ TCPSocketChild::Open(nsITCPSocketInternal* aSocket, const nsAString& aHost,
} }
AddIPDLReference(); AddIPDLReference();
gNeckoChild->SendPTCPSocketConstructor(this); gNeckoChild->SendPTCPSocketConstructor(this);
SendOpen(nsString(aHost), aPort, aUseSSL, nsString(aBinaryType)); PTCPSocketChild::SendOpen(nsString(aHost), aPort,
aUseSSL, nsString(aBinaryType));
return NS_OK; return NS_OK;
} }
@ -115,13 +117,22 @@ TCPSocketChild::~TCPSocketChild()
{ {
} }
bool
TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered,
const uint32_t& aTrackingNumber)
{
if (NS_FAILED(mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber))) {
NS_ERROR("Shouldn't fail!");
}
return true;
}
bool bool
TCPSocketChild::RecvCallback(const nsString& aType, TCPSocketChild::RecvCallback(const nsString& aType,
const CallbackData& aData, const CallbackData& aData,
const nsString& aReadyState, const nsString& aReadyState)
const uint32_t& aBuffered)
{ {
if (NS_FAILED(mSocket->UpdateReadyStateAndBuffered(aReadyState, aBuffered))) if (NS_FAILED(mSocket->UpdateReadyState(aReadyState)))
NS_ERROR("Shouldn't fail!"); NS_ERROR("Shouldn't fail!");
nsresult rv = NS_ERROR_FAILURE; nsresult rv = NS_ERROR_FAILURE;
@ -159,46 +170,46 @@ TCPSocketChild::RecvCallback(const nsString& aType,
} }
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketChild::StartTLS() TCPSocketChild::SendStartTLS()
{ {
SendStartTLS(); PTCPSocketChild::SendStartTLS();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketChild::Suspend() TCPSocketChild::SendSuspend()
{ {
SendSuspend(); PTCPSocketChild::SendSuspend();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketChild::Resume() TCPSocketChild::SendResume()
{ {
SendResume(); PTCPSocketChild::SendResume();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketChild::Close() TCPSocketChild::SendClose()
{ {
SendClose(); PTCPSocketChild::SendClose();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketChild::Send(const JS::Value& aData, TCPSocketChild::SendSend(const JS::Value& aData,
uint32_t aByteOffset, uint32_t aByteOffset,
uint32_t aByteLength, uint32_t aByteLength,
JSContext* aCx) uint32_t aTrackingNumber,
JSContext* aCx)
{ {
if (aData.isString()) { if (aData.isString()) {
JSString* jsstr = aData.toString(); JSString* jsstr = aData.toString();
nsDependentJSString str; nsDependentJSString str;
bool ok = str.init(aCx, jsstr); bool ok = str.init(aCx, jsstr);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
SendData(str); SendData(str, aTrackingNumber);
} else { } else {
NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE); NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
JS::Rooted<JSObject*> obj(aCx, &aData.toObject()); JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
@ -216,15 +227,15 @@ TCPSocketChild::Send(const JS::Value& aData,
} }
InfallibleTArray<uint8_t> arr; InfallibleTArray<uint8_t> arr;
arr.SwapElements(fallibleArr); arr.SwapElements(fallibleArr);
SendData(arr); SendData(arr, aTrackingNumber);
} }
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket, TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket,
const JS::Value& aWindowObj, const JS::Value& aWindowObj,
JSContext* aCx) JSContext* aCx)
{ {
mSocket = aSocket; mSocket = aSocket;
MOZ_ASSERT(aWindowObj.isObject()); MOZ_ASSERT(aWindowObj.isObject());

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

@ -44,9 +44,10 @@ public:
virtual bool RecvCallback(const nsString& aType, virtual bool RecvCallback(const nsString& aType,
const CallbackData& aData, const CallbackData& aData,
const nsString& aReadyState, const nsString& aReadyState) MOZ_OVERRIDE;
const uint32_t& aBuffered) MOZ_OVERRIDE;
virtual bool RecvRequestDelete() MOZ_OVERRIDE; virtual bool RecvRequestDelete() MOZ_OVERRIDE;
virtual bool RecvUpdateBufferedAmount(const uint32_t& aBufferred,
const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
private: private:
JSObject* mWindowObj; JSObject* mWindowObj;
}; };

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

@ -35,7 +35,7 @@ FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo)
mozilla::unused << mozilla::unused <<
aActor->SendCallback(NS_LITERAL_STRING("onerror"), aActor->SendCallback(NS_LITERAL_STRING("onerror"),
TCPError(NS_LITERAL_STRING("InvalidStateError")), TCPError(NS_LITERAL_STRING("InvalidStateError")),
NS_LITERAL_STRING("connecting"), 0); NS_LITERAL_STRING("connecting"));
} }
NS_IMPL_CYCLE_COLLECTION_2(TCPSocketParentBase, mSocket, mIntermediary) NS_IMPL_CYCLE_COLLECTION_2(TCPSocketParentBase, mSocket, mIntermediary)
@ -156,7 +156,8 @@ TCPSocketParent::RecvResume()
} }
bool bool
TCPSocketParent::RecvData(const SendableData& aData) TCPSocketParent::RecvData(const SendableData& aData,
const uint32_t& aTrackingNumber)
{ {
NS_ENSURE_TRUE(mIntermediary, true); NS_ENSURE_TRUE(mIntermediary, true);
@ -168,13 +169,13 @@ TCPSocketParent::RecvData(const SendableData& aData)
JS::Rooted<JS::Value> val(cx); JS::Rooted<JS::Value> val(cx);
JS::Rooted<JSObject*> obj(cx, mIntermediaryObj); JS::Rooted<JSObject*> obj(cx, mIntermediaryObj);
IPC::DeserializeArrayBuffer(obj, aData.get_ArrayOfuint8_t(), &val); IPC::DeserializeArrayBuffer(obj, aData.get_ArrayOfuint8_t(), &val);
rv = mIntermediary->SendArrayBuffer(val); rv = mIntermediary->OnRecvSendArrayBuffer(val, aTrackingNumber);
NS_ENSURE_SUCCESS(rv, true); NS_ENSURE_SUCCESS(rv, true);
break; break;
} }
case SendableData::TnsString: case SendableData::TnsString:
rv = mIntermediary->SendString(aData.get_nsString()); rv = mIntermediary->OnRecvSendString(aData.get_nsString(), aTrackingNumber);
NS_ENSURE_SUCCESS(rv, true); NS_ENSURE_SUCCESS(rv, true);
break; break;
@ -194,9 +195,8 @@ TCPSocketParent::RecvClose()
} }
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketParent::SendCallback(const nsAString& aType, const JS::Value& aDataVal, TCPSocketParent::SendEvent(const nsAString& aType, const JS::Value& aDataVal,
const nsAString& aReadyState, uint32_t aBuffered, const nsAString& aReadyState, JSContext* aCx)
JSContext* aCx)
{ {
if (!mIPCOpen) { if (!mIPCOpen) {
NS_WARNING("Dropping callback due to no IPC connection"); NS_WARNING("Dropping callback due to no IPC connection");
@ -255,7 +255,7 @@ TCPSocketParent::SendCallback(const nsAString& aType, const JS::Value& aDataVal,
} }
mozilla::unused << mozilla::unused <<
PTCPSocketParent::SendCallback(nsString(aType), data, PTCPSocketParent::SendCallback(nsString(aType), data,
nsString(aReadyState), aBuffered); nsString(aReadyState));
return NS_OK; return NS_OK;
} }
@ -269,6 +269,15 @@ TCPSocketParent::SetSocketAndIntermediary(nsIDOMTCPSocket *socket,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount,
uint32_t aTrackingNumber)
{
mozilla::unused << PTCPSocketParent::SendUpdateBufferedAmount(aBufferedAmount,
aTrackingNumber);
return NS_OK;
}
void void
TCPSocketParent::ActorDestroy(ActorDestroyReason why) TCPSocketParent::ActorDestroy(ActorDestroyReason why)
{ {

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

@ -51,7 +51,8 @@ public:
virtual bool RecvSuspend() MOZ_OVERRIDE; virtual bool RecvSuspend() MOZ_OVERRIDE;
virtual bool RecvResume() MOZ_OVERRIDE; virtual bool RecvResume() MOZ_OVERRIDE;
virtual bool RecvClose() MOZ_OVERRIDE; virtual bool RecvClose() MOZ_OVERRIDE;
virtual bool RecvData(const SendableData& aData) MOZ_OVERRIDE; virtual bool RecvData(const SendableData& aData,
const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
virtual bool RecvRequestDelete() MOZ_OVERRIDE; virtual bool RecvRequestDelete() MOZ_OVERRIDE;
private: private:

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

@ -20,15 +20,21 @@ TCPSocketParentIntermediary.prototype = {
// Create handlers for every possible callback that attempt to trigger // Create handlers for every possible callback that attempt to trigger
// corresponding callbacks on the child object. // corresponding callbacks on the child object.
["open", "drain", "data", "error", "close"].forEach( // ondrain event is not forwarded, since the decision of firing ondrain
// is made in child.
["open", "data", "error", "close"].forEach(
function(p) { function(p) {
socket["on" + p] = function(data) { socket["on" + p] = function(data) {
aParentSide.sendCallback(p, data.data, socket.readyState, aParentSide.sendEvent(p, data.data, socket.readyState,
socket.bufferedAmount); socket.bufferedAmount);
}; };
} }
); );
}, },
_onUpdateBufferedAmountHandler: function(aParentSide, aBufferedAmount, aTrackingNumber) {
aParentSide.sendUpdateBufferedAmount(aBufferedAmount, aTrackingNumber);
},
open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType, aAppId) { open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType, aAppId) {
let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket); let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
@ -41,6 +47,10 @@ TCPSocketParentIntermediary.prototype = {
socketInternal.setAppId(aAppId); socketInternal.setAppId(aAppId);
} }
// Handle parent's request to update buffered amount.
socketInternal.setOnUpdateBufferedAmountHandler(
this._onUpdateBufferedAmountHandler.bind(this, aParentSide));
// Handlers are set to the JS-implemented socket object on the parent side. // Handlers are set to the JS-implemented socket object on the parent side.
this._setCallbacks(aParentSide, socket); this._setCallbacks(aParentSide, socket);
return socket; return socket;
@ -79,12 +89,15 @@ TCPSocketParentIntermediary.prototype = {
return serverSocket; return serverSocket;
}, },
sendString: function(aData) { onRecvSendString: function(aData, aTrackingNumber) {
return this._socket.send(aData); let socketInternal = this._socket.QueryInterface(Ci.nsITCPSocketInternal);
return socketInternal.onRecvSendFromChild(aData, 0, 0, aTrackingNumber);
}, },
sendArrayBuffer: function(aData) { onRecvSendArrayBuffer: function(aData, aTrackingNumber) {
return this._socket.send(aData, 0, aData.byteLength); let socketInternal = this._socket.QueryInterface(Ci.nsITCPSocketInternal);
return socketInternal.onRecvSendFromChild(aData, 0, aData.byteLength,
aTrackingNumber);
}, },
classID: Components.ID("{afa42841-a6cb-4a91-912f-93099f6a3d18}"), classID: Components.ID("{afa42841-a6cb-4a91-912f-93099f6a3d18}"),

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

@ -80,6 +80,11 @@ function get_platform() {
return xulRuntime.OS; return xulRuntime.OS;
} }
function is_content() {
return this._inChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
}
/** /**
* Spin up a listening socket and associate at most one live, accepted socket * Spin up a listening socket and associate at most one live, accepted socket
* with ourselves. * with ourselves.
@ -418,9 +423,15 @@ function drainTwice() {
['ondrain', 'ondrain2', ['ondrain', 'ondrain2',
'ondata', 'ondata2', 'ondata', 'ondata2',
'serverclose', 'clientclose']); 'serverclose', 'clientclose']);
let ondrainCalled = false,
ondataCalled = false;
function maybeSendNextData() {
if (!ondrainCalled || !ondataCalled) {
// make sure server got data and client got ondrain.
return;
}
function serverSideCallback() {
yays.ondata();
server.ondata = makeExpectData( server.ondata = makeExpectData(
"ondata2", BIG_TYPED_ARRAY_2, false, yays.ondata2); "ondata2", BIG_TYPED_ARRAY_2, false, yays.ondata2);
@ -433,12 +444,24 @@ function drainTwice() {
sock.close(); sock.close();
} }
function clientOndrain() {
yays.ondrain();
ondrainCalled = true;
maybeSendNextData();
}
function serverSideCallback() {
yays.ondata();
ondataCalled = true;
maybeSendNextData();
}
server.onclose = yays.serverclose; server.onclose = yays.serverclose;
server.ondata = makeExpectData( server.ondata = makeExpectData(
"ondata", BIG_TYPED_ARRAY, false, serverSideCallback); "ondata", BIG_TYPED_ARRAY, false, serverSideCallback);
sock.onclose = yays.clientclose; sock.onclose = yays.clientclose;
sock.ondrain = yays.ondrain; sock.ondrain = clientOndrain;
if (sock.send(BIG_ARRAY_BUFFER)) { if (sock.send(BIG_ARRAY_BUFFER)) {
throw new Error("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering"); throw new Error("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
@ -482,6 +505,62 @@ function bufferTwice() {
} }
} }
// Test child behavior when child thinks it's buffering but parent doesn't
// buffer.
// 1. set bufferedAmount of content socket to a value that will make next
// send() call return false.
// 2. send a small data to make send() return false, but it won't make
// parent buffer.
// 3. we should get a ondrain.
function childbuffered() {
let yays = makeJointSuccess(['ondrain', 'serverdata',
'clientclose', 'serverclose']);
sock.ondrain = function() {
yays.ondrain();
sock.close();
};
server.ondata = makeExpectData(
'ondata', DATA_ARRAY, false, yays.serverdata);
let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
internalSocket.updateBufferedAmount(65535, // almost reach buffering threshold
0);
if (sock.send(DATA_ARRAY_BUFFER)) {
do_throw("expected sock.send to return false.");
}
sock.onclose = yays.clientclose;
server.onclose = yays.serverclose;
}
// Test child's behavior when send() of child return true but parent buffers
// data.
// 1. send BIG_ARRAY to make parent buffer. This would make child wait for
// drain as well.
// 2. set child's bufferedAmount to zero, so child will no longer wait for
// drain but parent will dispatch a drain event.
// 3. wait for 1 second, to make sure there's no ondrain event dispatched in
// child.
function childnotbuffered() {
let yays = makeJointSuccess(['serverdata', 'clientclose', 'serverclose']);
server.ondata = makeExpectData('ondata', BIG_ARRAY, false, yays.serverdata);
if (sock.send(BIG_ARRAY_BUFFER)) {
do_throw("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
}
let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
internalSocket.updateBufferedAmount(0, // setting zero will clear waitForDrain in sock.
1);
// shouldn't get ondrain, even after parent have cleared its buffer.
sock.ondrain = makeFailureCase('drain');
sock.onclose = yays.clientclose;
server.onclose = yays.serverclose;
do_timeout(1000, function() {
sock.close();
});
};
// - connect, data and events work both ways // - connect, data and events work both ways
add_test(connectSock); add_test(connectSock);
add_test(sendData); add_test(sendData);
@ -513,6 +592,14 @@ add_test(drainTwice);
add_test(connectSock); add_test(connectSock);
add_test(bufferTwice); add_test(bufferTwice);
if (is_content()) {
add_test(connectSock);
add_test(childnotbuffered);
add_test(connectSock);
add_test(childbuffered);
}
// clean up // clean up
add_test(cleanup); add_test(cleanup);

64
dom/nfc/MozNdefRecord.cpp Normal file
Просмотреть файл

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
/* Copyright © 2013 Deutsche Telekom, Inc. */
#include "MozNdefRecord.h"
#include "mozilla/dom/MozNdefRecordBinding.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(MozNdefRecord, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MozNdefRecord)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MozNdefRecord)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozNdefRecord)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
/* static */
already_AddRefed<MozNdefRecord>
MozNdefRecord::Constructor(const GlobalObject& aGlobal,
uint8_t aTnf, const nsAString& aType,
const nsAString& aId, const nsAString& aPayload,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
if (!win) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<MozNdefRecord> ndefrecord =
new MozNdefRecord(win, aTnf, aType, aId, aPayload);
return ndefrecord.forget();
}
MozNdefRecord::MozNdefRecord(nsPIDOMWindow* aWindow,
uint8_t aTnf, const nsAString& aType,
const nsAString& aId, const nsAString& aPayload)
: mTnf(aTnf)
, mType(aType)
, mId(aId)
, mPayload(aPayload)
{
mWindow = aWindow;
SetIsDOMBinding();
}
MozNdefRecord::~MozNdefRecord()
{
}
JSObject*
MozNdefRecord::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return MozNdefRecordBinding::Wrap(aCx, aScope, this);
}
} // namespace dom
} // namespace mozilla

88
dom/nfc/MozNdefRecord.h Normal file
Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
/* Copyright © 2013 Deutsche Telekom, Inc. */
#ifndef mozilla_dom_MozNdefRecord_h__
#define mozilla_dom_MozNdefRecord_h__
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "jsapi.h"
#include "nsIDocument.h"
struct JSContext;
namespace mozilla {
namespace dom {
class MozNdefRecord MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MozNdefRecord)
public:
MozNdefRecord(nsPIDOMWindow* aWindow,
uint8_t aTnf, const nsAString& aType,
const nsAString& aId, const nsAString& aPlayload);
~MozNdefRecord();
nsIDOMWindow* GetParentObject() const
{
return mWindow;
}
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
static already_AddRefed<MozNdefRecord> Constructor(
const GlobalObject& aGlobal,
uint8_t aTnf, const nsAString& aType,
const nsAString& aId,
const nsAString& aPayload,
ErrorResult& aRv);
uint8_t Tnf() const
{
return mTnf;
}
void GetType(nsString& aType) const
{
aType = mType;
}
void GetId(nsString& aId) const
{
aId = mId;
}
void GetPayload(nsString& aPayload) const
{
aPayload = mPayload;
}
private:
MozNdefRecord() MOZ_DELETE;
nsRefPtr<nsPIDOMWindow> mWindow;
uint8_t mTnf;
nsString mType;
nsString mId;
nsString mPayload;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MozNdefRecord_h__

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше