Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e28170c980 | ||
|
|
0507f298e9 | ||
|
|
d9c31941e7 | ||
|
|
2c2d82d310 | ||
|
|
781bcc3a2e | ||
|
|
2b6598bbb1 | ||
|
|
094bc0a678 | ||
|
|
a731633d7b | ||
|
|
cd2ffb4b8f | ||
|
|
df9ab936f2 | ||
|
|
8c7ca10cfe | ||
|
|
0a5ad190c3 | ||
|
|
97b0520d7b | ||
|
|
b33a151836 | ||
|
|
32ca14f34b | ||
|
|
0da8e0b496 | ||
|
|
473e75d5aa | ||
|
|
28613ba836 | ||
|
|
8a5b121489 |
No files matched your search
@@ -58,9 +58,21 @@ const Curl = {
|
||||
* A cURL command.
|
||||
*/
|
||||
generateCommand: function (data) {
|
||||
let utils = CurlUtils;
|
||||
const utils = CurlUtils;
|
||||
|
||||
let command = ["curl"];
|
||||
|
||||
// Make sure to use the following helpers to sanitize arguments before execution.
|
||||
const addParam = value => {
|
||||
const safe = /^[a-zA-Z-]+$/.test(value) ? value : escapeString(value);
|
||||
command.push(safe);
|
||||
};
|
||||
|
||||
const addPostData = value => {
|
||||
const safe = /^[a-zA-Z-]+$/.test(value) ? value : escapeString(value);
|
||||
postData.push(safe);
|
||||
};
|
||||
|
||||
let ignoredHeaders = new Set();
|
||||
|
||||
// The cURL command is expected to run on the same platform that Firefox runs
|
||||
@@ -69,7 +81,7 @@ const Curl = {
|
||||
utils.escapeStringWin : utils.escapeStringPosix;
|
||||
|
||||
// Add URL.
|
||||
command.push(escapeString(data.url));
|
||||
addParam(data.url);
|
||||
|
||||
let postDataText = null;
|
||||
let multipartRequest = utils.isMultipartRequest(data);
|
||||
@@ -79,15 +91,15 @@ const Curl = {
|
||||
if (utils.isUrlEncodedRequest(data) ||
|
||||
["PUT", "POST", "PATCH"].includes(data.method)) {
|
||||
postDataText = data.postDataText;
|
||||
postData.push("--data");
|
||||
postData.push(escapeString(utils.writePostDataTextParams(postDataText)));
|
||||
addPostData("--data");
|
||||
addPostData(utils.writePostDataTextParams(postDataText));
|
||||
ignoredHeaders.add("content-length");
|
||||
} else if (multipartRequest) {
|
||||
postDataText = data.postDataText;
|
||||
postData.push("--data-binary");
|
||||
addPostData("--data-binary");
|
||||
let boundary = utils.getMultipartBoundary(data);
|
||||
let text = utils.removeBinaryDataFromMultipartText(postDataText, boundary);
|
||||
postData.push(escapeString(text));
|
||||
addPostData(text);
|
||||
ignoredHeaders.add("content-length");
|
||||
}
|
||||
|
||||
@@ -95,15 +107,15 @@ const Curl = {
|
||||
// For GET and POST requests this is not necessary as GET is the
|
||||
// default. If --data or --binary is added POST is the default.
|
||||
if (!(data.method == "GET" || data.method == "POST")) {
|
||||
command.push("-X");
|
||||
command.push(data.method);
|
||||
addParam("-X");
|
||||
addParam(data.method);
|
||||
}
|
||||
|
||||
// Add -I (HEAD)
|
||||
// For servers that supports HEAD.
|
||||
// This will fetch the header of a document only.
|
||||
if (data.method == "HEAD") {
|
||||
command.push("-I");
|
||||
addParam("-I");
|
||||
}
|
||||
|
||||
// Add http version.
|
||||
@@ -114,7 +126,7 @@ const Curl = {
|
||||
// data.httpVersion are HTTP/1.0, HTTP/1.1 and HTTP/2.0
|
||||
// So in case of HTTP/2.0 (which should ideally be HTTP/2) we are using
|
||||
// only major version, and full version in other cases
|
||||
command.push("--http" + (version == "2.0" ? version.split(".")[0] : version));
|
||||
addParam("--http" + (version == "2.0" ? version.split(".")[0] : version));
|
||||
}
|
||||
|
||||
// Add request headers.
|
||||
@@ -126,14 +138,14 @@ const Curl = {
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
let header = headers[i];
|
||||
if (header.name.toLowerCase() === "accept-encoding") {
|
||||
command.push("--compressed");
|
||||
addParam("--compressed");
|
||||
continue;
|
||||
}
|
||||
if (ignoredHeaders.has(header.name.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
command.push("-H");
|
||||
command.push(escapeString(header.name + ": " + header.value));
|
||||
addParam("-H");
|
||||
addParam(header.name + ": " + header.value);
|
||||
}
|
||||
|
||||
// Add post data.
|
||||
|
||||
@@ -860,6 +860,12 @@ nsDocShell::~nsDocShell()
|
||||
shPrivate->SetRootDocShell(nullptr);
|
||||
}
|
||||
|
||||
if (mContentViewer) {
|
||||
mContentViewer->Close(nullptr);
|
||||
mContentViewer->Destroy();
|
||||
mContentViewer = nullptr;
|
||||
}
|
||||
|
||||
if (--gDocShellCount == 0) {
|
||||
NS_IF_RELEASE(sURIFixup);
|
||||
}
|
||||
|
||||
@@ -487,7 +487,7 @@ class CompileInfo
|
||||
|
||||
// Function.arguments can be used to access all arguments in non-strict
|
||||
// scripts, so we can't optimize out any arguments.
|
||||
if ((hasArguments() || !script()->strict()) &&
|
||||
if ((mayReadFrameArgsDirectly_ || !script()->strict()) &&
|
||||
firstArgSlot() <= slot && slot - firstArgSlot() < nargs())
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -851,12 +851,6 @@ NS_IMPL_ISUPPORTS(VsyncChildCreateCallback, nsIIPCBackgroundChildCreateCallback)
|
||||
static StaticRefPtr<RefreshDriverTimer> sRegularRateTimer;
|
||||
static StaticRefPtr<InactiveRefreshDriverTimer> sThrottledRateTimer;
|
||||
|
||||
#ifdef XP_WIN
|
||||
static int32_t sHighPrecisionTimerRequests = 0;
|
||||
// a bare pointer to avoid introducing a static constructor
|
||||
static nsITimer *sDisableHighPrecisionTimersTimer = nullptr;
|
||||
#endif
|
||||
|
||||
static void
|
||||
CreateContentVsyncRefreshTimer(void*)
|
||||
{
|
||||
@@ -934,16 +928,6 @@ nsRefreshDriver::Shutdown()
|
||||
|
||||
sRegularRateTimer = nullptr;
|
||||
sThrottledRateTimer = nullptr;
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (sDisableHighPrecisionTimersTimer) {
|
||||
sDisableHighPrecisionTimersTimer->Cancel();
|
||||
NS_RELEASE(sDisableHighPrecisionTimersTimer);
|
||||
timeEndPeriod(1);
|
||||
} else if (sHighPrecisionTimerRequests) {
|
||||
timeEndPeriod(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
@@ -1062,7 +1046,6 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
|
||||
mNeedToRecomputeVisibility(false),
|
||||
mTestControllingRefreshes(false),
|
||||
mViewManagerFlushIsPending(false),
|
||||
mRequestedHighPrecision(false),
|
||||
mInRefresh(false),
|
||||
mWaitingForTransaction(false),
|
||||
mSkippedPaints(false),
|
||||
@@ -1300,83 +1283,6 @@ nsRefreshDriver::StopTimer()
|
||||
|
||||
mActiveTimer->RemoveRefreshDriver(this);
|
||||
mActiveTimer = nullptr;
|
||||
|
||||
if (mRequestedHighPrecision) {
|
||||
SetHighPrecisionTimersEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
static void
|
||||
DisableHighPrecisionTimersCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
timeEndPeriod(1);
|
||||
NS_RELEASE(sDisableHighPrecisionTimersTimer);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsRefreshDriver::ConfigureHighPrecision()
|
||||
{
|
||||
bool haveUnthrottledFrameRequestCallbacks =
|
||||
mFrameRequestCallbackDocs.Length() > 0;
|
||||
|
||||
// if the only change that's needed is that we need high precision,
|
||||
// then just set that
|
||||
if (!mThrottled && !mRequestedHighPrecision &&
|
||||
haveUnthrottledFrameRequestCallbacks) {
|
||||
SetHighPrecisionTimersEnabled(true);
|
||||
} else if (mRequestedHighPrecision && !haveUnthrottledFrameRequestCallbacks) {
|
||||
SetHighPrecisionTimersEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::SetHighPrecisionTimersEnabled(bool aEnable)
|
||||
{
|
||||
LOG("[%p] SetHighPrecisionTimersEnabled (%s)", this, aEnable ? "true" : "false");
|
||||
|
||||
if (aEnable) {
|
||||
NS_ASSERTION(!mRequestedHighPrecision, "SetHighPrecisionTimersEnabled(true) called when already requested!");
|
||||
#ifdef XP_WIN
|
||||
if (++sHighPrecisionTimerRequests == 1) {
|
||||
// If we had a timer scheduled to disable it, that means that it's already
|
||||
// enabled; just cancel the timer. Otherwise, really enable it.
|
||||
if (sDisableHighPrecisionTimersTimer) {
|
||||
sDisableHighPrecisionTimersTimer->Cancel();
|
||||
NS_RELEASE(sDisableHighPrecisionTimersTimer);
|
||||
} else {
|
||||
timeBeginPeriod(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mRequestedHighPrecision = true;
|
||||
} else {
|
||||
NS_ASSERTION(mRequestedHighPrecision, "SetHighPrecisionTimersEnabled(false) called when not requested!");
|
||||
#ifdef XP_WIN
|
||||
if (--sHighPrecisionTimerRequests == 0) {
|
||||
// Don't jerk us around between high precision and low precision
|
||||
// timers; instead, only allow leaving high precision timers
|
||||
// after 90 seconds. This is arbitrary, but hopefully good
|
||||
// enough.
|
||||
NS_ASSERTION(!sDisableHighPrecisionTimersTimer, "We shouldn't have an outstanding disable-high-precision timer !");
|
||||
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
if (timer) {
|
||||
timer.forget(&sDisableHighPrecisionTimersTimer);
|
||||
sDisableHighPrecisionTimersTimer->InitWithFuncCallback(DisableHighPrecisionTimersCallback,
|
||||
nullptr,
|
||||
90 * 1000,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
} else {
|
||||
// might happen if we're shutting down XPCOM; just drop the time period down
|
||||
// immediately
|
||||
timeEndPeriod(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mRequestedHighPrecision = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@@ -1993,8 +1899,6 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
observer->DidRefresh();
|
||||
}
|
||||
|
||||
ConfigureHighPrecision();
|
||||
|
||||
NS_ASSERTION(mInRefresh, "Still in refresh");
|
||||
|
||||
if (mPresContext->IsRoot() && XRE_IsContentProcess() && gfxPrefs::AlwaysPaint()) {
|
||||
@@ -2247,7 +2151,6 @@ nsRefreshDriver::ScheduleFrameRequestCallbacks(nsIDocument* aDocument)
|
||||
}
|
||||
|
||||
// make sure that the timer is running
|
||||
ConfigureHighPrecision();
|
||||
EnsureTimerStarted();
|
||||
}
|
||||
|
||||
@@ -2256,7 +2159,6 @@ nsRefreshDriver::RevokeFrameRequestCallbacks(nsIDocument* aDocument)
|
||||
{
|
||||
mFrameRequestCallbackDocs.RemoveElement(aDocument);
|
||||
mThrottledFrameRequestCallbackDocs.RemoveElement(aDocument);
|
||||
ConfigureHighPrecision();
|
||||
// No need to worry about restarting our timer in slack mode if it's already
|
||||
// running; that will happen automatically when it fires.
|
||||
}
|
||||
|
||||
@@ -450,7 +450,6 @@ private:
|
||||
bool mNeedToRecomputeVisibility;
|
||||
bool mTestControllingRefreshes;
|
||||
bool mViewManagerFlushIsPending;
|
||||
bool mRequestedHighPrecision;
|
||||
bool mInRefresh;
|
||||
|
||||
// True if the refresh driver is suspended waiting for transaction
|
||||
@@ -502,10 +501,6 @@ private:
|
||||
|
||||
friend class mozilla::RefreshDriverTimer;
|
||||
|
||||
// turn on or turn off high precision based on various factors
|
||||
void ConfigureHighPrecision();
|
||||
void SetHighPrecisionTimersEnabled(bool aEnable);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
// `true` if we are currently in jank-critical mode.
|
||||
|
||||
@@ -18,9 +18,6 @@ const PREF_OVERRIDES_ENABLED = "general.useragent.site_specific_overrides";
|
||||
const DEFAULT_UA = Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Ci.nsIHttpProtocolHandler)
|
||||
.userAgent;
|
||||
const OS_SLICE = Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Ci.nsIHttpProtocolHandler)
|
||||
.oscpu + ";";
|
||||
const MAX_OVERRIDE_FOR_HOST_CACHE_SIZE = 250;
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
@@ -30,7 +27,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
var gPrefBranch;
|
||||
var gOverrides = new Map;
|
||||
var gUpdatedOverrides;
|
||||
var gOldDynOverrides;
|
||||
var gOverrideForHostCache = new Map;
|
||||
var gInitialized = false;
|
||||
var gOverrideFunctions = [
|
||||
@@ -56,10 +52,7 @@ this.UserAgentOverrides = {
|
||||
}
|
||||
|
||||
UserAgentUpdates.init(function(overrides) {
|
||||
if (overrides == gOldDynOverrides) {
|
||||
return;
|
||||
}
|
||||
gOldDynOverrides = overrides;
|
||||
gOverrideForHostCache.clear();
|
||||
if (overrides) {
|
||||
for (let domain in overrides) {
|
||||
overrides[domain] = getUserAgentFromOverride(overrides[domain]);
|
||||
@@ -67,7 +60,6 @@ this.UserAgentOverrides = {
|
||||
overrides.get = function(key) { return this[key]; };
|
||||
}
|
||||
gUpdatedOverrides = overrides;
|
||||
buildOverrides();
|
||||
});
|
||||
|
||||
buildOverrides();
|
||||
@@ -151,7 +143,7 @@ function getUserAgentFromOverride(override)
|
||||
if (search && replace) {
|
||||
userAgent = DEFAULT_UA.replace(new RegExp(search, "g"), replace);
|
||||
} else {
|
||||
userAgent = override.replace(/%OS_SLICE%/g, OS_SLICE);
|
||||
userAgent = override;
|
||||
}
|
||||
gBuiltUAs.set(override, userAgent);
|
||||
return userAgent;
|
||||
@@ -164,22 +156,15 @@ function buildOverrides() {
|
||||
if (!Services.prefs.getBoolPref(PREF_OVERRIDES_ENABLED))
|
||||
return;
|
||||
|
||||
let builtUAs = new Map;
|
||||
let domains = gPrefBranch.getChildList("");
|
||||
|
||||
// Since the static override map has the highest priority, we build it so
|
||||
// that it includes only domains with user-set overrides and domains with
|
||||
// default pre-set overrides that are not overridden by dynamic updates.
|
||||
for (let domain of domains) {
|
||||
if (!(gUpdatedOverrides && gUpdatedOverrides.get(domain)) ||
|
||||
gPrefBranch.prefHasUserValue(domain)) {
|
||||
// Here we selected domains that are not dynamically overridden
|
||||
// or have a user-set override.
|
||||
let override = gPrefBranch.getCharPref(domain);
|
||||
let userAgent = getUserAgentFromOverride(override);
|
||||
let override = gPrefBranch.getCharPref(domain);
|
||||
let userAgent = getUserAgentFromOverride(override);
|
||||
|
||||
if (userAgent != DEFAULT_UA) {
|
||||
gOverrides.set(domain, userAgent);
|
||||
}
|
||||
if (userAgent != DEFAULT_UA) {
|
||||
gOverrides.set(domain, userAgent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,28 +310,9 @@ nsHttpHandler::Init()
|
||||
}
|
||||
mAppName.StripChars(R"( ()<>@,;:\"/[]?={})");
|
||||
}
|
||||
|
||||
nsCString dynamicBuildID;
|
||||
if (appInfo) {
|
||||
appInfo->GetPlatformBuildID(dynamicBuildID);
|
||||
if (dynamicBuildID.Length() > 8 )
|
||||
dynamicBuildID.Left(dynamicBuildID, 8);
|
||||
}
|
||||
|
||||
if (mAppVersionIsBuildID) {
|
||||
// Override BuildID
|
||||
mAppVersion.AssignLiteral(MOZ_UA_BUILDID);
|
||||
} else if (appInfo) {
|
||||
appInfo->GetVersion(mAppVersion);
|
||||
} else {
|
||||
// Fall back to platform if appInfo is unavailable
|
||||
mAppVersion.AssignLiteral(MOZILLA_UAVERSION);
|
||||
}
|
||||
BuildAppVersion();
|
||||
|
||||
// If there's no override set, set it to the dynamic BuildID
|
||||
if (mAppVersion.IsEmpty())
|
||||
mAppVersion.Assign(dynamicBuildID);
|
||||
|
||||
mSessionStartTime = NowInSeconds();
|
||||
mHandlerActive = true;
|
||||
|
||||
@@ -350,8 +331,15 @@ nsHttpHandler::Init()
|
||||
// Goanna slice version
|
||||
mProductSub.AssignLiteral(MOZILLA_UAVERSION);
|
||||
|
||||
if (mProductSub.IsEmpty())
|
||||
mProductSub.Assign(dynamicBuildID);
|
||||
if (mProductSub.IsEmpty()) {
|
||||
nsCString dynamicBuildID;
|
||||
if (appInfo) {
|
||||
appInfo->GetPlatformBuildID(dynamicBuildID);
|
||||
if (dynamicBuildID.Length() > 8 )
|
||||
dynamicBuildID.Left(dynamicBuildID, 8);
|
||||
}
|
||||
mProductSub.Assign(dynamicBuildID);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
// dump user agent prefs
|
||||
@@ -657,6 +645,37 @@ nsHttpHandler::GenerateHostPort(const nsCString& host, int32_t port,
|
||||
// nsHttpHandler <private>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
nsHttpHandler::BuildAppVersion()
|
||||
{
|
||||
nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
|
||||
|
||||
nsCString dynamicBuildID;
|
||||
if (appInfo) {
|
||||
appInfo->GetPlatformBuildID(dynamicBuildID);
|
||||
if (dynamicBuildID.Length() > 8 )
|
||||
dynamicBuildID.Left(dynamicBuildID, 8);
|
||||
}
|
||||
|
||||
if (mAppVersionIsBuildID) {
|
||||
// Override BuildID
|
||||
mAppVersion.Assign(dynamicBuildID);
|
||||
} else if (appInfo) {
|
||||
appInfo->GetVersion(mAppVersion);
|
||||
} else {
|
||||
// Fall back to platform if appInfo is unavailable
|
||||
mAppVersion.AssignLiteral(MOZILLA_UAVERSION);
|
||||
}
|
||||
|
||||
// If there's still no version set, set it to a fixed BuildID
|
||||
if (mAppVersion.IsEmpty()) {
|
||||
mAppVersion.AssignLiteral(MOZ_UA_BUILDID);
|
||||
}
|
||||
if (mAppVersion.IsEmpty()) {
|
||||
mAppVersion.AssignLiteral("20200101");
|
||||
}
|
||||
}
|
||||
|
||||
const nsAFlatCString &
|
||||
nsHttpHandler::UserAgent()
|
||||
{
|
||||
@@ -782,21 +801,6 @@ nsHttpHandler::InitUserAgentComponents()
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MOZ_MULET
|
||||
{
|
||||
// Add the `Mobile` or `Tablet` or `TV` token when running in the b2g
|
||||
// desktop simulator via preference.
|
||||
nsCString deviceType;
|
||||
nsresult rv = Preferences::GetCString("devtools.useragent.device_type", &deviceType);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mCompatDevice.Assign(deviceType);
|
||||
} else {
|
||||
mCompatDevice.AssignLiteral("Mobile");
|
||||
}
|
||||
}
|
||||
#endif // MOZ_MULET
|
||||
|
||||
#ifndef MOZ_UA_OS_AGNOSTIC
|
||||
// Gather OS/CPU.
|
||||
#if defined(XP_WIN)
|
||||
@@ -924,6 +928,10 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
||||
if (PREF_CHANGED(UA_PREF("appVersionIsBuildID"))) {
|
||||
rv = prefs->GetBoolPref(UA_PREF("appVersionIsBuildID"), &cVar);
|
||||
mAppVersionIsBuildID = (NS_SUCCEEDED(rv) && cVar);
|
||||
|
||||
// Rebuild application version string.
|
||||
BuildAppVersion();
|
||||
|
||||
mUserAgentIsDirty = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -391,6 +391,7 @@ private:
|
||||
//
|
||||
// Useragent/prefs helper methods
|
||||
//
|
||||
void BuildAppVersion();
|
||||
void BuildUserAgent();
|
||||
void InitUserAgentComponents();
|
||||
void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
|
||||
|
||||
@@ -11,7 +11,7 @@ Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
function mozProtocolHandler() {
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "urlToLoad", "toolkit.mozprotocol.url",
|
||||
"https://www.mozilla.org/protocol");
|
||||
"http://thereisonlyxul.org/");
|
||||
}
|
||||
|
||||
mozProtocolHandler.prototype = {
|
||||
|
||||
@@ -211,6 +211,9 @@
|
||||
<!ENTITY addon.loadingReleaseNotes.label "Loading…">
|
||||
<!ENTITY addon.errorLoadingReleaseNotes.label "Sorry, but there was an error loading the release notes.">
|
||||
|
||||
<!ENTITY addon.nativeAddon "This add-on directly targets &brandFullName;">
|
||||
<!ENTITY addon.compatAddon "This add-on targets Mozilla Firefox and runs in compatibility mode">
|
||||
|
||||
<!ENTITY addon.createdBy.label "By ">
|
||||
|
||||
<!ENTITY eula.title "End-User License Agreement">
|
||||
|
||||
@@ -30,9 +30,6 @@ notification.blocked.link=More Information
|
||||
#LOCALIZATION NOTE (notification.softblocked) %1$S is the add-on name
|
||||
notification.softblocked=%1$S is known to cause issues.
|
||||
notification.softblocked.link=More Information
|
||||
#LOCALIZATION NOTE (notification.compatibility) %1$S is the add-on name, %2$S is brand name
|
||||
notification.compatibility=%1$S was not designed for %2$S. It may not function properly or cease to function.
|
||||
notification.compatibility.link=More Information
|
||||
#LOCALIZATION NOTE (notification.outdated) %1$S is the add-on name
|
||||
notification.outdated=An important update is available for %1$S.
|
||||
notification.outdated.link=Update Now
|
||||
@@ -81,9 +78,6 @@ details.notification.incompatible=%1$S is incompatible with %2$S %3$S.
|
||||
#LOCALIZATION NOTE (details.notification.blocked) %1$S is the add-on name
|
||||
details.notification.blocked=%1$S has been disabled due to security or stability issues.
|
||||
details.notification.blocked.link=More Information
|
||||
#LOCALIZATION NOTE (details.notification.compatibility) %1$S is the add-on name, %2$S is brand name
|
||||
details.notification.compatibility=%1$S was not designed for %2$S. It may not function properly or cease to function.
|
||||
details.notification.compatibility.link=More Information
|
||||
#LOCALIZATION NOTE (details.notification.softblocked) %1$S is the add-on name
|
||||
details.notification.softblocked=%1$S is known to cause issues.
|
||||
details.notification.softblocked.link=More Information
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ExtensionStorage"];
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
|
||||
"resource://gre/modules/AsyncShutdown.jsm");
|
||||
|
||||
function jsonReplacer(key, value) {
|
||||
switch (typeof(value)) {
|
||||
// Serialize primitive types as-is.
|
||||
case "string":
|
||||
case "number":
|
||||
case "boolean":
|
||||
return value;
|
||||
|
||||
case "object":
|
||||
if (value === null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
switch (Cu.getClassName(value, true)) {
|
||||
// Serialize arrays and ordinary objects as-is.
|
||||
case "Array":
|
||||
case "Object":
|
||||
return value;
|
||||
|
||||
// Serialize Date objects and regular expressions as their
|
||||
// string representations.
|
||||
case "Date":
|
||||
case "RegExp":
|
||||
return String(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
// If this is the root object, and we can't serialize it, serialize
|
||||
// the value to an empty object.
|
||||
return {};
|
||||
}
|
||||
|
||||
// Everything else, omit entirely.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.ExtensionStorage = {
|
||||
cache: new Map(),
|
||||
listeners: new Map(),
|
||||
|
||||
/**
|
||||
* Sanitizes the given value, and returns a JSON-compatible
|
||||
* representation of it, based on the privileges of the given global.
|
||||
*
|
||||
* @param {value} value
|
||||
* The value to sanitize.
|
||||
* @param {Context} context
|
||||
* The extension context in which to sanitize the value
|
||||
* @returns {value}
|
||||
* The sanitized value.
|
||||
*/
|
||||
sanitize(value, context) {
|
||||
let json = context.jsonStringify(value, jsonReplacer);
|
||||
return JSON.parse(json);
|
||||
},
|
||||
|
||||
getExtensionDir(extensionId) {
|
||||
return OS.Path.join(this.extensionDir, extensionId);
|
||||
},
|
||||
|
||||
getStorageFile(extensionId) {
|
||||
return OS.Path.join(this.extensionDir, extensionId, "storage.js");
|
||||
},
|
||||
|
||||
read(extensionId) {
|
||||
if (this.cache.has(extensionId)) {
|
||||
return this.cache.get(extensionId);
|
||||
}
|
||||
|
||||
let path = this.getStorageFile(extensionId);
|
||||
let decoder = new TextDecoder();
|
||||
let promise = OS.File.read(path);
|
||||
promise = promise.then(array => {
|
||||
return JSON.parse(decoder.decode(array));
|
||||
}).catch((error) => {
|
||||
if (!error.becauseNoSuchFile) {
|
||||
Cu.reportError("Unable to parse JSON data for extension storage.");
|
||||
}
|
||||
return {};
|
||||
});
|
||||
this.cache.set(extensionId, promise);
|
||||
return promise;
|
||||
},
|
||||
|
||||
write(extensionId) {
|
||||
let promise = this.read(extensionId).then(extData => {
|
||||
let encoder = new TextEncoder();
|
||||
let array = encoder.encode(JSON.stringify(extData));
|
||||
let path = this.getStorageFile(extensionId);
|
||||
OS.File.makeDir(this.getExtensionDir(extensionId), {
|
||||
ignoreExisting: true,
|
||||
from: OS.Constants.Path.profileDir,
|
||||
});
|
||||
let promise = OS.File.writeAtomic(path, array);
|
||||
return promise;
|
||||
}).catch(() => {
|
||||
// Make sure this promise is never rejected.
|
||||
Cu.reportError("Unable to write JSON data for extension storage.");
|
||||
});
|
||||
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
"ExtensionStorage: Finish writing extension data",
|
||||
promise);
|
||||
|
||||
return promise.then(() => {
|
||||
AsyncShutdown.profileBeforeChange.removeBlocker(promise);
|
||||
});
|
||||
},
|
||||
|
||||
set(extensionId, items, context) {
|
||||
return this.read(extensionId).then(extData => {
|
||||
let changes = {};
|
||||
for (let prop in items) {
|
||||
let item = this.sanitize(items[prop], context);
|
||||
changes[prop] = {oldValue: extData[prop], newValue: item};
|
||||
extData[prop] = item;
|
||||
}
|
||||
|
||||
this.notifyListeners(extensionId, changes);
|
||||
|
||||
return this.write(extensionId);
|
||||
});
|
||||
},
|
||||
|
||||
remove(extensionId, items) {
|
||||
return this.read(extensionId).then(extData => {
|
||||
let changes = {};
|
||||
for (let prop of [].concat(items)) {
|
||||
changes[prop] = {oldValue: extData[prop]};
|
||||
delete extData[prop];
|
||||
}
|
||||
|
||||
this.notifyListeners(extensionId, changes);
|
||||
|
||||
return this.write(extensionId);
|
||||
});
|
||||
},
|
||||
|
||||
clear(extensionId) {
|
||||
return this.read(extensionId).then(extData => {
|
||||
let changes = {};
|
||||
for (let prop of Object.keys(extData)) {
|
||||
changes[prop] = {oldValue: extData[prop]};
|
||||
delete extData[prop];
|
||||
}
|
||||
|
||||
this.notifyListeners(extensionId, changes);
|
||||
|
||||
return this.write(extensionId);
|
||||
});
|
||||
},
|
||||
|
||||
get(extensionId, keys) {
|
||||
return this.read(extensionId).then(extData => {
|
||||
let result = {};
|
||||
if (keys === null) {
|
||||
Object.assign(result, extData);
|
||||
} else if (typeof(keys) == "object" && !Array.isArray(keys)) {
|
||||
for (let prop in keys) {
|
||||
if (prop in extData) {
|
||||
result[prop] = extData[prop];
|
||||
} else {
|
||||
result[prop] = keys[prop];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let prop of [].concat(keys)) {
|
||||
if (prop in extData) {
|
||||
result[prop] = extData[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
|
||||
addOnChangedListener(extensionId, listener) {
|
||||
let listeners = this.listeners.get(extensionId) || new Set();
|
||||
listeners.add(listener);
|
||||
this.listeners.set(extensionId, listeners);
|
||||
},
|
||||
|
||||
removeOnChangedListener(extensionId, listener) {
|
||||
let listeners = this.listeners.get(extensionId);
|
||||
listeners.delete(listener);
|
||||
},
|
||||
|
||||
notifyListeners(extensionId, changes) {
|
||||
let listeners = this.listeners.get(extensionId);
|
||||
if (listeners) {
|
||||
for (let listener of listeners) {
|
||||
listener(changes);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
return;
|
||||
}
|
||||
Services.obs.addObserver(this, "extension-invalidate-storage-cache", false);
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic == "xpcom-shutdown") {
|
||||
Services.obs.removeObserver(this, "extension-invalidate-storage-cache");
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
} else if (topic == "extension-invalidate-storage-cache") {
|
||||
this.cache.clear();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(ExtensionStorage, "extensionDir",
|
||||
() => OS.Path.join(OS.Constants.Path.profileDir, "browser-extension-data"));
|
||||
|
||||
ExtensionStorage.init();
|
||||
@@ -11,7 +11,6 @@ EXTRA_JS_MODULES += [
|
||||
'addons/WebNavigation.jsm',
|
||||
'addons/WebNavigationContent.js',
|
||||
'addons/WebNavigationFrames.jsm',
|
||||
'addons/WebRequest.jsm',
|
||||
'addons/WebRequestCommon.jsm',
|
||||
'addons/WebRequestContent.js',
|
||||
'addons/WebRequestUpload.jsm',
|
||||
@@ -29,6 +28,7 @@ EXTRA_JS_MODULES += [
|
||||
'debug.js',
|
||||
'DeferredTask.jsm',
|
||||
'Deprecated.jsm',
|
||||
'ExtensionStorage.jsm',
|
||||
'FileUtils.jsm',
|
||||
'Finder.jsm',
|
||||
'FinderHighlighter.jsm',
|
||||
@@ -84,6 +84,7 @@ EXTRA_JS_MODULES.third_party.jsesc += ['third_party/jsesc/jsesc.js']
|
||||
EXTRA_JS_MODULES.sessionstore += ['sessionstore/Utils.jsm']
|
||||
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'addons/WebRequest.jsm',
|
||||
'NewTabUtils.jsm',
|
||||
'ResetProfile.jsm',
|
||||
'Troubleshoot.jsm',
|
||||
|
||||
@@ -152,6 +152,8 @@ setting[type="menulist"] {
|
||||
.addon:not([notification="info"]) .info,
|
||||
.addon:not([pending]) .pending,
|
||||
.addon:not([upgrade="true"]) .update-postfix,
|
||||
.addon:not([native="true"]) .nativeAddon,
|
||||
.addon:not([native="false"]) .compatAddon,
|
||||
.addon[active="true"] .disabled-postfix,
|
||||
.addon[pending="install"] .update-postfix,
|
||||
.addon[pending="install"] .disabled-postfix,
|
||||
@@ -264,6 +266,21 @@ richlistitem:not([selected]) * {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Indicator style for extension target application */
|
||||
.addon[native] .nativeIndicator {
|
||||
margin-left: 5pt;
|
||||
padding-bottom: 1pt;
|
||||
}
|
||||
.addon[native][active="false"] .nativeIndicator {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.addon[native] .nativeAddon {
|
||||
color: #3366FF;
|
||||
}
|
||||
.addon[native] .compatAddon {
|
||||
color: #FF6600;
|
||||
}
|
||||
|
||||
/* Translators for Language Pack details */
|
||||
.translators > label {
|
||||
-moz-margin-start: 0px;
|
||||
|
||||
@@ -3059,19 +3059,6 @@ var gDetailView = {
|
||||
warning.textContent =
|
||||
gStrings.ext.formatStringFromName("details.notification.gmpPending",
|
||||
[this._addon.name], 1);
|
||||
#ifdef MOZ_PHOENIX_EXTENSIONS
|
||||
} else if (this._addon.native == false) {
|
||||
this.node.setAttribute("notification", "warning");
|
||||
this.node.setAttribute("native", "false");
|
||||
document.getElementById("detail-warning").textContent = gStrings.ext.formatStringFromName(
|
||||
"details.notification.compatibility",
|
||||
[this._addon.name, gStrings.brandShortName], 2
|
||||
);
|
||||
var warningLink = document.getElementById("detail-warning-link");
|
||||
warningLink.value = gStrings.ext.GetStringFromName("details.notification.compatibility.link");
|
||||
warningLink.href = Services.urlFormatter.formatURLPref("extensions.compatibility.url");
|
||||
warningLink.hidden = false;
|
||||
#endif
|
||||
} else {
|
||||
this.node.removeAttribute("notification");
|
||||
}
|
||||
|
||||
@@ -857,6 +857,10 @@
|
||||
<xul:label anonid="name" class="name" crop="end" flex="1"
|
||||
xbl:inherits="value=name,tooltiptext=name"/>
|
||||
<xul:label anonid="version" class="version"/>
|
||||
#ifdef MOZ_PHOENIX_EXTENSIONS
|
||||
<xul:label class="nativeIndicator nativeAddon" value="●" tooltiptext="&addon.nativeAddon;"/>
|
||||
<xul:label class="nativeIndicator compatAddon" value="●" tooltiptext="&addon.compatAddon;"/>
|
||||
#endif
|
||||
<xul:label class="disabled-postfix" value="&addon.disabled.postfix;"/>
|
||||
<xul:label class="update-postfix" value="&addon.update.postfix;"/>
|
||||
<xul:spacer flex="5000"/> <!-- Necessary to make the name crop -->
|
||||
@@ -1355,20 +1359,8 @@
|
||||
} else {
|
||||
this.removeAttribute("notification");
|
||||
#ifdef MOZ_PHOENIX_EXTENSIONS
|
||||
if (this.mAddon.type == "extension") {
|
||||
if (this.mAddon.type == "extension")
|
||||
this.setAttribute("native", this.mAddon.native);
|
||||
if (this.mAddon.native == false) {
|
||||
this.setAttribute("notification", "warning");
|
||||
this._warning.textContent = gStrings.ext.formatStringFromName(
|
||||
"notification.compatibility",
|
||||
[this.mAddon.name, gStrings.brandShortName], 2
|
||||
);
|
||||
this._warningLink.value = gStrings.ext.GetStringFromName("notification.compatibility.link");
|
||||
this._warningLink.href = Services.urlFormatter.formatURLPref("extensions.compatibility.url");
|
||||
this._warningLink.hidden = false;
|
||||
this._warningBtn.hidden = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6472,8 +6472,8 @@ AddonInternal.prototype = {
|
||||
}
|
||||
else if (app.id == FIREFOX_ID) {
|
||||
version = FIREFOX_APPCOMPATVERSION;
|
||||
if (this.type != "extension")
|
||||
//Only allow extensions in Firefox compatibility mode
|
||||
if (this.type == "locale")
|
||||
//Never allow language packs in Firefox compatibility mode
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -6528,15 +6528,12 @@ AddonInternal.prototype = {
|
||||
app = targetApp;
|
||||
}
|
||||
#ifdef MOZ_PHOENIX_EXTENSIONS
|
||||
// Special case: check for Firefox TargetApps. this has to be done AFTER
|
||||
// the initial check to make sure appinfo.ID is preferred, even if
|
||||
// Firefox is listed before it in the install manifest.
|
||||
// Only do this for extensions. Other types should not be allowed.
|
||||
if (this.type == "extension") {
|
||||
for (let targetApp of this.targetApplications) {
|
||||
if (targetApp.id == FIREFOX_ID) //Firefox GUID
|
||||
return targetApp;
|
||||
}
|
||||
//Special case: check for Firefox TargetApps. this has to be done AFTER
|
||||
//the initial check to make sure appinfo.ID is preferred, even if
|
||||
//Firefox is listed before it in the install manifest.
|
||||
for (let targetApp of this.targetApplications) {
|
||||
if (targetApp.id == FIREFOX_ID) //Firefox GUID
|
||||
return targetApp;
|
||||
}
|
||||
#endif
|
||||
// Return toolkit ID if toolkit.
|
||||
|
||||
@@ -517,13 +517,6 @@
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.addon-view[notification="warning"][native="false"] {
|
||||
background-image: url("chrome://mozapps/skin/extensions/stripes-compatibility.png"),
|
||||
linear-gradient(rgba(255, 128, 0, 0.04),
|
||||
rgba(255, 128, 0, 0));
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.addon-view[notification="error"] {
|
||||
background-image: url("chrome://mozapps/skin/extensions/stripes-error.png"),
|
||||
linear-gradient(rgba(255, 0, 0, 0.04),
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -26,11 +26,6 @@ toolkit.jar:
|
||||
skin/classic/mozapps/extensions/themeGeneric.png (extensions/themeGeneric.png)
|
||||
skin/classic/mozapps/extensions/themeGeneric-16.png (extensions/themeGeneric-16.png)
|
||||
skin/classic/mozapps/extensions/localeGeneric.png (extensions/localeGeneric.png)
|
||||
skin/classic/mozapps/extensions/stripes-warning.png (extensions/stripes-warning.png)
|
||||
skin/classic/mozapps/extensions/stripes-compatibility.png (extensions/stripes-compatibility.png)
|
||||
skin/classic/mozapps/extensions/stripes-error.png (extensions/stripes-error.png)
|
||||
skin/classic/mozapps/extensions/stripes-info-positive.png (extensions/stripes-info-positive.png)
|
||||
skin/classic/mozapps/extensions/stripes-info-negative.png (extensions/stripes-info-negative.png)
|
||||
skin/classic/mozapps/extensions/newaddon.css (extensions/newaddon.css)
|
||||
skin/classic/mozapps/extensions/selectAddons.css (extensions/selectAddons.css)
|
||||
skin/classic/mozapps/xpinstall/xpinstallItemGeneric.png (extensions/extensionGeneric.png)
|
||||
|
||||
@@ -659,13 +659,6 @@
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.addon-view[notification="warning"][native="false"] {
|
||||
background-image: url("chrome://mozapps/skin/extensions/stripes-compatibility.png"),
|
||||
linear-gradient(rgba(255, 128, 0, 0.04),
|
||||
rgba(255, 128, 0, 0));
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.addon-view[notification="error"] {
|
||||
background-image: url("chrome://mozapps/skin/extensions/stripes-error.png"),
|
||||
linear-gradient(rgba(255, 0, 0, 0.04),
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -648,13 +648,6 @@
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.addon-view[notification="warning"][native="false"] {
|
||||
background-image: url("chrome://mozapps/skin/extensions/stripes-compatibility.png"),
|
||||
linear-gradient(rgba(255, 128, 0, 0.04),
|
||||
rgba(255, 128, 0, 0));
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.addon-view[notification="error"] {
|
||||
background-image: url("chrome://mozapps/skin/extensions/stripes-error.png"),
|
||||
linear-gradient(rgba(255, 0, 0, 0.04),
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -39,7 +39,6 @@ toolkit.jar:
|
||||
skin/classic/mozapps/extensions/heart.png (extensions/heart.png)
|
||||
skin/classic/mozapps/extensions/navigation.png (extensions/navigation.png)
|
||||
skin/classic/mozapps/extensions/stripes-warning.png (extensions/stripes-warning.png)
|
||||
skin/classic/mozapps/extensions/stripes-compatibility.png (extensions/stripes-compatibility.png)
|
||||
skin/classic/mozapps/extensions/stripes-error.png (extensions/stripes-error.png)
|
||||
skin/classic/mozapps/extensions/stripes-info-positive.png (extensions/stripes-info-positive.png)
|
||||
skin/classic/mozapps/extensions/stripes-info-negative.png (extensions/stripes-info-negative.png)
|
||||
|
||||
@@ -21,6 +21,9 @@ public:
|
||||
static bool OnYosemiteOrLater();
|
||||
static bool OnElCapitanOrLater();
|
||||
static bool OnSierraOrLater();
|
||||
static bool OnHighSierraOrLater();
|
||||
static bool OnMojaveOrLater();
|
||||
static bool OnCatalinaOrLater();
|
||||
|
||||
static bool IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix=0);
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#define MAC_OS_X_VERSION_10_10_HEX 0x000010A0
|
||||
#define MAC_OS_X_VERSION_10_11_HEX 0x000010B0
|
||||
#define MAC_OS_X_VERSION_10_12_HEX 0x000010C0
|
||||
#define MAC_OS_X_VERSION_10_13_HEX 0x000010D0
|
||||
#define MAC_OS_X_VERSION_10_14_HEX 0x000010E0
|
||||
#define MAC_OS_X_VERSION_10_15_HEX 0x000010F0
|
||||
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
@@ -167,6 +170,24 @@ nsCocoaFeatures::OnSierraOrLater()
|
||||
return (OSXVersion() >= MAC_OS_X_VERSION_10_12_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnHighSierraOrLater()
|
||||
{
|
||||
return (OSXVersion() >= MAC_OS_X_VERSION_10_13_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnMojaveOrLater()
|
||||
{
|
||||
return (OSXVersion() >= MAC_OS_X_VERSION_10_14_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnCatalinaOrLater()
|
||||
{
|
||||
return (OSXVersion() >= MAC_OS_X_VERSION_10_15_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
|
||||
{
|
||||
|
||||
@@ -810,15 +810,17 @@ NS_IMETHODIMP nsCocoaWindow::Show(bool bState)
|
||||
}
|
||||
}
|
||||
else if (mWindowType == eWindowType_popup) {
|
||||
// If a popup window is shown after being hidden, it needs to be "reset"
|
||||
// for it to receive any mouse events aside from mouse-moved events
|
||||
// (because it was removed from the "window cache" when it was hidden
|
||||
// -- see below). Setting the window number to -1 and then back to its
|
||||
// original value seems to accomplish this. The idea was "borrowed"
|
||||
// from the Java Embedding Plugin.
|
||||
NSInteger windowNumber = [mWindow windowNumber];
|
||||
[mWindow _setWindowNumber:-1];
|
||||
[mWindow _setWindowNumber:windowNumber];
|
||||
if (!nsCocoaFeatures::OnMojaveOrLater()) {
|
||||
// If a popup window is shown after being hidden, it needs to be "reset"
|
||||
// for it to receive any mouse events aside from mouse-moved events
|
||||
// (because it was removed from the "window cache" when it was hidden
|
||||
// -- see below). Setting the window number to -1 and then back to its
|
||||
// original value seems to accomplish this. The idea was "borrowed"
|
||||
// from the Java Embedding Plugin. This is fixed on macOS 10.14+.
|
||||
NSInteger windowNumber = [mWindow windowNumber];
|
||||
[mWindow _setWindowNumber:-1];
|
||||
[mWindow _setWindowNumber:windowNumber];
|
||||
}
|
||||
// For reasons that aren't yet clear, calls to [NSWindow orderFront:] or
|
||||
// [NSWindow makeKeyAndOrderFront:] can sometimes trigger "Error (1000)
|
||||
// creating CGSWindow", which in turn triggers an internal inconsistency
|
||||
@@ -951,17 +953,22 @@ NS_IMETHODIMP nsCocoaWindow::Show(bool bState)
|
||||
[nativeParentWindow removeChildWindow:mWindow];
|
||||
|
||||
[mWindow orderOut:nil];
|
||||
// Unless it's explicitly removed from NSApp's "window cache", a popup
|
||||
// window will keep receiving mouse-moved events even after it's been
|
||||
// "ordered out" (instead of the browser window that was underneath it,
|
||||
// until you click on that window). This is bmo bug 378645, but it's
|
||||
// surely an Apple bug. The "window cache" is an undocumented subsystem,
|
||||
// all of whose methods are included in the NSWindowCache category of
|
||||
// the NSApplication class (in header files generated using class-dump).
|
||||
// This workaround was "borrowed" from the Java Embedding Plugin (which
|
||||
// uses it for a different purpose).
|
||||
if (mWindowType == eWindowType_popup)
|
||||
[NSApp _removeWindowFromCache:mWindow];
|
||||
|
||||
if (!nsCocoaFeatures::OnMojaveOrLater()) {
|
||||
// Unless it's explicitly removed from NSApp's "window cache", a popup
|
||||
// window will keep receiving mouse-moved events even after it's been
|
||||
// "ordered out" (instead of the browser window that was underneath it,
|
||||
// until you click on that window). This is bmo bug 378645, but it's
|
||||
// surely an Apple bug. The "window cache" is an undocumented
|
||||
// subsystem, all of whose methods are included in the NSWindowCache
|
||||
// category of the NSApplication class (in header files generated using
|
||||
// class-dump). This workaround was "borrowed" from the Java Embedding
|
||||
// Plugin (which uses it for a different purpose). This is fixed on
|
||||
// macOS 10.14+.
|
||||
if (mWindowType == eWindowType_popup) {
|
||||
[NSApp _removeWindowFromCache:mWindow];
|
||||
}
|
||||
}
|
||||
|
||||
// If our popup window is a non-native context menu, tell the OS (and
|
||||
// other programs) that a menu has closed.
|
||||
|
||||