Merge mozilla-central to autoland. a=merge on a CLOSED TREE

--HG--
extra : rebase_source : 81b5f62e48ccbe6c941a80b72a4eebe0ed942ccf
This commit is contained in:
Daniel Varga 2018-11-29 11:59:02 +02:00
Родитель a2c7c837a5 e22c0d1520
Коммит d4b090ea42
37 изменённых файлов: 672 добавлений и 379 удалений

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

@ -1532,6 +1532,9 @@ pref("browser.contentblocking.allowlist.storage.enabled", true);
pref("dom.storage_access.enabled", true);
#endif
pref("dom.storage_access.auto_grants", true);
pref("dom.storage_access.max_concurrent_auto_grants", 5);
// Define a set of default features for the Content Blocking UI.
pref("browser.contentblocking.trackingprotection.control-center.ui.enabled", true);
pref("browser.contentblocking.rejecttrackers.control-center.ui.enabled", true);
@ -1795,3 +1798,5 @@ pref("prio.enabled", true);
pref("browser.discovery.enabled", false);
pref("browser.discovery.containers.enabled", true);
pref("browser.discovery.sites", "addons.mozilla.org");
pref("browser.engagement.recent_visited_origins.expiry", 86400); // 24 * 60 * 60 (24 hours in seconds)

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

