Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-05-29 09:45:10 -04:00
commit a1155fd152
793 changed files with 97637 additions and 9402 deletions

View File

@ -254,7 +254,7 @@ endif # MOZ_CRASHREPORTER
uploadsymbols:
ifdef MOZ_CRASHREPORTER
ifdef SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE
$(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.py '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
$(PYTHON) -u $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.py '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
else
$(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(SYMBOL_INDEX_NAME) '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
endif

View File

@ -316,7 +316,7 @@ pref("browser.urlbar.autoFill", true);
pref("browser.urlbar.autoFill.typed", true);
// Use the new unifiedComplete component
pref("browser.urlbar.unifiedcomplete", false);
pref("browser.urlbar.unifiedcomplete", true);
// 0: Match anywhere (e.g., middle of words)
// 1: Match on word boundaries and then try matching anywhere

View File

@ -143,8 +143,12 @@ const gXPInstallObserver = {
cancelButton.accessKey = gNavigatorBundle.getString("addonInstall.cancelButton.accesskey");
let acceptButton = document.getElementById("addon-progress-accept");
acceptButton.label = gNavigatorBundle.getString("addonInstall.acceptButton.label");
acceptButton.accessKey = gNavigatorBundle.getString("addonInstall.acceptButton.accesskey");
if (Preferences.get("xpinstall.customConfirmationUI", false)) {
acceptButton.label = gNavigatorBundle.getString("addonInstall.acceptButton.label");
acceptButton.accessKey = gNavigatorBundle.getString("addonInstall.acceptButton.accesskey");
} else {
acceptButton.hidden = true;
}
break; }
case "addon-install-failed": {
// TODO This isn't terribly ideal for the multiple failure case

View File

@ -15,6 +15,9 @@ var FullScreen = {
init: function() {
// called when we go into full screen, even if initiated by a web page script
window.addEventListener("fullscreen", this, true);
window.addEventListener("MozDOMFullscreen:Exited", this,
/* useCapture */ true,
/* wantsUntrusted */ false);
for (let type of this._MESSAGES) {
window.messageManager.addMessageListener(type, this);
}
@ -97,6 +100,9 @@ var FullScreen = {
if (event.propertyName == "opacity")
this.cancelWarning();
break;
case "MozDOMFullscreen:Exited":
this.cleanupDomFullscreen();
break;
}
},
@ -125,15 +131,7 @@ var FullScreen = {
if (this._isRemoteBrowser(browser)) {
this._windowUtils.remoteFrameFullscreenReverted();
}
document.documentElement.removeAttribute("inDOMFullscreen");
this.cleanupDomFullscreen();
this.showNavToolbox();
// If we are still in fullscreen mode, re-hide
// the toolbox with animation.
if (window.fullScreen) {
this._shouldAnimate = true;
this.hideNavToolbox();
}
break;
}
}
@ -189,8 +187,6 @@ var FullScreen = {
document.removeEventListener("keypress", this._keyToggleCallback, false);
document.removeEventListener("popupshown", this._setPopupOpen, false);
document.removeEventListener("popuphidden", this._setPopupOpen, false);
this.cleanupDomFullscreen();
}
},
@ -202,6 +198,15 @@ var FullScreen = {
if (!this.useLionFullScreen)
window.removeEventListener("activate", this);
document.documentElement.removeAttribute("inDOMFullscreen");
this.showNavToolbox();
// If we are still in fullscreen mode, re-hide
// the toolbox with animation.
if (window.fullScreen) {
this._shouldAnimate = true;
this.hideNavToolbox();
}
window.messageManager
.broadcastAsyncMessage("DOMFullscreen:CleanUp");
},

View File

@ -2367,7 +2367,9 @@ function BrowserViewSourceOfDocument(aArgsOrDocument) {
// In the case of sidebars and chat windows, gBrowser is defined but null,
// because no #content element exists. For these cases, we need to find
// the most recent browser window.
if (!tabBrowser) {
// In the case of popups, we need to find a non-popup browser window.
if (!tabBrowser || !window.toolbar.visible) {
// This returns only non-popup browser windows by default.
let browserWindow = RecentWindow.getMostRecentBrowserWindow();
tabBrowser = browserWindow.gBrowser;
}

View File

@ -1011,7 +1011,9 @@ nsContextMenu.prototype = {
// In the case of sidebars and chat windows, gBrowser is defined but null,
// because no #content element exists. For these cases, we need to find
// the most recent browser window.
if (!tabBrowser) {
// In the case of popups, we need to find a non-popup browser window.
if (!tabBrowser || !window.toolbar.visible) {
// This returns only non-popup browser windows by default.
let browserWindow = RecentWindow.getMostRecentBrowserWindow();
tabBrowser = browserWindow.gBrowser;
}

View File

@ -344,7 +344,7 @@ skip-if = asan # Disabled because it takes a long time (see test for more inform
[browser_popupUI.js]
skip-if = buildapp == 'mulet'
[browser_popup_blocker.js]
skip-if = e10s && debug # Frequent bug 1125520 failures
skip-if = (os == 'linux') || (e10s && debug) # Frequent bug 1081925 and bug 1125520 failures
[browser_printpreview.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1101973 - breaks the next test in e10s, and may be responsible for later timeout after logging "Error: Channel closing: too late to send/recv, messages will be lost"
[browser_private_browsing_window.js]

View File

@ -2,4 +2,4 @@
# 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/.
MOZ_APP_DISPLAYNAME=MozillaDeveloperPreview
MOZ_APP_DISPLAYNAME=Nightly

View File

@ -2,8 +2,8 @@
- 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/. -->
<!ENTITY brandShorterName "Mozilla Developer Preview">
<!ENTITY brandShortName "Mozilla Developer Preview">
<!ENTITY brandFullName "Mozilla Developer Preview">
<!ENTITY vendorShortName "mozilla.org">
<!ENTITY brandShorterName "Nightly">
<!ENTITY brandShortName "Nightly">
<!ENTITY brandFullName "Nightly">
<!ENTITY vendorShortName "Mozilla">
<!ENTITY trademarkInfo.part1 " ">

View File

@ -2,9 +2,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
brandShorterName=Mozilla Developer Preview
brandShortName=Mozilla Developer Preview
brandFullName=Mozilla Developer Preview
vendorShortName=mozilla.org
brandShorterName=Nightly
brandShortName=Nightly
brandFullName=Nightly
vendorShortName=Mozilla
syncBrandShortName=Sync

View File

@ -163,7 +163,7 @@ loop.conversation = (function(mozL10n) {
dispatcher: dispatcher,
mozLoop: navigator.mozLoop}), document.querySelector("#main"));
document.body.setAttribute("dir", "rtl");//mozL10n.getDirection());
document.body.setAttribute("dir", mozL10n.getDirection());
document.body.setAttribute("platform", loop.shared.utils.getPlatform());
dispatcher.dispatch(new sharedActions.GetWindowData({

View File

@ -163,7 +163,7 @@ loop.conversation = (function(mozL10n) {
dispatcher={dispatcher}
mozLoop={navigator.mozLoop} />, document.querySelector("#main"));
document.body.setAttribute("dir", "rtl");//mozL10n.getDirection());
document.body.setAttribute("dir", mozL10n.getDirection());
document.body.setAttribute("platform", loop.shared.utils.getPlatform());
dispatcher.dispatch(new sharedActions.GetWindowData({

View File

@ -17,23 +17,41 @@
<link rel="localization" href="l10n/{locale}/loop.properties">
<script>
// window.navigator.doNotTrack "yes" is for old versions of FF
// window.navigator.doNotTrack "1" is for current versions of FF + Chrome + Opera
// window.doNotTrack is safari
// window.navigator.msDoNotTrack
if (window.navigator.doNotTrack !== "yes" &&
window.navigator.doNotTrack !== "1" &&
window.doNotTrack !== "1" &&
window.navigator.msDoNotTrack !== "1") {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
(function() {
function insertScript(url) {
var node = document.createElement("script");
var sibling = document.getElementsByTagName("script")[0];
node.async = 1;
node.src = url;
sibling.parentNode.insertBefore(node, sibling);
}
ga('create', 'UA-36116321-15', 'auto');
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
}
// window.navigator.doNotTrack "yes" is for old versions of FF
// window.navigator.doNotTrack "1" is for current versions of FF + Chrome + Opera
// window.doNotTrack is safari
// window.navigator.msDoNotTrack
if (window.navigator.doNotTrack !== "yes" &&
window.navigator.doNotTrack !== "1" &&
window.doNotTrack !== "1" &&
window.navigator.msDoNotTrack !== "1") {
insertScript("//cdn.optimizely.com/js/2768540301.js");
// This is an unfolded, readable version of the official GA inclusion
// script.
window.GoogleAnalyticsObject = "ga";
window.ga = window.ga || function() {
(window.ga.q = window.ga.q || []).push(arguments);
};
window.ga.l = 1 * new Date();
insertScript("//www.google-analytics.com/analytics.js");
window.ga("create", "UA-36116321-15", "auto");
window.ga("set", "anonymizeIp", true);
window.ga("send", "pageview");
}
})();
</script>
</head>
@ -60,14 +78,14 @@
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
};
}
myCustomEvent.prototype = window.Event.prototype;
window.CustomEvent = myCustomEvent;
}
// To support IE for the l10n-gaia library on IE <= 10.
if (!"language" in navigator) {
if (!("language" in navigator)) {
navigator.language = navigator.browserLanguage;
}
@ -76,21 +94,21 @@
// Define a dummy MutationObserver object if one doesn't exist
// This could later be extended to use Mutation events but for
// now this will simply result in no-ops.
function myMutationObserver() {};
function myMutationObserver() {}
myMutationObserver.prototype = {
disconnect: function() {},
observe: function () {},
takeRecords: function() {},
takeRecords: function() {}
};
window.MutationObserver = myMutationObserver;
}
window.OTProperties = {
cdnURL: 'shared/libs/',
cdnURL: "shared/libs/"
};
window.OTProperties.assetURL = window.OTProperties.cdnURL + 'sdk-content/';
window.OTProperties.configURL = window.OTProperties.assetURL + 'js/dynamic_config.min.js';
window.OTProperties.cssURL = window.OTProperties.assetURL + 'css/ot.css';
window.OTProperties.assetURL = window.OTProperties.cdnURL + "sdk-content/";
window.OTProperties.configURL = window.OTProperties.assetURL + "js/dynamic_config.min.js";
window.OTProperties.cssURL = window.OTProperties.assetURL + "css/ot.css";
</script>
<script type="text/javascript" src="js/multiplexGum.js"></script>
<script type="text/javascript" src="shared/libs/sdk.js"></script>
@ -99,7 +117,7 @@
// defined until after sdk.js has been evaluated. This updates the
// navigator object to reference TBPlugin if it was defined by sdk.js.
if (!navigator.originalGum) {
navigator.originalGum = (window["TBPlugin"] && TBPlugin.getUserMedia);
navigator.originalGum = (window.TBPlugin && window.TBPlugin.getUserMedia);
}
</script>
<script type="text/javascript" src="libs/l10n-gaia-02ca67948fe8.js"></script>
@ -139,7 +157,7 @@
<script>
// Wait for all the localization notes to load
window.addEventListener('localized', function() {
window.addEventListener("localized", function() {
loop.webapp.init();
}, false);
</script>

View File

@ -36,56 +36,14 @@ var formHistoryStartup = Cc["@mozilla.org/satchel/form-history-startup;1"].
getService(Ci.nsIObserver);
formHistoryStartup.observe(null, "profile-after-change", null);
let notificationIndex = 0;
let notificationsObserver = {
observe: function observe(aSubject, aTopic, aData) {
print("Received notification: " + aTopic);
// Note that some of these notifications could arrive multiple times, for
// example in case of sync, we allow that.
if (EXPECTED_NOTIFICATIONS[notificationIndex] != aTopic)
notificationIndex++;
do_check_eq(EXPECTED_NOTIFICATIONS[notificationIndex], aTopic);
if (aTopic != TOPIC_CONNECTION_CLOSED)
return;
getDistinctNotifications().forEach(
function (topic) Services.obs.removeObserver(notificationsObserver, topic)
);
print("Looking for uncleared stuff.");
let stmt = DBConn().createStatement(
"SELECT id FROM moz_places WHERE url = :page_url "
);
try {
URIS.forEach(function(aUrl) {
stmt.params.page_url = aUrl;
do_check_false(stmt.executeStep());
stmt.reset();
});
} finally {
stmt.finalize();
}
// Check cache.
checkCache(FTP_URL);
}
}
let timeInMicroseconds = Date.now() * 1000;
function run_test() {
run_next_test();
}
add_task(function test_execute() {
do_test_pending();
print("Initialize browserglue before Places");
add_task(function* test_execute() {
do_print("Initialize browserglue before Places");
// Avoid default bookmarks import.
let glue = Cc["@mozilla.org/browser/browserglue;1"].
@ -105,66 +63,78 @@ add_task(function test_execute() {
Services.prefs.setBoolPref("privacy.sanitize.sanitizeOnShutdown", true);
print("Add visits.");
do_print("Add visits.");
for (let aUrl of URIS) {
yield PlacesTestUtils.addVisits({
uri: uri(aUrl), visitDate: timeInMicroseconds++,
transition: PlacesUtils.history.TRANSITION_TYPED
});
}
print("Add cache.");
storeCache(FTP_URL, "testData");
do_print("Add cache.");
yield storeCache(FTP_URL, "testData");
});
function run_test_continue()
{
print("Simulate and wait shutdown.");
getDistinctNotifications().forEach(
function (topic)
Services.obs.addObserver(notificationsObserver, topic, false)
add_task(function* run_test_continue() {
do_print("Simulate and wait shutdown.");
yield shutdownPlaces();
let stmt = DBConn().createStatement(
"SELECT id FROM moz_places WHERE url = :page_url "
);
shutdownPlaces();
try {
URIS.forEach(function(aUrl) {
stmt.params.page_url = aUrl;
do_check_false(stmt.executeStep());
stmt.reset();
});
} finally {
stmt.finalize();
}
do_print("Check cache");
// Check cache.
let promiseCacheChecked = checkCache(FTP_URL);
do_print("Shutdown the download manager");
// Shutdown the download manager.
Services.obs.notifyObservers(null, "quit-application", null);
}
function getDistinctNotifications() {
let ar = EXPECTED_NOTIFICATIONS.concat(UNEXPECTED_NOTIFICATIONS);
return [ar[i] for (i in ar) if (ar.slice(0, i).indexOf(ar[i]) == -1)];
}
yield promiseCacheChecked;
});
function storeCache(aURL, aContent) {
let cache = Services.cache2;
let storage = cache.diskCacheStorage(LoadContextInfo.default, false);
var storeCacheListener = {
onCacheEntryCheck: function (entry, appcache) {
return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED;
},
return new Promise(resolve => {
let storeCacheListener = {
onCacheEntryCheck: function (entry, appcache) {
return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED;
},
onCacheEntryAvailable: function (entry, isnew, appcache, status) {
do_check_eq(status, Cr.NS_OK);
onCacheEntryAvailable: function (entry, isnew, appcache, status) {
do_check_eq(status, Cr.NS_OK);
entry.setMetaDataElement("servertype", "0");
var os = entry.openOutputStream(0);
entry.setMetaDataElement("servertype", "0");
var os = entry.openOutputStream(0);
var written = os.write(aContent, aContent.length);
if (written != aContent.length) {
do_throw("os.write has not written all data!\n" +
" Expected: " + written + "\n" +
" Actual: " + aContent.length + "\n");
var written = os.write(aContent, aContent.length);
if (written != aContent.length) {
do_throw("os.write has not written all data!\n" +
" Expected: " + written + "\n" +
" Actual: " + aContent.length + "\n");
}
os.close();
entry.close();
resolve();
}
os.close();
entry.close();
do_execute_soon(run_test_continue);
}
};
};
storage.asyncOpenURI(Services.io.newURI(aURL, null, null), "",
Ci.nsICacheStorage.OPEN_NORMALLY,
storeCacheListener);
storage.asyncOpenURI(Services.io.newURI(aURL, null, null), "",
Ci.nsICacheStorage.OPEN_NORMALLY,
storeCacheListener);
});
}
@ -172,14 +142,16 @@ function checkCache(aURL) {
let cache = Services.cache2;
let storage = cache.diskCacheStorage(LoadContextInfo.default, false);
var checkCacheListener = {
onCacheEntryAvailable: function (entry, isnew, appcache, status) {
do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
do_test_finished();
}
};
return new Promise(resolve => {
let checkCacheListener = {
onCacheEntryAvailable: function (entry, isnew, appcache, status) {
do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
resolve();
}
};
storage.asyncOpenURI(Services.io.newURI(aURL, null, null), "",
Ci.nsICacheStorage.OPEN_READONLY,
checkCacheListener);
storage.asyncOpenURI(Services.io.newURI(aURL, null, null), "",
Ci.nsICacheStorage.OPEN_READONLY,
checkCacheListener);
});
}

View File

@ -166,7 +166,7 @@ var gMainPane = {
let tmp = {};
Components.utils.import("resource://gre/modules/UpdateChannel.jsm", tmp);
if (!e10sCheckbox.checked && tmp.UpdateChannel.get() == "nightly") {
if (!e10sCheckbox.checked && tmp.UpdateChannel.get() != "default") {
Services.prefs.setBoolPref("browser.requestE10sFeedback", true);
Services.prompt.alert(window, brandName, "After restart, a tab will open to input.mozilla.org where you can provide us feedback about your e10s experience.");
}

View File

@ -19,4 +19,6 @@ ac_add_options --enable-warnings-as-errors
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -11,6 +11,8 @@ ac_add_options --enable-js-diagnostics
# by 2 MBs.
STRIP_FLAGS="--strip-debug"
ac_add_options --with-branding=browser/branding/nightly
# Use ccache
. "$topsrcdir/build/mozconfig.cache"

View File

@ -19,4 +19,6 @@ ac_add_options --enable-warnings-as-errors
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -11,6 +11,8 @@ ac_add_options --enable-js-diagnostics
# by 2 MBs.
STRIP_FLAGS="--strip-debug"
ac_add_options --with-branding=browser/branding/nightly
# Use ccache
. "$topsrcdir/build/mozconfig.cache"

View File

@ -13,4 +13,6 @@ if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
ac_add_options --with-macbundlename-prefix=Firefox
fi
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -18,4 +18,6 @@ ac_add_options --enable-warnings-as-errors
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -16,4 +16,6 @@ ac_add_options --enable-warnings-as-errors
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -10,6 +10,7 @@ all_platforms = ['win64', 'win32', 'linux32', 'linux64', 'macosx-universal']
for platform in all_platforms:
whitelist['nightly'][platform] = [
'ac_add_options --enable-update-channel=nightly',
'ac_add_options --with-branding=browser/branding/nightly',
'ac_add_options --enable-profiling',
'mk_add_options CLIENT_PY_ARGS="--hg-options=\'--verbose --time\' --hgtool=../tools/buildfarm/utils/hgtool.py --skip-chatzilla --skip-comm --skip-inspector --tinderbox-print"'
]

View File

@ -26,6 +26,8 @@ ac_add_options --enable-warnings-as-errors
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.cache"
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -7,6 +7,8 @@ ac_add_options --enable-profiling
# Nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.cache"
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -26,6 +26,8 @@ ac_add_options --enable-warnings-as-errors
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
ac_add_options --with-branding=browser/branding/nightly
. $topsrcdir/build/win64/mozconfig.vs2013
. "$topsrcdir/build/mozconfig.cache"

View File

@ -8,6 +8,8 @@ ac_add_options --enable-profiling
# Nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.cache"
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -40,14 +40,12 @@ MOZ_SERVICES_CLOUDSYNC=1
MOZ_APP_VERSION=$FIREFOX_VERSION
MOZ_EXTENSIONS_DEFAULT=" gio"
# MOZ_APP_DISPLAYNAME will be set by branding/configure.sh
# Changing MOZ_*BRANDING_DIRECTORY requires a clobber to ensure correct results,
# because branding dependencies are broken.
# MOZ_BRANDING_DIRECTORY is the default branding directory used when none is
# specified. It should never point to the "official" branding directory.
# For mozilla-beta, mozilla-release, or mozilla-central repositories, use
# "nightly" branding (until bug 659568 is fixed).
# "unofficial" branding.
# For the mozilla-aurora repository, use "aurora".
MOZ_BRANDING_DIRECTORY=browser/branding/nightly
MOZ_BRANDING_DIRECTORY=browser/branding/unofficial
MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
# This should usually be the same as the value MAR_CHANNEL_ID.

View File

@ -202,6 +202,8 @@ skip-if = e10s && debug
skip-if = e10s && debug
[browser_dbg_conditional-breakpoints-05.js]
skip-if = e10s && debug
[browser_dbg_console-eval.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-01.js]
skip-if = e10s && debug
[browser_dbg_server-conditional-bp-02.js]

View File

@ -0,0 +1,42 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Breaking in the middle of a script evaluated by the console should
* work
*/
function test() {
Task.spawn(runTests);
}
function* runTests() {
let TAB_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
let [,, panel] = yield initDebugger(TAB_URL);
let dbgWin = panel.panelWin;
let sources = dbgWin.DebuggerView.Sources;
let frames = dbgWin.DebuggerView.StackFrames;
let editor = dbgWin.DebuggerView.editor;
let toolbox = gDevTools.getToolbox(panel.target);
let paused = promise.all([
waitForEditorEvents(panel, "cursorActivity"),
waitForDebuggerEvents(panel, dbgWin.EVENTS.SOURCE_SHOWN)
]);
toolbox.once("webconsole-ready", () => {
ok(toolbox.splitConsole, "Split console is shown.");
let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
jsterm.execute('debugger');
});
EventUtils.synthesizeKey("VK_ESCAPE", {}, dbgWin);
yield paused;
is(sources.selectedItem.attachment.label, 'SCRIPT0',
'Anonymous source is selected in sources');
dump('text ::' + editor.getText() + '::\n');
ok(editor.getText() === 'debugger', 'Editor has correct text');
yield toolbox.closeSplitConsole();
yield resumeDebuggerThenCloseAndFinish(panel);
}

View File

@ -20,7 +20,6 @@ browser.jar:
content/browser/devtools/webconsole.xul (webconsole/webconsole.xul)
* content/browser/devtools/scratchpad.xul (scratchpad/scratchpad.xul)
content/browser/devtools/scratchpad.js (scratchpad/scratchpad.js)
content/browser/devtools/scratchpad-commands.js (scratchpad/scratchpad-commands.js)
content/browser/devtools/splitview.css (shared/splitview.css)
content/browser/devtools/theme-switching.js (shared/theme-switching.js)
content/browser/devtools/frame-script-utils.js (shared/frame-script-utils.js)
@ -114,7 +113,6 @@ browser.jar:
content/browser/devtools/performance/views/details-memory-flamegraph.js (performance/views/details-memory-flamegraph.js)
content/browser/devtools/performance/views/recordings.js (performance/views/recordings.js)
content/browser/devtools/performance/views/jit-optimizations.js (performance/views/jit-optimizations.js)
content/browser/devtools/responsivedesign/resize-commands.js (responsivedesign/resize-commands.js)
content/browser/devtools/commandline.css (commandline/commandline.css)
content/browser/devtools/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml)
content/browser/devtools/commandlinetooltip.xhtml (commandline/commandlinetooltip.xhtml)

View File

@ -175,6 +175,7 @@ ThreadNode.prototype = {
let prevCalls = this.calls;
let prevFrameKey;
let isLeaf = mutableFrameKeyOptions.isLeaf = true;
let skipRoot = options.invertTree;
// Inflate the stack and build the FrameNode call tree directly.
//
@ -213,6 +214,13 @@ ThreadNode.prototype = {
// Fetch the stack prefix (i.e. older frames) index.
stackIndex = stackEntry[STACK_PREFIX_SLOT];
// Do not include the (root) node in this sample, as the costs of each frame
// will make it clear to differentiate (root)->B vs (root)->A->B
// when a tree is inverted, a revert of bug 1147604
if (stackIndex === null && skipRoot) {
break;
}
// Inflate the frame.
let inflatedFrame = getOrAddInflatedFrame(inflatedFrameCache, frameIndex, frameTable,
stringTable, allocationsTable);
@ -496,7 +504,7 @@ FrameNode.prototype = {
return null;
}
return new JITOptimizations(this._optimizations, this._stringTable);
}
},
};
exports.ThreadNode = ThreadNode;

View File

@ -21,9 +21,14 @@ const CALL_TREE_INDENTATION = 16; // px
const DEFAULT_SORTING_PREDICATE = (frameA, frameB) => {
let dataA = frameA.getDisplayedData();
let dataB = frameB.getDisplayedData();
return this.inverted
? (dataA.selfPercentage < dataB.selfPercentage ? 1 : -1)
: (dataA.samples < dataB.samples ? 1 : -1);
if (this.inverted) {
// Invert trees, sort by selfPercentage, and then totalPercentage
if (dataA.selfPercentage === dataB.selfPercentage) {
return dataA.totalPercentage < dataB.totalPercentage ? 1 : -1;
}
return dataA.selfPercentage < dataB.selfPercentage ? 1 : - 1;
}
return dataA.samples < dataB.samples ? 1 : -1;
};
const DEFAULT_AUTO_EXPAND_DEPTH = 3; // depth
@ -241,7 +246,7 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
cell.className = "plain call-tree-cell";
cell.setAttribute("type", "samples");
cell.setAttribute("crop", "end");
cell.setAttribute("value", count || "");
cell.setAttribute("value", count || 0);
return cell;
},
_createFunctionCell: function(doc, arrowNode, frameName, frameInfo, frameLevel) {
@ -335,20 +340,72 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
let data = this._cachedDisplayedData = Object.create(null);
let frameInfo = this.frame.getInfo();
// Self/total duration.
if (this.visibleCells.duration) {
data.totalDuration = this.frame.duration;
}
if (this.visibleCells.selfDuration) {
data.selfDuration = this.root.frame.selfDuration[this.frame.key];
}
/**
* When inverting call tree, the costs and times are dependent on position
* in the tree. We must only count leaf nodes with self cost, and total costs
* dependent on how many times the leaf node was found with a full stack path.
*
* Total | Self | Calls | Function
* ============================================================================
* 100% | 100% | 100 | C
* 50% | 0% | 50 | B
* 50% | 0% | 50 | A
* 50% | 0% | 50 | B
*
* Every instance of a `CallView` represents a row in the call tree. The same
* container node is used for all rows.
*/
// Self/total samples percentage.
if (this.visibleCells.percentage) {
data.totalPercentage = this.frame.samples / this.root.frame.samples * 100;
}
if (this.visibleCells.selfPercentage) {
data.selfPercentage = this.root.frame.selfCount[this.frame.key] / this.root.frame.samples * 100;
// Leaf nodes in an inverted tree don't have to do anything special.
let isLeaf = this._level === 0;
if (this.inverted && !isLeaf && this.parent != null) {
let calleeData = this.parent.getDisplayedData();
// Percentage of time that this frame called the callee
// in this branch
let callerPercentage = this.frame.samples / calleeData.samples;
// Self/total duration.
if (this.visibleCells.duration) {
data.totalDuration = calleeData.totalDuration * callerPercentage;
}
if (this.visibleCells.selfDuration) {
data.selfDuration = 0;
}
// Self/total samples percentage.
if (this.visibleCells.percentage) {
data.totalPercentage = calleeData.totalPercentage * callerPercentage;
}
if (this.visibleCells.selfPercentage) {
data.selfPercentage = 0;
}
// Raw samples.
if (this.visibleCells.samples) {
data.samples = this.frame.samples;
}
} else {
// Self/total duration.
if (this.visibleCells.duration) {
data.totalDuration = this.frame.duration;
}
if (this.visibleCells.selfDuration) {
data.selfDuration = this.root.frame.selfDuration[this.frame.key];
}
// Self/total samples percentage.
if (this.visibleCells.percentage) {
data.totalPercentage = this.frame.samples / this.root.frame.samples * 100;
}
if (this.visibleCells.selfPercentage) {
data.selfPercentage = this.root.frame.selfCount[this.frame.key] / this.root.frame.samples * 100;
}
// Raw samples.
if (this.visibleCells.samples) {
data.samples = this.frame.samples;
}
}
// Self/total allocations count.
@ -360,11 +417,6 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
data.selfAllocations = this.frame.allocations;
}
// Raw samples.
if (this.visibleCells.samples) {
data.samples = this.frame.samples;
}
// Frame name (function location or some meta information).
data.name = frameInfo.isMetaCategory
? frameInfo.categoryData.label
@ -396,7 +448,7 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
e.preventDefault();
e.stopPropagation();
this.root.emit("link", this);
}
},
});
exports.CallView = CallView;

View File

@ -140,6 +140,7 @@ skip-if = e10s # GC events seem unreliable in multiprocess
[browser_profiler_tree-view-07.js]
[browser_profiler_tree-view-08.js]
[browser_profiler_tree-view-09.js]
[browser_profiler_tree-view-10.js]
[browser_profiler-frame-utils-01.js]
[browser_timeline-blueprint.js]
[browser_timeline-filters.js]
@ -147,4 +148,5 @@ skip-if = e10s # GC events seem unreliable in multiprocess
[browser_timeline-waterfall-generic.js]
[browser_timeline-waterfall-rerender.js]
[browser_timeline-waterfall-sidebar.js]
skip-if = os == 'linux' # Bug 1161817
[browser_waterfall-collapse.js]

View File

@ -6,6 +6,9 @@
* and that they're cleared upon rerecording.
*/
function* spawnTest() {
// This test seems to take a long time to cleanup on Ubuntu VMs.
requestLongerTimeout(2);
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;

View File

@ -0,0 +1,151 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the profiler's tree view, when inverted, displays the self and
* total costs correctly.
*/
function test() {
let { ThreadNode } = devtools.require("devtools/performance/tree-model");
let { CallView } = devtools.require("devtools/performance/tree-view");
let threadNode = new ThreadNode(gThread, { invertTree: true });
let treeRoot = new CallView({ frame: threadNode, inverted: true, hidden: true });
let container = document.createElement("vbox");
treeRoot.attachTo(container);
// Add 1 to each index to skip the hidden root node
let $$fun = i => container.querySelectorAll(".call-tree-cell[type=function]")[i+1];
let $$name = i => container.querySelectorAll(".call-tree-cell[type=function] > .call-tree-name")[i+1];
let $$percentage = i => container.querySelectorAll(".call-tree-cell[type=percentage]")[i+1];
let $$selfpercentage = i => container.querySelectorAll(".call-tree-cell[type='self-percentage']")[i+1];
/**
* Samples
*
* A->C
* A->B
* A->B->C x4
* A->B->D x4
*
* Expected Tree
* +--total--+--self--+--tree-------------+
* | 50% | 50% | C
* | 40% | 0 | -> B
* | 30% | 0 | -> A
* | 10% | 0 | -> A
*
* | 40% | 40% | D
* | 40% | 0 | -> B
* | 40% | 0 | -> A
*
* | 10% | 10% | B
* | 10% | 0 | -> A
*/
is(container.childNodes.length, 10,
"The container node should have all children available.");
[ // total, self, indent + name
[ 50, 50, "C"],
[ 40, 0, " B"],
[ 30, 0, " A"],
[ 10, 0, " A"],
[ 40, 40, "D"],
[ 40, 0, " B"],
[ 40, 0, " A"],
[ 10, 10, "B"],
[ 10, 0, " A"],
].forEach(function (def, i) {
info(`Checking ${i}th tree item`);
let [total, self, name] = def;
name = name.trim();
is($$name(i).getAttribute("value"), name, `${name} has correct name.`);
is($$percentage(i).getAttribute("value"), `${total}%`, `${name} has correct total percent.`);
is($$selfpercentage(i).getAttribute("value"), `${self}%`, `${name} has correct self percent.`);
});
finish();
}
let gThread = synthesizeProfileForTest([{
time: 5,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
{ location: "C" }
]
}, {
time: 10,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
{ location: "D" }
]
}, {
time: 15,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "C" },
]
}, {
time: 20,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
]
}, {
time: 25,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
{ location: "C" }
]
}, {
time: 30,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
{ location: "C" }
]
}, {
time: 35,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
{ location: "D" }
]
}, {
time: 40,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
{ location: "D" }
]
}, {
time: 45,
frames: [
{ location: "(root)" },
{ location: "B" },
{ location: "C" }
]
}, {
time: 50,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
{ location: "D" }
]
}]);

View File

@ -49,8 +49,11 @@ function* spawnTest() {
is(afterResizeBarsCount, beforeResizeBarsCount,
"The same subset of the total markers remained visible.");
is(Array.indexOf($$(".waterfall-tree-item"), $(".waterfall-tree-item:focus")), 2,
"The correct item is still focused in the tree.");
// Temporarily disable the following assertion; intermittent failures.
// Bug 1169352.
// is(Array.indexOf($$(".waterfall-tree-item"), $(".waterfall-tree-item:focus")), 2,
// "The correct item is still focused in the tree.");
yield teardown(panel);
finish();

View File

@ -33,11 +33,16 @@ ul {
max-width: 512px;
}
#errorTitleText {
#errorTitle {
background: url("aboutNetError_info.svg") left 0 no-repeat;
background-size: 1.2em;
-moz-margin-start: -2em;
-moz-padding-start: 2em;
background-size: 3em;
-moz-margin-start: -5em;
-moz-padding-start: 5em;
}
#errorTitleText {
border-bottom: 1px solid #C1C1C1;
padding-bottom: 0.4em;
}
#errorTitleText:-moz-dir(rtl) {
@ -58,7 +63,7 @@ ul {
}
@media (max-width: 675px) {
#errorTitleText {
#errorTitle {
padding-top: 0;
background-image: none;
-moz-padding-start: 0;

View File

@ -264,8 +264,7 @@ public class SUTAgentAndroid extends Activity
{
if (ba != null)
{
sUniqueID = ba.getAddress();
sUniqueID.toLowerCase();
sUniqueID = ba.getAddress().toLowerCase();
}
}
}

View File

@ -25,6 +25,8 @@ packages.txt:testing/mozbase/packages.txt
objdir:build
gyp.pth:media/webrtc/trunk/tools/gyp/pylib
pyasn1.pth:python/pyasn1
pyasn1_modules.pth:python/pyasn1-modules
bitstring.pth:python/bitstring
redo.pth:python/redo
requests.pth:python/requests
rsa.pth:python/rsa

View File

@ -3034,6 +3034,7 @@ then
esac
LDFLAGS="${_PTHREAD_LDFLAGS} ${LDFLAGS}"
AC_SUBST(MOZ_USE_PTHREADS)
MOZ_CHECK_HEADERS(pthread.h)
fi
@ -3603,7 +3604,7 @@ MOZ_ARG_WITH_BOOL(system-nss,
_USE_SYSTEM_NSS=1 )
if test -n "$_USE_SYSTEM_NSS"; then
AM_PATH_NSS(3.19, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
AM_PATH_NSS(3.19.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
fi
if test -n "$MOZ_NATIVE_NSS"; then

View File

@ -17,11 +17,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782
// designMode document is in a frame inside the window, as this means
// the editable region is not in the root docshell (a less complicated case).
var pageShowChecker = '<scr' + 'ipt>' +
'window.addEventListener("pageshow", function(event) {' +
'window.opener.postMessage({persisted:event.persisted}, "*");' +
'});</scr' + 'ipt>';
var gTests = [
{
// <html><body><p>designModeDocument</p></body></html>
url: "data:text/html;charset=utf-8,<html><body><p>designModeDocument</p></body></html>",
url: "data:text/html;charset=utf-8,<html><head>" + pageShowChecker + "</head><body><p>designModeDocument</p></body></html>",
name: 'designModeNavigate',
onload(doc) { doc.designMode = "on"; },
expectedBodyBeforeEdit: '<p>designModeDocument</p>',
@ -30,7 +34,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782
},
{
// <html><body contentEditable="true"><p>contentEditable</p></body></html>
url: 'data:text/html;charset=utf-8,<html><body contentEditable="true"><p>contentEditable</p></body></html>',
url: "data:text/html;charset=utf-8,<html><head>" + pageShowChecker + "</head><body contentEditable=\"true\"><p>contentEditable</p></body></html>",
name: 'contentEditableNavigate',
expectedBodyBeforeEdit: '<p>contentEditable</p>',
expectedBodyAfterEdit: 'EDITED <br><p>contentEditable</p>',
@ -51,12 +55,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782
}
gTest = gTests[gTestNum];
gTest.window = window.open(gTest.url, gTest.name, "width=500,height=500");
gTest.window.addEventListener("load", function() {
window.onmessage = function(e) {
is(e.data.persisted, false, "Initial load cannot be persisted");
window.onmessage = null;
if ("onload" in gTest) {
gTest.onload(gTest.window.document);
}
SimpleTest.waitForFocus(beginTest, gTest.window);
}, false);
};
}
function beginTest() {
@ -73,10 +79,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782
}
function goBack() {
window.onmessage = function(e) {
window.onmessage = null;
// Skip the test if the page is not loaded from the bf-cache when going back.
if (e.data.persisted) {
checkStillEditable();
} else {
gTest.window.close();
goNext();
}
};
gTest.window.history.back();
setTimeout(function() {
SimpleTest.waitForFocus(checkStillEditable, gTest.window);
}, 0);
}
function checkStillEditable() {

View File

@ -43,6 +43,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=669671
* *should* load from the cache.
*
**/
SimpleTest.requestLongerTimeout(2);
SimpleTest.waitForExplicitFinish();
function onChildLoad()

View File

@ -668,7 +668,7 @@ private:
return;
}
if (!arguments.AppendElement(value)) {
if (!arguments.AppendElement(value, fallible)) {
return;
}
}
@ -830,7 +830,7 @@ Console::Time(JSContext* aCx, const JS::Handle<JS::Value> aTime)
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(aCx, &data);
if (!aTime.isUndefined() && !data.AppendElement(aTime)) {
if (!aTime.isUndefined() && !data.AppendElement(aTime, fallible)) {
return;
}
@ -843,7 +843,7 @@ Console::TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime)
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(aCx, &data);
if (!aTime.isUndefined() && !data.AppendElement(aTime)) {
if (!aTime.isUndefined() && !data.AppendElement(aTime, fallible)) {
return;
}
@ -856,7 +856,7 @@ Console::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(aCx, &data);
if (aData.isString() && !data.AppendElement(aData)) {
if (aData.isString() && !data.AppendElement(aData, fallible)) {
return;
}
@ -896,7 +896,7 @@ Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
Sequence<JS::Value>& sequence = event.mArguments.Value();
for (uint32_t i = 0; i < aData.Length(); ++i) {
if (!sequence.AppendElement(aData[i])) {
if (!sequence.AppendElement(aData[i], fallible)) {
return;
}
}
@ -1440,7 +1440,7 @@ FlushOutput(JSContext* aCx, Sequence<JS::Value>& aSequence, nsString &aOutput)
return false;
}
if (!aSequence.AppendElement(JS::StringValue(str))) {
if (!aSequence.AppendElement(JS::StringValue(str), fallible)) {
return false;
}
@ -1571,7 +1571,7 @@ Console::ProcessArguments(JSContext* aCx,
v = aData[index++];
}
if (!aSequence.AppendElement(v)) {
if (!aSequence.AppendElement(v, fallible)) {
return false;
}
@ -1594,13 +1594,13 @@ Console::ProcessArguments(JSContext* aCx,
int32_t diff = aSequence.Length() - aStyles.Length();
if (diff > 0) {
for (int32_t i = 0; i < diff; i++) {
if (!aStyles.AppendElement(JS::NullValue())) {
if (!aStyles.AppendElement(JS::NullValue(), fallible)) {
return false;
}
}
}
if (!aStyles.AppendElement(JS::StringValue(jsString))) {
if (!aStyles.AppendElement(JS::StringValue(jsString), fallible)) {
return false;
}
}
@ -1672,7 +1672,7 @@ Console::ProcessArguments(JSContext* aCx,
// The rest of the array, if unused by the format string.
for (; index < aData.Length(); ++index) {
if (!aSequence.AppendElement(aData[index])) {
if (!aSequence.AppendElement(aData[index], fallible)) {
return false;
}
}
@ -1808,7 +1808,7 @@ Console::ArgumentsToValueList(const nsTArray<JS::Heap<JS::Value>>& aData,
Sequence<JS::Value>& aSequence)
{
for (uint32_t i = 0; i < aData.Length(); ++i) {
if (!aSequence.AppendElement(aData[i])) {
if (!aSequence.AppendElement(aData[i], fallible)) {
return false;
}
}

View File

@ -960,7 +960,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv)
{
Sequence<nsString> protocols;
if (!protocols.AppendElement(aProtocol)) {
if (!protocols.AppendElement(aProtocol, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}

View File

@ -620,8 +620,13 @@ IsSelectionInsideRuby(nsISelection* aSelection)
}
bool
nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell, nsISelection* aSelection)
nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell,
nsISelection* aSelection, bool* aActionTaken)
{
if (aActionTaken) {
*aActionTaken = false;
}
NS_ASSERTION(aType == NS_CUT || aType == NS_COPY || aType == NS_PASTE,
"Invalid clipboard event type");
@ -646,14 +651,6 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
// retrieve the event target node from the start of the selection
nsresult rv;
if (sel) {
// Only cut or copy when there is an uncollapsed selection
if (aType == NS_CUT || aType == NS_COPY) {
bool isCollapsed;
sel->GetIsCollapsed(&isCollapsed);
if (isCollapsed)
return false;
}
nsCOMPtr<nsIDOMRange> range;
rv = sel->GetRangeAt(0, getter_AddRefs(range));
if (NS_SUCCEEDED(rv) && range) {
@ -696,7 +693,7 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
// If the event was cancelled, don't do the clipboard operation
doDefault = (status != nsEventStatus_eConsumeNoDefault);
}
// No need to do anything special during a paste. Either an event listener
// took care of it and cancelled the event, or the caller will handle it.
// Return true to indicate that the event wasn't cancelled.
@ -708,6 +705,9 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
clipboardData->SetReadOnly();
}
if (aActionTaken) {
*aActionTaken = true;
}
return doDefault;
}
@ -721,20 +721,43 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
// use the data added to the data transfer and copy that instead.
uint32_t count = 0;
if (doDefault) {
// get the data from the selection if any
bool isCollapsed;
sel->GetIsCollapsed(&isCollapsed);
if (isCollapsed) {
return false;
// find the focused node
nsCOMPtr<nsIContent> srcNode = content;
if (content->IsInNativeAnonymousSubtree()) {
srcNode = content->FindFirstNonChromeOnlyAccessContent();
}
// XXX Code which decides whether we should copy text with ruby
// annotation is currenct depending on whether each range of the
// selection is inside a same ruby container. But we really should
// expose the full functionality in browser. See bug 1130891.
bool withRubyAnnotation = IsSelectionInsideRuby(sel);
// call the copy code
rv = HTMLCopy(sel, doc, aClipboardType, withRubyAnnotation);
if (NS_FAILED(rv)) {
// check if we are looking at a password input
nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(srcNode);
if (formControl) {
if (formControl->GetType() == NS_FORM_INPUT_PASSWORD) {
return false;
}
}
// when cutting non-editable content, do nothing
// XXX this is probably the wrong editable flag to check
if (aType != NS_CUT || content->IsEditable()) {
// get the data from the selection if any
bool isCollapsed;
sel->GetIsCollapsed(&isCollapsed);
if (isCollapsed) {
if (aActionTaken) {
*aActionTaken = true;
}
return false;
}
// XXX Code which decides whether we should copy text with ruby
// annotation is currenct depending on whether each range of the
// selection is inside a same ruby container. But we really should
// expose the full functionality in browser. See bug 1130891.
bool withRubyAnnotation = IsSelectionInsideRuby(sel);
// call the copy code
rv = HTMLCopy(sel, doc, aClipboardType, withRubyAnnotation);
if (NS_FAILED(rv)) {
return false;
}
} else {
return false;
}
} else if (clipboardData) {
@ -763,5 +786,8 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"), nullptr, 0);
}
if (aActionTaken) {
*aActionTaken = true;
}
return doDefault;
}

View File

@ -83,12 +83,16 @@ class nsCopySupport
*
* aClipboardType specifies which clipboard to use, from nsIClipboard.
*
* If aActionTaken is non-NULL, it will be set to true if an action was
* taken, whether it be the default action or the default being prevented.
*
* If the event is cancelled or an error occurs, false will be returned.
*/
static bool FireClipboardEvent(int32_t aType,
int32_t aClipboardType,
nsIPresShell* aPresShell,
nsISelection* aSelection);
nsISelection* aSelection,
bool* aActionTaken = nullptr);
};
#endif

View File

@ -714,7 +714,8 @@ nsDOMMutationObserver::GetObservingInfo(
mozilla::dom::Sequence<nsString>& filtersAsStrings =
info.mAttributeFilter.Value();
for (int32_t j = 0; j < filters.Count(); ++j) {
if (!filtersAsStrings.AppendElement(nsDependentAtomString(filters[j]))) {
if (!filtersAsStrings.AppendElement(nsDependentAtomString(filters[j]),
mozilla::fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
@ -773,7 +774,7 @@ nsDOMMutationObserver::HandleMutation()
for (uint32_t i = 0; i < mPendingMutationCount; ++i) {
nsRefPtr<nsDOMMutationRecord> next;
current->mNext.swap(next);
*mutations.AppendElement() = current;
*mutations.AppendElement(mozilla::fallible) = current;
current.swap(next);
}
}

View File

@ -2976,19 +2976,10 @@ nsDocument::InitCSP(nsIChannel* aChannel)
rv = csp->GetReferrerPolicy(&referrerPolicy, &hasReferrerPolicy);
NS_ENSURE_SUCCESS(rv, rv);
if (hasReferrerPolicy) {
// Referrer policy spec (section 6.1) says that once the referrer policy
// is set, any future attempts to change it result in No-Referrer.
if (!mReferrerPolicySet) {
mReferrerPolicy = static_cast<ReferrerPolicy>(referrerPolicy);
mReferrerPolicySet = true;
} else if (mReferrerPolicy != referrerPolicy) {
mReferrerPolicy = mozilla::net::RP_No_Referrer;
{
MOZ_LOG(gCspPRLog, PR_LOG_DEBUG, ("%s %s",
"CSP wants to set referrer, but nsDocument"
"already has it set. No referrers will be sent"));
}
}
// Referrer policy spec (section 6.1) says that we always use the newest
// referrer policy we find
mReferrerPolicy = static_cast<ReferrerPolicy>(referrerPolicy);
mReferrerPolicySet = true;
// Referrer Policy is set separately for the speculative parser in
// nsHTMLDocument::StartDocumentLoad() so there's nothing to do here for
@ -3776,14 +3767,10 @@ nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
if (aHeaderField == nsGkAtoms::referrer && !aData.IsEmpty()) {
ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aData);
// Referrer policy spec (section 6.1) says that once the referrer policy
// is set, any future attempts to change it result in No-Referrer.
if (!mReferrerPolicySet) {
mReferrerPolicy = policy;
mReferrerPolicySet = true;
} else if (mReferrerPolicy != policy) {
mReferrerPolicy = mozilla::net::RP_No_Referrer;
}
// Referrer policy spec (section 6.1) says that we always use the newest
// referrer policy we find
mReferrerPolicy = policy;
mReferrerPolicySet = true;
}
}

View File

@ -500,7 +500,8 @@ nsClipboardCommand::IsCommandEnabled(const char* aCommandName, nsISupports *aCon
nsresult
nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext)
{
if (strcmp(aCommandName, "cmd_copy") &&
if (strcmp(aCommandName, "cmd_cut") &&
strcmp(aCommandName, "cmd_copy") &&
strcmp(aCommandName, "cmd_copyAndCollapseToEnd"))
return NS_OK;
@ -513,7 +514,13 @@ nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext)
nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
nsCopySupport::FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, presShell, nullptr);
int32_t eventType = NS_COPY;
if (strcmp(aCommandName, "cmd_cut") == 0) {
eventType = NS_CUT;
}
bool actionTaken = false;
nsCopySupport::FireClipboardEvent(eventType, nsIClipboard::kGlobalClipboard, presShell, nullptr, &actionTaken);
if (!strcmp(aCommandName, "cmd_copyAndCollapseToEnd")) {
dom::Selection *sel =
@ -522,7 +529,10 @@ nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext)
sel->CollapseToEnd();
}
return NS_OK;
if (actionTaken) {
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP

View File

@ -368,7 +368,7 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval,
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t idx = 0; idx < argCount; ++idx) {
*args.AppendElement() = argv[idx + 2];
*args.AppendElement(fallible) = argv[idx + 2];
}
args.SwapElements(mArgs);
} else {
@ -409,7 +409,7 @@ NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow, Function& aFunction,
ErrorResult& aError)
{
FallibleTArray<JS::Heap<JS::Value> > args;
if (!args.AppendElements(aArguments)) {
if (!args.AppendElements(aArguments, fallible)) {
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}

View File

@ -20,6 +20,7 @@
#include "nsIDOMHTMLObjectElement.h"
#include "nsIDOMHTMLAppletElement.h"
#include "nsIExternalProtocolHandler.h"
#include "nsIHttpChannelInternal.h"
#include "nsIObjectFrame.h"
#include "nsIPermissionManager.h"
#include "nsPluginHost.h"
@ -2509,6 +2510,13 @@ nsObjectLoadingContent::OpenChannel()
scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
}
nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChan);
if (internalChannel) {
// Bug 1168676. object/embed tags are not allowed to be intercepted by
// ServiceWorkers.
internalChannel->ForceNoIntercept();
}
// AsyncOpen can fail if a file does not exist.
rv = chan->AsyncOpen(shim, nullptr);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -228,7 +228,7 @@ nsScreen::MozLockOrientation(const nsAString& aOrientation, ErrorResult& aRv)
{
nsString orientation(aOrientation);
Sequence<nsString> orientations;
if (!orientations.AppendElement(orientation)) {
if (!orientations.AppendElement(orientation, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return false;
}

View File

@ -44,17 +44,23 @@ function create2ndLevelIframeUrl(schemeFrom, schemeTo, policy, type) {
// loaded. The click triggers a redirection to file_bug704320_redirect.html,
// which in turn notifies the main window that it's time to check the test
// results.
function createTest(schemeFrom, schemeTo, policy) {
function createTest(schemeFrom, schemeTo, policy, optionalEarlierPolicy) {
var _createTestUrl = createTestUrl.bind(
null, schemeFrom, schemeTo, policy, 'test');
var _create2ndLevelIframeUrl = create2ndLevelIframeUrl.bind(
null, schemeFrom, schemeTo, policy);
var metaReferrerPolicyString = '';
if (optionalEarlierPolicy && optionalEarlierPolicy != '') {
metaReferrerPolicyString += '<meta name="referrer" content="' + optionalEarlierPolicy + '">\n';
}
metaReferrerPolicyString += '<meta name="referrer" content="' + policy + '">';
return '<!DOCTYPE HTML>\n\
<html>\n\
<head>\n\
<meta name="referrer" content="' + policy + '">\n\
'+metaReferrerPolicyString+'\n\
<link rel="stylesheet" type="text/css" href="' + _createTestUrl('stylesheet') + '">\n\
<style type="text/css">\n\
@import "' + _createTestUrl('import-css') + '";\n\
@ -165,11 +171,17 @@ function createIframedWindowLocationTest(schemeFrom, schemeTo, policy) {
</html>';
}
function createPolicyTest(refpol) {
function createPolicyTest(policy, optionalEarlierPolicy) {
var metaReferrerPolicyString = '';
if (optionalEarlierPolicy && optionalEarlierPolicy != '') {
metaReferrerPolicyString += '<meta name="referrer" content="' + optionalEarlierPolicy + '">\n';
}
metaReferrerPolicyString += '<meta name="referrer" content="' + policy + '">';
return '<!DOCTYPE HTML>\n\
<html>\n\
<head>\n\
<meta name="referrer" content="' + refpol + '">\n\
'+metaReferrerPolicyString+'\n\
<script type="text/javascript" src="/tests/dom/base/test/file_bug704320_preload_common.js"></script>\n\
</head>\n\
<body>\n\
@ -191,10 +203,14 @@ function handleRequest(request, response) {
var schemeFrom = params[1].split('=')[1];
var schemeTo = params[2].split('=')[1];
var policy = params[3].split('=')[1];
var optionalEarlierPolicy = '';
if (params[4]) {
optionalEarlierPolicy = params[4].split('=')[1];
}
response.setHeader('Content-Type', 'text/html; charset=utf-8', false);
response.setHeader('Cache-Control', 'no-cache', false);
response.write(createTest(schemeFrom, schemeTo, policy));
response.write(createTest(schemeFrom, schemeTo, policy, optionalEarlierPolicy));
}
else if (action === 'create-2nd-level-iframe') {
// ?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=origin&type=form"
@ -266,7 +282,12 @@ function handleRequest(request, response) {
// ?action=generate-policy-test&policy=b64-encoded-string
response.setHeader('Cache-Control', 'no-cache', false);
response.setHeader('Content-Type', 'text/html', false);
var refpol = unescape(params[1].split('=')[1]);
response.write(createPolicyTest(refpol));
var policy = unescape(params[1].split('=')[1]);
var optionalEarlierPolicy = '';
if (params[2]) {
optionalEarlierPolicy = params[2].split('=')[1];
}
response.write(createPolicyTest(policy, optionalEarlierPolicy));
}
}

View File

@ -1,3 +1,3 @@
<out><div id="top" xmlns="http://www.w3.org/1999/xhtml"><link href="chrome://global/content/xml/XMLPrettyPrint.css" type="text/css" rel="stylesheet"/><div id="header"><p>
<out><div id="top" class="highlight" xmlns="http://www.w3.org/1999/xhtml"><link href="chrome://global/content/xml/XMLPrettyPrint.css" type="text/css" rel="stylesheet"/><div id="header"><p>
This XML file does not appear to have any style information associated with it. The document tree is shown below.
</p></div><div>&lt;<span class="start-tag">out</span>&gt;<span class="text">Here be sea hags</span>&lt;/<span class="end-tag">out</span>&gt;</div></div></out>

View File

@ -678,6 +678,8 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
[test_bug1163743.html]
support-files = referrerHelper.js
[test_bug1165501.html]
support-files = referrerHelper.js
[test_caretPositionFromPoint.html]
[test_classList.html]
# This test fails on the Mac for some reason

View File

@ -0,0 +1,51 @@
<!DOCTYPE HTML>
<html>
<!--
Spot test to see if newer meta-referrer policy is used
https://bugzilla.mozilla.org/show_bug.cgi?id=1165501
-->
<head>
<meta charset="utf-8">
<title>Test policies for Bug 1165501</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="referrerHelper.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript;version=1.7">
SimpleTest.waitForExplicitFinish();
var advance = function() { tests.next(); };
/**
* testing if policy is overwritten if there are two meta statements (1165501)
* XXX: would be nice to test this with CSP and meta as well
*/
var tests = (function() {
var iframe = document.getElementById("testframe");
const sjs = "/tests/dom/base/test/bug704320.sjs?action=generate-policy-test";
// setting first unsafe-url and then origin - origin shall prevail
yield resetCounter();
yield iframe.src = sjs + "&policy=" + escape('origin')+ "&wrongPolicy=" + escape('unsafe-url');
yield checkIndividualResults("unsafe-url then origin", ["origin"]);
// setting first no-referrer and then default - default shall prevail
yield resetCounter();
yield iframe.src = sjs + "&policy=" + escape('default')+ "&wrongPolicy=" + escape('no-referrer');
yield checkIndividualResults("no-referrer then default", ["full"]);
// complete. Be sure to yield so we don't call this twice.
yield SimpleTest.finish();
})();
</script>
</head>
<body onload="tests.next();">
<iframe id="testframe"></iframe>
</body>
</html>

View File

@ -25,8 +25,9 @@
performance.clearMarks();
performance.clearMeasures();
performance.clearResourceTimings();
arr = performance.getEntries();
is(arr.length, 0, "clearing performance entries");
is(performance.getEntriesByType("resource").length, 0, "clearing performance resource entries");
is(performance.getEntriesByType("mark").length, 0, "clearing performance mark entries");
is(performance.getEntriesByType("measure").length, 0, "clearing performance measure entries");
steps[i]();
} catch(ex) {
ok(false, "Caught exception", ex);

View File

@ -266,6 +266,14 @@ DOMInterfaces = {
'concrete': False
},
'ChromeUtils': {
# The codegen is dumb, and doesn't understand that this interface is only a
# collection of static methods, so we have this `concrete: False` hack.
'concrete': False,
'nativeType': 'mozilla::devtools::ChromeUtils',
'implicitJSContext': ['readHeapSnapshot', 'saveHeapSnapshot']
},
'ChromeWindow': {
'concrete': False,
},
@ -501,6 +509,10 @@ DOMInterfaces = {
'headerFile': 'nsGeolocation.h'
},
'HeapSnapshot': {
'nativeType': 'mozilla::devtools::HeapSnapshot'
},
'History': {
'headerFile': 'nsHistory.h',
'nativeType': 'nsHistory'

View File

@ -4315,7 +4315,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if (done${nestingLevel}) {
break;
}
${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement();
${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement(mozilla::fallible);
if (!slotPtr${nestingLevel}) {
JS_ReportOutOfMemory(cx);
$*{exceptionCode}
@ -5610,7 +5610,7 @@ class CGArgumentConverter(CGThing):
return false;
}
for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
${elemType}& slot = *${declName}.AppendElement();
${elemType}& slot = *${declName}.AppendElement(mozilla::fallible);
""")
).substitute(replacer)

277
dom/cache/Connection.cpp vendored Normal file
View File

@ -0,0 +1,277 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/cache/Connection.h"
#include "mozilla/dom/cache/DBSchema.h"
#include "mozStorageHelper.h"
namespace mozilla {
namespace dom {
namespace cache {
NS_IMPL_ISUPPORTS(cache::Connection, mozIStorageAsyncConnection,
mozIStorageConnection);
Connection::Connection(mozIStorageConnection* aBase)
: mBase(aBase)
, mClosed(false)
{
MOZ_ASSERT(mBase);
}
Connection::~Connection()
{
NS_ASSERT_OWNINGTHREAD(Connection);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(Close()));
}
NS_IMETHODIMP
Connection::Close()
{
NS_ASSERT_OWNINGTHREAD(Connection);
if (mClosed) {
return NS_OK;
}
mClosed = true;
// If we are closing here, then Cache must not have a transaction
// open anywhere else. This should be guaranteed to succeed.
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(db::IncrementalVacuum(this)));
return mBase->Close();
}
// The following methods are all boilerplate that either forward to the
// base connection or block the method. All the async execution methods
// are blocked because Cache does not use them and they would require more
// work to wrap properly.
// mozIStorageAsyncConnection methods
NS_IMETHODIMP
Connection::AsyncClose(mozIStorageCompletionCallback*)
{
// async methods are not supported
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
Connection::AsyncClone(bool, mozIStorageCompletionCallback*)
{
// async methods are not supported
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
Connection::GetDatabaseFile(nsIFile** aFileOut)
{
return mBase->GetDatabaseFile(aFileOut);
}
NS_IMETHODIMP
Connection::CreateAsyncStatement(const nsACString&, mozIStorageAsyncStatement**)
{
// async methods are not supported
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
Connection::ExecuteAsync(mozIStorageBaseStatement**, uint32_t,
mozIStorageStatementCallback*,
mozIStoragePendingStatement**)
{
// async methods are not supported
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
Connection::ExecuteSimpleSQLAsync(const nsACString&,
mozIStorageStatementCallback*,
mozIStoragePendingStatement**)
{
// async methods are not supported
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
Connection::CreateFunction(const nsACString& aFunctionName,
int32_t aNumArguments,
mozIStorageFunction* aFunction)
{
// async methods are not supported
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
Connection::CreateAggregateFunction(const nsACString& aFunctionName,
int32_t aNumArguments,
mozIStorageAggregateFunction* aFunction)
{
return mBase->CreateAggregateFunction(aFunctionName, aNumArguments,
aFunction);
}
NS_IMETHODIMP
Connection::RemoveFunction(const nsACString& aFunctionName)
{
return mBase->RemoveFunction(aFunctionName);
}
NS_IMETHODIMP
Connection::SetProgressHandler(int32_t aGranularity,
mozIStorageProgressHandler* aHandler,
mozIStorageProgressHandler** aHandlerOut)
{
return mBase->SetProgressHandler(aGranularity, aHandler, aHandlerOut);
}
NS_IMETHODIMP
Connection::RemoveProgressHandler(mozIStorageProgressHandler** aHandlerOut)
{
return mBase->RemoveProgressHandler(aHandlerOut);
}
// mozIStorageConnection methods
NS_IMETHODIMP
Connection::Clone(bool aReadOnly, mozIStorageConnection** aConnectionOut)
{
nsCOMPtr<mozIStorageConnection> conn;
nsresult rv = mBase->Clone(aReadOnly, getter_AddRefs(conn));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
nsCOMPtr<mozIStorageConnection> wrapped = new Connection(conn);
wrapped.forget(aConnectionOut);
return rv;
}
NS_IMETHODIMP
Connection::GetDefaultPageSize(int32_t* aSizeOut)
{
return mBase->GetDefaultPageSize(aSizeOut);
}
NS_IMETHODIMP
Connection::GetConnectionReady(bool* aReadyOut)
{
return mBase->GetConnectionReady(aReadyOut);
}
NS_IMETHODIMP
Connection::GetLastInsertRowID(int64_t* aRowIdOut)
{
return mBase->GetLastInsertRowID(aRowIdOut);
}
NS_IMETHODIMP
Connection::GetAffectedRows(int32_t* aCountOut)
{
return mBase->GetAffectedRows(aCountOut);
}
NS_IMETHODIMP
Connection::GetLastError(int32_t* aErrorOut)
{
return mBase->GetLastError(aErrorOut);
}
NS_IMETHODIMP
Connection::GetLastErrorString(nsACString& aErrorOut)
{
return mBase->GetLastErrorString(aErrorOut);
}
NS_IMETHODIMP
Connection::GetSchemaVersion(int32_t* aVersionOut)
{
return mBase->GetSchemaVersion(aVersionOut);
}
NS_IMETHODIMP
Connection::SetSchemaVersion(int32_t aVersion)
{
return mBase->SetSchemaVersion(aVersion);
}
NS_IMETHODIMP
Connection::CreateStatement(const nsACString& aQuery,
mozIStorageStatement** aStatementOut)
{
return mBase->CreateStatement(aQuery, aStatementOut);
}
NS_IMETHODIMP
Connection::ExecuteSimpleSQL(const nsACString& aQuery)
{
return mBase->ExecuteSimpleSQL(aQuery);
}
NS_IMETHODIMP
Connection::TableExists(const nsACString& aTableName, bool* aExistsOut)
{
return mBase->TableExists(aTableName, aExistsOut);
}
NS_IMETHODIMP
Connection::IndexExists(const nsACString& aIndexName, bool* aExistsOut)
{
return mBase->IndexExists(aIndexName, aExistsOut);
}
NS_IMETHODIMP
Connection::GetTransactionInProgress(bool* aResultOut)
{
return mBase->GetTransactionInProgress(aResultOut);
}
NS_IMETHODIMP
Connection::BeginTransaction()
{
return mBase->BeginTransaction();
}
NS_IMETHODIMP
Connection::BeginTransactionAs(int32_t aType)
{
return mBase->BeginTransactionAs(aType);
}
NS_IMETHODIMP
Connection::CommitTransaction()
{
return mBase->CommitTransaction();
}
NS_IMETHODIMP
Connection::RollbackTransaction()
{
return mBase->RollbackTransaction();
}
NS_IMETHODIMP
Connection::CreateTable(const char* aTable, const char* aSchema)
{
return mBase->CreateTable(aTable, aSchema);
}
NS_IMETHODIMP
Connection::SetGrowthIncrement(int32_t aIncrement, const nsACString& aDatabase)
{
return mBase->SetGrowthIncrement(aIncrement, aDatabase);
}
NS_IMETHODIMP
Connection::EnableModule(const nsACString& aModule)
{
return mBase->EnableModule(aModule);
}
} // namespace cache
} // namespace dom
} // namespace mozilla

36
dom/cache/Connection.h vendored Normal file
View File

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_cache_Connection_h
#define mozilla_dom_cache_Connection_h
#include "mozIStorageConnection.h"
namespace mozilla {
namespace dom {
namespace cache {
class Connection final : public mozIStorageConnection
{
public:
explicit Connection(mozIStorageConnection* aBase);
private:
~Connection();
nsCOMPtr<mozIStorageConnection> mBase;
bool mClosed;
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGEASYNCCONNECTION
NS_DECL_MOZISTORAGECONNECTION
};
} // namespace cache
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_cache_Connection_h

84
dom/cache/Context.cpp vendored
View File

@ -131,11 +131,15 @@ class Context::QuotaInitRunnable final : public nsIRunnable
public:
QuotaInitRunnable(Context* aContext,
Manager* aManager,
Action* aQuotaIOThreadAction)
Data* aData,
nsIThread* aTarget,
Action* aInitAction)
: mContext(aContext)
, mThreadsafeHandle(aContext->CreateThreadsafeHandle())
, mManager(aManager)
, mQuotaIOThreadAction(aQuotaIOThreadAction)
, mData(aData)
, mTarget(aTarget)
, mInitAction(aInitAction)
, mInitiatingThread(NS_GetCurrentThread())
, mResult(NS_OK)
, mState(STATE_INIT)
@ -144,6 +148,8 @@ public:
{
MOZ_ASSERT(mContext);
MOZ_ASSERT(mManager);
MOZ_ASSERT(mData);
MOZ_ASSERT(mTarget);
MOZ_ASSERT(mInitiatingThread);
}
@ -166,7 +172,7 @@ public:
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
MOZ_ASSERT(!mCanceled);
mCanceled = true;
mQuotaIOThreadAction->CancelOnInitiatingThread();
mInitAction->CancelOnInitiatingThread();
}
private:
@ -202,7 +208,7 @@ private:
{
MOZ_ASSERT(mState == STATE_COMPLETE);
MOZ_ASSERT(!mContext);
MOZ_ASSERT(!mQuotaIOThreadAction);
MOZ_ASSERT(!mInitAction);
}
enum State
@ -211,6 +217,7 @@ private:
STATE_CALL_WAIT_FOR_OPEN_ALLOWED,
STATE_WAIT_FOR_OPEN_ALLOWED,
STATE_ENSURE_ORIGIN_INITIALIZED,
STATE_RUN_ON_TARGET,
STATE_RUNNING,
STATE_COMPLETING,
STATE_COMPLETE
@ -222,13 +229,15 @@ private:
MOZ_ASSERT(mContext);
mContext = nullptr;
mManager = nullptr;
mQuotaIOThreadAction = nullptr;
mInitAction = nullptr;
}
nsRefPtr<Context> mContext;
nsRefPtr<ThreadsafeHandle> mThreadsafeHandle;
nsRefPtr<Manager> mManager;
nsRefPtr<Action> mQuotaIOThreadAction;
nsRefPtr<Data> mData;
nsCOMPtr<nsIThread> mTarget;
nsRefPtr<Action> mInitAction;
nsCOMPtr<nsIThread> mInitiatingThread;
nsresult mResult;
QuotaInfo mQuotaInfo;
@ -266,9 +275,14 @@ NS_IMPL_ISUPPORTS(mozilla::dom::cache::Context::QuotaInitRunnable, nsIRunnable);
// | (Quota IO Thread) +----------------+
// +----------+------------+ |
// | |
// +----------v------------+ |
// | RunOnTarget | Resolve(error) |
// | (Target Thread) +----------------+
// +----------+------------+ |
// | |
// +---------v---------+ +------v------+
// | Running | | Completing |
// | (Quota IO Thread) +------------>(Orig Thread)|
// | (Target Thread) +------------>(Orig Thread)|
// +-------------------+ +------+------+
// |
// +-----v----+
@ -384,16 +398,27 @@ Context::QuotaInitRunnable::Run()
break;
}
mState = STATE_RUNNING;
if (!mQuotaIOThreadAction) {
if (!mInitAction) {
resolver->Resolve(NS_OK);
break;
}
mState = STATE_RUN_ON_TARGET;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mTarget->Dispatch(this, nsIThread::DISPATCH_NORMAL)));
break;
}
// -------------------
case STATE_RUN_ON_TARGET:
{
MOZ_ASSERT(NS_GetCurrentThread() == mTarget);
mState = STATE_RUNNING;
// Execute the provided initialization Action. The Action must Resolve()
// before returning.
mQuotaIOThreadAction->RunOnTarget(resolver, mQuotaInfo, nullptr);
mInitAction->RunOnTarget(resolver, mQuotaInfo, mData);
MOZ_ASSERT(resolver->Resolved());
break;
@ -402,8 +427,8 @@ Context::QuotaInitRunnable::Run()
case STATE_COMPLETING:
{
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
if (mQuotaIOThreadAction) {
mQuotaIOThreadAction->CompleteOnInitiatingThread(mResult);
if (mInitAction) {
mInitAction->CompleteOnInitiatingThread(mResult);
}
mContext->OnQuotaInit(mResult, mQuotaInfo, mOfflineStorage);
mState = STATE_COMPLETE;
@ -776,21 +801,10 @@ Context::ThreadsafeHandle::ContextDestroyed(Context* aContext)
// static
already_AddRefed<Context>
Context::Create(Manager* aManager, nsIThread* aTarget,
Action* aQuotaIOThreadAction, Context* aOldContext)
Action* aInitAction, Context* aOldContext)
{
nsRefPtr<Context> context = new Context(aManager, aTarget);
// Do this here to avoid doing an AddRef() in the constructor
// TODO: pass context->mData to allow connetion sharing with init
context->mInitRunnable = new QuotaInitRunnable(context, aManager,
aQuotaIOThreadAction);
if (aOldContext) {
aOldContext->SetNextContext(context);
} else {
context->Start();
}
context->Init(aInitAction, aOldContext);
return context.forget();
}
@ -913,6 +927,24 @@ Context::~Context()
}
}
void
Context::Init(Action* aInitAction, Context* aOldContext)
{
NS_ASSERT_OWNINGTHREAD(Context);
MOZ_ASSERT(!mInitRunnable);
// Do this here to avoid doing an AddRef() in the constructor
mInitRunnable = new QuotaInitRunnable(this, mManager, mData, mTarget,
aInitAction);
if (aOldContext) {
aOldContext->SetNextContext(this);
return;
}
Start();
}
void
Context::Start()
{

3
dom/cache/Context.h vendored
View File

@ -112,7 +112,7 @@ public:
// be execute synchronously.
static already_AddRefed<Context>
Create(Manager* aManager, nsIThread* aTarget,
Action* aQuotaIOThreadAction, Context* aOldContext);
Action* aInitAction, Context* aOldContext);
// Execute given action on the target once the quota manager has been
// initialized.
@ -173,6 +173,7 @@ private:
Context(Manager* aManager, nsIThread* aTarget);
~Context();
void Init(Action* aInitAction, Context* aOldContext);
void Start();
void DispatchAction(Action* aAction, bool aDoomData = false);
void OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo,

View File

@ -6,6 +6,9 @@
#include "mozilla/dom/cache/DBAction.h"
#include "mozilla/dom/cache/Connection.h"
#include "mozilla/dom/cache/DBSchema.h"
#include "mozilla/dom/cache/FileUtils.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "mozilla/net/nsFileProtocolHandler.h"
#include "mozIStorageConnection.h"
@ -15,8 +18,6 @@
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "DBSchema.h"
#include "FileUtils.h"
namespace mozilla {
namespace dom {
@ -79,7 +80,12 @@ DBAction::RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
// Save this connection in the shared Data object so later Actions can
// use it. This avoids opening a new connection for every Action.
if (aOptionalData) {
aOptionalData->SetConnection(conn);
// Since we know this connection will be around for as long as the
// Cache is open, use our special wrapped connection class. This
// will let us perform certain operations once the Cache origin
// is closed.
nsCOMPtr<mozIStorageConnection> wrapped = new Connection(conn);
aOptionalData->SetConnection(wrapped);
}
}

176
dom/cache/DBSchema.cpp vendored
View File

@ -29,13 +29,30 @@ namespace dom {
namespace cache {
namespace db {
const int32_t kMaxWipeSchemaVersion = 9;
const int32_t kMaxWipeSchemaVersion = 10;
namespace {
const int32_t kLatestSchemaVersion = 9;
const int32_t kLatestSchemaVersion = 10;
const int32_t kMaxEntriesPerStatement = 255;
const uint32_t kPageSize = 4 * 1024;
// Grow the database in chunks to reduce fragmentation
const uint32_t kGrowthSize = 32 * 1024;
const uint32_t kGrowthPages = kGrowthSize / kPageSize;
static_assert(kGrowthSize % kPageSize == 0,
"Growth size must be multiple of page size");
// Only release free pages when we have more than this limit
const int32_t kMaxFreePages = kGrowthPages;
// Limit WAL journal to a reasonable size
const uint32_t kWalAutoCheckpointSize = 512 * 1024;
const uint32_t kWalAutoCheckpointPages = kWalAutoCheckpointSize / kPageSize;
static_assert(kWalAutoCheckpointSize % kPageSize == 0,
"WAL checkpoint size must be multiple of page size");
} // anonymous namespace
// If any of the static_asserts below fail, it means that you have changed
@ -213,28 +230,12 @@ CreateSchema(mozIStorageConnection* aConn)
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aConn);
nsAutoCString pragmas(
// Enable auto-vaccum but in incremental mode in order to avoid doing a lot
// of work at the end of each transaction.
// NOTE: This must be done here instead of InitializeConnection() because it
// only works when the database is empty.
"PRAGMA auto_vacuum = INCREMENTAL; "
);
nsresult rv = aConn->ExecuteSimpleSQL(pragmas);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
int32_t schemaVersion;
rv = aConn->GetSchemaVersion(&schemaVersion);
nsresult rv = aConn->GetSchemaVersion(&schemaVersion);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
if (schemaVersion == kLatestSchemaVersion) {
// We already have the correct schema, so just do an incremental vaccum and
// get started.
rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"PRAGMA incremental_vacuum;"));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// We already have the correct schema, so just get started.
return rv;
}
@ -380,24 +381,69 @@ InitializeConnection(mozIStorageConnection* aConn)
// This function needs to perform per-connection initialization tasks that
// need to happen regardless of the schema.
nsAutoCString pragmas(
"PRAGMA journal_mode = WAL; "
// Use default mozStorage 32kb page size for now
// WAL journal can grow to 512kb before being flushed to disk
"PRAGMA wal_autocheckpoint = 16; "
// Always truncate the journal back to 512kb after large transactions
"PRAGMA journal_size_limit = 524288; "
"PRAGMA foreign_keys = ON; "
// Note, the default encoding of UTF-8 is preferred. mozStorage does all
// the work necessary to convert UTF-16 nsString values for us. We don't
// need ordering and the binary equality operations are correct. So, do
// NOT set PRAGMA encoding to UTF-16.
nsPrintfCString pragmas(
// Use a smaller page size to improve perf/footprint; default is too large
"PRAGMA page_size = %u; "
// Enable auto_vacuum; this must happen after page_size and before WAL
"PRAGMA auto_vacuum = INCREMENTAL; "
"PRAGMA foreign_keys = ON; ",
kPageSize
);
// Note, the default encoding of UTF-8 is preferred. mozStorage does all
// the work necessary to convert UTF-16 nsString values for us. We don't
// need ordering and the binary equality operations are correct. So, do
// NOT set PRAGMA encoding to UTF-16.
nsresult rv = aConn->ExecuteSimpleSQL(pragmas);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// Limit fragmentation by growing the database by many pages at once.
rv = aConn->SetGrowthIncrement(kGrowthSize, EmptyCString());
if (rv == NS_ERROR_FILE_TOO_BIG) {
NS_WARNING("Not enough disk space to set sqlite growth increment.");
rv = NS_OK;
}
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// Enable WAL journaling. This must be performed in a separate transaction
// after changing the page_size and enabling auto_vacuum.
nsPrintfCString wal(
// WAL journal can grow to given number of *pages*
"PRAGMA wal_autocheckpoint = %u; "
// Always truncate the journal back to given number of *bytes*
"PRAGMA journal_size_limit = %u; "
// WAL must be enabled at the end to allow page size to be changed, etc.
"PRAGMA journal_mode = WAL; ",
kWalAutoCheckpointPages,
kWalAutoCheckpointSize
);
rv = aConn->ExecuteSimpleSQL(wal);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// Verify that we successfully set the vacuum mode to incremental. It
// is very easy to put the database in a state where the auto_vacuum
// pragma above fails silently.
#ifdef DEBUG
nsCOMPtr<mozIStorageStatement> state;
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
"PRAGMA auto_vacuum;"
), getter_AddRefs(state));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
bool hasMoreData = false;
rv = state->ExecuteStep(&hasMoreData);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
int32_t mode;
rv = state->GetInt32(0, &mode);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// integer value 2 is incremental mode
if (NS_WARN_IF(mode != 2)) { return NS_ERROR_UNEXPECTED; }
#endif
return NS_OK;
}
@ -1916,6 +1962,70 @@ CreateAndBindKeyStatement(mozIStorageConnection* aConn,
} // anonymouns namespace
nsresult
IncrementalVacuum(mozIStorageConnection* aConn)
{
// Determine how much free space is in the database.
nsCOMPtr<mozIStorageStatement> state;
nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
"PRAGMA freelist_count;"
), getter_AddRefs(state));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
bool hasMoreData = false;
rv = state->ExecuteStep(&hasMoreData);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
int32_t freePages = 0;
rv = state->GetInt32(0, &freePages);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// We have a relatively small page size, so we want to be careful to avoid
// fragmentation. We already use a growth incremental which will cause
// sqlite to allocate and release multiple pages at the same time. We can
// further reduce fragmentation by making our allocated chunks a bit
// "sticky". This is done by creating some hysteresis where we allocate
// pages/chunks as soon as we need them, but we only release pages/chunks
// when we have a large amount of free space. This helps with the case
// where a page is adding and remove resources causing it to dip back and
// forth across a chunk boundary.
//
// So only proceed with releasing pages if we have more than our constant
// threshold.
if (freePages <= kMaxFreePages) {
return NS_OK;
}
// Release the excess pages back to the sqlite VFS. This may also release
// chunks of multiple pages back to the OS.
int32_t pagesToRelease = freePages - kMaxFreePages;
rv = aConn->ExecuteSimpleSQL(nsPrintfCString(
"PRAGMA incremental_vacuum(%d);", pagesToRelease
));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// Verify that our incremental vacuum actually did something
#ifdef DEBUG
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
"PRAGMA freelist_count;"
), getter_AddRefs(state));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
hasMoreData = false;
rv = state->ExecuteStep(&hasMoreData);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
freePages = 0;
rv = state->GetInt32(0, &freePages);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
MOZ_ASSERT(freePages <= kMaxFreePages);
#endif
return NS_OK;
}
} // namespace db
} // namespace cache
} // namespace dom

View File

@ -32,6 +32,7 @@ namespace db {
nsresult
CreateSchema(mozIStorageConnection* aConn);
// Note, this cannot be executed within a transaction.
nsresult
InitializeConnection(mozIStorageConnection* aConn);
@ -104,6 +105,10 @@ nsresult
StorageGetKeys(mozIStorageConnection* aConn, Namespace aNamespace,
nsTArray<nsString>& aKeysOut);
// Note, this works best when its NOT executed within a transaction.
nsresult
IncrementalVacuum(mozIStorageConnection* aConn);
// We will wipe out databases with a schema versions less than this.
extern const int32_t kMaxWipeSchemaVersion;

2
dom/cache/moz.build vendored
View File

@ -21,6 +21,7 @@ EXPORTS.mozilla.dom.cache += [
'CacheStorageParent.h',
'CacheStreamControlChild.h',
'CacheStreamControlParent.h',
'Connection.h',
'Context.h',
'DBAction.h',
'DBSchema.h',
@ -56,6 +57,7 @@ UNIFIED_SOURCES += [
'CacheStorageParent.cpp',
'CacheStreamControlChild.cpp',
'CacheStreamControlParent.cpp',
'Connection.cpp',
'Context.cpp',
'DBAction.cpp',
'DBSchema.cpp',

1002
dom/cache/test/mochitest/large_url_list.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@ support-files =
test_cache_delete.js
test_cache_put_reorder.js
test_cache_https.js
large_url_list.js
[test_cache.html]
[test_cache_add.html]
@ -37,3 +38,4 @@ support-files =
[test_cache_https.html]
skip-if = buildapp == 'b2g' # bug 1162353
[test_cache_restart.html]
[test_cache_shrink.html]

View File

@ -0,0 +1,131 @@
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE HTML>
<html>
<head>
<title>Test Cache with QuotaManager Restart</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="large_url_list.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script class="testbody" type="text/javascript">
function clearStorage() {
return new Promise(function(resolve, reject) {
var principal = SpecialPowers.wrap(document).nodePrincipal;
var appId, inBrowser;
var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
principal.appId != nsIPrincipal.NO_APP_ID) {
appId = principal.appId;
inBrowser = principal.isInBrowserElement;
}
SpecialPowers.clearStorageForURI(document.documentURI, resolve, appId,
inBrowser);
});
}
function storageUsage() {
return new Promise(function(resolve, reject) {
var principal = SpecialPowers.wrap(document).nodePrincipal;
var appId, inBrowser;
var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
principal.appId != nsIPrincipal.NO_APP_ID) {
appId = principal.appId;
inBrowser = principal.isInBrowserElement;
}
SpecialPowers.getStorageUsageForURI(document.documentURI, resolve, appId,
inBrowser);
});
}
function resetStorage() {
return new Promise(function(resolve, reject) {
var principal = SpecialPowers.wrap(document).nodePrincipal;
var appId, inBrowser;
var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
principal.appId != nsIPrincipal.NO_APP_ID) {
appId = principal.appId;
inBrowser = principal.isInBrowserElement;
}
SpecialPowers.resetStorageForURI(document.documentURI, resolve, appId,
inBrowser);
});
}
function gc() {
return new Promise(function(resolve, reject) {
SpecialPowers.exactGC(window, resolve);
});
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
"set": [["dom.caches.enabled", true],
["dom.quotaManager.testing", true]],
}, function() {
var name = 'foo';
var cache = null;
var initialUsage = 0;
var fullUsage = 0;
var endUsage = 0;
// start from a fresh origin directory so other tests do not influence our
// results
clearStorage().then(function() {
return storageUsage();
}).then(function(usage) {
is(0, usage, 'disk usage should be zero to start');
return caches.open(name);
}).then(function(c) {
cache = c;
return storageUsage();
}).then(function(usage) {
initialUsage = usage;
return Promise.all(largeUrlList.map(function(url) {
return cache.put(new Request(url), new Response());
}));
}).then(function() {
return cache.keys();
}).then(function(keyList) {
is(keyList.length, largeUrlList.length, 'Large URL list is stored in cache');
cache = null;
// Ensure the Cache DOM object is gone before proceeding. If its alive
// it will keep the related entries on-disk as well.
return gc();
}).then(function() {
// reset the quota manager storage to ensure the DB connection is flushed
return resetStorage();
}).then(function() {
return storageUsage();
}).then(function(usage) {
fullUsage = usage;
ok(fullUsage > initialUsage, 'disk usage should have grown');
return caches.delete(name);
}).then(function(result) {
ok(result, 'cache should be deleted');
// This is a bit superfluous, but its necessary to make sure the Cache is
// fully deleted before we proceed. The deletion actually takes place in
// two async steps. We don't want to resetStorage() until the second step
// has taken place. This extra Cache operation ensure that all the
// runnables have been flushed through the threads, etc.
return caches.has(name);
}).then(function(result) {
ok(!result, 'cache should not exist in storage');
// reset the quota manager storage to ensure the DB connection is flushed
return resetStorage();
}).then(function() {
return storageUsage();
}).then(function(usage) {
endUsage = usage;
dump("### ### initial:" + initialUsage + ", full:" + fullUsage +
", end:" + endUsage + "\n");
ok(endUsage < (fullUsage / 2), 'disk usage should have shrank significantly');
ok(endUsage > initialUsage, 'disk usage should not shrink back to orig size');
SimpleTest.finish();
});
});
</script>
</body>
</html>

View File

@ -1381,7 +1381,7 @@ nsDOMCameraControl::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces
if (faces.SetCapacity(len, fallible)) {
for (uint32_t i = 0; i < len; ++i) {
*faces.AppendElement() =
*faces.AppendElement(fallible) =
new DOMCameraDetectedFace(static_cast<DOMMediaStream*>(this), aFaces[i]);
}
}

View File

@ -2676,7 +2676,7 @@ void CanvasRenderingContext2D::DrawFocusIfNeeded(mozilla::dom::Element& aElement
// set dashing for foreground
FallibleTArray<mozilla::gfx::Float>& dash = CurrentState().dash;
for (uint32_t i = 0; i < 2; ++i) {
if (!dash.AppendElement(1)) {
if (!dash.AppendElement(1, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
@ -3964,14 +3964,14 @@ CanvasRenderingContext2D::SetLineDash(const Sequence<double>& aSegments,
return;
}
if (!dash.AppendElement(aSegments[x])) {
if (!dash.AppendElement(aSegments[x], fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
if (aSegments.Length() % 2) { // If the number of elements is odd, concatenate again
for (uint32_t x = 0; x < aSegments.Length(); x++) {
if (!dash.AppendElement(aSegments[x])) {
if (!dash.AppendElement(aSegments[x], fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}

View File

@ -129,7 +129,7 @@ JSValToDashArray(JSContext* cx, const JS::Value& patternArray,
} else if (d > 0.0) {
haveNonzeroElement = true;
}
if (!dashes.AppendElement(d)) {
if (!dashes.AppendElement(d, mozilla::fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}

View File

@ -349,19 +349,19 @@ TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenu
for (size_t i = 0; i < in.Length(); i++) {
switch (in[i]) {
case LOCAL_GL_COLOR:
if (!out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0)) {
if (!out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0, fallible)) {
return false;
}
break;
case LOCAL_GL_DEPTH:
if (!out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT)) {
if (!out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT, fallible)) {
return false;
}
break;
case LOCAL_GL_STENCIL:
if (!out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT)) {
if (!out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT, fallible)) {
return false;
}
break;

View File

@ -377,7 +377,7 @@ WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
if (requiredNumLeaves != NumLeaves()) {
// See class comment for why we the tree storage size is 2 * numLeaves.
if (!mTreeData.SetLength(2 * requiredNumLeaves, fallible)) {
mTreeData.SetLength(0);
mTreeData.Clear();
return false;
}
MOZ_ASSERT(NumLeaves() == requiredNumLeaves);
@ -471,7 +471,7 @@ WebGLElementArrayCache::BufferData(const void* ptr, size_t byteLength)
{
if (mBytes.Length() != byteLength) {
if (!mBytes.SetLength(byteLength, fallible)) {
mBytes.SetLength(0);
mBytes.Clear();
return false;
}
}

View File

@ -59,7 +59,7 @@ CryptoBuffer::Assign(const ArrayBufferViewOrArrayBuffer& aData)
// If your union is uninitialized, something's wrong
MOZ_ASSERT(false);
SetLength(0);
Clear();
return nullptr;
}
@ -74,7 +74,7 @@ CryptoBuffer::Assign(const OwningArrayBufferViewOrArrayBuffer& aData)
// If your union is uninitialized, something's wrong
MOZ_ASSERT(false);
SetLength(0);
Clear();
return nullptr;
}

View File

@ -951,6 +951,41 @@ CryptoKey::PrivateKeyToJwk(SECKEYPrivateKey* aPrivKey,
}
}
SECKEYPublicKey*
CreateECPublicKey(const SECItem* aKeyData, const nsString& aNamedCurve)
{
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
if (!arena) {
return nullptr;
}
SECKEYPublicKey* key = PORT_ArenaZNew(arena, SECKEYPublicKey);
if (!key) {
return nullptr;
}
key->keyType = ecKey;
key->pkcs11Slot = nullptr;
key->pkcs11ID = CK_INVALID_HANDLE;
// Create curve parameters.
SECItem* params = CreateECParamsForCurve(aNamedCurve, arena);
if (!params) {
return nullptr;
}
key->u.ec.DEREncodedParams = *params;
// Set public point.
key->u.ec.publicValue = *aKeyData;
// Ensure the given point is on the curve.
if (!CryptoKey::PublicKeyValid(key)) {
return nullptr;
}
return SECKEY_CopyPublicKey(key);
}
SECKEYPublicKey*
CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk,
const nsNSSShutDownPreventionLock& /*proofOfLock*/)
@ -1002,39 +1037,18 @@ CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk,
return nullptr;
}
SECKEYPublicKey* key = PORT_ArenaZNew(arena, SECKEYPublicKey);
if (!key) {
// Create point.
SECItem* point = CreateECPointForCoordinates(x, y, arena.get());
if (!point) {
return nullptr;
}
key->keyType = ecKey;
key->pkcs11Slot = nullptr;
key->pkcs11ID = CK_INVALID_HANDLE;
nsString namedCurve;
if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) {
return nullptr;
}
// Create parameters.
SECItem* params = CreateECParamsForCurve(namedCurve, arena.get());
if (!params) {
return nullptr;
}
key->u.ec.DEREncodedParams = *params;
// Create point.
SECItem* point = CreateECPointForCoordinates(x, y, arena.get());
if (!point) {
return nullptr;
}
key->u.ec.publicValue = *point;
if (!PublicKeyValid(key)) {
return nullptr;
}
return SECKEY_CopyPublicKey(key);
return CreateECPublicKey(point, namedCurve);
}
return nullptr;
@ -1115,6 +1129,57 @@ CryptoKey::PublicDhKeyToRaw(SECKEYPublicKey* aPubKey,
return NS_OK;
}
SECKEYPublicKey*
CryptoKey::PublicECKeyFromRaw(CryptoBuffer& aKeyData,
const nsString& aNamedCurve,
const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
if (!arena) {
return nullptr;
}
SECItem rawItem = { siBuffer, nullptr, 0 };
if (!aKeyData.ToSECItem(arena, &rawItem)) {
return nullptr;
}
uint32_t flen;
if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P256)) {
flen = 32; // bytes
} else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P384)) {
flen = 48; // bytes
} else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P521)) {
flen = 66; // bytes
} else {
return nullptr;
}
// Check length of uncompressed point coordinates. There are 2 field elements
// and a leading point form octet (which must EC_POINT_FORM_UNCOMPRESSED).
if (rawItem.len != (2 * flen + 1)) {
return nullptr;
}
// No support for compressed points.
if (rawItem.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
return nullptr;
}
return CreateECPublicKey(&rawItem, aNamedCurve);
}
nsresult
CryptoKey::PublicECKeyToRaw(SECKEYPublicKey* aPubKey,
CryptoBuffer& aRetVal,
const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
if (!aRetVal.Assign(&aPubKey->u.ec.publicValue)) {
return NS_ERROR_DOM_OPERATION_ERR;
}
return NS_OK;
}
bool
CryptoKey::PublicKeyValid(SECKEYPublicKey* aPubKey)
{

View File

@ -180,6 +180,13 @@ public:
CryptoBuffer& aRetVal,
const nsNSSShutDownPreventionLock& /*proofOfLock*/);
static SECKEYPublicKey* PublicECKeyFromRaw(CryptoBuffer& aKeyData,
const nsString& aNamedCurve,
const nsNSSShutDownPreventionLock& /*proofOfLock*/);
static nsresult PublicECKeyToRaw(SECKEYPublicKey* aPubKey,
CryptoBuffer& aRetVal,
const nsNSSShutDownPreventionLock& /*proofOfLock*/);
static bool PublicKeyValid(SECKEYPublicKey* aPubKey);
// Structured clone methods use these to clone keys

View File

@ -563,16 +563,18 @@ private:
// Perform the encryption/decryption
if (mEncrypt) {
rv = MapSECStatus(PK11_Encrypt(symKey.get(), mMechanism, &param,
mResult.Elements(), &outLen, maxLen,
mData.Elements(), mData.Length()));
mResult.Elements(), &outLen,
mResult.Length(), mData.Elements(),
mData.Length()));
} else {
rv = MapSECStatus(PK11_Decrypt(symKey.get(), mMechanism, &param,
mResult.Elements(), &outLen, maxLen,
mData.Elements(), mData.Length()));
mResult.Elements(), &outLen,
mResult.Length(), mData.Elements(),
mData.Length()));
}
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
mResult.SetLength(outLen);
mResult.TruncateLength(outLen);
return rv;
}
};
@ -848,7 +850,7 @@ private:
}
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
mResult.SetLength(outLen);
mResult.TruncateLength(outLen);
return NS_OK;
}
};
@ -934,10 +936,10 @@ private:
rv = MapSECStatus(PK11_DigestOp(ctx.get(), mData.Elements(), mData.Length()));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
rv = MapSECStatus(PK11_DigestFinal(ctx.get(), mResult.Elements(),
&outLen, HASH_LENGTH_MAX));
&outLen, mResult.Length()));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
mResult.SetLength(outLen);
mResult.TruncateLength(outLen);
return rv;
}
@ -1644,7 +1646,7 @@ public:
const ObjectOrString& aAlgorithm, bool aExtractable,
const Sequence<nsString>& aKeyUsages)
{
ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
}
ImportEcKeyTask(JSContext* aCx, const nsAString& aFormat,
@ -1652,7 +1654,7 @@ public:
const ObjectOrString& aAlgorithm, bool aExtractable,
const Sequence<nsString>& aKeyUsages)
{
ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
if (NS_FAILED(mEarlyRv)) {
return;
}
@ -1661,6 +1663,30 @@ public:
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
}
void Init(JSContext* aCx, const nsAString& aFormat,
const ObjectOrString& aAlgorithm, bool aExtractable,
const Sequence<nsString>& aKeyUsages)
{
ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
if (NS_FAILED(mEarlyRv)) {
return;
}
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
RootedDictionary<EcKeyImportParams> params(aCx);
mEarlyRv = Coerce(aCx, params, aAlgorithm);
if (NS_FAILED(mEarlyRv) || !params.mNamedCurve.WasPassed()) {
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
return;
}
if (!NormalizeToken(params.mNamedCurve.Value(), mNamedCurve)) {
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
return;
}
}
}
private:
nsString mNamedCurve;
@ -1680,14 +1706,19 @@ private:
mKey->SetPrivateKey(privKey.get());
mKey->SetType(CryptoKey::PRIVATE);
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) ||
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) ||
mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) ||
(mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
!mJwk.mD.WasPassed())) {
// Public key import
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
pubKey = CryptoKey::PublicECKeyFromRaw(mKeyData, mNamedCurve, locker);
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
pubKey = CryptoKey::PublicKeyFromSpki(mKeyData, locker);
} else {
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
pubKey = CryptoKey::PublicKeyFromJwk(mJwk, locker);
} else {
MOZ_ASSERT(false);
}
if (!pubKey) {
@ -1901,6 +1932,14 @@ private:
return NS_OK;
}
if (mPublicKey && mPublicKey->keyType == ecKey) {
nsresult rv = CryptoKey::PublicECKeyToRaw(mPublicKey, mResult, locker);
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_OPERATION_ERR;
}
return NS_OK;
}
mResult = mSymKey;
if (mResult.Length() == 0) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
@ -1966,7 +2005,7 @@ private:
if (!mKeyUsages.IsEmpty()) {
mJwk.mKey_ops.Construct();
if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages)) {
if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}

View File

@ -518,6 +518,11 @@ tv = {
"405dd1f1adeb090107edcfb2b4963739d87679e3056cb0557d0adf"
),
raw: util.hex2abv(
"045ce7b86e3b32660403e63712ef0998deae1027faec3c1be9f76f934dfeb58e" +
"98f4cf075b39405dd1f1adeb090107edcfb2b4963739d87679e3056cb0557d0adf"
),
secret: util.hex2abv(
"35669cd5c244ba6c1ea89b8802c3d1db815cd769979072e6556eb98548c65f7d"
)
@ -606,7 +611,31 @@ tv = {
kty: "EC",
crv: "P-256",
x: "XOe4bjsyZgQD5jcS7wmY3q4QJ_rsPBvp92-TTf61jpg",
}
},
// Public point with Y not on the curve.
raw_bad: util.hex2abv(
"045ce7b86e3b32660403e63712ef0998deae1027faec3c1be9f76f934dfeb58e" +
"98f4cf075b39405dd1f1adeb090106edcfb2b4963739d87679e3056cb0557d0adf"
),
// Public point with Y a little too short.
raw_short: util.hex2abv(
"045ce7b86e3b32660403e63712ef0998deae1027faec3c1be9f76f934dfeb58e" +
"98f4cf075b39405dd1f1adeb090107edcfb2b4963739d87679e3056cb0557d0a"
),
// Public point with Y a little too long.
raw_long: util.hex2abv(
"045ce7b86e3b32660403e63712ef0998deae1027faec3c1be9f76f934dfeb58e" +
"98f4cf075b39405dd1f1adeb090107edcfb2b4963739d87679e3056cb0557d0adfff"
),
// Public point with EC_POINT_FORM_COMPRESSED_Y0.
raw_compressed: util.hex2abv(
"025ce7b86e3b32660403e63712ef0998deae1027faec3c1be9f76f934dfeb58e" +
"98f4cf075b39405dd1f1adeb090107edcfb2b4963739d87679e3056cb0557d0adf"
)
},
// NIST ECDSA test vectors
@ -626,6 +655,13 @@ tv = {
"9Y33NGQ1_wQ0GZWDyXxmWpfxL3BvI1faS0Aoje-Ijlnm",
},
raw: util.hex2abv(
"040061387fd6b95914e885f912edfbb5fb274655027f216c4091ca83e19336740fd" +
"81aedfe047f51b42bdf68161121013e0d55b117a14e4303f926c8debb77a7fdaad1" +
"00e7d0c75c38626e895ca21526b9f9fdf84dcecb93f2b233390550d2b1463b7ee3f" +
"58df7346435ff0434199583c97c665a97f12f706f2357da4b40288def888e59e6"
),
"data": util.hex2abv(
"9ecd500c60e701404922e58ab20cc002651fdee7cbc9336adda33e4c1088fab1" +
"964ecb7904dc6856865d6c8e15041ccf2d5ac302e99d346ff2f686531d255216" +

View File

@ -438,6 +438,114 @@ TestArray.addTest(
.then(memcmp_complete(that, tv.ecdh_p256.secret), error(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Raw import/export of a public ECDH key (P-256)",
function () {
var that = this;
var alg = { name: "ECDH", namedCurve: "P-256" };
function doExport(x) {
return crypto.subtle.exportKey("raw", x);
}
crypto.subtle.importKey("raw", tv.ecdh_p256.raw, alg, true, ["deriveBits"])
.then(doExport)
.then(memcmp_complete(that, tv.ecdh_p256.raw), error(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Test that importing bad raw ECDH keys fails",
function () {
var that = this;
var alg = { name: "ECDH", namedCurve: "P-256" };
var tvs = tv.ecdh_p256_negative.raw_bad;
crypto.subtle.importKey("raw", tv, alg, false, ["deriveBits"])
.then(error(that), complete(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Test that importing ECDH keys with an unknown format fails",
function () {
var that = this;
var alg = { name: "ECDH", namedCurve: "P-256" };
var tvs = tv.ecdh_p256.raw;
crypto.subtle.importKey("unknown", tv, alg, false, ["deriveBits"])
.then(error(that), complete(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Test that importing too short raw ECDH keys fails",
function () {
var that = this;
var alg = { name: "ECDH", namedCurve: "P-256" };
var tvs = tv.ecdh_p256_negative.raw_short;
crypto.subtle.importKey("raw", tv, alg, false, ["deriveBits"])
.then(error(that), complete(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Test that importing too long raw ECDH keys fails",
function () {
var that = this;
var alg = { name: "ECDH", namedCurve: "P-256" };
var tvs = tv.ecdh_p256_negative.raw_long;
crypto.subtle.importKey("raw", tv, alg, false, ["deriveBits"])
.then(error(that), complete(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Test that importing compressed raw ECDH keys fails",
function () {
var that = this;
var alg = { name: "ECDH", namedCurve: "P-256" };
var tvs = tv.ecdh_p256_negative.raw_compressed;
crypto.subtle.importKey("raw", tv, alg, false, ["deriveBits"])
.then(error(that), complete(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"RAW/JWK import ECDH keys (P-256) and derive a known secret",
function () {
var that = this;
var alg = { name: "ECDH", namedCurve: "P-256" };
var pubKey, privKey;
function setPub(x) { pubKey = x; }
function setPriv(x) { privKey = x; }
function doDerive() {
var alg = { name: "ECDH", public: pubKey };
return crypto.subtle.deriveBits(alg, privKey, tv.ecdh_p256.secret.byteLength * 8);
}
Promise.all([
crypto.subtle.importKey("raw", tv.ecdh_p256.raw, alg, false, ["deriveBits"])
.then(setPub),
crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_priv, alg, false, ["deriveBits"])
.then(setPriv)
]).then(doDerive)
.then(memcmp_complete(that, tv.ecdh_p256.secret), error(that));
}
);
/*]]>*/</script>
</head>

View File

@ -144,6 +144,40 @@ TestArray.addTest(
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Raw import/export of a public ECDSA key (P-521)",
function () {
var that = this;
var alg = { name: "ECDSA", namedCurve: "P-521", hash: "SHA-512" };
function doExport(x) {
return crypto.subtle.exportKey("raw", x);
}
crypto.subtle.importKey("raw", tv.ecdsa_verify.raw, alg, true, ["verify"])
.then(doExport)
.then(memcmp_complete(that, tv.ecdsa_verify.raw), error(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"ECDSA raw import and verify a known-good signature",
function() {
var that = this;
var alg = { name: "ECDSA", namedCurve: "P-521", hash: "SHA-512" };
function doVerify(x) {
return crypto.subtle.verify(alg, x, tv.ecdsa_verify.sig, tv.ecdsa_verify.data);
}
crypto.subtle.importKey("raw", tv.ecdsa_verify.raw, alg, true, ["verify"])
.then(doVerify)
.then(complete(that), error(that))
}
);
/*]]>*/</script>
</head>

View File

@ -316,7 +316,8 @@ DataStoreDB::DatabaseOpened()
}
StringOrStringSequence objectStores;
if (!objectStores.RawSetAsStringSequence().AppendElements(mObjectStores)) {
if (!objectStores.RawSetAsStringSequence().AppendElements(mObjectStores,
fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -1358,7 +1358,7 @@ DataStoreService::CreateFirstRevisionId(uint32_t aAppId,
new FirstRevisionIdCallback(aAppId, aName, aManifestURL);
Sequence<nsString> dbs;
if (!dbs.AppendElement(NS_LITERAL_STRING(DATASTOREDB_REVISION))) {
if (!dbs.AppendElement(NS_LITERAL_STRING(DATASTOREDB_REVISION), fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -43,6 +43,13 @@ HTMLAnchorElement::~HTMLAnchorElement()
{
}
bool
HTMLAnchorElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
return HasAttr(kNameSpaceID_None, nsGkAtoms::href) ||
nsGenericHTMLElement::IsInteractiveHTMLContent(aIgnoreTabindex);
}
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement)
NS_INTERFACE_TABLE_INHERITED(HTMLAnchorElement,
nsIDOMHTMLAnchorElement,

View File

@ -43,10 +43,7 @@ public:
virtual bool Draggable() const override;
// Element
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
{
return true;
}
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
// nsIDOMHTMLAnchorElement
NS_DECL_NSIDOMHTMLANCHORELEMENT

View File

@ -1860,7 +1860,7 @@ HTMLInputElement::SetValue(const nsAString& aValue, ErrorResult& aRv)
return;
}
Sequence<nsString> list;
if (!list.AppendElement(aValue)) {
if (!list.AppendElement(aValue, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
@ -2445,7 +2445,7 @@ HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames, uint32_t aLen
Sequence<nsString> list;
for (uint32_t i = 0; i < aLength; ++i) {
if (!list.AppendElement(nsDependentString(aFileNames[i]))) {
if (!list.AppendElement(nsDependentString(aFileNames[i]), fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
@ -2498,7 +2498,7 @@ HTMLInputElement::SetUserInput(const nsAString& aValue)
if (mType == NS_FORM_INPUT_FILE)
{
Sequence<nsString> list;
if (!list.AppendElement(aValue)) {
if (!list.AppendElement(aValue, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -3251,8 +3251,11 @@ nsHTMLDocument::ExecCommand(const nsAString& commandID,
return false;
}
bool isCutCopy = (commandID.LowerCaseEqualsLiteral("cut") ||
commandID.LowerCaseEqualsLiteral("copy"));
// if editing is not on, bail
if (!IsEditingOnAfterFlush()) {
if (!isCutCopy && !IsEditingOnAfterFlush()) {
rv.Throw(NS_ERROR_FAILURE);
return false;
}
@ -3262,14 +3265,33 @@ nsHTMLDocument::ExecCommand(const nsAString& commandID,
return false;
}
// special case for cut & copy
// cut & copy are allowed in non editable documents
if (isCutCopy) {
if (!nsContentUtils::IsCutCopyAllowed()) {
return false;
}
// For cut & copy commands, we need the behaviour from nsWindowRoot::GetControllers
// which is to look at the focused element, and defer to a focused textbox's controller
// The code past taken by other commands in ExecCommand always uses the window directly,
// rather than deferring to the textbox, which is desireable for most editor commands,
// but not 'cut' and 'copy' (as those should allow copying out of embedded editors).
// This behaviour is invoked if we call DoCommand directly on the docShell.
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
if (docShell) {
nsresult res = docShell->DoCommand(cmdToDispatch.get());
return NS_SUCCEEDED(res);
}
return false;
}
if (commandID.LowerCaseEqualsLiteral("gethtml")) {
rv.Throw(NS_ERROR_FAILURE);
return false;
}
bool restricted = commandID.LowerCaseEqualsLiteral("cut") ||
commandID.LowerCaseEqualsLiteral("copy")||
commandID.LowerCaseEqualsLiteral("paste");
bool restricted = commandID.LowerCaseEqualsLiteral("paste");
if (restricted && !nsContentUtils::IsCallerChrome()) {
rv = NS_ERROR_DOM_SECURITY_ERR;
return false;

View File

@ -33,6 +33,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=229925
<textarea class="yes" cols="1" rows="1"></textarea>
<video class="yes" controls></video>
<a class="no">a</a>
<audio class="no"></audio>
<img class="no" src="data:image/png,">
<input class="no" type="hidden">

View File

@ -8521,7 +8521,7 @@ ConvertBlobsToActors(PBackgroundParent* aBackgroundActor,
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
MOZ_ALWAYS_TRUE(aActors.AppendElement(actor));
MOZ_ALWAYS_TRUE(aActors.AppendElement(actor, fallible));
if (collectFileInfos) {
nsRefPtr<FileInfo> fileInfo = file.mFileInfo;
@ -8529,7 +8529,7 @@ ConvertBlobsToActors(PBackgroundParent* aBackgroundActor,
// Transfer a reference to the receiver.
auto transferedFileInfo =
reinterpret_cast<intptr_t>(fileInfo.forget().take());
MOZ_ALWAYS_TRUE(aFileInfos.AppendElement(transferedFileInfo));
MOZ_ALWAYS_TRUE(aFileInfos.AppendElement(transferedFileInfo, fallible));
}
}
@ -12358,7 +12358,7 @@ Database::Invalidate()
auto* array =
static_cast<FallibleTArray<nsRefPtr<TransactionBase>>*>(aUserData);
if (NS_WARN_IF(!array->AppendElement(aEntry->GetKey()))) {
if (NS_WARN_IF(!array->AppendElement(aEntry->GetKey(), fallible))) {
return PL_DHASH_STOP;
}
@ -12626,7 +12626,7 @@ Database::AllocPBackgroundIDBTransactionParent(
if (closure->mName == aValue->mCommonMetadata.name() &&
!aValue->mDeleted) {
MOZ_ALWAYS_TRUE(closure->mObjectStores.AppendElement(aValue));
MOZ_ALWAYS_TRUE(closure->mObjectStores.AppendElement(aValue, fallible));
return PL_DHASH_STOP;
}
@ -18785,7 +18785,7 @@ FactoryOp::SendVersionChangeMessages(DatabaseActorInfo* aDatabaseActorInfo,
Database* database = aDatabaseActorInfo->mLiveDatabases[index];
if ((!aOpeningDatabase || database != aOpeningDatabase) &&
!database->IsClosed() &&
NS_WARN_IF(!maybeBlockedDatabases.AppendElement(database))) {
NS_WARN_IF(!maybeBlockedDatabases.AppendElement(database, fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
@ -20904,7 +20904,8 @@ VersionChangeOp::RunOnOwningThread()
MOZ_ASSERT(!info->mLiveDatabases.IsEmpty());
FallibleTArray<Database*> liveDatabases;
if (NS_WARN_IF(!liveDatabases.AppendElements(info->mLiveDatabases))) {
if (NS_WARN_IF(!liveDatabases.AppendElements(info->mLiveDatabases,
fallible))) {
deleteOp->SetFailureCode(NS_ERROR_OUT_OF_MEMORY);
} else {
#ifdef DEBUG
@ -23046,7 +23047,7 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
TPBackgroundIDBDatabaseFileParent ||
fileOrFileId.type() == DatabaseFileOrMutableFileId::Tint64_t);
StoredFileInfo* storedFileInfo = mStoredFileInfos.AppendElement();
StoredFileInfo* storedFileInfo = mStoredFileInfos.AppendElement(fallible);
MOZ_ASSERT(storedFileInfo);
switch (fileOrFileId.type()) {
@ -23609,7 +23610,7 @@ ObjectStoreGetRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
bool hasResult;
while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
StructuredCloneReadInfo* cloneInfo = mResponse.AppendElement();
StructuredCloneReadInfo* cloneInfo = mResponse.AppendElement(fallible);
if (NS_WARN_IF(!cloneInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -23736,7 +23737,7 @@ ObjectStoreGetAllKeysRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
bool hasResult;
while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
Key* key = mResponse.AppendElement();
Key* key = mResponse.AppendElement(fallible);
if (NS_WARN_IF(!key)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -24158,7 +24159,7 @@ IndexGetRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
bool hasResult;
while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
StructuredCloneReadInfo* cloneInfo = mResponse.AppendElement();
StructuredCloneReadInfo* cloneInfo = mResponse.AppendElement(fallible);
if (NS_WARN_IF(!cloneInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -24350,7 +24351,7 @@ IndexGetKeyRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
bool hasResult;
while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
Key* key = mResponse.AppendElement();
Key* key = mResponse.AppendElement(fallible);
if (NS_WARN_IF(!key)) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -1230,14 +1230,17 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
return nullptr;
}
MOZ_ALWAYS_TRUE(fileActorOrMutableFileIds.AppendElement(fileActor));
MOZ_ALWAYS_TRUE(fileActorOrMutableFileIds.AppendElement(fileActor,
fallible));
} else {
const int64_t fileId = blobOrFileInfo.mFileInfo->Id();
MOZ_ASSERT(fileId > 0);
MOZ_ALWAYS_TRUE(fileActorOrMutableFileIds.AppendElement(fileId));
MOZ_ALWAYS_TRUE(fileActorOrMutableFileIds.AppendElement(fileId,
fallible));
nsRefPtr<FileInfo>* newFileInfo = fileInfosToKeepAlive.AppendElement();
nsRefPtr<FileInfo>* newFileInfo =
fileInfosToKeepAlive.AppendElement(fallible);
if (NS_WARN_IF(!newFileInfo)) {
aRv = NS_ERROR_OUT_OF_MEMORY;
return nullptr;

View File

@ -2035,6 +2035,15 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
}
// Remove any and all idle listeners.
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1");
MOZ_ASSERT(idleService);
nsRefPtr<ParentIdleListener> listener;
for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
idleService->RemoveIdleObserver(listener, listener->mTime);
}
mIdleListeners.Clear();
MessageLoop::current()->
@ -4660,30 +4669,34 @@ ContentParent::RecvAddIdleObserver(const uint64_t& aObserver, const uint32_t& aI
{
nsresult rv;
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
nsRefPtr<ParentIdleListener> listener = new ParentIdleListener(this, aObserver);
mIdleListeners.Put(aObserver, listener);
idleService->AddIdleObserver(listener, aIdleTimeInS);
nsRefPtr<ParentIdleListener> listener =
new ParentIdleListener(this, aObserver, aIdleTimeInS);
rv = idleService->AddIdleObserver(listener, aIdleTimeInS);
NS_ENSURE_SUCCESS(rv, false);
mIdleListeners.AppendElement(listener);
return true;
}
bool
ContentParent::RecvRemoveIdleObserver(const uint64_t& aObserver, const uint32_t& aIdleTimeInS)
{
nsresult rv;
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
nsRefPtr<ParentIdleListener> listener;
bool found = mIdleListeners.Get(aObserver, &listener);
if (found) {
mIdleListeners.Remove(aObserver);
idleService->RemoveIdleObserver(listener, aIdleTimeInS);
for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
if (listener->mObserver == aObserver &&
listener->mTime == aIdleTimeInS) {
nsresult rv;
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
idleService->RemoveIdleObserver(listener, aIdleTimeInS);
mIdleListeners.RemoveElementAt(i);
break;
}
}
return true;
}

View File

@ -922,7 +922,7 @@ private:
nsRefPtr<nsConsoleService> mConsoleService;
nsConsoleService* GetConsoleService();
nsDataHashtable<nsUint64HashKey, nsRefPtr<ParentIdleListener> > mIdleListeners;
nsTArray<nsCOMPtr<nsIObserver>> mIdleListeners;
#ifdef MOZ_X11
// Dup of child's X socket, used to scope its resources to this
@ -942,17 +942,20 @@ private:
} // namespace mozilla
class ParentIdleListener : public nsIObserver {
friend class mozilla::dom::ContentParent;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
ParentIdleListener(mozilla::dom::ContentParent* aParent, uint64_t aObserver)
: mParent(aParent), mObserver(aObserver)
ParentIdleListener(mozilla::dom::ContentParent* aParent, uint64_t aObserver, uint32_t aTime)
: mParent(aParent), mObserver(aObserver), mTime(aTime)
{}
private:
virtual ~ParentIdleListener() {}
nsRefPtr<mozilla::dom::ContentParent> mParent;
uint64_t mObserver;
uint32_t mTime;
};
#endif

View File

@ -508,8 +508,8 @@ MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize)
}
// We ensure sufficient capacity above so this shouldn't fail.
MOZ_ALWAYS_TRUE(mBuffer->AppendElements(aData, aSize));
MOZ_ALWAYS_TRUE(mBuffer->AppendElements(RAW_DATA_ALIGNMENT));
MOZ_ALWAYS_TRUE(mBuffer->AppendElements(aData, aSize, fallible));
MOZ_ALWAYS_TRUE(mBuffer->AppendElements(RAW_DATA_ALIGNMENT, fallible));
mSize = aSize;
}
@ -530,8 +530,8 @@ MediaRawData::Clone() const
}
// We ensure sufficient capacity above so this shouldn't fail.
MOZ_ALWAYS_TRUE(s->mBuffer->AppendElements(mData, mSize));
MOZ_ALWAYS_TRUE(s->mBuffer->AppendElements(RAW_DATA_ALIGNMENT));
MOZ_ALWAYS_TRUE(s->mBuffer->AppendElements(mData, mSize, fallible));
MOZ_ALWAYS_TRUE(s->mBuffer->AppendElements(RAW_DATA_ALIGNMENT, fallible));
s->mSize = mSize;
}
return s.forget();

View File

@ -579,8 +579,8 @@ void MediaDecoder::CallSeek(const SeekTarget& aTarget)
mSeekRequest.Begin(ProxyMediaCall(mDecoderStateMachine->TaskQueue(),
mDecoderStateMachine.get(), __func__,
&MediaDecoderStateMachine::Seek, aTarget)
->RefableThen(AbstractThread::MainThread(), __func__, this,
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
->Then(AbstractThread::MainThread(), __func__, this,
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
}
double MediaDecoder::GetCurrentTime()

View File

@ -1019,7 +1019,7 @@ protected:
virtual void CallSeek(const SeekTarget& aTarget);
MediaPromiseConsumerHolder<SeekPromise> mSeekRequest;
MediaPromiseRequestHolder<SeekPromise> mSeekRequest;
// True when seeking or otherwise moving the play position around in
// such a manner that progress event data is inaccurate. This is set

View File

@ -182,9 +182,6 @@ MediaDecoderReader::AsyncReadMetadata()
mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
DECODER_LOG("MediaDecoderReader::AsyncReadMetadata");
// PreReadMetadata causes us to try to allocate various hardware and OS
// resources, which may not be available at the moment.
PreReadMetadata();
if (IsWaitingMediaResources()) {
return MetadataPromise::CreateAndReject(Reason::WAITING_FOR_RESOURCES, __func__);
}

View File

@ -165,13 +165,10 @@ public:
virtual bool HasVideo() = 0;
// The default implementation of AsyncReadMetadata is implemented in terms of
// synchronous PreReadMetadata() / ReadMetadata() calls. Implementations may also
// synchronous ReadMetadata() calls. Implementations may also
// override AsyncReadMetadata to create a more proper async implementation.
virtual nsRefPtr<MetadataPromise> AsyncReadMetadata();
// A function that is called before ReadMetadata() call.
virtual void PreReadMetadata() {};
// Read header data for all bitstreams in the file. Fills aInfo with
// the data required to present the media, and optionally fills *aTags
// with tag metadata from the file.

View File

@ -976,16 +976,16 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
nsRefPtr<MediaDecoderStateMachine> self = this;
WaitRequestRef(aType).Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::WaitForData, aType)
->RefableThen(TaskQueue(), __func__,
[self] (MediaData::Type aType) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->WaitRequestRef(aType).Complete();
self->DispatchDecodeTasksIfNeeded();
},
[self] (WaitForDataRejectValue aRejection) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->WaitRequestRef(aRejection.mType).Complete();
}));
->Then(TaskQueue(), __func__,
[self] (MediaData::Type aType) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->WaitRequestRef(aType).Complete();
self->DispatchDecodeTasksIfNeeded();
},
[self] (WaitForDataRejectValue aRejection) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->WaitRequestRef(aRejection.mType).Complete();
}));
return;
}
@ -1961,20 +1961,20 @@ MediaDecoderStateMachine::InitiateSeek()
mSeekRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime,
GetEndTime())
->RefableThen(TaskQueue(), __func__,
[self] (int64_t) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->mSeekRequest.Complete();
// We must decode the first samples of active streams, so we can determine
// the new stream time. So dispatch tasks to do that.
self->mDecodeToSeekTarget = true;
self->DispatchDecodeTasksIfNeeded();
}, [self] (nsresult aResult) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->mSeekRequest.Complete();
MOZ_ASSERT(NS_FAILED(aResult), "Cancels should also disconnect mSeekRequest");
self->DecodeError();
}));
->Then(TaskQueue(), __func__,
[self] (int64_t) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->mSeekRequest.Complete();
// We must decode the first samples of active streams, so we can determine
// the new stream time. So dispatch tasks to do that.
self->mDecodeToSeekTarget = true;
self->DispatchDecodeTasksIfNeeded();
}, [self] (nsresult aResult) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->mSeekRequest.Complete();
MOZ_ASSERT(NS_FAILED(aResult), "Cancels should also disconnect mSeekRequest");
self->DecodeError();
}));
}
nsresult
@ -2020,9 +2020,9 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData)
->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
->Then(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
return NS_OK;
}
@ -2080,9 +2080,9 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime)
->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
->Then(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
return NS_OK;
}
@ -2364,18 +2364,18 @@ MediaDecoderStateMachine::DecodeFirstFrame()
if (HasAudio()) {
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData)
->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
->Then(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
}
if (HasVideo()) {
mVideoDecodeStartTime = TimeStamp::Now();
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestVideoData, false,
int64_t(0))
->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
->Then(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
}
}
@ -2648,9 +2648,9 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
DECODER_LOG("Dispatching AsyncReadMetadata");
mMetadataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::AsyncReadMetadata)
->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnMetadataRead,
&MediaDecoderStateMachine::OnMetadataNotRead));
->Then(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnMetadataRead,
&MediaDecoderStateMachine::OnMetadataNotRead));
}
return NS_OK;

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