зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central into services-central
This commit is contained in:
Коммит
89af42f6ad
|
@ -202,6 +202,7 @@
|
|||
</html:select>
|
||||
</markup>
|
||||
|
||||
<!-- Temporarily disabled for causing bug 733848
|
||||
<markup ref="html:img" ruleset="htmlimage">
|
||||
<html:span id="l1" a11yname="test2">test2</html:span>
|
||||
<html:span id="l2" a11yname="test3">test3</html:span>
|
||||
|
@ -223,6 +224,7 @@
|
|||
alt=""
|
||||
src="../moz.png"/>
|
||||
</markup>
|
||||
-->
|
||||
|
||||
<markup ref="html:table/html:tr/html:td" ruleset="htmlelm"
|
||||
id="markup4test">
|
||||
|
|
|
@ -77,14 +77,17 @@ const gXPInstallObserver = {
|
|||
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
|
||||
[brandShortName, installInfo.originatingURI.host]);
|
||||
|
||||
let secHistogram = Components.classes["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry).getHistogramById("SECURITY_UI");
|
||||
action = {
|
||||
label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
|
||||
accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
|
||||
callback: function() {
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED_CLICK_THROUGH);
|
||||
installInfo.install();
|
||||
}
|
||||
};
|
||||
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED);
|
||||
PopupNotifications.show(browser, notificationID, messageString, anchorID,
|
||||
action, null, options);
|
||||
break;
|
||||
|
|
|
@ -160,10 +160,10 @@ let SocialShareButton = {
|
|||
updateProfileInfo: function SSB_updateProfileInfo() {
|
||||
let profileRow = document.getElementById("editSharePopupHeader");
|
||||
let profile = Social.provider.profile;
|
||||
if (profile && profile.portrait && profile.displayName) {
|
||||
if (profile && profile.displayName) {
|
||||
profileRow.hidden = false;
|
||||
let portrait = document.getElementById("socialUserPortrait");
|
||||
portrait.style.listStyleImage = profile.portrait;
|
||||
portrait.setAttribute("src", profile.portrait || "chrome://browser/skin/social/social.png");
|
||||
let displayName = document.getElementById("socialUserDisplayName");
|
||||
displayName.setAttribute("label", profile.displayName);
|
||||
} else {
|
||||
|
|
|
@ -2519,9 +2519,13 @@ let BrowserOnClick = {
|
|||
|
||||
onAboutCertError: function BrowserOnClick_onAboutCertError(aTargetElm, aOwnerDoc) {
|
||||
let elmId = aTargetElm.getAttribute("id");
|
||||
let secHistogram = Cc["@mozilla.org/base/telemetry;1"].
|
||||
getService(Ci.nsITelemetry).
|
||||
getHistogramById("SECURITY_UI");
|
||||
|
||||
switch (elmId) {
|
||||
case "exceptionDialogButton":
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_CLICK_ADD_EXCEPTION);
|
||||
let params = { exceptionAdded : false, handlePrivateBrowsing : true };
|
||||
|
||||
try {
|
||||
|
@ -2545,21 +2549,37 @@ let BrowserOnClick = {
|
|||
break;
|
||||
|
||||
case "getMeOutOfHereButton":
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_GET_ME_OUT_OF_HERE);
|
||||
getMeOutOfHere();
|
||||
break;
|
||||
|
||||
case "technicalContent":
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TECHNICAL_DETAILS);
|
||||
break;
|
||||
|
||||
case "expertContent":
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_UNDERSTAND_RISKS);
|
||||
break;
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
onAboutBlocked: function BrowserOnClick_onAboutBlocked(aTargetElm, aOwnerDoc) {
|
||||
let elmId = aTargetElm.getAttribute("id");
|
||||
let secHistogram = Cc["@mozilla.org/base/telemetry;1"].
|
||||
getService(Ci.nsITelemetry).
|
||||
getHistogramById("SECURITY_UI");
|
||||
|
||||
// The event came from a button on a malware/phishing block page
|
||||
// First check whether it's malware or phishing, so that we can
|
||||
// use the right strings/links
|
||||
let isMalware = /e=malwareBlocked/.test(aOwnerDoc.documentURI);
|
||||
let bucketName = isMalware ? "WARNING_MALWARE_PAGE_":"WARNING_PHISHING_PAGE_";
|
||||
let nsISecTel = Ci.nsISecurityUITelemetry;
|
||||
|
||||
switch (elmId) {
|
||||
case "getMeOutButton":
|
||||
secHistogram.add(nsISecTel[bucketName + "GET_ME_OUT_OF_HERE"]);
|
||||
getMeOutOfHere();
|
||||
break;
|
||||
|
||||
|
@ -2568,6 +2588,10 @@ let BrowserOnClick = {
|
|||
// we can fetch a site-specific report, for phishing, we redirect
|
||||
// to the generic page describing phishing protection.
|
||||
|
||||
// We log even if malware/phishing info URL couldn't be found:
|
||||
// the measurement is for how many users clicked the WHY BLOCKED button
|
||||
secHistogram.add(nsISecTel[bucketName + "WHY_BLOCKED"]);
|
||||
|
||||
if (isMalware) {
|
||||
// Get the stop badware "why is this blocked" report url,
|
||||
// append the current url, and go there.
|
||||
|
@ -2589,6 +2613,7 @@ let BrowserOnClick = {
|
|||
break;
|
||||
|
||||
case "ignoreWarningButton":
|
||||
secHistogram.add(nsISecTel[bucketName + "IGNORE_WARNING"]);
|
||||
this.ignoreWarningButton(isMalware);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ function test() {
|
|||
var tests = {
|
||||
testProfileSet: function(next) {
|
||||
let profile = {
|
||||
portrait: "chrome://branding/content/icon48.png",
|
||||
portrait: "https://example.com/portrait.jpg",
|
||||
userName: "trickster",
|
||||
displayName: "Kuma Lisa",
|
||||
profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
|
||||
|
@ -31,7 +31,7 @@ var tests = {
|
|||
Social.provider.updateUserProfile(profile);
|
||||
// check dom values
|
||||
let portrait = document.getElementById("social-statusarea-user-portrait").getAttribute("src");
|
||||
is(portrait, profile.portrait, "portrait is set");
|
||||
is(profile.portrait, portrait, "portrait is set");
|
||||
let userButton = document.getElementById("social-statusarea-username");
|
||||
ok(!userButton.hidden, "username is visible");
|
||||
is(userButton.label, profile.userName, "username is set");
|
||||
|
|
|
@ -611,7 +611,6 @@ WebConsole.prototype = {
|
|||
|
||||
let position = Services.prefs.getCharPref("devtools.webconsole.position");
|
||||
this.positionConsole(position);
|
||||
this._currentUIPosition = position;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -622,8 +621,10 @@ WebConsole.prototype = {
|
|||
{
|
||||
this.iframe.removeEventListener("load", this._onIframeLoad, true);
|
||||
|
||||
let position = Services.prefs.getCharPref("devtools.webconsole.position");
|
||||
|
||||
this.iframeWindow = this.iframe.contentWindow.wrappedJSObject;
|
||||
this.ui = new this.iframeWindow.WebConsoleFrame(this, this._currentUIPosition);
|
||||
this.ui = new this.iframeWindow.WebConsoleFrame(this, position);
|
||||
this._setupMessageManager();
|
||||
},
|
||||
|
||||
|
@ -695,8 +696,6 @@ WebConsole.prototype = {
|
|||
this.iframe.flex = 1;
|
||||
|
||||
panel.setAttribute("height", height);
|
||||
|
||||
this._afterPositionConsole("window", lastIndex);
|
||||
}).bind(this);
|
||||
|
||||
panel.addEventListener("popupshown", onPopupShown,false);
|
||||
|
@ -736,6 +735,9 @@ WebConsole.prototype = {
|
|||
if (this.splitter.parentNode) {
|
||||
this.splitter.parentNode.removeChild(this.splitter);
|
||||
}
|
||||
|
||||
this._beforePositionConsole("window", lastIndex);
|
||||
|
||||
panel.appendChild(this.iframe);
|
||||
|
||||
let space = this.chromeDocument.createElement("spacer");
|
||||
|
@ -822,6 +824,8 @@ WebConsole.prototype = {
|
|||
this.splitter.parentNode.removeChild(this.splitter);
|
||||
}
|
||||
|
||||
this._beforePositionConsole(aPosition, lastIndex);
|
||||
|
||||
if (aPosition == "below") {
|
||||
nBox.appendChild(this.splitter);
|
||||
nBox.appendChild(this.iframe);
|
||||
|
@ -841,12 +845,10 @@ WebConsole.prototype = {
|
|||
this.iframe.removeAttribute("height");
|
||||
this.iframe.style.height = height + "px";
|
||||
}
|
||||
|
||||
this._afterPositionConsole(aPosition, lastIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Common code that needs to execute after the Web Console is repositioned.
|
||||
* Common code that needs to execute before the Web Console is repositioned.
|
||||
* @private
|
||||
* @param string aPosition
|
||||
* The new position: "above", "below" or "window".
|
||||
|
@ -854,8 +856,8 @@ WebConsole.prototype = {
|
|||
* The last visible message in the console output before repositioning
|
||||
* occurred.
|
||||
*/
|
||||
_afterPositionConsole:
|
||||
function WC__afterPositionConsole(aPosition, aLastIndex)
|
||||
_beforePositionConsole:
|
||||
function WC__beforePositionConsole(aPosition, aLastIndex)
|
||||
{
|
||||
if (!this.ui) {
|
||||
return;
|
||||
|
|
|
@ -37,7 +37,7 @@ function waitForPosition(aPosition, aCallback) {
|
|||
{
|
||||
return hudRef._currentUIPosition == aPosition;
|
||||
},
|
||||
successFn: aCallback,
|
||||
successFn: executeSoon.bind(null, aCallback),
|
||||
failureFn: finishTest,
|
||||
});
|
||||
}
|
||||
|
@ -55,9 +55,10 @@ function consoleOpened(aHudRef) {
|
|||
"position menu checkbox is below");
|
||||
is(Services.prefs.getCharPref(POSITION_PREF), "below", "pref is below");
|
||||
|
||||
hudRef.positionConsole("above");
|
||||
|
||||
waitForPosition("above", onPositionAbove);
|
||||
executeSoon(function() {
|
||||
hudRef.positionConsole("above");
|
||||
waitForPosition("above", onPositionAbove);
|
||||
});
|
||||
}
|
||||
|
||||
function onPositionAbove() {
|
||||
|
@ -81,8 +82,10 @@ function onPositionAbove() {
|
|||
Services.prefs.setIntPref(TOP_PREF, 50);
|
||||
Services.prefs.setIntPref(LEFT_PREF, 51);
|
||||
|
||||
hudRef.positionConsole("window");
|
||||
waitForPosition("window", onPositionWindow);
|
||||
executeSoon(function() {
|
||||
hudRef.positionConsole("window");
|
||||
waitForPosition("window", onPositionWindow);
|
||||
});
|
||||
}
|
||||
|
||||
function onPositionWindow() {
|
||||
|
|
|
@ -55,6 +55,24 @@ public:
|
|||
NS_DECL_NSIXHRSENDABLE
|
||||
NS_DECL_NSIMUTABLE
|
||||
|
||||
void
|
||||
SetLazyData(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength)
|
||||
{
|
||||
NS_ASSERTION(aLength, "must have length");
|
||||
|
||||
mName = aName;
|
||||
mContentType = aContentType;
|
||||
mLength = aLength;
|
||||
|
||||
mIsFile = !aName.IsVoid();
|
||||
}
|
||||
|
||||
bool IsSizeUnknown() const
|
||||
{
|
||||
return mLength == UINT64_MAX;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsDOMFileBase(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength)
|
||||
|
@ -86,11 +104,6 @@ protected:
|
|||
|
||||
virtual ~nsDOMFileBase() {}
|
||||
|
||||
bool IsSizeUnknown() const
|
||||
{
|
||||
return mLength == UINT64_MAX;
|
||||
}
|
||||
|
||||
virtual bool IsStoredFile() const
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -105,16 +105,13 @@ MOCHITEST_FILES = \
|
|||
test_reactivate.html \
|
||||
test_readyState.html \
|
||||
test_replay_metadata.html \
|
||||
test_seek.html \
|
||||
test_seek2.html \
|
||||
test_seek_out_of_range.html \
|
||||
test_source.html \
|
||||
test_source_write.html \
|
||||
test_source_null.html \
|
||||
test_standalone.html \
|
||||
test_streams_element_capture.html \
|
||||
test_streams_element_capture_reset.html \
|
||||
test_timeupdate_small_files.html \
|
||||
test_too_many_elements.html \
|
||||
test_volume.html \
|
||||
test_video_to_canvas.html \
|
||||
|
@ -122,10 +119,6 @@ MOCHITEST_FILES = \
|
|||
test_audiowrite.html \
|
||||
test_mozHasAudio.html \
|
||||
test_source_media.html \
|
||||
$(NULL)
|
||||
|
||||
# Bug 759221
|
||||
MOCHITEST_FILES += \
|
||||
test_autoplay_contentEditable.html \
|
||||
test_buffered.html \
|
||||
test_bug448534.html \
|
||||
|
@ -136,6 +129,19 @@ MOCHITEST_FILES += \
|
|||
test_seekLies.html \
|
||||
$(NULL)
|
||||
|
||||
# Tests disabled on Linux for frequent intermittent failures
|
||||
ifneq (Linux,$(OS_ARCH))
|
||||
MOCHITEST_FILES += \
|
||||
test_seek.html \
|
||||
test_seek_out_of_range.html \
|
||||
test_timeupdate_small_files.html \
|
||||
$(NULL)
|
||||
else
|
||||
$(warning test_seek.html is disabled on Linux for timeouts. Bug 620598)
|
||||
$(warning test_seek_out_of_range.html is disabled on Linux for timeouts. Bug 661076)
|
||||
$(warning test_timeupdate_small_files.html is disabled on Linux for timeouts. Bug 687972)
|
||||
endif
|
||||
|
||||
# Don't run in suite
|
||||
ifndef MOZ_SUITE
|
||||
MOCHITEST_FILES += test_play_twice.html
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
var gSmallTests = [
|
||||
{ name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
|
||||
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233 },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266 },
|
||||
{ name:"seek.webm", type:"video/webm", width:320, height:240, duration:3.966 },
|
||||
{ name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
|
||||
{ name:"bogus.duh", type:"bogus/duh" }
|
||||
|
@ -19,7 +19,7 @@ var gProgressTests = [
|
|||
{ name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0, size:11069 },
|
||||
{ name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444 },
|
||||
{ name:"seek.ogv", type:"video/ogg", duration:3.966, size:285310 },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233, size:28942 },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942 },
|
||||
{ name:"seek.webm", type:"video/webm", duration:3.966, size:215529 },
|
||||
{ name:"bogus.duh", type:"bogus/duh" }
|
||||
];
|
||||
|
@ -40,7 +40,7 @@ var gCloneTests = gSmallTests.concat([
|
|||
{ name:"bug520908.ogv", type:"video/ogg", duration:9000 },
|
||||
// short-video is more like 1s, so if you load this twice you'll get an unexpected duration
|
||||
{ name:"dynamic_resource.sjs?key=" + cloneKey + "&res1=320x240.ogv&res2=short-video.ogv",
|
||||
type:"video/ogg", duration:0.233 },
|
||||
type:"video/ogg", duration:0.266 },
|
||||
]);
|
||||
|
||||
// Used by test_play_twice. Need one test file per decoder backend, plus
|
||||
|
@ -59,7 +59,7 @@ var gPausedAfterEndedTests = gSmallTests.concat([
|
|||
// Test the mozHasAudio property
|
||||
var gMozHasAudioTests = [
|
||||
{ name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444, hasAudio:undefined },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233, size:28942, hasAudio:false },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942, hasAudio:false },
|
||||
{ name:"short-video.ogv", type:"video/ogg", duration:1.081, hasAudio:true },
|
||||
{ name:"seek.webm", type:"video/webm", duration:3.966, size:215529, hasAudio:false },
|
||||
{ name:"bogus.duh", type:"bogus/duh" }
|
||||
|
@ -128,7 +128,7 @@ var gPlayTests = [
|
|||
|
||||
// Test playback/metadata work after a redirect
|
||||
{ name:"redirect.sjs?domain=mochi.test:8888&file=320x240.ogv",
|
||||
type:"video/ogg", duration:0.233 },
|
||||
type:"video/ogg", duration:0.266 },
|
||||
|
||||
// Test playback of a webm file
|
||||
{ name:"seek.webm", type:"video/webm", duration:3.966 },
|
||||
|
@ -258,7 +258,7 @@ var gSeekTests = [
|
|||
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
|
||||
{ name:"audio.wav", type:"audio/x-wav", duration:0.031247 },
|
||||
{ name:"seek.ogv", type:"video/ogg", duration:3.966 },
|
||||
{ name:"320x240.ogv", type:"video/ogg", duration:0.233 },
|
||||
{ name:"320x240.ogv", type:"video/ogg", duration:0.266 },
|
||||
{ name:"seek.webm", type:"video/webm", duration:3.966 },
|
||||
{ name:"bug516323.indexed.ogv", type:"video/ogg", duration:4.208 },
|
||||
{ name:"split.webm", type:"video/webm", duration:1.967 },
|
||||
|
|
|
@ -54,7 +54,11 @@ var eventsToLog = ["play", "canplay", "canplaythrough", "loadstart", "loadedmeta
|
|||
"waiting", "pause"];
|
||||
function logEvent(event) {
|
||||
if (event.target.gotEnded > (event.type == "ended" ? 1 : 0)) {
|
||||
ok(false, event.target.currentSrc + " got unexpected " + event.type + " after ended");
|
||||
if (event.target.currentSrc.slice(-9) == "seek.webm" && event.type == "stalled") {
|
||||
todo(false, event.target.currentSrc + " got unexpected stalled after ended (bug 760770)");
|
||||
} else {
|
||||
ok(false, event.target.currentSrc + " got unexpected " + event.type + " after ended");
|
||||
}
|
||||
} else {
|
||||
info(event.target.currentSrc + " got " + event.type);
|
||||
}
|
||||
|
|
|
@ -192,6 +192,9 @@
|
|||
#include "mozilla/StartupTimeline.h"
|
||||
#include "nsIFrameMessageManager.h"
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsISecurityUITelemetry.h"
|
||||
|
||||
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
|
||||
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
|
||||
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
|
@ -4040,8 +4043,16 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
|||
rv = stss->IsStsURI(aURI, &isStsHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (isStsHost)
|
||||
PRUint32 bucketId;
|
||||
if (isStsHost) {
|
||||
cssClass.AssignLiteral("badStsCert");
|
||||
//measuring STS separately allows us to measure click through
|
||||
//rates easily
|
||||
bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_STS;
|
||||
} else {
|
||||
bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT;
|
||||
}
|
||||
|
||||
|
||||
if (Preferences::GetBool(
|
||||
"browser.xul.error_pages.expert_bad_cert", false)) {
|
||||
|
@ -4054,6 +4065,10 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
|||
"security.alternate_certificate_error_page");
|
||||
if (alternateErrorPage)
|
||||
errorPage.Assign(alternateErrorPage);
|
||||
|
||||
if (errorPage.EqualsIgnoreCase("certerror"))
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId);
|
||||
|
||||
} else {
|
||||
error.AssignLiteral("nssFailure2");
|
||||
}
|
||||
|
@ -4071,10 +4086,19 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
|||
if (alternateErrorPage)
|
||||
errorPage.Assign(alternateErrorPage);
|
||||
|
||||
if (NS_ERROR_PHISHING_URI == aError)
|
||||
PRUint32 bucketId;
|
||||
if (NS_ERROR_PHISHING_URI == aError) {
|
||||
error.AssignLiteral("phishingBlocked");
|
||||
else
|
||||
bucketId = nsISecurityUITelemetry::WARNING_PHISHING_PAGE;
|
||||
} else {
|
||||
error.AssignLiteral("malwareBlocked");
|
||||
bucketId = nsISecurityUITelemetry::WARNING_MALWARE_PAGE;
|
||||
}
|
||||
|
||||
if (errorPage.EqualsIgnoreCase("blocked"))
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI,
|
||||
bucketId);
|
||||
|
||||
cssClass.AssignLiteral("blacklist");
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "IDBObjectStore.h"
|
||||
|
||||
#include "mozilla/dom/ipc/nsIRemoteBlob.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
|
@ -585,6 +586,47 @@ GetAddInfoCallback(JSContext* aCx, void* aClosure)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
inline
|
||||
BlobChild*
|
||||
ActorFromRemoteBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
|
||||
if (remoteBlob) {
|
||||
BlobChild* actor =
|
||||
static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
|
||||
NS_ASSERTION(actor, "Null actor?!");
|
||||
return actor;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aName,
|
||||
const nsString& aContentType, PRUint64 aSize)
|
||||
{
|
||||
BlobChild* actor = ActorFromRemoteBlob(aBlob);
|
||||
if (actor) {
|
||||
return actor->SetMysteryBlobInfo(aName, aContentType, aSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aContentType,
|
||||
PRUint64 aSize)
|
||||
{
|
||||
BlobChild* actor = ActorFromRemoteBlob(aBlob);
|
||||
if (actor) {
|
||||
return actor->SetMysteryBlobInfo(aContentType, aSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
JSClass IDBObjectStore::sDummyPropJSClass = {
|
||||
|
@ -1098,6 +1140,9 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
|||
if (aTag == SCTAG_DOM_BLOB) {
|
||||
nsCOMPtr<nsIDOMBlob> domBlob;
|
||||
if (file.mFile) {
|
||||
if (!ResolveMysteryBlob(file.mFile, convType, size)) {
|
||||
return nullptr;
|
||||
}
|
||||
domBlob = file.mFile;
|
||||
}
|
||||
else {
|
||||
|
@ -1126,6 +1171,9 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
|||
|
||||
nsCOMPtr<nsIDOMFile> domFile;
|
||||
if (file.mFile) {
|
||||
if (!ResolveMysteryBlob(file.mFile, convName, convType, size)) {
|
||||
return nullptr;
|
||||
}
|
||||
domFile = do_QueryInterface(file.mFile);
|
||||
NS_ASSERTION(domFile, "This should never fail!");
|
||||
}
|
||||
|
|
|
@ -182,7 +182,6 @@
|
|||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="file.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
|
165
dom/ipc/Blob.cpp
165
dom/ipc/Blob.cpp
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/net/NeckoMessageUtils.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
@ -301,6 +302,16 @@ SetBlobOnParams(BlobParent* aActor, SlicedBlobConstructorParams& aParams)
|
|||
aParams.sourceParent() = aActor;
|
||||
}
|
||||
|
||||
inline
|
||||
nsDOMFileBase*
|
||||
ToConcreteBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to grow
|
||||
// a real interface or something.
|
||||
return static_cast<nsDOMFileBase*>(aBlob);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -530,13 +541,23 @@ public:
|
|||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
RemoteBlob(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength)
|
||||
PRUint64 aLength)
|
||||
: nsDOMFile(aName, aContentType, aLength), mActor(nullptr)
|
||||
{ }
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
RemoteBlob(const nsAString& aContentType, PRUint64 aLength)
|
||||
: nsDOMFile(aContentType, aLength), mActor(nullptr)
|
||||
{ }
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
RemoteBlob()
|
||||
: nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX), mActor(nullptr)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
virtual ~RemoteBlob()
|
||||
{
|
||||
|
@ -594,16 +615,22 @@ public:
|
|||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
Blob<ActorFlavor>::Blob(nsIDOMBlob* aBlob)
|
||||
: mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true)
|
||||
: mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true), mBlobIsFile(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aBlob);
|
||||
aBlob->AddRef();
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
mBlobIsFile = !!file;
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
Blob<ActorFlavor>::Blob(const BlobConstructorParams& aParams)
|
||||
: mBlob(nullptr), mRemoteBlob(nullptr), mOwnsBlob(true)
|
||||
: mBlob(nullptr), mRemoteBlob(nullptr), mOwnsBlob(false), mBlobIsFile(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<RemoteBlobType> remoteBlob;
|
||||
|
||||
switch (aParams.type()) {
|
||||
|
@ -620,6 +647,13 @@ Blob<ActorFlavor>::Blob(const BlobConstructorParams& aParams)
|
|||
remoteBlob =
|
||||
new RemoteBlobType(params.name(), params.contentType(),
|
||||
params.length());
|
||||
mBlobIsFile = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case BlobConstructorParams::TMysteryBlobConstructorParams: {
|
||||
remoteBlob = new RemoteBlobType();
|
||||
mBlobIsFile = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -629,23 +663,19 @@ Blob<ActorFlavor>::Blob(const BlobConstructorParams& aParams)
|
|||
|
||||
MOZ_ASSERT(remoteBlob);
|
||||
|
||||
if (NS_FAILED(remoteBlob->SetMutable(false))) {
|
||||
MOZ_NOT_REACHED("Failed to make remote blob immutable!");
|
||||
}
|
||||
|
||||
remoteBlob->SetActor(this);
|
||||
remoteBlob.forget(&mRemoteBlob);
|
||||
|
||||
mBlob = mRemoteBlob;
|
||||
SetRemoteBlob(remoteBlob);
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
Blob<ActorFlavor>*
|
||||
Blob<ActorFlavor>::Create(const BlobConstructorParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
switch (aParams.type()) {
|
||||
case BlobConstructorParams::TNormalBlobConstructorParams:
|
||||
case BlobConstructorParams::TFileBlobConstructorParams:
|
||||
case BlobConstructorParams::TMysteryBlobConstructorParams:
|
||||
return new Blob<ActorFlavor>(aParams);
|
||||
|
||||
case BlobConstructorParams::TSlicedBlobConstructorParams: {
|
||||
|
@ -675,6 +705,7 @@ template <ActorFlavorEnum ActorFlavor>
|
|||
already_AddRefed<nsIDOMBlob>
|
||||
Blob<ActorFlavor>::GetBlob()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mBlob);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob;
|
||||
|
@ -695,6 +726,63 @@ Blob<ActorFlavor>::GetBlob()
|
|||
return blob.forget();
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
bool
|
||||
Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aName,
|
||||
const nsString& aContentType,
|
||||
PRUint64 aLength)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mBlob);
|
||||
MOZ_ASSERT(mRemoteBlob);
|
||||
MOZ_ASSERT(aLength);
|
||||
|
||||
ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength);
|
||||
|
||||
FileBlobConstructorParams params(aName, aContentType, aLength);
|
||||
return BaseType::SendResolveMystery(params);
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
bool
|
||||
Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aContentType,
|
||||
PRUint64 aLength)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mBlob);
|
||||
MOZ_ASSERT(mRemoteBlob);
|
||||
MOZ_ASSERT(aLength);
|
||||
|
||||
nsString voidString;
|
||||
voidString.SetIsVoid(true);
|
||||
|
||||
ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength);
|
||||
|
||||
NormalBlobConstructorParams params(aContentType, aLength);
|
||||
return BaseType::SendResolveMystery(params);
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
void
|
||||
Blob<ActorFlavor>::SetRemoteBlob(nsRefPtr<RemoteBlobType>& aRemoteBlob)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mBlob);
|
||||
MOZ_ASSERT(!mRemoteBlob);
|
||||
MOZ_ASSERT(!mOwnsBlob);
|
||||
MOZ_ASSERT(aRemoteBlob);
|
||||
|
||||
if (NS_FAILED(aRemoteBlob->SetMutable(false))) {
|
||||
MOZ_NOT_REACHED("Failed to make remote blob immutable!");
|
||||
}
|
||||
|
||||
aRemoteBlob->SetActor(this);
|
||||
aRemoteBlob.forget(&mRemoteBlob);
|
||||
|
||||
mBlob = mRemoteBlob;
|
||||
mOwnsBlob = true;
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
void
|
||||
Blob<ActorFlavor>::NoteDyingRemoteBlob()
|
||||
|
@ -703,12 +791,15 @@ Blob<ActorFlavor>::NoteDyingRemoteBlob()
|
|||
MOZ_ASSERT(mRemoteBlob);
|
||||
MOZ_ASSERT(!mOwnsBlob);
|
||||
|
||||
// This may be called on any thread due to the fact that RemoteBlob is
|
||||
// designed to be passed between threads. We must start the shutdown process
|
||||
// on the main thread, so we proxy here if necessary.
|
||||
if (!NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewNonOwningRunnableMethod(this,
|
||||
&Blob<ActorFlavor>::NoteDyingRemoteBlob);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
|
||||
MOZ_NOT_REACHED("Should never fail!");
|
||||
MOZ_ASSERT(false, "Should never fail!");
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -718,13 +809,14 @@ Blob<ActorFlavor>::NoteDyingRemoteBlob()
|
|||
// access a dangling pointer.
|
||||
mRemoteBlob = nullptr;
|
||||
|
||||
BaseType::Send__delete__(this);
|
||||
mozilla::unused << BaseType::Send__delete__(this);
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
void
|
||||
Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mBlob);
|
||||
|
||||
if (mRemoteBlob) {
|
||||
|
@ -736,10 +828,51 @@ Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
|
|||
}
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
bool
|
||||
Blob<ActorFlavor>::RecvResolveMystery(const ResolveMysteryParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mBlob);
|
||||
MOZ_ASSERT(!mRemoteBlob);
|
||||
MOZ_ASSERT(mOwnsBlob);
|
||||
|
||||
if (!mBlobIsFile) {
|
||||
MOZ_ASSERT(false, "Must always be a file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDOMFileBase* blob = ToConcreteBlob(mBlob);
|
||||
|
||||
switch (aParams.type()) {
|
||||
case ResolveMysteryParams::TNormalBlobConstructorParams: {
|
||||
const NormalBlobConstructorParams& params =
|
||||
aParams.get_NormalBlobConstructorParams();
|
||||
nsString voidString;
|
||||
voidString.SetIsVoid(true);
|
||||
blob->SetLazyData(voidString, params.contentType(), params.length());
|
||||
break;
|
||||
}
|
||||
|
||||
case ResolveMysteryParams::TFileBlobConstructorParams: {
|
||||
const FileBlobConstructorParams& params =
|
||||
aParams.get_FileBlobConstructorParams();
|
||||
blob->SetLazyData(params.name(), params.contentType(), params.length());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_NOT_REACHED("Unknown params!");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
bool
|
||||
Blob<ActorFlavor>::RecvPBlobStreamConstructor(StreamType* aActor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mBlob);
|
||||
MOZ_ASSERT(!mRemoteBlob);
|
||||
|
||||
|
@ -754,6 +887,7 @@ template <ActorFlavorEnum ActorFlavor>
|
|||
typename Blob<ActorFlavor>::StreamType*
|
||||
Blob<ActorFlavor>::AllocPBlobStream()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return new InputStreamActor<ActorFlavor>();
|
||||
}
|
||||
|
||||
|
@ -761,6 +895,7 @@ template <ActorFlavorEnum ActorFlavor>
|
|||
bool
|
||||
Blob<ActorFlavor>::DeallocPBlobStream(StreamType* aActor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ class RemoteBlob;
|
|||
template <ActorFlavorEnum ActorFlavor>
|
||||
class Blob : public BlobTraits<ActorFlavor>::BaseType
|
||||
{
|
||||
friend class RemoteBlob<ActorFlavor>;
|
||||
|
||||
public:
|
||||
typedef typename BlobTraits<ActorFlavor>::BaseType BaseType;
|
||||
typedef typename BlobTraits<ActorFlavor>::StreamType StreamType;
|
||||
|
@ -69,6 +71,7 @@ protected:
|
|||
nsIDOMBlob* mBlob;
|
||||
RemoteBlobType* mRemoteBlob;
|
||||
bool mOwnsBlob;
|
||||
bool mBlobIsFile;
|
||||
|
||||
public:
|
||||
// This create function is called on the sending side.
|
||||
|
@ -82,11 +85,20 @@ public:
|
|||
static Blob*
|
||||
Create(const BlobConstructorParams& aParams);
|
||||
|
||||
// Get the blob associated with this actor. This may always be called on the
|
||||
// sending side. It may also be called on the receiving side unless this is a
|
||||
// "mystery" blob that has not yet received a SetMysteryBlobInfo() call.
|
||||
already_AddRefed<nsIDOMBlob>
|
||||
GetBlob();
|
||||
|
||||
void
|
||||
NoteDyingRemoteBlob();
|
||||
// Use this for files.
|
||||
bool
|
||||
SetMysteryBlobInfo(const nsString& aName, const nsString& aContentType,
|
||||
PRUint64 aLength);
|
||||
|
||||
// Use this for non-file blobs.
|
||||
bool
|
||||
SetMysteryBlobInfo(const nsString& aContentType, PRUint64 aLength);
|
||||
|
||||
private:
|
||||
// This constructor is called on the sending side.
|
||||
|
@ -95,10 +107,19 @@ private:
|
|||
// This constructor is called on the receiving side.
|
||||
Blob(const BlobConstructorParams& aParams);
|
||||
|
||||
void
|
||||
SetRemoteBlob(nsRefPtr<RemoteBlobType>& aRemoteBlob);
|
||||
|
||||
void
|
||||
NoteDyingRemoteBlob();
|
||||
|
||||
// These methods are only called by the IPDL message machinery.
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvResolveMystery(const ResolveMysteryParams& aParams) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvPBlobStreamConstructor(StreamType* aActor) MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
#include "mozilla/dom/sms/SmsChild.h"
|
||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsIRemoteBlob.h"
|
||||
#include "StructuredCloneUtils.h"
|
||||
|
||||
|
@ -433,6 +433,7 @@ ContentChild::DeallocPBlob(PBlobChild* aActor)
|
|||
BlobChild*
|
||||
ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aBlob, "Null pointer!");
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
|
||||
|
@ -444,32 +445,44 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
|||
return actor;
|
||||
}
|
||||
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to grow
|
||||
// a real interface or something.
|
||||
const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
|
||||
BlobConstructorParams params;
|
||||
|
||||
nsString contentType;
|
||||
nsresult rv = aBlob->GetType(contentType);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
PRUint64 length;
|
||||
rv = aBlob->GetSize(&length);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
FileBlobConstructorParams fileParams;
|
||||
|
||||
rv = file->GetName(fileParams.name());
|
||||
if (blob->IsSizeUnknown()) {
|
||||
// We don't want to call GetSize yet since that may stat a file on the main
|
||||
// thread here. Instead we'll learn the size lazily from the other process.
|
||||
params = MysteryBlobConstructorParams();
|
||||
}
|
||||
else {
|
||||
nsString contentType;
|
||||
nsresult rv = aBlob->GetType(contentType);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
fileParams.contentType() = contentType;
|
||||
fileParams.length() = length;
|
||||
PRUint64 length;
|
||||
rv = aBlob->GetSize(&length);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
params = fileParams;
|
||||
} else {
|
||||
NormalBlobConstructorParams blobParams;
|
||||
blobParams.contentType() = contentType;
|
||||
blobParams.length() = length;
|
||||
params = blobParams;
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
FileBlobConstructorParams fileParams;
|
||||
|
||||
rv = file->GetName(fileParams.name());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
fileParams.contentType() = contentType;
|
||||
fileParams.length() = length;
|
||||
|
||||
params = fileParams;
|
||||
} else {
|
||||
NormalBlobConstructorParams blobParams;
|
||||
blobParams.contentType() = contentType;
|
||||
blobParams.length() = length;
|
||||
params = blobParams;
|
||||
}
|
||||
}
|
||||
|
||||
BlobChild* actor = BlobChild::Create(aBlob);
|
||||
|
|
|
@ -42,13 +42,13 @@
|
|||
#include "nsConsoleMessage.h"
|
||||
#include "nsDebugImpl.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsExternalHelperAppService.h"
|
||||
#include "nsFrameMessageManager.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "nsIAlertsService.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMGeoGeolocation.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIFilePicker.h"
|
||||
|
@ -891,6 +891,7 @@ ContentParent::DeallocPBlob(PBlobParent* aActor)
|
|||
BlobParent*
|
||||
ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aBlob, "Null pointer!");
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
|
||||
|
@ -903,32 +904,44 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
|||
return actor;
|
||||
}
|
||||
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to grow
|
||||
// a real interface or something.
|
||||
const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
|
||||
BlobConstructorParams params;
|
||||
|
||||
nsString contentType;
|
||||
nsresult rv = aBlob->GetType(contentType);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
PRUint64 length;
|
||||
rv = aBlob->GetSize(&length);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
FileBlobConstructorParams fileParams;
|
||||
|
||||
rv = file->GetName(fileParams.name());
|
||||
if (blob->IsSizeUnknown()) {
|
||||
// We don't want to call GetSize yet since that may stat a file on the main
|
||||
// thread here. Instead we'll learn the size lazily from the other process.
|
||||
params = MysteryBlobConstructorParams();
|
||||
}
|
||||
else {
|
||||
nsString contentType;
|
||||
nsresult rv = aBlob->GetType(contentType);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
fileParams.contentType() = contentType;
|
||||
fileParams.length() = length;
|
||||
PRUint64 length;
|
||||
rv = aBlob->GetSize(&length);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
params = fileParams;
|
||||
} else {
|
||||
NormalBlobConstructorParams blobParams;
|
||||
blobParams.contentType() = contentType;
|
||||
blobParams.length() = length;
|
||||
params = blobParams;
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
FileBlobConstructorParams fileParams;
|
||||
|
||||
rv = file->GetName(fileParams.name());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
fileParams.contentType() = contentType;
|
||||
fileParams.length() = length;
|
||||
|
||||
params = fileParams;
|
||||
} else {
|
||||
NormalBlobConstructorParams blobParams;
|
||||
blobParams.contentType() = contentType;
|
||||
blobParams.length() = length;
|
||||
params = blobParams;
|
||||
}
|
||||
}
|
||||
|
||||
BlobParent* actor = BlobParent::Create(aBlob);
|
||||
|
|
|
@ -17,5 +17,18 @@ struct ClonedMessageData
|
|||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
struct NormalBlobConstructorParams
|
||||
{
|
||||
nsString contentType;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
struct FileBlobConstructorParams
|
||||
{
|
||||
nsString name;
|
||||
nsString contentType;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -5,9 +5,17 @@
|
|||
include protocol PBlobStream;
|
||||
include protocol PContent;
|
||||
|
||||
include DOMTypes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
union ResolveMysteryParams
|
||||
{
|
||||
NormalBlobConstructorParams;
|
||||
FileBlobConstructorParams;
|
||||
};
|
||||
|
||||
protocol PBlob
|
||||
{
|
||||
manager PContent;
|
||||
|
@ -17,6 +25,8 @@ both:
|
|||
__delete__();
|
||||
|
||||
PBlobStream();
|
||||
|
||||
ResolveMystery(ResolveMysteryParams params);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -101,19 +101,6 @@ union DeviceStorageParams
|
|||
DeviceStorageEnumerationParams;
|
||||
};
|
||||
|
||||
struct NormalBlobConstructorParams
|
||||
{
|
||||
nsString contentType;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
struct FileBlobConstructorParams
|
||||
{
|
||||
nsString name;
|
||||
nsString contentType;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
struct SlicedBlobConstructorParams
|
||||
{
|
||||
PBlob source;
|
||||
|
@ -122,11 +109,17 @@ struct SlicedBlobConstructorParams
|
|||
nsString contentType;
|
||||
};
|
||||
|
||||
struct MysteryBlobConstructorParams
|
||||
{
|
||||
// Nothing is known about this type of blob.
|
||||
};
|
||||
|
||||
union BlobConstructorParams
|
||||
{
|
||||
NormalBlobConstructorParams;
|
||||
FileBlobConstructorParams;
|
||||
SlicedBlobConstructorParams;
|
||||
MysteryBlobConstructorParams;
|
||||
};
|
||||
|
||||
rpc protocol PContent
|
||||
|
|
|
@ -139,7 +139,7 @@ void nsVolumeService::UpdateVolume(const nsVolume *aVolume)
|
|||
return;
|
||||
}
|
||||
vol->Set(aVolume);
|
||||
nsRefPtr<nsIObserverService> obs = GetObserverService();
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
if (!obs) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -301,6 +301,23 @@ struct RemoteImageData {
|
|||
* (because layers can only be used on the main thread) and we want to
|
||||
* be able to set the current Image from any thread, to facilitate
|
||||
* video playback without involving the main thread, for example.
|
||||
*
|
||||
* An ImageContainer can operate in one of three modes:
|
||||
* 1) Normal. Triggered by constructing the ImageContainer with
|
||||
* DISABLE_ASYNC or when compositing is happening on the main thread.
|
||||
* SetCurrentImage changes ImageContainer state but nothing is sent to the
|
||||
* compositor until the next layer transaction.
|
||||
* 2) Asynchronous. Initiated by constructing the ImageContainer with
|
||||
* ENABLE_ASYNC when compositing is happening on the main thread.
|
||||
* SetCurrentImage sends a message through the ImageBridge to the compositor
|
||||
* thread to update the image, without going through the main thread or
|
||||
* a layer transaction.
|
||||
* 3) Remote. Initiated by calling SetRemoteImageData on the ImageContainer
|
||||
* before any other activity.
|
||||
* The ImageContainer uses a shared memory block containing a cross-process mutex
|
||||
* to communicate with the compositor thread. SetCurrentImage synchronously
|
||||
* updates the shared state to point to the new image and the old image
|
||||
* is immediately released (not true in Normal or Asynchronous modes).
|
||||
*/
|
||||
class THEBES_API ImageContainer {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
|
||||
|
|
|
@ -444,7 +444,7 @@ jsd_AppendUCSourceText(JSDContext* jsdc,
|
|||
}
|
||||
}
|
||||
while(remaining && jsdsrc) {
|
||||
int bytes = JS_MIN(remaining, UNICODE_TRUNCATE_BUF_SIZE);
|
||||
int bytes = (remaining < UNICODE_TRUNCATE_BUF_SIZE) ? remaining : UNICODE_TRUNCATE_BUF_SIZE;
|
||||
int i;
|
||||
for(i = 0; i < bytes; i++)
|
||||
buf[i] = (const char) *(text++);
|
||||
|
|
|
@ -6715,7 +6715,7 @@ frontend::NewSrcNote(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type)
|
|||
bce->current->lastNoteOffset = offset;
|
||||
if (delta >= SN_DELTA_LIMIT) {
|
||||
do {
|
||||
xdelta = JS_MIN(delta, SN_XDELTA_MASK);
|
||||
xdelta = Min(delta, SN_XDELTA_MASK);
|
||||
SN_MAKE_XDELTA(sn, xdelta);
|
||||
delta -= xdelta;
|
||||
index = AllocSrcNote(cx, bce);
|
||||
|
@ -6948,7 +6948,7 @@ frontend::FinishTakingSrcNotes(JSContext *cx, BytecodeEmitter *bce, jssrcnote *n
|
|||
offset -= delta;
|
||||
if (offset == 0)
|
||||
break;
|
||||
delta = JS_MIN(offset, SN_XDELTA_MASK);
|
||||
delta = Min(offset, SN_XDELTA_MASK);
|
||||
sn = bce->main.notes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -323,7 +323,7 @@ MapAlignedPages(size_t size, size_t alignment)
|
|||
}
|
||||
|
||||
/* Overallocate and unmap the region's edges. */
|
||||
size_t reqSize = JS_MIN(size + 2 * alignment, 2 * size);
|
||||
size_t reqSize = Min(size + 2 * alignment, 2 * size);
|
||||
void *region = mmap(NULL, reqSize, prot, flags, -1, 0);
|
||||
if (region == MAP_FAILED)
|
||||
return NULL;
|
||||
|
|
|
@ -2111,7 +2111,7 @@ AddNameToArray(JSContext *cx, PropertyName *name, JSIdArray *ida, int *ip)
|
|||
int i = *ip;
|
||||
int length = ida->length;
|
||||
if (i >= length) {
|
||||
ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
|
||||
ida = SetIdArrayLength(cx, ida, Max(length * 2, 8));
|
||||
if (!ida)
|
||||
return NULL;
|
||||
JS_ASSERT(i < ida->length);
|
||||
|
|
|
@ -2653,9 +2653,9 @@ array_splice(JSContext *cx, unsigned argc, Value *vp)
|
|||
/* Step 6. */
|
||||
uint32_t actualStart;
|
||||
if (relativeStart < 0)
|
||||
actualStart = JS_MAX(len + relativeStart, 0);
|
||||
actualStart = Max(len + relativeStart, 0.0);
|
||||
else
|
||||
actualStart = JS_MIN(relativeStart, len);
|
||||
actualStart = Min(relativeStart, double(len));
|
||||
|
||||
/* Step 7. */
|
||||
uint32_t actualDeleteCount;
|
||||
|
@ -2663,7 +2663,7 @@ array_splice(JSContext *cx, unsigned argc, Value *vp)
|
|||
double deleteCountDouble;
|
||||
if (!ToInteger(cx, argc >= 2 ? args[1] : Int32Value(0), &deleteCountDouble))
|
||||
return false;
|
||||
actualDeleteCount = JS_MIN(JS_MAX(deleteCountDouble, 0), len - actualStart);
|
||||
actualDeleteCount = Min(Max(deleteCountDouble, 0.0), double(len - actualStart));
|
||||
} else {
|
||||
/*
|
||||
* Non-standard: if start was specified but deleteCount was omitted,
|
||||
|
|
|
@ -379,7 +379,7 @@ JSStructuredCloneWriter::checkStack()
|
|||
/* To avoid making serialization O(n^2), limit stack-checking at 10. */
|
||||
const size_t MAX = 10;
|
||||
|
||||
size_t limit = JS_MIN(counts.length(), MAX);
|
||||
size_t limit = Min(counts.length(), MAX);
|
||||
JS_ASSERT(objs.length() == counts.length());
|
||||
size_t total = 0;
|
||||
for (size_t i = 0; i < limit; i++) {
|
||||
|
|
|
@ -541,6 +541,9 @@ struct JSRuntime : js::RuntimeFriendFields
|
|||
/* The gcNumber at the time of the most recent GC's first slice. */
|
||||
uint64_t gcStartNumber;
|
||||
|
||||
/* Whether the currently running GC can finish in multiple slices. */
|
||||
int gcIsIncremental;
|
||||
|
||||
/* Whether all compartments are being collected in first GC slice. */
|
||||
bool gcIsFull;
|
||||
|
||||
|
|
|
@ -738,7 +738,7 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
|
|||
{
|
||||
size_t init = *i;
|
||||
|
||||
if (digits(result, s, i, JS_MIN(limit, init+n)))
|
||||
if (digits(result, s, i, Min(limit, init+n)))
|
||||
return ((*i - init) == n);
|
||||
|
||||
*i = init;
|
||||
|
|
|
@ -275,7 +275,7 @@ JS_DHashTableSetAlphaBounds(JSDHashTable *table,
|
|||
JS_ASSERT(JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) >= 1);
|
||||
if (JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) < 1) {
|
||||
maxAlpha = (float)
|
||||
(JS_DHASH_MIN_SIZE - JS_MAX(JS_DHASH_MIN_SIZE / 256, 1))
|
||||
(JS_DHASH_MIN_SIZE - Max(JS_DHASH_MIN_SIZE / 256, 1))
|
||||
/ JS_DHASH_MIN_SIZE;
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ JS_DHashTableSetAlphaBounds(JSDHashTable *table,
|
|||
JS_ASSERT(minAlpha < maxAlpha / 2);
|
||||
if (minAlpha >= maxAlpha / 2) {
|
||||
size = JS_DHASH_TABLE_SIZE(table);
|
||||
minAlpha = (size * maxAlpha - JS_MAX(size / 256, 1)) / (2 * size);
|
||||
minAlpha = (size * maxAlpha - Max(size / 256, 1U)) / (2 * size);
|
||||
}
|
||||
|
||||
table->maxAlphaFrac = (uint8_t)(maxAlpha * 256);
|
||||
|
|
|
@ -780,6 +780,12 @@ SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
|
|||
return old;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
WasIncrementalGC(JSRuntime *rt)
|
||||
{
|
||||
return rt->gcIsIncremental;
|
||||
}
|
||||
|
||||
jschar *
|
||||
GCDescription::formatMessage(JSRuntime *rt) const
|
||||
{
|
||||
|
|
|
@ -745,6 +745,10 @@ typedef void
|
|||
extern JS_FRIEND_API(GCSliceCallback)
|
||||
SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback);
|
||||
|
||||
/* Was the most recent GC run incrementally? */
|
||||
extern JS_FRIEND_API(bool)
|
||||
WasIncrementalGC(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* Signals a good place to do an incremental slice, because the browser is
|
||||
* drawing a frame.
|
||||
|
|
|
@ -3186,7 +3186,7 @@ ShouldPreserveJITCode(JSCompartment *c, int64_t currentTime)
|
|||
}
|
||||
|
||||
static void
|
||||
BeginMarkPhase(JSRuntime *rt, bool isIncremental)
|
||||
BeginMarkPhase(JSRuntime *rt)
|
||||
{
|
||||
int64_t currentTime = PRMJ_Now();
|
||||
|
||||
|
@ -3197,7 +3197,7 @@ BeginMarkPhase(JSRuntime *rt, bool isIncremental)
|
|||
* arenas. This purge call ensures that we only mark arenas that have had
|
||||
* allocations after the incremental GC started.
|
||||
*/
|
||||
if (isIncremental) {
|
||||
if (rt->gcIsIncremental) {
|
||||
for (GCCompartmentsIter c(rt); !c.done(); c.next())
|
||||
c->arenas.purge();
|
||||
}
|
||||
|
@ -3221,7 +3221,7 @@ BeginMarkPhase(JSRuntime *rt, bool isIncremental)
|
|||
JS_ASSERT(IS_GC_MARKING_TRACER(&rt->gcMarker));
|
||||
|
||||
/* For non-incremental GC the following sweep discards the jit code. */
|
||||
if (isIncremental) {
|
||||
if (rt->gcIsIncremental) {
|
||||
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_DISCARD_CODE);
|
||||
c->discardJitCode(rt->defaultFreeOp());
|
||||
|
@ -3314,7 +3314,7 @@ ValidateIncrementalMarking(JSRuntime *rt);
|
|||
#endif
|
||||
|
||||
static void
|
||||
EndMarkPhase(JSRuntime *rt, bool isIncremental)
|
||||
EndMarkPhase(JSRuntime *rt)
|
||||
{
|
||||
{
|
||||
gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_MARK);
|
||||
|
@ -3324,7 +3324,7 @@ EndMarkPhase(JSRuntime *rt, bool isIncremental)
|
|||
JS_ASSERT(rt->gcMarker.isDrained());
|
||||
|
||||
#ifdef DEBUG
|
||||
if (isIncremental)
|
||||
if (rt->gcIsIncremental)
|
||||
ValidateIncrementalMarking(rt);
|
||||
#endif
|
||||
|
||||
|
@ -3889,8 +3889,8 @@ IncrementalCollectSlice(JSRuntime *rt,
|
|||
}
|
||||
#endif
|
||||
|
||||
bool isIncremental = rt->gcIncrementalState != NO_INCREMENTAL ||
|
||||
budget != SliceBudget::Unlimited;
|
||||
rt->gcIsIncremental = rt->gcIncrementalState != NO_INCREMENTAL ||
|
||||
budget != SliceBudget::Unlimited;
|
||||
|
||||
if (zeal == ZealIncrementalRootsThenFinish || zeal == ZealIncrementalMarkAllThenFinish) {
|
||||
/*
|
||||
|
@ -3908,7 +3908,7 @@ IncrementalCollectSlice(JSRuntime *rt,
|
|||
switch (rt->gcIncrementalState) {
|
||||
|
||||
case MARK_ROOTS:
|
||||
BeginMarkPhase(rt, isIncremental);
|
||||
BeginMarkPhase(rt);
|
||||
PushZealSelectedObjects(rt);
|
||||
|
||||
rt->gcIncrementalState = MARK;
|
||||
|
@ -3943,7 +3943,7 @@ IncrementalCollectSlice(JSRuntime *rt,
|
|||
break;
|
||||
}
|
||||
|
||||
EndMarkPhase(rt, isIncremental);
|
||||
EndMarkPhase(rt);
|
||||
|
||||
rt->gcIncrementalState = SWEEP;
|
||||
|
||||
|
|
|
@ -2707,7 +2707,7 @@ END_VARLEN_CASE
|
|||
|
||||
BEGIN_CASE(JSOP_ACTUALSFILLED)
|
||||
{
|
||||
PUSH_INT32(JS_MAX(regs.fp()->numActualArgs(), GET_UINT16(regs.pc)));
|
||||
PUSH_INT32(Max(regs.fp()->numActualArgs(), GET_UINT16(regs.pc)));
|
||||
}
|
||||
END_CASE(JSOP_ACTUALSFILLED)
|
||||
|
||||
|
|
|
@ -3617,7 +3617,7 @@ JSObject::growElements(JSContext *cx, unsigned newcap)
|
|||
? oldcap * 2
|
||||
: oldcap + (oldcap >> 3);
|
||||
|
||||
uint32_t actualCapacity = JS_MAX(newcap, nextsize);
|
||||
uint32_t actualCapacity = Max(newcap, nextsize);
|
||||
if (actualCapacity >= CAPACITY_CHUNK)
|
||||
actualCapacity = JS_ROUNDUP(actualCapacity, CAPACITY_CHUNK);
|
||||
else if (actualCapacity < SLOT_CAPACITY_MIN)
|
||||
|
|
|
@ -629,7 +629,7 @@ js_Stringify(JSContext *cx, MutableHandleValue vp, JSObject *replacer_, Value sp
|
|||
uint32_t len;
|
||||
JS_ALWAYS_TRUE(js_GetLengthProperty(cx, replacer, &len));
|
||||
if (replacer->isDenseArray())
|
||||
len = JS_MIN(len, replacer->getDenseArrayCapacity());
|
||||
len = Min(len, replacer->getDenseArrayCapacity());
|
||||
|
||||
HashSet<jsid> idSet(cx);
|
||||
if (!idSet.init(len))
|
||||
|
@ -702,7 +702,7 @@ js_Stringify(JSContext *cx, MutableHandleValue vp, JSObject *replacer_, Value sp
|
|||
/* Step 6. */
|
||||
double d;
|
||||
JS_ALWAYS_TRUE(ToInteger(cx, space, &d));
|
||||
d = JS_MIN(10, d);
|
||||
d = Min(10.0, d);
|
||||
if (d >= 1 && !gap.appendN(' ', uint32_t(d)))
|
||||
return false;
|
||||
} else if (space.isString()) {
|
||||
|
@ -711,7 +711,7 @@ js_Stringify(JSContext *cx, MutableHandleValue vp, JSObject *replacer_, Value sp
|
|||
if (!str)
|
||||
return false;
|
||||
JS::Anchor<JSString *> anchor(str);
|
||||
size_t len = JS_MIN(10, space.toString()->length());
|
||||
size_t len = Min(size_t(10), space.toString()->length());
|
||||
if (!gap.append(str->chars(), len))
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
@ -110,7 +110,7 @@ SkipSpace(const jschar *s, const jschar *end)
|
|||
inline bool
|
||||
CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2, int32_t *result)
|
||||
{
|
||||
size_t n = JS_MIN(l1, l2);
|
||||
size_t n = Min(l1, l2);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (int32_t cmp = s1[i] - s2[i]) {
|
||||
*result = cmp;
|
||||
|
|
|
@ -147,8 +147,6 @@
|
|||
***********************************************************************/
|
||||
#define JS_HOWMANY(x,y) (((x)+(y)-1)/(y))
|
||||
#define JS_ROUNDUP(x,y) (JS_HOWMANY(x,y)*(y))
|
||||
#define JS_MIN(x,y) ((x)<(y)?(x):(y))
|
||||
#define JS_MAX(x,y) ((x)>(y)?(x):(y))
|
||||
|
||||
#include "jscpucfg.h"
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ ValToBin(unsigned logscale, uint32_t val)
|
|||
: (logscale == 2)
|
||||
? (unsigned) JS_CEILING_LOG2W(val)
|
||||
: val;
|
||||
return JS_MIN(bin, 10);
|
||||
return Min(bin, 10U);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -74,8 +74,8 @@ VerifyRange(void *start1, size_t size1, void *start2, size_t size2)
|
|||
uintptr_t end1 = uintptr_t(start1) + size1;
|
||||
uintptr_t end2 = uintptr_t(start2) + size2;
|
||||
|
||||
uintptr_t lowest = JS_MIN(uintptr_t(start1), uintptr_t(start2));
|
||||
uintptr_t highest = JS_MAX(end1, end2);
|
||||
uintptr_t lowest = Min(uintptr_t(start1), uintptr_t(start2));
|
||||
uintptr_t highest = Max(end1, end2);
|
||||
|
||||
return (highest - lowest < INT_MAX);
|
||||
}
|
||||
|
|
|
@ -423,7 +423,7 @@ PRMJ_Now(void)
|
|||
|
||||
/* On some dual processor/core systems, we might get an earlier time
|
||||
so we cache the last time that we returned */
|
||||
calibration.last = JS_MAX(calibration.last, int64_t(highresTime));
|
||||
calibration.last = js::Max(calibration.last, int64_t(highresTime));
|
||||
returnedTime = calibration.last;
|
||||
MUTEX_UNLOCK(&calibration.data_lock);
|
||||
|
||||
|
@ -692,7 +692,7 @@ DSTOffsetCache::getDSTOffsetMilliseconds(int64_t localTimeMilliseconds, JSContex
|
|||
oldRangeEndSeconds = rangeEndSeconds;
|
||||
|
||||
if (rangeStartSeconds <= localTimeSeconds) {
|
||||
int64_t newEndSeconds = JS_MIN(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET);
|
||||
int64_t newEndSeconds = js::Min(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET);
|
||||
if (newEndSeconds >= localTimeSeconds) {
|
||||
int64_t endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds);
|
||||
if (endOffsetMilliseconds == offsetMilliseconds) {
|
||||
|
@ -715,7 +715,7 @@ DSTOffsetCache::getDSTOffsetMilliseconds(int64_t localTimeMilliseconds, JSContex
|
|||
return offsetMilliseconds;
|
||||
}
|
||||
|
||||
int64_t newStartSeconds = JS_MAX(rangeStartSeconds - RANGE_EXPANSION_AMOUNT, 0);
|
||||
int64_t newStartSeconds = js::Max(rangeStartSeconds - RANGE_EXPANSION_AMOUNT, int64_t(0));
|
||||
if (newStartSeconds <= localTimeSeconds) {
|
||||
int64_t startOffsetMilliseconds = computeDSTOffsetMilliseconds(newStartSeconds);
|
||||
if (startOffsetMilliseconds == offsetMilliseconds) {
|
||||
|
|
|
@ -178,7 +178,7 @@ OptionParser::printHelp(const char *progname)
|
|||
size_t fmtChars = sizeof(fmt) - 2;
|
||||
size_t lhsLen = 0;
|
||||
for (Option **it = arguments.begin(), **end = arguments.end(); it != end; ++it)
|
||||
lhsLen = JS_MAX(lhsLen, strlen((*it)->longflag) + fmtChars);
|
||||
lhsLen = Max(lhsLen, strlen((*it)->longflag) + fmtChars);
|
||||
|
||||
for (Option **it = arguments.begin(), **end = arguments.end(); it != end; ++it) {
|
||||
Option *arg = *it;
|
||||
|
@ -206,7 +206,7 @@ OptionParser::printHelp(const char *progname)
|
|||
size_t len = fmtLen + longflagLen;
|
||||
if (opt->isValued())
|
||||
len += strlen(opt->asValued()->metavar);
|
||||
lhsLen = JS_MAX(lhsLen, len);
|
||||
lhsLen = Max(lhsLen, len);
|
||||
}
|
||||
|
||||
/* Print option help text. */
|
||||
|
|
|
@ -4102,13 +4102,13 @@ ApplyOrCall(JSContext *cx, unsigned argc, Value *vp, ApplyOrCallMode mode)
|
|||
RootedObject argsobj(cx, &args[1].toObject());
|
||||
if (!js_GetLengthProperty(cx, argsobj, &callArgc))
|
||||
return false;
|
||||
callArgc = unsigned(JS_MIN(callArgc, StackSpace::ARGS_LENGTH_MAX));
|
||||
callArgc = unsigned(Min(callArgc, StackSpace::ARGS_LENGTH_MAX));
|
||||
if (!argv.growBy(callArgc) || !GetElements(cx, argsobj, callArgc, argv.begin()))
|
||||
return false;
|
||||
callArgv = argv.begin();
|
||||
}
|
||||
} else {
|
||||
callArgc = argc > 0 ? unsigned(JS_MIN(argc - 1, StackSpace::ARGS_LENGTH_MAX)) : 0;
|
||||
callArgc = argc > 0 ? unsigned(Min(argc - 1, StackSpace::ARGS_LENGTH_MAX)) : 0;
|
||||
callArgv = args.array() + 1;
|
||||
}
|
||||
for (unsigned i = 0; i < callArgc; i++) {
|
||||
|
|
|
@ -277,14 +277,14 @@ template<typename T>
|
|||
inline T
|
||||
min(T t1, T t2)
|
||||
{
|
||||
return JS_MIN(t1, t2);
|
||||
return js::Min(t1, t2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T
|
||||
max(T t1, T t2)
|
||||
{
|
||||
return JS_MAX(t1, t2);
|
||||
return js::Max(t1, t2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -482,7 +482,7 @@ inline JSBool
|
|||
XPCNativeSet::MatchesSetUpToInterface(const XPCNativeSet* other,
|
||||
XPCNativeInterface* iface) const
|
||||
{
|
||||
int count = JS_MIN((int)mInterfaceCount, (int)other->mInterfaceCount);
|
||||
int count = js::Min(int(mInterfaceCount), int(other->mInterfaceCount));
|
||||
|
||||
XPCNativeInterface* const * pp1 = mInterfaces;
|
||||
XPCNativeInterface* const * pp2 = other->mInterfaces;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "nsLayoutStatics.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCCUncollectableMarker.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
@ -564,6 +565,103 @@ DoDeferredRelease(nsTArray<T> &array)
|
|||
}
|
||||
}
|
||||
|
||||
class XPCIncrementalReleaseRunnable : public nsRunnable
|
||||
{
|
||||
XPCJSRuntime *runtime;
|
||||
nsTArray<nsISupports *> items;
|
||||
|
||||
static const PRTime SliceMillis = 10; /* ms */
|
||||
|
||||
public:
|
||||
XPCIncrementalReleaseRunnable(XPCJSRuntime *rt, nsTArray<nsISupports *> &items);
|
||||
virtual ~XPCIncrementalReleaseRunnable();
|
||||
|
||||
void ReleaseNow(bool limited);
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
XPCIncrementalReleaseRunnable::XPCIncrementalReleaseRunnable(XPCJSRuntime *rt,
|
||||
nsTArray<nsISupports *> &items)
|
||||
: runtime(rt)
|
||||
{
|
||||
nsLayoutStatics::AddRef();
|
||||
this->items.SwapElements(items);
|
||||
}
|
||||
|
||||
XPCIncrementalReleaseRunnable::~XPCIncrementalReleaseRunnable()
|
||||
{
|
||||
MOZ_ASSERT(this != runtime->mReleaseRunnable);
|
||||
nsLayoutStatics::Release();
|
||||
}
|
||||
|
||||
void
|
||||
XPCIncrementalReleaseRunnable::ReleaseNow(bool limited)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
TimeDuration sliceTime = TimeDuration::FromMilliseconds(SliceMillis);
|
||||
TimeStamp started = TimeStamp::Now();
|
||||
PRUint32 counter = 0;
|
||||
while (1) {
|
||||
PRUint32 count = items.Length();
|
||||
if (!count)
|
||||
break;
|
||||
|
||||
nsISupports *wrapper = items[count - 1];
|
||||
items.RemoveElementAt(count - 1);
|
||||
NS_RELEASE(wrapper);
|
||||
|
||||
if (limited) {
|
||||
/* We don't want to read the clock too often. */
|
||||
counter++;
|
||||
if (counter == 100) {
|
||||
counter = 0;
|
||||
if (TimeStamp::Now() - started >= sliceTime)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(items.Length(), limited);
|
||||
|
||||
if (!items.Length()) {
|
||||
MOZ_ASSERT(runtime->mReleaseRunnable == this);
|
||||
runtime->mReleaseRunnable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
XPCIncrementalReleaseRunnable::Run()
|
||||
{
|
||||
if (runtime->mReleaseRunnable != this) {
|
||||
/* These items were already processed synchronously in JSGC_BEGIN. */
|
||||
MOZ_ASSERT(!items.Length());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ReleaseNow(true);
|
||||
|
||||
if (items.Length()) {
|
||||
nsresult rv = NS_DispatchToMainThread(this);
|
||||
if (NS_FAILED(rv))
|
||||
ReleaseNow(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::ReleaseIncrementally(nsTArray<nsISupports *> &array)
|
||||
{
|
||||
MOZ_ASSERT(!mReleaseRunnable);
|
||||
mReleaseRunnable = new XPCIncrementalReleaseRunnable(this, array);
|
||||
|
||||
nsresult rv = NS_DispatchToMainThread(mReleaseRunnable);
|
||||
if (NS_FAILED(rv))
|
||||
mReleaseRunnable->ReleaseNow(false);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status)
|
||||
{
|
||||
|
@ -585,15 +683,21 @@ XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status)
|
|||
}
|
||||
case JSGC_END:
|
||||
{
|
||||
/*
|
||||
* If the previous GC created a runnable to release objects
|
||||
* incrementally, and if it hasn't finished yet, finish it now. We
|
||||
* don't want these to build up. We also don't want to allow any
|
||||
* existing incremental release runnables to run after a
|
||||
* non-incremental GC, since they are often used to detect leaks.
|
||||
*/
|
||||
if (self->mReleaseRunnable)
|
||||
self->mReleaseRunnable->ReleaseNow(false);
|
||||
|
||||
// Do any deferred releases of native objects.
|
||||
#ifdef XPC_TRACK_DEFERRED_RELEASES
|
||||
printf("XPC - Begin deferred Release of %d nsISupports pointers\n",
|
||||
self->mNativesToReleaseArray.Length());
|
||||
#endif
|
||||
DoDeferredRelease(self->mNativesToReleaseArray);
|
||||
#ifdef XPC_TRACK_DEFERRED_RELEASES
|
||||
printf("XPC - End deferred Releases\n");
|
||||
#endif
|
||||
if (js::WasIncrementalGC(rt))
|
||||
self->ReleaseIncrementally(self->mNativesToReleaseArray);
|
||||
else
|
||||
DoDeferredRelease(self->mNativesToReleaseArray);
|
||||
|
||||
self->GetXPConnect()->ClearGCBeforeCC();
|
||||
break;
|
||||
|
@ -964,6 +1068,8 @@ XPCJSRuntime::GetJSCycleCollectionContext()
|
|||
|
||||
XPCJSRuntime::~XPCJSRuntime()
|
||||
{
|
||||
MOZ_ASSERT(!mReleaseRunnable);
|
||||
|
||||
if (mWatchdogWakeup) {
|
||||
// If the watchdog thread is running, tell it to terminate waking it
|
||||
// up if necessary and wait until it signals that it finished. As we
|
||||
|
@ -2000,6 +2106,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
|||
mWatchdogThread(nullptr),
|
||||
mWatchdogHibernating(false),
|
||||
mLastActiveTime(-1),
|
||||
mReleaseRunnable(nullptr),
|
||||
mExceptionManagerNotAvailable(false)
|
||||
{
|
||||
#ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
|
||||
|
|
|
@ -638,6 +638,7 @@ private:
|
|||
|
||||
// no virtuals. no refcounting.
|
||||
class XPCJSContextStack;
|
||||
class XPCIncrementalReleaseRunnable;
|
||||
class XPCJSRuntime
|
||||
{
|
||||
public:
|
||||
|
@ -866,6 +867,8 @@ private:
|
|||
|
||||
static void WatchdogMain(void *arg);
|
||||
|
||||
void ReleaseIncrementally(nsTArray<nsISupports *> &array);
|
||||
|
||||
static bool gNewDOMBindingsEnabled;
|
||||
static bool gExperimentalBindingsEnabled;
|
||||
|
||||
|
@ -906,12 +909,14 @@ private:
|
|||
nsTArray<JSGCCallback> extraGCCallbacks;
|
||||
bool mWatchdogHibernating;
|
||||
PRTime mLastActiveTime; // -1 if active NOW
|
||||
XPCIncrementalReleaseRunnable *mReleaseRunnable;
|
||||
|
||||
nsCOMPtr<nsIException> mPendingException;
|
||||
nsCOMPtr<nsIExceptionManager> mExceptionManager;
|
||||
bool mExceptionManagerNotAvailable;
|
||||
|
||||
friend class AutoLockWatchdog;
|
||||
friend class XPCIncrementalReleaseRunnable;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
|
|
@ -220,17 +220,47 @@ bool
|
|||
CommonElementAnimationData::CanAnimatePropertyOnCompositor(const dom::Element *aElement,
|
||||
nsCSSProperty aProperty)
|
||||
{
|
||||
static bool sShouldLog;
|
||||
static bool sShouldLogPrefCached;
|
||||
|
||||
if (!sShouldLogPrefCached) {
|
||||
sShouldLogPrefCached = true;
|
||||
Preferences::AddBoolVarCache(&sShouldLog,
|
||||
"layers.offmainthreadcomposition.log-animations");
|
||||
}
|
||||
|
||||
nsIFrame* frame = aElement->GetPrimaryFrame();
|
||||
if (aProperty == eCSSProperty_opacity) {
|
||||
return nsLayoutUtils::AreOpacityAnimationsEnabled();
|
||||
bool enabled = nsLayoutUtils::AreOpacityAnimationsEnabled();
|
||||
if (!enabled && sShouldLog) {
|
||||
printf_stderr("Performance warning: Async animation of 'opacity' is disabled\n");
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
if (aProperty == eCSSProperty_transform && !(frame &&
|
||||
frame->Preserves3D() &&
|
||||
frame->Preserves3DChildren())) {
|
||||
if (frame && frame->IsSVGTransformed()) {
|
||||
if (aProperty == eCSSProperty_transform) {
|
||||
if (frame &&
|
||||
frame->Preserves3D() &&
|
||||
frame->Preserves3DChildren()) {
|
||||
if (sShouldLog) {
|
||||
printf_stderr("Gecko bug: Async animation of 'preserve-3d' transforms is not supported. See bug 779598\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return nsLayoutUtils::AreTransformAnimationsEnabled();
|
||||
if (frame && frame->IsSVGTransformed()) {
|
||||
if (sShouldLog) {
|
||||
printf_stderr("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported. See bug 779599\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool enabled = nsLayoutUtils::AreTransformAnimationsEnabled();
|
||||
if (!enabled && sShouldLog) {
|
||||
printf_stderr("Performance warning: Async animation of 'transform' is disabled\n");
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
if (sShouldLog) {
|
||||
const nsAFlatCString propName = nsCSSProps::GetStringValue(aProperty);
|
||||
printf_stderr("Performance warning: Async animation cancelled because of unsupported property '%s'\n", propName.get());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -504,4 +504,20 @@ public class Utils {
|
|||
final long duration = endMillis - startMillis;
|
||||
return new DecimalFormat("#0.00 seconds").format(((double) duration) / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will take a string containing a UTF-8 representation of a UTF-8
|
||||
* byte array — e.g., "pïgéons1" — and return UTF-8 (e.g., "pïgéons1").
|
||||
*
|
||||
* This is the format produced by desktop Firefox when exchanging credentials
|
||||
* containing non-ASCII characters.
|
||||
*/
|
||||
public static String decodeUTF8(final String in) throws UnsupportedEncodingException {
|
||||
final int length = in.length();
|
||||
final byte[] asciiBytes = new byte[length];
|
||||
for (int i = 0; i < length; ++i) {
|
||||
asciiBytes[i] = (byte) in.codePointAt(i);
|
||||
}
|
||||
return new String(asciiBytes, "UTF-8");
|
||||
}
|
||||
}
|
|
@ -129,14 +129,22 @@ public class BaseResource implements Resource {
|
|||
context.setAttribute(ClientContext.AUTH_CACHE, authCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Header object representing an Authentication header for HTTP Basic.
|
||||
*/
|
||||
public static Header getBasicAuthHeader(final String credentials) {
|
||||
Credentials creds = new UsernamePasswordCredentials(credentials);
|
||||
|
||||
// This must be UTF-8 to generate the same Basic Auth headers as desktop for non-ASCII passwords.
|
||||
return BasicScheme.authenticate(creds, "UTF-8", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the provided credentials string to the provided request.
|
||||
* @param credentials a string, "user:pass".
|
||||
*/
|
||||
private static void applyCredentials(String credentials, HttpUriRequest request, HttpContext context) {
|
||||
Credentials creds = new UsernamePasswordCredentials(credentials);
|
||||
Header header = BasicScheme.authenticate(creds, "US-ASCII", false);
|
||||
request.addHeader(header);
|
||||
request.addHeader(getBasicAuthHeader(credentials));
|
||||
Logger.trace(LOG_TAG, "Adding Basic Auth header.");
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package org.mozilla.gecko.sync.setup.activities;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
@ -11,6 +12,7 @@ import org.mozilla.gecko.R;
|
|||
import org.mozilla.gecko.sync.GlobalConstants;
|
||||
import org.mozilla.gecko.sync.Logger;
|
||||
import org.mozilla.gecko.sync.ThreadPool;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.jpake.JPakeClient;
|
||||
import org.mozilla.gecko.sync.jpake.JPakeNoActivePairingException;
|
||||
import org.mozilla.gecko.sync.setup.Constants;
|
||||
|
@ -392,6 +394,13 @@ public class SetupSyncActivity extends AccountAuthenticatorActivity {
|
|||
String syncKey = (String) jCreds.get(Constants.JSON_KEY_SYNCKEY);
|
||||
String serverURL = (String) jCreds.get(Constants.JSON_KEY_SERVER);
|
||||
|
||||
// The password we get is double-encoded.
|
||||
try {
|
||||
password = Utils.decodeUTF8(password);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Logger.warn(LOG_TAG, "Unsupported encoding when decoding UTF-8 ASCII J-PAKE message. Ignoring.");
|
||||
}
|
||||
|
||||
final SyncAccountParameters syncAccount = new SyncAccountParameters(mContext, mAccountManager, accountName,
|
||||
syncKey, password, serverURL);
|
||||
createAccountOnThread(syncAccount);
|
||||
|
|
|
@ -226,6 +226,21 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
|
|||
return delayMilliseconds() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that no sync start right away. A new sync won't start until
|
||||
* at least <code>backoff</code> milliseconds from now.
|
||||
*
|
||||
* @param backoff time to wait in milliseconds.
|
||||
*/
|
||||
@Override
|
||||
public void requestBackoff(long backoff) {
|
||||
if (backoff > 0) {
|
||||
// Fuzz the backoff time (up to 25% more) to prevent client lock-stepping; agrees with desktop.
|
||||
backoff = backoff + Math.round((double) backoff * 0.25d * Math.random());
|
||||
this.extendEarliestNextSync(System.currentTimeMillis() + backoff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously request an immediate sync, optionally syncing only the given
|
||||
* named stages.
|
||||
|
@ -530,13 +545,6 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter implements GlobalSe
|
|||
Logger.trace(LOG_TAG, "Stage completed: " + currentState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestBackoff(long backoff) {
|
||||
if (backoff > 0) {
|
||||
this.extendEarliestNextSync(System.currentTimeMillis() + backoff);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String getAccountGUID() {
|
||||
String accountGUID = mAccountManager.getUserData(localAccount, Constants.ACCOUNT_GUID);
|
||||
|
|
|
@ -229,7 +229,7 @@ pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true);
|
|||
pref("gfx.canvas.azure.enabled", true);
|
||||
// comma separated list of backends to use in order of preference
|
||||
// e.g., pref("gfx.canvas.azure.backends", "direct2d,skia,cairo");
|
||||
pref("gfx.canvas.azure.backends", "direct2d");
|
||||
pref("gfx.canvas.azure.backends", "direct2d,cairo");
|
||||
pref("gfx.content.azure.enabled", true);
|
||||
#else
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -237,7 +237,7 @@ pref("gfx.canvas.azure.enabled", true);
|
|||
pref("gfx.canvas.azure.backends", "cg");
|
||||
#else
|
||||
pref("gfx.canvas.azure.enabled", false);
|
||||
pref("gfx.canvas.azure.backends", "cairo,skia");
|
||||
pref("gfx.canvas.azure.backends", "cairo");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <windows.h>
|
||||
#include "../../../../toolkit/components/maintenanceservice/pathhash.h"
|
||||
#include "../../../../toolkit/mozapps/update/common/pathhash.h"
|
||||
|
||||
#pragma comment(lib, "advapi32.lib")
|
||||
|
||||
|
|
|
@ -92,11 +92,11 @@ LINK32=link.exe
|
|||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=\toolkit\components\maintenanceservice\pathhash.cpp
|
||||
SOURCE=\toolkit\mozapps\update\common\pathhash.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=\toolkit\components\maintenanceservice\pathhash.h
|
||||
SOURCE=\toolkit\mozapps\update\common\pathhash.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@
|
|||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\..\..\toolkit\components\maintenanceservice\pathhash.cpp"
|
||||
RelativePath="..\..\..\..\toolkit\mozapps\update\common\pathhash.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
|
@ -19,6 +19,7 @@ SDK_XPIDLSRCS = \
|
|||
XPIDLSRCS = \
|
||||
nsISSLStatusProvider.idl \
|
||||
nsIBufEntropyCollector.idl \
|
||||
nsISecurityUITelemetry.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(454b5cbb-fd18-4f34-a616-4d543f68717d)]
|
||||
|
||||
interface nsISecurityUITelemetry : nsISupports {
|
||||
|
||||
/*
|
||||
* Addon installation warnings
|
||||
*/
|
||||
|
||||
// Firefox prevented this site from asking you to install addon
|
||||
const PRUint32 WARNING_ADDON_ASKING_PREVENTED = 1;
|
||||
// User clicks through and allows site to ask to install addons
|
||||
const PRUint32 WARNING_ADDON_ASKING_PREVENTED_CLICK_THROUGH = 2;
|
||||
// Are you sure you want to install this addon? Only install addons you trust
|
||||
const PRUint32 WARNING_CONFIRM_ADDON_INSTALL = 3;
|
||||
// User clicked she is sure after waiting 3secs
|
||||
const PRUint32 WARNING_CONFIRM_ADDON_INSTALL_CLICK_THROUGH = 4;
|
||||
|
||||
|
||||
/*
|
||||
* modal dialogs/warnings
|
||||
*/
|
||||
|
||||
const PRUint32 WARNING_ENTERING_SECURE_SITE = 5;
|
||||
const PRUint32 WARNING_ENTERING_WEAK_SITE = 6;
|
||||
const PRUint32 WARNING_LEAVING_SECURE_SITE = 7;
|
||||
const PRUint32 WARNING_MIXED_CONTENT = 8;
|
||||
|
||||
// For confirmation dialogs, the clickthrough constant needs to be 1
|
||||
// more than the dialog constant so that
|
||||
// WARNING_CONFIRM_<X> + 1 == WARNING_CONFIRM_<X>_CLICK_THROUGH
|
||||
const PRUint32 WARNING_CONFIRM_POST_TO_INSECURE_FROM_SECURE = 9;
|
||||
const PRUint32 WARNING_CONFIRM_POST_TO_INSECURE_FROM_SECURE_CLICK_THROUGH = 10;
|
||||
const PRUint32 WARNING_CONFIRM_POST_TO_INSECURE_FROM_INSECURE = 11;
|
||||
const PRUint32 WARNING_CONFIRM_POST_TO_INSECURE_FROM_INSECURE_CLICK_THROUGH = 12;
|
||||
|
||||
/*
|
||||
* Phishing / Malware page warnings
|
||||
*/
|
||||
|
||||
const PRUint32 WARNING_MALWARE_PAGE = 13;
|
||||
const PRUint32 WARNING_MALWARE_PAGE_WHY_BLOCKED = 14;
|
||||
const PRUint32 WARNING_MALWARE_PAGE_GET_ME_OUT_OF_HERE = 15;
|
||||
const PRUint32 WARNING_MALWARE_PAGE_IGNORE_WARNING = 16;
|
||||
|
||||
const PRUint32 WARNING_PHISHING_PAGE = 17;
|
||||
const PRUint32 WARNING_PHISHING_PAGE_WHY_BLOCKED = 18;
|
||||
const PRUint32 WARNING_PHISHING_PAGE_GET_ME_OUT_OF_HERE = 19;
|
||||
const PRUint32 WARNING_PHISHING_PAGE_IGNORE_WARNING = 20;
|
||||
|
||||
/*
|
||||
* SSL Error dialogs
|
||||
*/
|
||||
|
||||
const PRUint32 WARNING_BAD_CERT = 21;
|
||||
const PRUint32 WARNING_BAD_CERT_STS = 22;
|
||||
const PRUint32 WARNING_BAD_CERT_CLICK_ADD_EXCEPTION = 23;
|
||||
const PRUint32 WARNING_BAD_CERT_CLICK_VIEW_CERT = 24;
|
||||
const PRUint32 WARNING_BAD_CERT_DONT_REMEMBER_EXCEPTION = 25;
|
||||
const PRUint32 WARNING_BAD_CERT_GET_ME_OUT_OF_HERE = 27;
|
||||
const PRUint32 WARNING_BAD_CERT_UNDERSTAND_RISKS = 28;
|
||||
const PRUint32 WARNING_BAD_CERT_TECHINICAL_DETAILS = 29;
|
||||
|
||||
/*
|
||||
* Note that if we add more possibilities in the warning dialogs,
|
||||
* it is a new experiment and we shouldn't reuse these buckets.
|
||||
*/
|
||||
const PRUint32 WARNING_BAD_CERT_ADD_EXCEPTION_BASE = 30;
|
||||
const PRUint32 WARNING_BAD_CERT_ADD_EXCEPTION_FLAG_UNTRUSTED = 1;
|
||||
const PRUint32 WARNING_BAD_CERT_ADD_EXCEPTION_FLAG_DOMAIN = 2;
|
||||
const PRUint32 WARNING_BAD_CERT_ADD_EXCEPTION_FLAG_TIME = 4;
|
||||
|
||||
const PRUint32 WARNING_BAD_CERT_CONFIRM_ADD_EXCEPTION_BASE = 38;
|
||||
const PRUint32 WARNING_BAD_CERT_CONFIRM_ADD_EXCEPTION_FLAG_UNTRUSTED = 1;
|
||||
const PRUint32 WARNING_BAD_CERT_CONFIRM_ADD_EXCEPTION_FLAG_DOMAIN = 2;
|
||||
const PRUint32 WARNING_BAD_CERT_CONFIRM_ADD_EXCEPTION_FLAG_TIME = 4;
|
||||
// This uses up buckets till 45
|
||||
|
||||
};
|
|
@ -17,6 +17,9 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsISecurityUITelemetry.h"
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsSecurityWarningDialogs, nsISecurityWarningDialogs)
|
||||
|
||||
#define STRING_BUNDLE_URL "chrome://pipnss/locale/security.properties"
|
||||
|
@ -60,7 +63,8 @@ nsSecurityWarningDialogs::ConfirmEnteringSecure(nsIInterfaceRequestor *ctx, bool
|
|||
rv = AlertDialog(ctx, ENTER_SITE_PREF,
|
||||
NS_LITERAL_STRING("EnterSecureMessage").get(),
|
||||
NS_LITERAL_STRING("EnterSecureShowAgain").get(),
|
||||
false);
|
||||
false,
|
||||
nsISecurityUITelemetry::WARNING_ENTERING_SECURE_SITE);
|
||||
|
||||
*_retval = true;
|
||||
return rv;
|
||||
|
@ -74,7 +78,8 @@ nsSecurityWarningDialogs::ConfirmEnteringWeak(nsIInterfaceRequestor *ctx, bool *
|
|||
rv = AlertDialog(ctx, WEAK_SITE_PREF,
|
||||
NS_LITERAL_STRING("WeakSecureMessage").get(),
|
||||
NS_LITERAL_STRING("WeakSecureShowAgain").get(),
|
||||
false);
|
||||
false,
|
||||
nsISecurityUITelemetry::WARNING_ENTERING_WEAK_SITE);
|
||||
|
||||
*_retval = true;
|
||||
return rv;
|
||||
|
@ -88,7 +93,8 @@ nsSecurityWarningDialogs::ConfirmLeavingSecure(nsIInterfaceRequestor *ctx, bool
|
|||
rv = AlertDialog(ctx, LEAVE_SITE_PREF,
|
||||
NS_LITERAL_STRING("LeaveSecureMessage").get(),
|
||||
NS_LITERAL_STRING("LeaveSecureShowAgain").get(),
|
||||
false);
|
||||
false,
|
||||
nsISecurityUITelemetry::WARNING_LEAVING_SECURE_SITE);
|
||||
|
||||
*_retval = true;
|
||||
return rv;
|
||||
|
@ -103,7 +109,8 @@ nsSecurityWarningDialogs::ConfirmMixedMode(nsIInterfaceRequestor *ctx, bool *_re
|
|||
rv = AlertDialog(ctx, MIXEDCONTENT_PREF,
|
||||
NS_LITERAL_STRING("MixedContentMessage").get(),
|
||||
NS_LITERAL_STRING("MixedContentShowAgain").get(),
|
||||
true);
|
||||
true,
|
||||
nsISecurityUITelemetry::WARNING_MIXED_CONTENT);
|
||||
|
||||
*_retval = true;
|
||||
return rv;
|
||||
|
@ -117,11 +124,13 @@ public:
|
|||
const PRUnichar* aDialogMessageName,
|
||||
const PRUnichar* aShowAgainName,
|
||||
nsIPrefBranch* aPrefBranch,
|
||||
nsIStringBundle* aStringBundle)
|
||||
nsIStringBundle* aStringBundle,
|
||||
PRUint32 aBucket)
|
||||
: mPrompt(aPrompt), mPrefName(aPrefName),
|
||||
mDialogMessageName(aDialogMessageName),
|
||||
mShowAgainName(aShowAgainName), mPrefBranch(aPrefBranch),
|
||||
mStringBundle(aStringBundle) {}
|
||||
mStringBundle(aStringBundle),
|
||||
mBucket(aBucket) {}
|
||||
NS_IMETHOD Run();
|
||||
|
||||
protected:
|
||||
|
@ -131,6 +140,7 @@ protected:
|
|||
nsString mShowAgainName;
|
||||
nsCOMPtr<nsIPrefBranch> mPrefBranch;
|
||||
nsCOMPtr<nsIStringBundle> mStringBundle;
|
||||
PRUint32 mBucket;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -146,6 +156,7 @@ nsAsyncAlert::Run()
|
|||
// Stop if alert is not requested
|
||||
if (!prefValue) return NS_OK;
|
||||
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, mBucket);
|
||||
// Check for a show-once pref for this dialog.
|
||||
// If the show-once pref is set to true:
|
||||
// - The default value of the "show every time" checkbox is unchecked
|
||||
|
@ -189,7 +200,8 @@ nsSecurityWarningDialogs::AlertDialog(nsIInterfaceRequestor* aCtx,
|
|||
const char* aPrefName,
|
||||
const PRUnichar* aDialogMessageName,
|
||||
const PRUnichar* aShowAgainName,
|
||||
bool aAsync)
|
||||
bool aAsync,
|
||||
const PRUint32 aBucket)
|
||||
{
|
||||
// Get Prompt to use
|
||||
nsCOMPtr<nsIPrompt> prompt = do_GetInterface(aCtx);
|
||||
|
@ -200,7 +212,9 @@ nsSecurityWarningDialogs::AlertDialog(nsIInterfaceRequestor* aCtx,
|
|||
aDialogMessageName,
|
||||
aShowAgainName,
|
||||
mPrefBranch,
|
||||
mStringBundle);
|
||||
mStringBundle,
|
||||
aBucket);
|
||||
|
||||
NS_ENSURE_TRUE(alert, NS_ERROR_OUT_OF_MEMORY);
|
||||
return aAsync ? NS_DispatchToCurrentThread(alert) : alert->Run();
|
||||
}
|
||||
|
@ -212,9 +226,11 @@ nsSecurityWarningDialogs::ConfirmPostToInsecure(nsIInterfaceRequestor *ctx, bool
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
// The Telemetry clickthrough constant is 1 more than the constant for the dialog.
|
||||
rv = ConfirmDialog(ctx, INSECURE_SUBMIT_PREF,
|
||||
NS_LITERAL_STRING("PostToInsecureFromInsecureMessage").get(),
|
||||
NS_LITERAL_STRING("PostToInsecureFromInsecureShowAgain").get(),
|
||||
nsISecurityUITelemetry::WARNING_CONFIRM_POST_TO_INSECURE_FROM_INSECURE,
|
||||
_result);
|
||||
|
||||
return rv;
|
||||
|
@ -225,9 +241,11 @@ nsSecurityWarningDialogs::ConfirmPostToInsecureFromSecure(nsIInterfaceRequestor
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
// The Telemetry clickthrough constant is 1 more than the constant for the dialog.
|
||||
rv = ConfirmDialog(ctx, nullptr, // No preference for this one - it's too important
|
||||
NS_LITERAL_STRING("PostToInsecureFromSecureMessage").get(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nsISecurityUITelemetry::WARNING_CONFIRM_POST_TO_INSECURE_FROM_SECURE,
|
||||
_result);
|
||||
|
||||
return rv;
|
||||
|
@ -237,6 +255,7 @@ nsresult
|
|||
nsSecurityWarningDialogs::ConfirmDialog(nsIInterfaceRequestor *ctx, const char *prefName,
|
||||
const PRUnichar *messageName,
|
||||
const PRUnichar *showAgainName,
|
||||
const PRUint32 aBucket,
|
||||
bool* _result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
@ -256,6 +275,8 @@ nsSecurityWarningDialogs::ConfirmDialog(nsIInterfaceRequestor *ctx, const char *
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, aBucket);
|
||||
// See AlertDialog() for a description of how showOnce works.
|
||||
nsCAutoString showOncePref(prefName);
|
||||
showOncePref += ".show_once";
|
||||
|
@ -312,6 +333,11 @@ nsSecurityWarningDialogs::ConfirmDialog(nsIInterfaceRequestor *ctx, const char *
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
*_result = (buttonPressed != 1);
|
||||
if (*_result) {
|
||||
// For confirmation dialogs, the clickthrough constant is 1 more
|
||||
// than the constant for the dialog.
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, aBucket + 1);
|
||||
}
|
||||
|
||||
if (!prefValue && prefName != nullptr) {
|
||||
mPrefBranch->SetBoolPref(prefName, false);
|
||||
|
|
|
@ -27,10 +27,11 @@ protected:
|
|||
nsresult AlertDialog(nsIInterfaceRequestor *ctx, const char *prefName,
|
||||
const PRUnichar *messageName,
|
||||
const PRUnichar *showAgainName,
|
||||
bool aAsync);
|
||||
bool aAsync, const PRUint32 aBucket);
|
||||
nsresult ConfirmDialog(nsIInterfaceRequestor *ctx, const char *prefName,
|
||||
const PRUnichar *messageName,
|
||||
const PRUnichar *showAgainName, bool* _result);
|
||||
const PRUnichar *showAgainName, const PRUint32 aBucket,
|
||||
bool* _result);
|
||||
nsCOMPtr<nsIStringBundle> mStringBundle;
|
||||
nsCOMPtr<nsIPrefBranch> mPrefBranch;
|
||||
};
|
||||
|
|
|
@ -11,6 +11,8 @@ var gCert;
|
|||
var gChecking;
|
||||
var gBroken;
|
||||
var gNeedReset;
|
||||
var gSecHistogram;
|
||||
var gNsISecTel;
|
||||
|
||||
function badCertListener() {}
|
||||
badCertListener.prototype = {
|
||||
|
@ -42,6 +44,10 @@ function initExceptionDialog() {
|
|||
gDialog = document.documentElement;
|
||||
gBundleBrand = srGetStrBundle("chrome://branding/locale/brand.properties");
|
||||
gPKIBundle = srGetStrBundle("chrome://pippki/locale/pippki.properties");
|
||||
gSecHistogram = Components.classes["@mozilla.org/base/telemetry;1"].
|
||||
getService(Components.interfaces.nsITelemetry).
|
||||
getHistogramById("SECURITY_UI");
|
||||
gNsISecTel = Components.interfaces.nsISecurityUITelemetry;
|
||||
|
||||
var brandName = gBundleBrand.GetStringFromName("brandShortName");
|
||||
|
||||
|
@ -203,6 +209,7 @@ function updateCertStatus() {
|
|||
var shortDesc3, longDesc3;
|
||||
var use2 = false;
|
||||
var use3 = false;
|
||||
let bucketId = gNsISecTel.WARNING_BAD_CERT_ADD_EXCEPTION_BASE;
|
||||
if(gCert) {
|
||||
if(gBroken) {
|
||||
var mms = "addExceptionDomainMismatchShort";
|
||||
|
@ -213,11 +220,13 @@ function updateCertStatus() {
|
|||
var utl = "addExceptionUnverifiedOrBadSignatureLong";
|
||||
var use1 = false;
|
||||
if (gSSLStatus.isDomainMismatch) {
|
||||
bucketId += gNsISecTel.WARNING_BAD_CERT_ADD_EXCEPTION_FLAG_DOMAIN;
|
||||
use1 = true;
|
||||
shortDesc = mms;
|
||||
longDesc = mml;
|
||||
}
|
||||
if (gSSLStatus.isNotValidAtThisTime) {
|
||||
bucketId += gNsISecTel.WARNING_BAD_CERT_ADD_EXCEPTION_FLAG_TIME;
|
||||
if (!use1) {
|
||||
use1 = true;
|
||||
shortDesc = exs;
|
||||
|
@ -230,6 +239,7 @@ function updateCertStatus() {
|
|||
}
|
||||
}
|
||||
if (gSSLStatus.isUntrusted) {
|
||||
bucketId += gNsISecTel.WARNING_BAD_CERT_ADD_EXCEPTION_FLAG_UNTRUSTED;
|
||||
if (!use1) {
|
||||
use1 = true;
|
||||
shortDesc = uts;
|
||||
|
@ -246,7 +256,8 @@ function updateCertStatus() {
|
|||
longDesc3 = utl;
|
||||
}
|
||||
}
|
||||
|
||||
gSecHistogram.add(bucketId);
|
||||
|
||||
// In these cases, we do want to enable the "Add Exception" button
|
||||
gDialog.getButton("extra1").disabled = false;
|
||||
|
||||
|
@ -317,6 +328,7 @@ function updateCertStatus() {
|
|||
* Handle user request to display certificate details
|
||||
*/
|
||||
function viewCertButtonClick() {
|
||||
gSecHistogram.add(gNsISecTel.WARNING_BAD_CERT_CLICK_VIEW_CERT);
|
||||
if (gCert)
|
||||
viewCertHelper(this, gCert);
|
||||
|
||||
|
@ -332,16 +344,26 @@ function addException() {
|
|||
var overrideService = Components.classes["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Components.interfaces.nsICertOverrideService);
|
||||
var flags = 0;
|
||||
if(gSSLStatus.isUntrusted)
|
||||
let confirmBucketId = gNsISecTel.WARNING_BAD_CERT_CONFIRM_ADD_EXCEPTION_BASE;
|
||||
if (gSSLStatus.isUntrusted) {
|
||||
flags |= overrideService.ERROR_UNTRUSTED;
|
||||
if(gSSLStatus.isDomainMismatch)
|
||||
confirmBucketId += gNsISecTel.WARNING_BAD_CERT_CONFIRM_ADD_EXCEPTION_FLAG_UNTRUSTED;
|
||||
}
|
||||
if (gSSLStatus.isDomainMismatch) {
|
||||
flags |= overrideService.ERROR_MISMATCH;
|
||||
if(gSSLStatus.isNotValidAtThisTime)
|
||||
confirmBucketId += gNsISecTel.WARNING_BAD_CERT_CONFIRM_ADD_EXCEPTION_FLAG_DOMAIN;
|
||||
}
|
||||
if (gSSLStatus.isNotValidAtThisTime) {
|
||||
flags |= overrideService.ERROR_TIME;
|
||||
confirmBucketId += gNsISecTel.WARNING_BAD_CERT_CONFIRM_ADD_EXCEPTION_FLAG_TIME;
|
||||
}
|
||||
|
||||
var permanentCheckbox = document.getElementById("permanent");
|
||||
var shouldStorePermanently = permanentCheckbox.checked && !inPrivateBrowsingMode();
|
||||
if(!permanentCheckbox.checked)
|
||||
gSecHistogram.add(gNsISecTel.WARNING_BAD_CERT_DONT_REMEMBER_EXCEPTION);
|
||||
|
||||
gSecHistogram.add(confirmBucketId);
|
||||
var uri = getURI();
|
||||
overrideService.rememberValidityOverride(
|
||||
uri.asciiHost, uri.port,
|
||||
|
|
|
@ -13,21 +13,22 @@ def print_test_dirs(topsrcdir, manifest_file):
|
|||
into manifests, as we currently have no need for that.
|
||||
"""
|
||||
|
||||
dirs = set()
|
||||
# output the directory of this (parent) manifest
|
||||
topsrcdir = os.path.abspath(topsrcdir)
|
||||
scriptdir = os.path.abspath(os.path.dirname(__file__))
|
||||
print scriptdir[len(topsrcdir) + 1:]
|
||||
dirs.add(scriptdir[len(topsrcdir) + 1:])
|
||||
|
||||
# output the directories of all the other manifests
|
||||
dirs = set()
|
||||
manifest = TestManifest()
|
||||
manifest.read(manifest_file)
|
||||
for i in manifest.get():
|
||||
dirs.add(os.path.dirname(i['manifest'])[len(topsrcdir) + 1:])
|
||||
d = os.path.dirname(i['manifest'])[len(topsrcdir) + 1:]
|
||||
dirs.add(d)
|
||||
for path in dirs:
|
||||
path = path.replace('\\', '/')
|
||||
print path
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 3:
|
||||
print >>sys.stderr, "Usage: %s topsrcdir manifest.ini" % sys.argv[0]
|
||||
|
|
|
@ -201,6 +201,20 @@ SocialProvider.prototype = {
|
|||
updateUserProfile: function(profile) {
|
||||
this.profile = profile;
|
||||
|
||||
// Sanitize the portrait from any potential script-injection.
|
||||
if (profile.portrait) {
|
||||
try {
|
||||
let portraitUri = Services.io.newURI(profile.portrait, null, null);
|
||||
|
||||
let scheme = portraitUri ? portraitUri.scheme : "";
|
||||
if (scheme != "data" && scheme != "http" && scheme != "https") {
|
||||
profile.portrait = "";
|
||||
}
|
||||
} catch (ex) {
|
||||
profile.portrait = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (profile.iconURL)
|
||||
this.iconURL = profile.iconURL;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ let tests = {
|
|||
|
||||
testProfile: function(next) {
|
||||
let expect = {
|
||||
portrait: "chrome://branding/content/icon48.png",
|
||||
portrait: "https://example.com/portrait.jpg",
|
||||
userName: "trickster",
|
||||
displayName: "Kuma Lisa",
|
||||
profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
|
||||
|
|
|
@ -518,6 +518,11 @@ HISTOGRAM(BROWSERPROVIDER_XUL_IMPORT_BOOKMARKS, 1, 50000, 20, EXPONENTIAL, "Numb
|
|||
HISTOGRAM(BROWSERPROVIDER_XUL_IMPORT_HISTORY, 1, 1000000, 20, EXPONENTIAL, "Number of history entries in the original XUL places database")
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Security UI Telemetry
|
||||
*/
|
||||
HISTOGRAM_ENUMERATED_VALUES(SECURITY_UI, 100, "Security UI Telemetry")
|
||||
|
||||
#undef HISTOGRAM_ENUMERATED_VALUES
|
||||
#undef HISTOGRAM_BOOLEAN
|
||||
#undef HISTOGRAM_FLAG
|
||||
|
|
|
@ -173,6 +173,10 @@ Installer.prototype = {
|
|||
args.wrappedJSObject = args;
|
||||
|
||||
try {
|
||||
Cc["@mozilla.org/base/telemetry;1"].
|
||||
getService(Ci.nsITelemetry).
|
||||
getHistogramById("SECURITY_UI").
|
||||
add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL);
|
||||
Services.ww.openWindow(this.window, URI_XPINSTALL_DIALOG,
|
||||
null, "chrome,modal,centerscreen", args);
|
||||
} catch (e) {
|
||||
|
|
|
@ -138,6 +138,10 @@ XPInstallConfirm.init = function ()
|
|||
|
||||
XPInstallConfirm.onOK = function ()
|
||||
{
|
||||
Components.classes["@mozilla.org/base/telemetry;1"].
|
||||
getService(Components.interfaces.nsITelemetry).
|
||||
getHistogramById("SECURITY_UI").
|
||||
add(Components.interfaces.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL_CLICK_THROUGH);
|
||||
args.installs.forEach(function(install) {
|
||||
install.install();
|
||||
});
|
||||
|
|
|
@ -151,8 +151,11 @@ function test2() {
|
|||
ok(box.mozMatchesSelector(":hover"), "Box should be hovered");
|
||||
// Unhover box and iframe by moving the mouse outside the window.
|
||||
moveMouseTo(0, 150, function () {
|
||||
ok(!gIFrame.mozMatchesSelector(":hover"), "iframe shouldn't be hovered");
|
||||
ok(!box.mozMatchesSelector(":hover"), "box shouldn't be hovered");
|
||||
const isOSXSnowLeopard = navigator.userAgent.indexOf("Mac OS X 10.6") != -1;
|
||||
if (!isOSXSnowLeopard) {
|
||||
ok(!gIFrame.mozMatchesSelector(":hover"), "iframe shouldn't be hovered");
|
||||
ok(!box.mozMatchesSelector(":hover"), "box shouldn't be hovered");
|
||||
}
|
||||
finalize();
|
||||
});
|
||||
}, gLeftWindow, box);
|
||||
|
|
Загрузка…
Ссылка в новой задаче