@ -7,6 +7,7 @@
var EXPORTED_SYMBOLS = [
"BrowserUsageTelemetry",
"URICountListener",
"URLBAR_SELECTED_RESULT_TYPES",
"URLBAR_SELECTED_RESULT_METHODS",
"MINIMUM_TAB_COUNT_INTERVAL_MS",
@ -18,8 +19,14 @@ XPCOMUtils.defineLazyModuleGetters(this, {
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
SearchTelemetry: "resource:///modules/SearchTelemetry.jsm",
Services: "resource://gre/modules/Services.jsm",
setTimeout: "resource://gre/modules/Timer.jsm",
});
// This pref is in seconds!
XPCOMUtils.defineLazyPreferenceGetter(this,
"gRecentVisitedOriginsExpiry",
"browser.engagement.recent_visited_origins.expiry");
// The upper bound for the count of the visited unique domain names.
const MAX_UNIQUE_VISITED_DOMAINS = 100;
@ -128,6 +135,8 @@ function shouldRecordSearchCount(tabbrowser) {
let URICountListener = {
// A set containing the visited domains, see bug 1271310.
_domainSet: new Set(),
// A set containing the visited origins during the last 24 hours (similar to domains, but not quite the same)
_origin24hrSet: new Set(),
// A map to keep track of the URIs loaded from the restored tabs.
_restoredURIsMap: new WeakMap(),
@ -230,13 +239,26 @@ let URICountListener = {
// Unique domains should be aggregated by (eTLD + 1): x.test.com and y.test.com
// are counted once as test.com.
let baseDomain;
try {
// Even if only considering http(s) URIs, |getBaseDomain| could still throw
// due to the URI containing invalid characters or the domain actually being
// an ipv4 or ipv6 address.
this._domainSet.add(Services.eTLD.getBaseDomain(uri));
baseDomain = Services.eTLD.getBaseDomain(uri);
this._domainSet.add(baseDomain);
} catch (e) {
return;
baseDomain = uri.host;
}
// Record the origin, but with the base domain (eTLD + 1).
let baseDomainURI = uri.mutate()
.setHost(baseDomain)
.finalize();
this._origin24hrSet.add(baseDomainURI.prePath);
if (gRecentVisitedOriginsExpiry) {
setTimeout(() => {
this._origin24hrSet.delete(baseDomainURI.prePath);
}, gRecentVisitedOriginsExpiry * 1000);
}
Services.telemetry.scalarSet(UNIQUE_DOMAINS_COUNT_SCALAR_NAME, this._domainSet.size);
@ -249,6 +271,21 @@ let URICountListener = {
this._domainSet.clear();
},
/**
* Returns the number of unique origins visited in this session during the
* last 24 hours.
*/
get uniqueOriginsVisitedInPast24Hours() {
return this._origin24hrSet.size;
},
/**
* Resets the number of unique origins visited in this session.
*/
resetUniqueOriginsVisitedInPast24Hours() {
this._origin24hrSet.clear();
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference]),
};

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

@ -68,6 +68,8 @@ ChromeUtils.defineModuleGetter(this, "SitePermissions",
"resource:///modules/SitePermissions.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
ChromeUtils.defineModuleGetter(this, "URICountListener",
"resource:///modules/BrowserUsageTelemetry.jsm");
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
return Services.strings
@ -253,8 +255,12 @@ var PermissionPromptPrototype = {
* be called just before. Subclasses may want to override this
* in order to, for example, bump a counter Telemetry probe for
* how often a particular permission request is seen.
*
* If this returns false, it cancels the process of showing the prompt. In
* that case, it is the responsibility of the onBeforeShow() implementation
* to ensure that allow() or cancel() are called on the object appropriately.
*/
onBeforeShow() {},
onBeforeShow() { return true; },
/**
* If the prompt was shown to the user, this callback will be called just
@ -440,14 +446,15 @@ var PermissionPromptPrototype = {
return false;
};
this.onBeforeShow();
chromeWin.PopupNotifications.show(this.browser,
this.notificationID,
this.message,
this.anchorID,
mainAction,
secondaryActions,
options);
if (this.onBeforeShow() !== false) {
chromeWin.PopupNotifications.show(this.browser,
this.notificationID,
this.message,
this.anchorID,
mainAction,
secondaryActions,
options);
}
},
};
@ -590,6 +597,7 @@ GeolocationPermissionPrompt.prototype = {
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
const SHOW_REQUEST = Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST;
secHistogram.add(SHOW_REQUEST);
return true;
},
};
@ -826,9 +834,6 @@ MIDIPermissionPrompt.prototype = {
action: Ci.nsIPermissionManager.DENY_ACTION,
}];
},
onBeforeShow() {
},
};
PermissionUI.MIDIPermissionPrompt = MIDIPermissionPrompt;
@ -911,6 +916,7 @@ AutoplayPermissionPrompt.prototype = {
};
this.browser.addEventListener(
"DOMAudioPlaybackStarted", this.handlePlaybackStart);
return true;
},
};
@ -918,6 +924,11 @@ PermissionUI.AutoplayPermissionPrompt = AutoplayPermissionPrompt;
function StorageAccessPermissionPrompt(request) {
this.request = request;
XPCOMUtils.defineLazyPreferenceGetter(this, "_autoGrants",
"dom.storage_access.auto_grants");
XPCOMUtils.defineLazyPreferenceGetter(this, "_maxConcurrentAutoGrants",
"dom.storage_access.max_concurrent_auto_grants");
}
StorageAccessPermissionPrompt.prototype = {
@ -1008,6 +1019,38 @@ StorageAccessPermissionPrompt.prototype = {
get topLevelPrincipal() {
return this.request.topLevelPrincipal;
},
get maxConcurrentAutomaticGrants() {
// one percent of the number of top-levels origins visited in the current
// session (but not to exceed 24 hours), or the value of the
// dom.storage_access.max_concurrent_auto_grants preference, whichever is
// higher.
return Math.max(Math.max(Math.floor(URICountListener.uniqueOriginsVisitedInPast24Hours / 100),
this._maxConcurrentAutoGrants), 0);
},
getOriginsThirdPartyHasAccessTo(thirdPartyOrigin) {
let prefix = `3rdPartyStorage^${thirdPartyOrigin}`;
let perms = Services.perms.getAllWithTypePrefix(prefix);
let origins = new Set();
while (perms.length) {
let perm = perms.shift();
origins.add(perm.principal.origin);
}
return origins.size;
},
onBeforeShow() {
let thirdPartyOrigin = this.request.principal.origin;
if (this._autoGrants &&
this.getOriginsThirdPartyHasAccessTo(thirdPartyOrigin) <
this.maxConcurrentAutomaticGrants) {
// Automatically accept the prompt
this.allow({"storage-access": "allow-auto-grant"});
return false;
}
return true;
},
};
PermissionUI.StorageAccessPermissionPrompt = StorageAccessPermissionPrompt;

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

@ -39,6 +39,7 @@ run-if = crashreporter
[browser_UsageTelemetry_domains.js]
[browser_UsageTelemetry_private_and_restore.js]
skip-if = verify && debug
[browser_UsageTelemetry_uniqueOriginsVisitedInPast24Hours.js]
[browser_UsageTelemetry_urlbar.js]
support-files =
usageTelemetrySearchSuggestions.sjs

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

@ -294,6 +294,7 @@ add_task(async function test_on_before_show() {
promptActions: [mainAction],
onBeforeShow() {
beforeShown = true;
return true;
},
};
@ -353,6 +354,7 @@ add_task(async function test_no_request() {
promptActions: [mainAction, secondaryAction],
onBeforeShow() {
beforeShown = true;
return true;
},
};

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

@ -39,7 +39,9 @@ add_task(async function test_autoplay_permission_prompt() {
// Tests that AutoplayPermissionPrompt works as expected
add_task(async function test_storage_access_permission_prompt() {
Services.prefs.setBoolPref("dom.storage_access.auto_grants", false);
await testPrompt(PermissionUI.StorageAccessPermissionPrompt);
Services.prefs.clearUserPref("dom.storage_access.auto_grants");
});
async function testPrompt(Prompt) {

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

@ -0,0 +1,56 @@
/* eslint-disable mozilla/no-arbitrary-setTimeout */
/* 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";
ChromeUtils.defineModuleGetter(this, "URICountListener",
"resource:///modules/BrowserUsageTelemetry.jsm");
add_task(async function test_uniqueOriginsVisitedInPast24Hours() {
registerCleanupFunction(async () => {
info("Cleaning up");
URICountListener.resetUniqueOriginsVisitedInPast24Hours();
});
URICountListener.resetUniqueOriginsVisitedInPast24Hours();
let startingCount = URICountListener.uniqueOriginsVisitedInPast24Hours;
is(startingCount, 0, "We should have no origins recorded in the history right after resetting");
// Add a new window and then some tabs in it.
let win = await BrowserTestUtils.openNewBrowserWindow();
await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://example.com");
await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://test1.example.com");
is(URICountListener.uniqueOriginsVisitedInPast24Hours, startingCount + 1,
"test1.example.com should only count as a unique visit if example.com wasn't visited before");
// http://www.exämple.test
await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://xn--exmple-cua.test");
is(URICountListener.uniqueOriginsVisitedInPast24Hours, startingCount + 2,
"www.exämple.test should count as a unique visit");
// Set the expiry time to 1 second
await SpecialPowers.pushPrefEnv({set: [["browser.engagement.recent_visited_origins.expiry", 1]]});
await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://127.0.0.1");
is(URICountListener.uniqueOriginsVisitedInPast24Hours, startingCount + 3,
"127.0.0.1 should count as a unique visit");
let countBefore = URICountListener.uniqueOriginsVisitedInPast24Hours;
await new Promise(resolve => {
setTimeout(_ => {
let countAfter = URICountListener.uniqueOriginsVisitedInPast24Hours;
is(countAfter, countBefore - 1,
"The expiry should work correctly");
resolve();
}, 1100);
});
BrowserTestUtils.removeTab(win.gBrowser.selectedTab);
BrowserTestUtils.removeTab(win.gBrowser.selectedTab);
await BrowserTestUtils.closeWindow(win);
});

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

@ -36,6 +36,7 @@ function PageError(props) {
} = props;
const {
id: messageId,
executionPoint,
indent,
source,
type,
@ -58,6 +59,7 @@ function PageError(props) {
return Message({
dispatch,
messageId,
executionPoint,
isPaused,
open,
collapsible: Array.isArray(stacktrace),

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

@ -22,7 +22,6 @@
#include "mozilla/dom/Text.h"
#include "mozilla/gfx/Matrix.h"
#include "nsAtom.h"
#include "nsCSSFrameConstructor.h"
#include "nsDOMAttributeMap.h"
#include "nsIContentInlines.h"
#include "mozilla/dom/NodeInfo.h"

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

@ -19,12 +19,14 @@ StorageAccessPermissionRequest::StorageAccessPermissionRequest(
nsPIDOMWindowInner* aWindow,
nsIPrincipal* aNodePrincipal,
AllowCallback&& aAllowCallback,
AllowAutoGrantCallback&& aAllowAutoGrantCallback,
AllowAnySiteCallback&& aAllowAnySiteCallback,
CancelCallback&& aCancelCallback)
: ContentPermissionRequestBase(aNodePrincipal, false, aWindow,
NS_LITERAL_CSTRING("dom.storage_access"),
NS_LITERAL_CSTRING("storage-access")),
mAllowCallback(std::move(aAllowCallback)),
mAllowAutoGrantCallback(std::move(aAllowAutoGrantCallback)),
mAllowAnySiteCallback(std::move(aAllowAnySiteCallback)),
mCancelCallback(std::move(aCancelCallback)),
mCallbackCalled(false)
@ -61,6 +63,9 @@ StorageAccessPermissionRequest::Allow(JS::HandleValue aChoices)
if (choices.Length() == 1 &&
choices[0].choice().EqualsLiteral("allow-on-any-site")) {
mAllowAnySiteCallback();
} else if (choices.Length() == 1 &&
choices[0].choice().EqualsLiteral("allow-auto-grant")) {
mAllowAutoGrantCallback();
} else {
mAllowCallback();
}
@ -71,6 +76,7 @@ StorageAccessPermissionRequest::Allow(JS::HandleValue aChoices)
already_AddRefed<StorageAccessPermissionRequest>
StorageAccessPermissionRequest::Create(nsPIDOMWindowInner* aWindow,
AllowCallback&& aAllowCallback,
AllowAutoGrantCallback&& aAllowAutoGrantCallback,
AllowAnySiteCallback&& aAllowAnySiteCallback,
CancelCallback&& aCancelCallback)
{
@ -85,6 +91,7 @@ StorageAccessPermissionRequest::Create(nsPIDOMWindowInner* aWindow,
new StorageAccessPermissionRequest(aWindow,
win->GetPrincipal(),
std::move(aAllowCallback),
std::move(aAllowAutoGrantCallback),
std::move(aAllowAnySiteCallback),
std::move(aCancelCallback));
return request.forget();

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

@ -28,12 +28,14 @@ public:
NS_IMETHOD Allow(JS::HandleValue choices) override;
typedef std::function<void()> AllowCallback;
typedef std::function<void()> AllowAutoGrantCallback;
typedef std::function<void()> AllowAnySiteCallback;
typedef std::function<void()> CancelCallback;
static already_AddRefed<StorageAccessPermissionRequest> Create(
nsPIDOMWindowInner* aWindow,
AllowCallback&& aAllowCallback,
AllowAutoGrantCallback&& aAllowAutoGrantCallback,
AllowAnySiteCallback&& aAllowAnySiteCallback,
CancelCallback&& aCancelCallback);
@ -41,11 +43,13 @@ private:
StorageAccessPermissionRequest(nsPIDOMWindowInner* aWindow,
nsIPrincipal* aNodePrincipal,
AllowCallback&& aAllowCallback,
AllowAutoGrantCallback&& aAllowAutoGrantCallback,
AllowAnySiteCallback&& aAllowAnySiteCallback,
CancelCallback&& aCancelCallback);
~StorageAccessPermissionRequest();
AllowCallback mAllowCallback;
AllowAutoGrantCallback mAllowAutoGrantCallback;
AllowAnySiteCallback mAllowAnySiteCallback;
CancelCallback mCancelCallback;
nsTArray<PermissionRequest> mPermissionRequests;

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

@ -13988,9 +13988,11 @@ nsIDocument::RequestStorageAccess(mozilla::ErrorResult& aRv)
RefPtr<StorageAccessPermissionRequest> sapr =
StorageAccessPermissionRequest::Create(inner,
// Allow
[p] { p->Resolve(false, __func__); },
[p] { p->Resolve(AntiTrackingCommon::eAllow, __func__); },
// Allow auto grant
[p] { p->Resolve(AntiTrackingCommon::eAllowAutoGrant, __func__); },
// Allow on any site
[p] { p->Resolve(true, __func__); },
[p] { p->Resolve(AntiTrackingCommon::eAllowOnAnySite, __func__); },
// Block
[p] { p->Reject(false, __func__); });
@ -14011,7 +14013,8 @@ nsIDocument::RequestStorageAccess(mozilla::ErrorResult& aRv)
pr == PromptResult::Denied);
if (pr == PromptResult::Granted) {
return AntiTrackingCommon::StorageAccessFinalCheckPromise::
CreateAndResolve(onAnySite, __func__);
CreateAndResolve(onAnySite ? AntiTrackingCommon::eAllowOnAnySite :
AntiTrackingCommon::eAllow, __func__);
}
return AntiTrackingCommon::StorageAccessFinalCheckPromise::
CreateAndReject(false, __func__);

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

@ -7632,10 +7632,6 @@ nsGlobalWindowInner::GetSidebar(OwningExternalOrWindowProxy& aResult,
void
nsGlobalWindowInner::ClearDocumentDependentSlots(JSContext* aCx)
{
if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(GetWrapperPreserveColor())) {
MOZ_CRASH("Looks like bug 1488480/1405521, with ClearDocumentDependentSlots in a bogus compartment");
}
// If JSAPI OOMs here, there is basically nothing we can do to recover safely.
if (!Window_Binding::ClearCachedDocumentValue(aCx, this) ||
!Window_Binding::ClearCachedPerformanceValue(aCx, this)) {

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

@ -2886,9 +2886,6 @@ nsINode::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
if (!OwnerDoc()->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
!hasHadScriptHandlingObject &&
!nsContentUtils::IsSystemCaller(aCx)) {
if (IsDocument()) {
MOZ_CRASH("Looks like bug 1488480/1405521, with a document that lost its script handling object");
}
Throw(aCx, NS_ERROR_UNEXPECTED);
return nullptr;
}
@ -2897,9 +2894,6 @@ nsINode::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
MOZ_ASSERT_IF(obj && ChromeOnlyAccess(),
xpc::IsInContentXBLScope(obj) ||
!xpc::UseContentXBLScope(JS::GetObjectRealmOrNull(obj)));
if (!obj && IsDocument()) {
MOZ_CRASH("Looks like bug 1488480/1405521, with WrapNode on a document returning null");
}
return obj;
}

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

@ -689,48 +689,16 @@ DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
}
static inline bool
Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* spec)
{
bool ok = JS_DefineFunctions(cx, obj, spec);
if (ok) {
return true;
}
if (!strcmp(js::GetObjectClass(obj)->name, "DocumentPrototype")) {
MOZ_CRASH("Bug 1405521/1488480: JS_DefineFunctions failed for Document.prototype");
}
return false;
Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* spec) {
return JS_DefineFunctions(cx, obj, spec);
}
static inline bool
Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSPropertySpec* spec)
{
bool ok = JS_DefineProperties(cx, obj, spec);
if (ok) {
return true;
}
if (!strcmp(js::GetObjectClass(obj)->name, "DocumentPrototype")) {
MOZ_CRASH("Bug 1405521/1488480: JS_DefineProperties failed for Document.prototype");
}
return false;
Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSPropertySpec* spec) {
return JS_DefineProperties(cx, obj, spec);
}
static inline bool
Define(JSContext* cx, JS::Handle<JSObject*> obj, const ConstantSpec* spec)
{
bool ok = DefineConstants(cx, obj, spec);
if (ok) {
return true;
}
if (!strcmp(js::GetObjectClass(obj)->name, "DocumentPrototype")) {
MOZ_CRASH("Bug 1405521/1488480: DefineConstants failed for Document.prototype");
}
return false;
Define(JSContext* cx, JS::Handle<JSObject*> obj, const ConstantSpec* spec) {
return DefineConstants(cx, obj, spec);
}
template<typename T>
@ -966,13 +934,6 @@ CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
// properties go on the global itself.
(!isGlobal &&
!DefineProperties(cx, ourProto, properties, chromeOnlyProperties))) {
if (!strcmp(protoClass->name, "DocumentPrototype")) {
if (!ourProto) {
MOZ_CRASH("Bug 1405521/1488480: JS_NewObjectWithUniqueType failed for Document.prototype");
} else {
MOZ_CRASH("Bug 1405521/1488480: DefineProperties failed for Document.prototype");
}
}
return nullptr;
}
@ -980,18 +941,12 @@ CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
JS::Rooted<JSObject*> unscopableObj(cx,
JS_NewObjectWithGivenProto(cx, nullptr, nullptr));
if (!unscopableObj) {
if (!strcmp(protoClass->name, "DocumentPrototype")) {
MOZ_CRASH("Bug 1405521/1488480: Unscopable object creation failed for Document.prototype");
}
return nullptr;
}
for (; *unscopableNames; ++unscopableNames) {
if (!JS_DefineProperty(cx, unscopableObj, *unscopableNames,
JS::TrueHandleValue, JSPROP_ENUMERATE)) {
if (!strcmp(protoClass->name, "DocumentPrototype")) {
MOZ_CRASH("Bug 1405521/1488480: Defining property on unscopable object failed for Document.prototype");
}
return nullptr;
}
}
@ -1001,9 +956,6 @@ CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
// Readonly and non-enumerable to match Array.prototype.
if (!JS_DefinePropertyById(cx, ourProto, unscopableId, unscopableObj,
JSPROP_READONLY)) {
if (!strcmp(protoClass->name, "DocumentPrototype")) {
MOZ_CRASH("Bug 1405521/1488480: Defining @@unscopables failed for Document.prototype");
}
return nullptr;
}
}
@ -1012,9 +964,6 @@ CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
JS::Rooted<JSString*> toStringTagStr(cx,
JS_NewStringCopyZ(cx, toStringTag));
if (!toStringTagStr) {
if (!strcmp(protoClass->name, "DocumentPrototype")) {
MOZ_CRASH("Bug 1405521/1488480: Copying string tag failed for Document.prototype");
}
return nullptr;
}
@ -1022,9 +971,6 @@ CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::toStringTag)));
if (!JS_DefinePropertyById(cx, ourProto, toStringTagId, toStringTagStr,
JSPROP_READONLY)) {
if (!strcmp(protoClass->name, "DocumentPrototype")) {
MOZ_CRASH("Bug 1405521/1488480: Defining @@toStringTag failed for Document.prototype");
}
return nullptr;
}
}
@ -1129,9 +1075,6 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
isChrome ? chromeOnlyProperties : nullptr,
unscopableNames, toStringTag, isGlobal);
if (!proto) {
if (name && !strcmp(name, "Document")) {
MOZ_CRASH("Bug 1405521/1488480: CreateInterfacePrototypeObject failed for Document.prototype");
}
return;
}
@ -1150,9 +1093,6 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
isChrome,
defineOnGlobal);
if (!interface) {
if (name && !strcmp(name, "Document")) {
MOZ_CRASH("Bug 1405521/1488480: CreateInterfaceObject failed for Document");
}
if (protoCache) {
// If we fail we need to make sure to clear the value of protoCache we
// set above.
@ -4299,10 +4239,6 @@ GetPerInterfaceObjectHandle(JSContext* aCx,
/* Make sure our global is sane. Hopefully we can remove this sometime */
JSObject* global = JS::CurrentGlobalOrNull(aCx);
if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
if (aSlotId == prototypes::id::HTMLDocument ||
aSlotId == prototypes::id::Document) {
MOZ_CRASH("Looks like bug 1488480/1405521, with a non-DOM global in GetPerInterfaceObjectHandle");
}
return nullptr;
}
@ -4327,30 +4263,6 @@ GetPerInterfaceObjectHandle(JSContext* aCx,
const JS::Heap<JSObject*>& entrySlot =
protoAndIfaceCache.EntrySlotMustExist(aSlotId);
MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
if (!entrySlot) {
switch (aSlotId) {
case prototypes::id::HTMLDocument: {
MOZ_CRASH("Looks like bug 1488480/1405521, with aCreator failing to create HTMLDocument.prototype");
break;
}
case prototypes::id::Document: {
MOZ_CRASH("Looks like bug 1488480/1405521, with aCreator failing to create Document.prototype");
break;
}
case prototypes::id::Node: {
MOZ_CRASH("Looks like bug 1488480/1405521, with aCreator failing to create Node.prototype");
break;
}
case prototypes::id::EventTarget: {
MOZ_CRASH("Looks like bug 1488480/1405521, with aCreator failing to create EventTarget.prototype");
break;
}
default:
break;
}
}
return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
}

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

@ -2979,20 +2979,13 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
# if we don't need to create anything, why are we generating this?
assert needInterfaceObject or needInterfacePrototypeObject
def maybecrash(reason):
if self.descriptor.name == "Document":
return 'MOZ_CRASH("Bug 1405521/1488480: %s");\n' % reason
return ""
getParentProto = fill(
"""
JS::${type}<JSObject*> parentProto(${getParentProto});
if (!parentProto) {
$*{maybeCrash}
return;
}
""",
maybeCrash=maybecrash("Can't get Node.prototype"),
type=parentProtoType,
getParentProto=getParentProto)
@ -3000,11 +2993,9 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
"""
JS::${type}<JSObject*> constructorProto(${getConstructorProto});
if (!constructorProto) {
$*{maybeCrash}
return;
}
""",
maybeCrash=maybecrash("Can't get Node"),
type=constructorProtoType,
getConstructorProto=getConstructorProto)
@ -3020,12 +3011,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
for properties in idsToInit]
idsInitedFlag = CGGeneric("static bool sIdsInited = false;\n")
setFlag = CGGeneric("sIdsInited = true;\n")
initIdConditionals = [CGIfWrapper(CGGeneric(fill(
"""
$*{maybeCrash}
return;
""",
maybeCrash=maybecrash("Can't init IDs"))), call)
initIdConditionals = [CGIfWrapper(CGGeneric("return;\n"), call)
for call in initIdCalls]
initIds = CGList([idsInitedFlag,
CGIfWrapper(CGList(initIdConditionals + [setFlag]),
@ -3112,9 +3098,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
${name}, aDefineOnGlobal,
${unscopableNames},
${isGlobal});
if (protoCache && !*protoCache) {
$*{maybeCrash}
}
""",
protoClass=protoClass,
parentProto=parentProto,
@ -3129,8 +3112,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
chromeProperties=chromeProperties,
name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr",
unscopableNames="unscopableNames" if self.haveUnscopables else "nullptr",
isGlobal=toStringBool(isGlobal),
maybeCrash=maybecrash("dom::CreateInterfaceObjects failed for Document"))
isGlobal=toStringBool(isGlobal))
# If we fail after here, we must clear interface and prototype caches
# using this code: intermediate failure must not expose the interface in
@ -3232,12 +3214,10 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
JS::Rooted<JSObject*> holderProto(aCx, ${holderProto});
unforgeableHolder = JS_NewObjectWithoutMetadata(aCx, ${holderClass}, holderProto);
if (!unforgeableHolder) {
$*{maybeCrash}
$*{failureCode}
}
}
""",
maybeCrash=maybecrash("Can't create unforgeable holder"),
holderProto=holderProto,
holderClass=holderClass,
failureCode=failureCode))
@ -3522,7 +3502,7 @@ class CGConstructorEnabled(CGAbstractMethod):
return body.define()
def CreateBindingJSObject(descriptor, properties, failureCode = ""):
def CreateBindingJSObject(descriptor, properties):
objDecl = "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor.nativeType
# We don't always need to root obj, but there are a variety
@ -3547,14 +3527,12 @@ def CreateBindingJSObject(descriptor, properties, failureCode = ""):
"""
creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
""")
return objDecl + create + fill(
return objDecl + create + dedent(
"""
if (!aReflector) {
$*{failureCode}
return false;
}
""",
failureCode=failureCode)
""")
def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode,
@ -3573,22 +3551,12 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode,
unforgeables = []
if descriptor.name == "Document":
maybeCrash = dedent(
"""
MOZ_CRASH("Bug 1405521/1488480: Can't define unforgeable attributes");
""");
else:
maybeCrash = "";
defineUnforgeableAttrs = fill(
"""
if (!DefineUnforgeableAttributes(aCx, ${holderName}, %s)) {
$*{maybeCrash}
$*{failureCode}
}
""",
maybeCrash=maybeCrash,
failureCode=failureCode,
holderName=holderName)
defineUnforgeableMethods = fill(
@ -3734,15 +3702,14 @@ def SetImmutablePrototype(descriptor, failureCode):
failureCode=failureCode)
def DeclareProto(noProto = "", wrapFail = ""):
def DeclareProto():
"""
Declare the canonicalProto and proto we have for our wrapping operation.
"""
return fill(
return dedent(
"""
JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
if (!canonicalProto) {
$*{noProto}
return false;
}
JS::Rooted<JSObject*> proto(aCx);
@ -3753,16 +3720,13 @@ def DeclareProto(noProto = "", wrapFail = ""):
// to wrap the proto here.
if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
if (!JS_WrapObject(aCx, &proto)) {
$*{wrapFail}
return false;
}
}
} else {
proto = canonicalProto;
}
""",
noProto=noProto,
wrapFail=wrapFail)
""")
class CGWrapWithCacheMethod(CGAbstractMethod):
@ -3789,47 +3753,6 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
return false;
""")
isDocument = False
iface = self.descriptor.interface
while iface:
if iface.identifier.name == "Document":
isDocument = True
break
iface = iface.parent
if isDocument:
noGlobal = fill(
"""
MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} not having a global");
""",
name = self.descriptor.name)
noProto = fill(
"""
MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} not having a proto");
""",
name = self.descriptor.name)
protoWrapFail = fill(
"""
MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} failing to wrap a custom proto");
""",
name = self.descriptor.name)
createObjectFailed = fill(
"""
MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} failing to CreateObject/CreateProxyObject");
""",
name = self.descriptor.name)
expandoAllocFail = fill(
"""
MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} failing to EnsureExpandoObject or JS_InitializePropertiesFromCompatibleNativeObject");
""",
name = self.descriptor.name)
else:
noGlobal = ""
noProto = ""
protoWrapFail = ""
createObjectFailed = ""
expandoAllocFail = ""
return fill(
"""
static_assert(!IsBaseOf<NonRefcountedDOMObject, ${nativeType}>::value,
@ -3845,7 +3768,6 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
if (!global) {
$*{noGlobal}
return false;
}
MOZ_ASSERT(JS_IsGlobalObject(global));
@ -3886,14 +3808,11 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
return true;
""",
noGlobal=noGlobal,
nativeType=self.descriptor.nativeType,
assertInheritance=AssertInheritanceChain(self.descriptor),
declareProto=DeclareProto(noProto, protoWrapFail),
createObject=CreateBindingJSObject(self.descriptor, self.properties,
createObjectFailed),
declareProto=DeclareProto(),
createObject=CreateBindingJSObject(self.descriptor, self.properties),
unforgeable=CopyUnforgeablePropertiesToInstance(self.descriptor,
expandoAllocFail +
failureCode),
slots=InitMemberSlots(self.descriptor, failureCode),
setImmutablePrototype=SetImmutablePrototype(self.descriptor,

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

@ -203,11 +203,7 @@ ImageDocument::Init()
JSObject*
ImageDocument::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
JSObject* obj = ImageDocument_Binding::Wrap(aCx, this, aGivenProto);
if (!obj) {
MOZ_CRASH("Looks like bug 1488480/1405521, with ImageDocument::WrapNode failing");
}
return obj;
return ImageDocument_Binding::Wrap(aCx, this, aGivenProto);
}
nsresult

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

@ -203,11 +203,7 @@ NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsHTMLDocument,
JSObject*
nsHTMLDocument::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
JSObject* obj = HTMLDocument_Binding::Wrap(aCx, this, aGivenProto);
if (!obj) {
MOZ_CRASH("Looks like bug 1488480/1405521, with nsHTMLDocument::WrapNode failing");
}
return obj;
return HTMLDocument_Binding::Wrap(aCx, this, aGivenProto);
}
nsresult

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

@ -56,7 +56,6 @@
#include "mozilla/TouchEvents.h"
#include "mozilla/Unused.h"
#include "nsContentUtils.h"
#include "nsCSSFrameConstructor.h"
#include "nsDocShell.h"
#include "nsEmbedCID.h"
#include "nsGlobalWindow.h"

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

@ -4,7 +4,6 @@
* 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 "nsCSSFrameConstructor.h"
#include "nsTArray.h"
#include "nsString.h"
#include "nsIDocument.h"

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

@ -628,16 +628,11 @@ XMLDocument::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const
JSObject*
XMLDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
JSObject* obj;
if (mIsPlainDocument) {
obj = Document_Binding::Wrap(aCx, this, aGivenProto);
} else {
obj = XMLDocument_Binding::Wrap(aCx, this, aGivenProto);
return Document_Binding::Wrap(aCx, this, aGivenProto);
}
if (!obj) {
MOZ_CRASH("Looks like bug 1488480/1405521, with XMLDocument::WrapNode failing");
}
return obj;
return XMLDocument_Binding::Wrap(aCx, this, aGivenProto);
}
} // namespace dom

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

@ -1648,11 +1648,7 @@ XULDocument::DirectionChanged(const char* aPrefName, XULDocument* aDoc)
JSObject*
XULDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
JSObject* obj = XULDocument_Binding::Wrap(aCx, this, aGivenProto);
if (!obj) {
MOZ_CRASH("Looks like bug 1488480/1405521, with XULDocument_Binding::Wrap failing");
}
return obj;
return XULDocument_Binding::Wrap(aCx, this, aGivenProto);
}
} // namespace dom

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

@ -0,0 +1,38 @@
var verified = false;
function f(a) {
if (a < 10000)
return 5;
assertEq(g_fwd.caller.arguments.length, 0);
assertEq(h_fwd.caller.arguments.length, 0);
verified = true;
return 6;
}
function g_fwd(x) {
with({}) {};
return f(x);
}
function g(a) {
var x = a;
function inline() {
return g_fwd(x);
}
return inline();
}
function h_fwd(x) {
with({}) {};
return g(x);
}
function h(a) {
var x = a;
function inline() {
return h_fwd(x);
}
return inline();
}
var i = 0;
while (!verified) {
h(i++);
}

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

@ -1103,17 +1103,42 @@ JitRuntime::getBaselineDebugModeOSRHandlerAddress(JSContext* cx, bool popFrameRe
: baselineDebugModeOSRHandlerNoFrameRegPopAddr_.ref();
}
static void
PushCallVMOutputRegisters(MacroAssembler& masm)
{
// callVMs can use several different output registers, depending on the
// type of their outparam.
masm.push(ReturnReg);
masm.push(ReturnDoubleReg);
masm.Push(JSReturnOperand);
}
static void
PopCallVMOutputRegisters(MacroAssembler& masm)
{
masm.Pop(JSReturnOperand);
masm.pop(ReturnDoubleReg);
masm.pop(ReturnReg);
}
static void
TakeCallVMOutputRegisters(AllocatableGeneralRegisterSet& regs)
{
regs.take(ReturnReg);
regs.take(JSReturnOperand);
}
static void
EmitBaselineDebugModeOSRHandlerTail(MacroAssembler& masm, Register temp, bool returnFromCallVM)
{
// Save real return address on the stack temporarily.
//
// If we're returning from a callVM, we don't need to worry about R0 and
// R1 but do need to propagate the original ReturnReg value. Otherwise we
// need to worry about R0 and R1 but can clobber ReturnReg. Indeed, on
// x86, R1 contains ReturnReg.
// R1 but do need to propagate the registers the call might write to.
// Otherwise we need to worry about R0 and R1 but can clobber ReturnReg.
// Indeed, on x86, R1 contains ReturnReg.
if (returnFromCallVM) {
masm.push(ReturnReg);
PushCallVMOutputRegisters(masm);
} else {
masm.pushValue(Address(temp, offsetof(BaselineDebugModeOSRInfo, valueR0)));
masm.pushValue(Address(temp, offsetof(BaselineDebugModeOSRInfo, valueR1)));
@ -1130,7 +1155,7 @@ EmitBaselineDebugModeOSRHandlerTail(MacroAssembler& masm, Register temp, bool re
// Restore saved values.
AllocatableGeneralRegisterSet jumpRegs(GeneralRegisterSet::All());
if (returnFromCallVM) {
jumpRegs.take(ReturnReg);
TakeCallVMOutputRegisters(jumpRegs);
} else {
jumpRegs.take(R0);
jumpRegs.take(R1);
@ -1141,7 +1166,7 @@ EmitBaselineDebugModeOSRHandlerTail(MacroAssembler& masm, Register temp, bool re
masm.pop(target);
masm.pop(BaselineFrameReg);
if (returnFromCallVM) {
masm.pop(ReturnReg);
PopCallVMOutputRegisters(masm);
} else {
masm.popValue(R1);
masm.popValue(R0);
@ -1157,7 +1182,7 @@ JitRuntime::generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrame
AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
regs.take(BaselineFrameReg);
regs.take(ReturnReg);
TakeCallVMOutputRegisters(regs);
Register temp = regs.takeAny();
Register syncedStackStart = regs.takeAny();
@ -1170,7 +1195,7 @@ JitRuntime::generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrame
// Record the stack pointer for syncing.
masm.moveStackPtrTo(syncedStackStart);
masm.push(ReturnReg);
PushCallVMOutputRegisters(masm);
masm.push(BaselineFrameReg);
// Call a stub to fully initialize the info.
@ -1186,7 +1211,7 @@ JitRuntime::generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrame
// a callVM, and prepareCallVM in BaselineCompiler always fully syncs the
// stack.
masm.pop(BaselineFrameReg);
masm.pop(ReturnReg);
PopCallVMOutputRegisters(masm);
masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScratchValue()), temp);
masm.addToStackPtr(Address(temp, offsetof(BaselineDebugModeOSRInfo, stackAdjust)));

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

@ -1835,7 +1835,7 @@ jit::JitActivation::registerIonFrameRecovery(RInstructionResults&& results)
jit::RInstructionResults*
jit::JitActivation::maybeIonFrameRecovery(JitFrameLayout* fp)
{
for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); ) {
for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); it++) {
if (it->frame() == fp) {
return it;
}

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

@ -11030,13 +11030,6 @@ nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
}
}
bool
nsIFrame::IsSelected() const
{
return (GetContent() && GetContent()->IsSelectionDescendant()) ?
IsFrameSelected() : false;
}
bool
nsIFrame::IsStackingContext(EffectSet* aEffectSet,
const nsStyleDisplay* aStyleDisplay,

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

@ -3232,7 +3232,10 @@ public:
/**
* @returns true if this frame is selected.
*/
bool IsSelected() const;
bool IsSelected() const {
return (GetContent() && GetContent()->IsSelectionDescendant()) ?
IsFrameSelected() : false;
}
/**
* called to discover where this frame, or a parent frame has user-select style

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

@ -72,7 +72,7 @@ public:
// nsIFrame
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
const nsDisplayListSet& aLists) final;
void Init(nsIContent* aContent,
nsContainerFrame* aParent,
@ -80,7 +80,7 @@ public:
void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
nsresult GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor) override;
nsresult GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor) final;
nsresult CharacterDataChanged(const CharacterDataChangeInfo&) final;
@ -103,7 +103,7 @@ public:
GetContent()->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
}
}
nsIFrame* GetNextInFlowVirtual() const override { return GetNextInFlow(); }
nsIFrame* GetNextInFlowVirtual() const final { return GetNextInFlow(); }
nsTextFrame* GetNextInFlow() const
{
return mNextContinuation &&
@ -156,20 +156,20 @@ public:
return Style()->ShouldSuppressLineBreak();
}
void InvalidateFrame(uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) override;
void InvalidateFrame(uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) final;
void InvalidateFrameWithRect(const nsRect& aRect,
uint32_t aDisplayItemKey = 0,
bool aRebuildDisplayItems = true) override;
bool aRebuildDisplayItems = true) final;
#ifdef DEBUG_FRAME_DUMP
void List(FILE* out = stderr,
const char* aPrefix = "",
uint32_t aFlags = 0) const override;
nsresult GetFrameName(nsAString& aResult) const override;
uint32_t aFlags = 0) const final;
nsresult GetFrameName(nsAString& aResult) const final;
void ToCString(nsCString& aBuf, int32_t* aTotalContentLength) const;
#endif
ContentOffsets CalcContentOffsetsFromFramePoint(const nsPoint& aPoint) override;
ContentOffsets CalcContentOffsetsFromFramePoint(const nsPoint& aPoint) final;
ContentOffsets GetCharacterOffsetAtFramePoint(const nsPoint& aPoint);
/**
@ -187,24 +187,24 @@ public:
SelectionType aSelectionType);
FrameSearchResult PeekOffsetNoAmount(bool aForward,
int32_t* aOffset) override;
int32_t* aOffset) final;
FrameSearchResult
PeekOffsetCharacter(bool aForward,
int32_t* aOffset,
PeekOffsetCharacterOptions aOptions =
PeekOffsetCharacterOptions()) override;
PeekOffsetCharacterOptions()) final;
FrameSearchResult PeekOffsetWord(bool aForward,
bool aWordSelectEatSpace,
bool aIsKeyboardSelect,
int32_t* aOffset,
PeekWordState* aState) override;
PeekWordState* aState) final;
nsresult CheckVisibility(nsPresContext* aContext,
int32_t aStartIndex,
int32_t aEndIndex,
bool aRecurse,
bool* aFinished,
bool* _retval) override;
bool* _retval) final;
// Flags for aSetLengthFlags
enum
@ -217,27 +217,27 @@ public:
nsLineLayout* aLineLayout,
uint32_t aSetLengthFlags = 0);
nsresult GetOffsets(int32_t& start, int32_t& end) const override;
nsresult GetOffsets(int32_t& start, int32_t& end) const final;
void AdjustOffsetsForBidi(int32_t start, int32_t end) override;
void AdjustOffsetsForBidi(int32_t start, int32_t end) final;
nsresult GetPointFromOffset(int32_t inOffset, nsPoint* outPoint) override;
nsresult GetPointFromOffset(int32_t inOffset, nsPoint* outPoint) final;
nsresult GetCharacterRectsInRange(int32_t aInOffset,
int32_t aLength,
nsTArray<nsRect>& aRects) override;
nsTArray<nsRect>& aRects) final;
nsresult GetChildFrameContainingOffset(int32_t inContentOffset,
bool inHint,
int32_t* outFrameContentOffset,
nsIFrame** outChildFrame) override;
nsIFrame** outChildFrame) final;
bool IsVisibleInSelection(mozilla::dom::Selection* aSelection) override;
bool IsVisibleInSelection(mozilla::dom::Selection* aSelection) final;
bool IsEmpty() override;
bool IsSelfEmpty() override { return IsEmpty(); }
bool IsEmpty() final;
bool IsSelfEmpty() final { return IsEmpty(); }
nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const final;
bool HasSignificantTerminalNewline() const override;
bool HasSignificantTerminalNewline() const final;
/**
* Returns true if this text frame is logically adjacent to the end of the
@ -255,7 +255,7 @@ public:
}
#ifdef ACCESSIBILITY
mozilla::a11y::AccType AccessibleType() override;
mozilla::a11y::AccType AccessibleType() final;
#endif
float GetFontSizeInflation() const;
@ -266,9 +266,9 @@ public:
}
void SetFontSizeInflation(float aInflation);
void MarkIntrinsicISizesDirty() override;
nscoord GetMinISize(gfxContext* aRenderingContext) override;
nscoord GetPrefISize(gfxContext* aRenderingContext) override;
void MarkIntrinsicISizesDirty() final;
nscoord GetMinISize(gfxContext* aRenderingContext) final;
nscoord GetPrefISize(gfxContext* aRenderingContext) final;
void AddInlineMinISize(gfxContext* aRenderingContext,
InlineMinISizeData* aData) override;
void AddInlinePrefISize(gfxContext* aRenderingContext,
@ -280,16 +280,16 @@ public:
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
const mozilla::LogicalSize& aPadding,
ComputeSizeFlags aFlags) override;
nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const override;
ComputeSizeFlags aFlags) final;
nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const final;
nsresult GetPrefWidthTightBounds(gfxContext* aContext,
nscoord* aX,
nscoord* aXMost) override;
nscoord* aXMost) final;
void Reflow(nsPresContext* aPresContext,
ReflowOutput& aMetrics,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;
bool CanContinueTextRun() const override;
nsReflowStatus& aStatus) final;
bool CanContinueTextRun() const final;
// Method that is called for a text frame that is logically
// adjacent to the end of the line (i.e. followed only by empty text frames,
// placeholders or inlines containing such).
@ -307,7 +307,7 @@ public:
uint32_t aEndOffset = UINT32_MAX,
TextOffsetType aOffsetType = TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
TrailingWhitespace aTrimTrailingWhitespace =
TrailingWhitespace::TRIM_TRAILING_WHITESPACE) override;
TrailingWhitespace::TRIM_TRAILING_WHITESPACE) final;
nsOverflowAreas RecomputeOverflow(nsIFrame* aBlockFrame);
@ -544,7 +544,7 @@ public:
const nscolor* aDecorationOverrideColor,
PropertyProvider* aProvider);
nscolor GetCaretColorAt(int32_t aOffset) override;
nscolor GetCaretColorAt(int32_t aOffset) final;
int16_t GetSelectionStatus(int16_t* aSelectionFlags);
@ -655,14 +655,14 @@ public:
bool IsInitialLetterChild() const;
bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) final;
void AssignJustificationGaps(const mozilla::JustificationAssignment& aAssign);
mozilla::JustificationAssignment GetJustificationAssignment() const;
uint32_t CountGraphemeClusters() const;
bool HasAnyNoncollapsedCharacters() override;
bool HasAnyNoncollapsedCharacters() final;
/**
* Call this after you have manually changed the text node contents without
@ -704,7 +704,7 @@ protected:
* Return true if the frame is part of a Selection.
* Helper method to implement the public IsSelected() API.
*/
bool IsFrameSelected() const override;
bool IsFrameSelected() const final;
mozilla::UniquePtr<SelectionDetails> GetSelectionDetails();

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

@ -90,6 +90,7 @@
#include "nsSVGMaskFrame.h"
#include "nsTableCellFrame.h"
#include "nsTableColFrame.h"
#include "nsTextFrame.h"
#include "nsSliderFrame.h"
#include "ClientLayerManager.h"
#include "mozilla/layers/StackingContextHelper.h"
@ -9614,6 +9615,18 @@ nsCharClipDisplayItem::ComputeInvalidationRegion(
}
}
bool
nsCharClipDisplayItem::IsSelected() const
{
if (mIsFrameSelected.isNothing()) {
MOZ_ASSERT((nsTextFrame*)do_QueryFrame(mFrame));
auto* f = static_cast<nsTextFrame*>(mFrame);
mIsFrameSelected.emplace(f->IsSelected());
}
return mIsFrameSelected.value();
}
nsDisplayEffectsBase::nsDisplayEffectsBase(
nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,

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

@ -7798,14 +7798,7 @@ public:
: nullptr;
}
bool IsSelected() const
{
if (mIsFrameSelected.isNothing()) {
mIsFrameSelected.emplace(mFrame->IsSelected());
}
return mIsFrameSelected.value();
}
bool IsSelected() const;
// Lengths measured from the visual inline start and end sides
// (i.e. left and right respectively in horizontal writing modes,

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

@ -408,6 +408,89 @@ CompareBaseDomains(nsIURI* aTrackingURI,
nsCaseInsensitiveCStringComparator());
}
class TemporaryAccessGrantObserver final : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static void
Create(nsIPermissionManager* aPM,
nsIPrincipal* aPrincipal,
const nsACString& aType)
{
nsCOMPtr<nsITimer> timer;
RefPtr<TemporaryAccessGrantObserver> observer =
new TemporaryAccessGrantObserver(aPM, aPrincipal, aType);
nsresult rv =
NS_NewTimerWithObserver(getter_AddRefs(timer),
observer,
24 * 60 * 60 * 1000, // 24 hours
nsITimer::TYPE_ONE_SHOT);
if (NS_SUCCEEDED(rv)) {
observer->SetTimer(timer);
} else {
timer->Cancel();
}
}
void SetTimer(nsITimer* aTimer)
{
mTimer = aTimer;
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
}
}
private:
TemporaryAccessGrantObserver(nsIPermissionManager* aPM,
nsIPrincipal* aPrincipal,
const nsACString& aType)
: mPM(aPM)
, mPrincipal(aPrincipal)
, mType(aType)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Enforcing temporary access grant lifetimes can only be done in "
"the parent process");
}
~TemporaryAccessGrantObserver() = default;
private:
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsIPermissionManager> mPM;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCString mType;
};
NS_IMPL_ISUPPORTS(TemporaryAccessGrantObserver, nsIObserver)
NS_IMETHODIMP
TemporaryAccessGrantObserver::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC) == 0) {
Unused << mPM->RemoveFromPrincipal(mPrincipal, mType.get());
} else if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
}
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
}
return NS_OK;
}
} // anonymous
/* static */ RefPtr<AntiTrackingCommon::StorageAccessGrantPromise>
@ -439,11 +522,11 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipa
nsICookieService::BEHAVIOR_REJECT_TRACKER) {
LOG(("Disabled by network.cookie.cookieBehavior pref (%d), bailing out early",
StaticPrefs::network_cookie_cookieBehavior()));
return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
return StorageAccessGrantPromise::CreateAndResolve(eAllowOnAnySite, __func__);
}
if (CheckContentBlockingAllowList(aParentWindow)) {
return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
return StorageAccessGrantPromise::CreateAndResolve(eAllowOnAnySite, __func__);
}
nsCOMPtr<nsIPrincipal> topLevelStoragePrincipal;
@ -534,7 +617,7 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipa
auto storePermission = [pwin, parentWindow, origin, trackingOrigin,
trackingPrincipal, trackingURI, topInnerWindow,
topLevelStoragePrincipal, aReason]
(bool aAnySite) -> RefPtr<StorageAccessGrantPromise> {
(int aAllowMode) -> RefPtr<StorageAccessGrantPromise> {
NS_ConvertUTF16toUTF8 grantedOrigin(origin);
nsAutoCString permissionKey;
@ -562,11 +645,12 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipa
trackingPrincipal,
trackingOrigin,
grantedOrigin,
aAnySite)
aAllowMode)
->Then(GetCurrentThreadSerialEventTarget(), __func__,
[] (FirstPartyStorageAccessGrantPromise::ResolveOrRejectValue&& aValue) {
if (aValue.IsResolve()) {
return StorageAccessGrantPromise::CreateAndResolve(NS_SUCCEEDED(aValue.ResolveValue()), __func__);
return StorageAccessGrantPromise::CreateAndResolve(NS_SUCCEEDED(aValue.ResolveValue()) ?
eAllowOnAnySite : eAllow, __func__);
}
return StorageAccessGrantPromise::CreateAndReject(false, __func__);
});
@ -584,7 +668,7 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipa
IPC::Principal(trackingPrincipal),
trackingOrigin,
grantedOrigin,
aAnySite)
aAllowMode)
->Then(GetCurrentThreadSerialEventTarget(), __func__,
[] (const ContentChild::FirstPartyStorageAccessGrantedForOriginPromise::ResolveOrRejectValue& aValue) {
if (aValue.IsResolve()) {
@ -612,9 +696,12 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(n
nsIPrincipal* aTrackingPrincipal,
const nsCString& aTrackingOrigin,
const nsCString& aGrantedOrigin,
bool aAnySite)
int aAllowMode)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(aAllowMode == eAllow ||
aAllowMode == eAllowAutoGrant ||
aAllowMode == eAllowOnAnySite);
nsCOMPtr<nsIURI> parentPrincipalURI;
Unused << aParentPrincipal->GetURI(getter_AddRefs(parentPrincipalURI));
@ -640,7 +727,7 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(n
int64_t when = (PR_Now() / PR_USEC_PER_MSEC) + expirationTime;
nsresult rv;
if (aAnySite) {
if (aAllowMode == eAllowOnAnySite) {
uint32_t privateBrowsingId = 0;
rv = aTrackingPrincipal->GetPrivateBrowsingId(&privateBrowsingId);
if (!NS_WARN_IF(NS_FAILED(rv)) && privateBrowsingId > 0) {
@ -659,9 +746,11 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(n
} else {
uint32_t privateBrowsingId = 0;
rv = aParentPrincipal->GetPrivateBrowsingId(&privateBrowsingId);
if (!NS_WARN_IF(NS_FAILED(rv)) && privateBrowsingId > 0) {
// If we are coming from a private window, make sure to store a session-only
// permission which won't get persisted to disk.
if ((!NS_WARN_IF(NS_FAILED(rv)) && privateBrowsingId > 0) ||
(aAllowMode == eAllowAutoGrant)) {
// If we are coming from a private window or are automatically granting a
// permission, make sure to store a session-only permission which won't
// get persisted to disk.
expirationType = nsIPermissionManager::EXPIRE_SESSION;
when = 0;
}
@ -675,6 +764,11 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(n
rv = pm->AddFromPrincipal(aParentPrincipal, type.get(),
nsIPermissionManager::ALLOW_ACTION,
expirationType, when);
if (NS_SUCCEEDED(rv) && (aAllowMode == eAllowAutoGrant)) {
// Make sure temporary access grants do not survive more than 24 hours.
TemporaryAccessGrantObserver::Create(pm, aParentPrincipal, type);
}
}
Unused << NS_WARN_IF(NS_FAILED(rv));

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

@ -77,6 +77,12 @@ public:
eOpenerAfterUserInteraction,
eOpener
};
enum StorageAccessPromptChoices
{
eAllow,
eAllowAutoGrant,
eAllowOnAnySite
};
// Grant the permission for aOrigin to have access to the first party storage.
// This method can handle 2 different scenarios:
@ -93,9 +99,9 @@ public:
// Ex: example.net import tracker.com/script.js which does opens a popup and
// the user interacts with it. tracker.com is allowed when loaded by
// example.net.
typedef MozPromise<bool, bool, true> StorageAccessFinalCheckPromise;
typedef MozPromise<int, bool, true> StorageAccessFinalCheckPromise;
typedef std::function<RefPtr<StorageAccessFinalCheckPromise>()> PerformFinalChecks;
typedef MozPromise<bool, bool, true> StorageAccessGrantPromise;
typedef MozPromise<int, bool, true> StorageAccessGrantPromise;
static MOZ_MUST_USE RefPtr<StorageAccessGrantPromise>
AddFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal,
nsPIDOMWindowInner* aParentWindow,
@ -120,7 +126,7 @@ public:
nsIPrincipal* aTrackingPrinciapl,
const nsCString& aParentOrigin,
const nsCString& aGrantedOrigin,
bool aAnySite);
int aAllowMode);
enum ContentBlockingAllowListPurpose {
eStorageChecks,

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

@ -1,18 +1,30 @@
/* eslint-disable mozilla/no-arbitrary-setTimeout */
ChromeUtils.import("resource://gre/modules/Services.jsm");
const CHROME_BASE = "chrome://mochitests/content/browser/browser/modules/test/browser/";
Services.scriptloader.loadSubScript(CHROME_BASE + "head.js", this);
/* import-globals-from ../../../../../browser/modules/test/browser/head.js */
async function testDoorHanger(choice) {
info(`Running doorhanger test with choice #${choice}`);
const BLOCK = 0;
const ALLOW = 1;
const ALLOW_ON_ANY_SITE = 2;
async function testDoorHanger(choice, showPrompt, topPage, maxConcurrent) {
info(`Running doorhanger test with choice #${choice}, showPrompt: ${showPrompt} and ` +
`topPage: ${topPage}, maxConcurrent: ${maxConcurrent}`);
if (!showPrompt) {
is(choice, ALLOW, "When not showing a prompt, we can only auto-grant");
}
await SpecialPowers.flushPrefEnv();
await SpecialPowers.pushPrefEnv({"set": [
["browser.contentblocking.allowlist.annotations.enabled", true],
["browser.contentblocking.allowlist.storage.enabled", true],
[ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS],
["dom.storage_access.auto_grants", true],
["dom.storage_access.enabled", true],
["dom.storage_access.max_concurrent_auto_grants", maxConcurrent],
["dom.storage_access.prompt.testing", false],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
["privacy.trackingprotection.enabled", false],
@ -23,13 +35,17 @@ async function testDoorHanger(choice) {
await UrlClassifierTestUtils.addTestTrackers();
let tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE);
let tab = BrowserTestUtils.addTab(gBrowser, topPage);
gBrowser.selectedTab = tab;
let browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
async function runChecks() {
// We need to repeat this constant here since runChecks is stringified
// and sent to the content process.
const BLOCK = 0;
await new Promise(resolve => {
addEventListener("message", function onMessage(e) {
if (e.data.startsWith("choice:")) {
@ -61,7 +77,7 @@ async function testDoorHanger(choice) {
/* import-globals-from storageAccessAPIHelpers.js */
await callRequestStorageAccess();
if (choice == 0) {
if (choice == BLOCK) {
// We've said no, so cookies are still blocked
is(document.cookie, "", "Still no cookies for me");
document.cookie = "name=value";
@ -74,49 +90,55 @@ async function testDoorHanger(choice) {
}
}
let permChanged = TestUtils.topicObserved("perm-changed",
(subject, data) => {
let result;
if (choice == ALLOW) {
result = subject &&
subject.QueryInterface(Ci.nsIPermission)
.type.startsWith("3rdPartyStorage^") &&
subject.principal.origin == (new URL(topPage)).origin &&
data == "added";
} else if (choice == ALLOW_ON_ANY_SITE) {
result = subject &&
subject.QueryInterface(Ci.nsIPermission)
.type == "cookie" &&
subject.principal.origin == "https://tracking.example.org" &&
data == "added";
}
return result;
});
let shownPromise =
BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
shownPromise.then(async _ => {
let notification =
PopupNotifications.getNotification("storage-access", browser);
if (topPage != gBrowser.currentURI.spec) {
return;
}
ok(showPrompt, "We shouldn't show the prompt when we don't intend to");
let notification = await new Promise(function poll(resolve) {
let notification =
PopupNotifications.getNotification("storage-access", browser);
if (notification) {
resolve(notification);
return;
}
setTimeout(poll, 10);
});
Assert.ok(notification, "Should have gotten the notification");
let permChanged = TestUtils.topicObserved("perm-changed",
(subject, data) => {
let result;
if (choice == 1) {
result = subject &&
subject.QueryInterface(Ci.nsIPermission)
.type.startsWith("3rdPartyStorage^") &&
subject.principal.origin == "http://example.net" &&
data == "added";
} else if (choice == 2) {
result = subject &&
subject.QueryInterface(Ci.nsIPermission)
.type == "cookie" &&
subject.principal.origin == "https://tracking.example.org" &&
data == "added";
}
return result;
});
if (choice == 0) {
if (choice == BLOCK) {
await clickMainAction();
} else if (choice == 1) {
} else if (choice == ALLOW) {
await clickSecondaryAction(choice - 1);
} else if (choice == 2) {
} else if (choice == ALLOW_ON_ANY_SITE) {
await clickSecondaryAction(choice - 1);
}
if (choice != 0) {
if (choice != BLOCK) {
await permChanged;
}
});
let url;
if (choice == 2) {
url = TEST_3RD_PARTY_PAGE + "?disableWaitUntilPermission";
} else {
url = TEST_3RD_PARTY_PAGE;
}
let url = TEST_3RD_PARTY_PAGE + "?disableWaitUntilPermission";
let ct = ContentTask.spawn(browser,
{ page: url,
callback: runChecks.toString(),
@ -159,13 +181,114 @@ async function testDoorHanger(choice) {
ifr.src = obj.page;
});
});
await Promise.all([ct, shownPromise]);
if (showPrompt) {
await Promise.all([ct, shownPromise]);
} else {
await Promise.all([ct, permChanged]);
}
BrowserTestUtils.removeTab(tab);
UrlClassifierTestUtils.cleanupTestTrackers();
}
async function preparePermissionsFromOtherSites(topPage) {
info("Faking permissions from other sites");
let type = "3rdPartyStorage^https://tracking.example.org";
let permission = Services.perms.ALLOW_ACTION;
let expireType = Services.perms.EXPIRE_SESSION;
if (topPage == TEST_TOP_PAGE) {
// For the first page, don't do anything
} else if (topPage == TEST_TOP_PAGE_2) {
// For the second page, only add the permission from the first page
Services.perms.add(Services.io.newURI(TEST_DOMAIN),
type,
permission,
expireType,
0);
} else if (topPage == TEST_TOP_PAGE_3) {
// For the third page, add the permissions from the first two pages
Services.perms.add(Services.io.newURI(TEST_DOMAIN),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_2),
type,
permission,
expireType,
0);
} else if (topPage == TEST_TOP_PAGE_4) {
// For the fourth page, add the permissions from the first three pages
Services.perms.add(Services.io.newURI(TEST_DOMAIN),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_2),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_3),
type,
permission,
expireType,
0);
} else if (topPage == TEST_TOP_PAGE_5) {
// For the fifth page, add the permissions from the first four pages
Services.perms.add(Services.io.newURI(TEST_DOMAIN),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_2),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_3),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_4),
type,
permission,
expireType,
0);
} else if (topPage == TEST_TOP_PAGE_6) {
// For the sixth page, add the permissions from the first five pages
Services.perms.add(Services.io.newURI(TEST_DOMAIN),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_2),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_3),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_4),
type,
permission,
expireType,
0);
Services.perms.add(Services.io.newURI(TEST_DOMAIN_5),
type,
permission,
expireType,
0);
} else {
ok(false, "Unexpected top page: " + topPage);
}
}
async function cleanUp() {
info("Cleaning up.");
await new Promise(resolve => {
@ -173,13 +296,30 @@ async function cleanUp() {
});
}
async function runRound(n) {
await testDoorHanger(n);
async function runRound(topPage, showPrompt, maxConcurrent) {
if (showPrompt) {
await preparePermissionsFromOtherSites(topPage);
await testDoorHanger(BLOCK, showPrompt, topPage, maxConcurrent);
await cleanUp();
await preparePermissionsFromOtherSites(topPage);
await testDoorHanger(ALLOW, showPrompt, topPage, maxConcurrent);
await cleanUp();
await preparePermissionsFromOtherSites(topPage);
await testDoorHanger(ALLOW_ON_ANY_SITE, showPrompt, topPage, maxConcurrent);
} else {
await preparePermissionsFromOtherSites(topPage);
await testDoorHanger(ALLOW, showPrompt, topPage, maxConcurrent);
}
await cleanUp();
}
add_task(async function() {
await runRound(0);
await runRound(1);
await runRound(2);
await runRound(TEST_TOP_PAGE, false, 1);
await runRound(TEST_TOP_PAGE_2, true, 1);
await runRound(TEST_TOP_PAGE, false, 5);
await runRound(TEST_TOP_PAGE_2, false, 5);
await runRound(TEST_TOP_PAGE_3, false, 5);
await runRound(TEST_TOP_PAGE_4, false, 5);
await runRound(TEST_TOP_PAGE_5, false, 5);
await runRound(TEST_TOP_PAGE_6, true, 5);
});

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

@ -1,4 +1,9 @@
const TEST_DOMAIN = "http://example.net";
const TEST_DOMAIN_2 = "http://xn--exmple-cua.test";
const TEST_DOMAIN_3 = "https://xn--hxajbheg2az3al.xn--jxalpdlp";
const TEST_DOMAIN_4 = "http://prefixexample.com";
const TEST_DOMAIN_5 = "http://test";
const TEST_DOMAIN_6 = "http://mochi.test:8888";
const TEST_3RD_PARTY_DOMAIN = "https://tracking.example.org";
const TEST_3RD_PARTY_DOMAIN_TP = "https://tracking.example.com";
const TEST_4TH_PARTY_DOMAIN = "http://not-tracking.example.com";
@ -7,6 +12,11 @@ const TEST_ANOTHER_3RD_PARTY_DOMAIN = "https://another-tracking.example.net";
const TEST_PATH = "/browser/toolkit/components/antitracking/test/browser/";
const TEST_TOP_PAGE = TEST_DOMAIN + TEST_PATH + "page.html";
const TEST_TOP_PAGE_2 = TEST_DOMAIN_2 + TEST_PATH + "page.html";
const TEST_TOP_PAGE_3 = TEST_DOMAIN_3 + TEST_PATH + "page.html";
const TEST_TOP_PAGE_4 = TEST_DOMAIN_4 + TEST_PATH + "page.html";
const TEST_TOP_PAGE_5 = TEST_DOMAIN_5 + TEST_PATH + "page.html";
const TEST_TOP_PAGE_6 = TEST_DOMAIN_6 + TEST_PATH + "page.html";
const TEST_EMBEDDER_PAGE = TEST_DOMAIN + TEST_PATH + "embedder.html";
const TEST_POPUP_PAGE = TEST_DOMAIN + TEST_PATH + "popup.html";
const TEST_3RD_PARTY_PAGE = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdParty.html";

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

@ -172,12 +172,16 @@ ProcessMiddlemanCall(const char* aInputData, size_t aInputSize,
CallArguments arguments;
call->mArguments.CopyTo(&arguments);
bool skipCall;
{
MiddlemanCallContext cx(call, &arguments, MiddlemanCallPhase::MiddlemanInput);
redirection.mMiddlemanCall(cx);
skipCall = cx.mSkipCallInMiddleman;
}
RecordReplayInvokeCall(redirection.mBaseFunction, &arguments);
if (!skipCall) {
RecordReplayInvokeCall(redirection.mBaseFunction, &arguments);
}
{
MiddlemanCallContext cx(call, &arguments, MiddlemanCallPhase::MiddlemanOutput);

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

@ -172,6 +172,10 @@ struct MiddlemanCallContext
// divergence and associated rewind will occur.
bool mFailed;
// This can be set in the MiddlemanInput phase to avoid performing the call
// in the middleman process.
bool mSkipCallInMiddleman;
// During the ReplayInput phase, this can be used to fill in any middleman
// calls whose output the current one depends on.
InfallibleVector<MiddlemanCall*>* mDependentCalls;
@ -198,7 +202,8 @@ struct MiddlemanCallContext
MiddlemanCallContext(MiddlemanCall* aCall, CallArguments* aArguments, MiddlemanCallPhase aPhase)
: mCall(aCall), mArguments(aArguments), mPhase(aPhase),
mFailed(false), mDependentCalls(nullptr), mReplayOutputIsOld(false)
mFailed(false), mSkipCallInMiddleman(false),
mDependentCalls(nullptr), mReplayOutputIsOld(false)
{
switch (mPhase) {
case MiddlemanCallPhase::ReplayPreface:
@ -429,6 +434,15 @@ MM_StackArgumentData(MiddlemanCallContext& aCx)
}
}
// Avoid calling a function in the middleman process.
static inline void
MM_SkipInMiddleman(MiddlemanCallContext& aCx)
{
if (aCx.mPhase == MiddlemanCallPhase::MiddlemanInput) {
aCx.mSkipCallInMiddleman = true;
}
}
static inline void
MM_NoOp(MiddlemanCallContext& aCx)
{

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

@ -199,6 +199,7 @@ MM_ObjCInput(MiddlemanCallContext& aCx, id* aThingPtr)
// List of the Objective C classes which messages might be sent to directly.
static const char* gStaticClasses[] = {
// Standard classes.
"NSAutoreleasePool",
"NSBezierPath",
"NSButtonCell",
"NSColor",
@ -1131,31 +1132,23 @@ RR_objc_msgSend(Stream& aEvents, CallArguments* aArguments, ErrorType* aError)
}
}
static PreambleResult
MiddlemanPreamble_objc_msgSend(CallArguments* aArguments)
static void
MM_Alloc(MiddlemanCallContext& aCx)
{
auto obj = aArguments->Arg<0, id>();
auto message = aArguments->Arg<1, const char*>();
// Fake object value which allows null checks in the caller to pass.
static const size_t FakeId = 1;
// Ignore uses of NSAutoreleasePool after diverging from the recording.
// These are not performed in the middleman because the middleman has its
// own autorelease pool, and because the middleman can process calls from
// multiple threads which will cause these messages to behave differently.
// release messages are also ignored, as for CFRelease.
if ((!strcmp(message, "alloc") && obj == (id) objc_lookUpClass("NSAutoreleasePool")) ||
(!strcmp(message, "init") && obj == (id) FakeId) ||
!strcmp(message, "drain") ||
!strcmp(message, "release")) {
// Fake a return value in case the caller null checks it.
aArguments->Rval<size_t>() = 1;
return PreambleResult::Veto;
if (aCx.mPhase == MiddlemanCallPhase::MiddlemanInput) {
// Refuse to allocate NSAutoreleasePools in the middleman: the order in
// which middleman calls happen does not guarantee the pools will be
// created and released in LIFO order, as the pools require. Instead,
// allocate an NSString instead so we have something to release later.
// Messages sent to NSAutoreleasePools will all be skipped in the
// middleman, so no one should notice this subterfuge.
auto& obj = aCx.mArguments->Arg<0, id>();
if (obj == (id) objc_lookUpClass("NSAutoreleasePool")) {
obj = (id) objc_lookUpClass("NSString");
}
}
// Other messages will be handled by MM_objc_msgSend.
return PreambleResult::Redirect;
MM_CreateCFTypeRval(aCx);
}
static void
@ -1255,15 +1248,19 @@ struct ObjCMessageInfo
// arguments / return values.
static ObjCMessageInfo gObjCMiddlemanCallMessages[] = {
// Generic
{ "alloc", MM_CreateCFTypeRval },
{ "alloc", MM_Alloc },
{ "init", MM_AutoreleaseCFTypeRval },
{ "performSelector:withObject:", MM_PerformSelector },
{ "release", MM_SkipInMiddleman },
{ "respondsToSelector:", MM_CString<2> },
// NSAppearance
{ "_drawInRect:context:options:",
MM_Compose<MM_StackArgumentData<sizeof(CGRect)>, MM_CFTypeArg<2>, MM_CFTypeArg<3>> },
// NSAutoreleasePool
{ "drain", MM_SkipInMiddleman },
// NSArray
{ "count" },
{ "objectAtIndex:", MM_AutoreleaseCFTypeRval },
@ -2088,7 +2085,7 @@ static SystemRedirection gSystemRedirections[] = {
{ "objc_autoreleasePoolPop" },
{ "objc_autoreleasePoolPush", RR_ScalarRval },
{ "objc_msgSend",
RR_objc_msgSend, Preamble_objc_msgSend, MM_objc_msgSend, MiddlemanPreamble_objc_msgSend },
RR_objc_msgSend, Preamble_objc_msgSend, MM_objc_msgSend },
/////////////////////////////////////////////////////////////////////////////
// Cocoa and CoreFoundation library functions