Update On Thu Jun 16 20:31:13 CEST 2022

This commit is contained in:
github-action[bot] 2022-06-16 20:31:14 +02:00
parent df6f62ff91
commit b2b8c15115
548 changed files with 9615 additions and 6844 deletions

51
Cargo.lock generated
View file

@ -99,9 +99,9 @@ dependencies = [
[[package]]
name = "arbitrary"
version = "1.1.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490"
checksum = "4f7487a7cc86cea29c97c91007ad21294f9959949577b305ae118b8c11738ccf"
dependencies = [
"derive_arbitrary",
]
@ -805,9 +805,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.2.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613"
dependencies = [
"os_str_bytes",
]
@ -1363,9 +1363,9 @@ dependencies = [
[[package]]
name = "derive_arbitrary"
version = "1.1.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98e23c06c035dac87bd802d98f368df73a7f2cb05a66ffbd1f377e821fac4af9"
checksum = "91d001046c3cc126eb2ee9bdc946d9f482fe9e74d4a5ef191a6834fdbf84d45c"
dependencies = [
"proc-macro2",
"quote",
@ -2112,13 +2112,13 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
@ -2256,9 +2256,9 @@ dependencies = [
[[package]]
name = "glean"
version = "50.0.1"
version = "50.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea3a101f9b9ccffbbcb7fe5159aabc22f7a5b8a266a9a810abff92ffe4b7bfc1"
checksum = "0857be0c251ae1fc3b5672237c99f5115a6546cd8b171cb240173098ab5e9629"
dependencies = [
"chrono",
"crossbeam-channel",
@ -2276,9 +2276,9 @@ dependencies = [
[[package]]
name = "glean-core"
version = "50.0.1"
version = "50.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e474434da0bdd88a97e06b9b47cd2eaa419e3707c21fee02f5c4d66577f3360"
checksum = "f1bdfa0e2e6476190b4762c4cdc87c1a7a0347f601864b091cf9ad674a909c68"
dependencies = [
"android_logger",
"bincode",
@ -4584,9 +4584,9 @@ dependencies = [
[[package]]
name = "rust_decimal"
version = "1.24.0"
version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2ee7337df68898256ad0d4af4aad178210d9e44d2ff900ce44064a97cd86530"
checksum = "34a3bb58e85333f1ab191bf979104b586ebd77475bc6681882825f4532dfe87c"
dependencies = [
"arrayvec",
"num-traits",
@ -4705,9 +4705,9 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
[[package]]
name = "semver"
version = "1.0.9"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd"
checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c"
dependencies = [
"serde",
]
@ -5251,7 +5251,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"wasi 0.10.0+wasi-snapshot-preview999",
"winapi",
]
@ -5637,9 +5637,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-ident"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]]
name = "unicode-normalization"
@ -5843,9 +5843,16 @@ dependencies = [
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
version = "0.10.0+wasi-snapshot-preview999"
dependencies = [
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"

View file

@ -135,6 +135,9 @@ parking_lot = { path = "build/rust/parking_lot" }
# Override tinyvec with smallvec
tinyvec = { path = "build/rust/tinyvec" }
# Patch wasi 0.10 to 0.11
wasi = { path = "build/rust/wasi" }
# Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30
autocfg = { path = "third_party/rust/autocfg" }

View file

@ -9,6 +9,7 @@
#include "nsEventShell.h"
#include "DocAccessible.h"
#include "DocAccessibleChild.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "nsAccessibilityService.h"
#include "nsTextEquivUtils.h"
#ifdef A11Y_LOG
@ -307,6 +308,9 @@ void EventQueue::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
void EventQueue::ProcessEventQueue() {
// Process only currently queued events.
const nsTArray<RefPtr<AccEvent> > events = std::move(mEvents);
nsTArray<uint64_t> selectedIDs;
nsTArray<uint64_t> unselectedIDs;
uint32_t eventCount = events.Length();
#ifdef A11Y_LOG
if ((eventCount > 0 || mFocusEvent) && logging::IsEnabled(logging::eEvents)) {
@ -336,48 +340,81 @@ void EventQueue::ProcessEventQueue() {
for (uint32_t idx = 0; idx < eventCount; idx++) {
AccEvent* event = events[idx];
if (event->mEventRule != AccEvent::eDoNotEmit) {
LocalAccessible* target = event->GetAccessible();
if (!target || target->IsDefunct()) continue;
uint32_t eventType = event->mEventType;
LocalAccessible* target = event->GetAccessible();
if (!target || target->IsDefunct()) continue;
// Dispatch caret moved and text selection change events.
if (event->mEventType ==
nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) {
SelectionMgr()->ProcessTextSelChangeEvent(event);
continue;
}
// Fire selected state change events in support to selection events.
if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_ADD) {
nsEventShell::FireEvent(event->mAccessible, states::SELECTED, true,
event->mIsFromUserInput);
} else if (event->mEventType ==
nsIAccessibleEvent::EVENT_SELECTION_REMOVE) {
nsEventShell::FireEvent(event->mAccessible, states::SELECTED, false,
event->mIsFromUserInput);
} else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION) {
// Collect select changes
if (IPCAccessibilityActive() &&
StaticPrefs::accessibility_cache_enabled_AtStartup()) {
if ((event->mEventRule == AccEvent::eDoNotEmit &&
(eventType == nsIAccessibleEvent::EVENT_SELECTION_ADD ||
eventType == nsIAccessibleEvent::EVENT_SELECTION_REMOVE ||
eventType == nsIAccessibleEvent::EVENT_SELECTION)) ||
eventType == nsIAccessibleEvent::EVENT_SELECTION_WITHIN) {
// The selection even was either dropped or morphed to a
// selection-within. We need to collect the items from all these events
// and manually push their new state to the parent process.
AccSelChangeEvent* selChangeEvent = downcast_accEvent(event);
nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
(selChangeEvent->mSelChangeType ==
AccSelChangeEvent::eSelectionAdd),
event->mIsFromUserInput);
if (selChangeEvent->mPackedEvent) {
nsEventShell::FireEvent(
selChangeEvent->mPackedEvent->mAccessible, states::SELECTED,
(selChangeEvent->mPackedEvent->mSelChangeType ==
AccSelChangeEvent::eSelectionAdd),
selChangeEvent->mPackedEvent->mIsFromUserInput);
LocalAccessible* item = selChangeEvent->mItem;
uint64_t itemID =
item->IsDoc() ? 0 : reinterpret_cast<uint64_t>(item->UniqueID());
bool selected =
selChangeEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd;
if (selected) {
selectedIDs.AppendElement(itemID);
} else {
unselectedIDs.AppendElement(itemID);
}
}
nsEventShell::FireEvent(event);
}
if (event->mEventRule == AccEvent::eDoNotEmit) {
continue;
}
// Dispatch caret moved and text selection change events.
if (eventType == nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) {
SelectionMgr()->ProcessTextSelChangeEvent(event);
continue;
}
// Fire selected state change events in support to selection events.
if (eventType == nsIAccessibleEvent::EVENT_SELECTION_ADD) {
nsEventShell::FireEvent(event->mAccessible, states::SELECTED, true,
event->mIsFromUserInput);
} else if (eventType == nsIAccessibleEvent::EVENT_SELECTION_REMOVE) {
nsEventShell::FireEvent(event->mAccessible, states::SELECTED, false,
event->mIsFromUserInput);
} else if (eventType == nsIAccessibleEvent::EVENT_SELECTION) {
AccSelChangeEvent* selChangeEvent = downcast_accEvent(event);
nsEventShell::FireEvent(
event->mAccessible, states::SELECTED,
(selChangeEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
event->mIsFromUserInput);
if (selChangeEvent->mPackedEvent) {
nsEventShell::FireEvent(selChangeEvent->mPackedEvent->mAccessible,
states::SELECTED,
(selChangeEvent->mPackedEvent->mSelChangeType ==
AccSelChangeEvent::eSelectionAdd),
selChangeEvent->mPackedEvent->mIsFromUserInput);
}
}
nsEventShell::FireEvent(event);
if (!mDocument) return;
}
if (mDocument && IPCAccessibilityActive() &&
StaticPrefs::accessibility_cache_enabled_AtStartup() &&
(!selectedIDs.IsEmpty() || !unselectedIDs.IsEmpty())) {
DocAccessibleChild* ipcDoc = mDocument->IPCDoc();
ipcDoc->SendSelectedAccessiblesChanged(selectedIDs, unselectedIDs);
}
}
} // namespace a11y

View file

@ -97,6 +97,10 @@ bool Accessible::HasGenericType(AccGenericType aType) const {
(roleMapEntry && roleMapEntry->IsOfType(aType));
}
nsIntRect Accessible::BoundsInCSSPixels() const {
return BoundsInAppUnits().ToNearestPixels(AppUnitsPerCSSPixel());
}
LayoutDeviceIntSize Accessible::Size() const { return Bounds().Size(); }
LayoutDeviceIntPoint Accessible::Position(uint32_t aCoordType) {

View file

@ -197,6 +197,16 @@ class Accessible {
*/
virtual LayoutDeviceIntRect Bounds() const = 0;
/**
* Return boundaries in screen coordinates in app units.
*/
virtual nsRect BoundsInAppUnits() const = 0;
/**
* Return boundaries in screen coordinates in CSS pixels.
*/
virtual nsIntRect BoundsInCSSPixels() const;
/**
* Returns text of accessible if accessible has text role otherwise empty
* string.

View file

@ -789,10 +789,6 @@ LayoutDeviceIntRect LocalAccessible::Bounds() const {
BoundsInAppUnits(), mDoc->PresContext()->AppUnitsPerDevPixel());
}
nsIntRect LocalAccessible::BoundsInCSSPixels() const {
return BoundsInAppUnits().ToNearestPixels(AppUnitsPerCSSPixel());
}
void LocalAccessible::SetSelected(bool aSelect) {
if (!HasOwnContent()) return;

View file

@ -405,18 +405,10 @@ class LocalAccessible : public nsISupports, public Accessible {
virtual void AppendTextTo(nsAString& aText, uint32_t aStartOffset = 0,
uint32_t aLength = UINT32_MAX) override;
/**
* Return boundaries in screen coordinates in app units.
*/
virtual nsRect BoundsInAppUnits() const;
virtual nsRect BoundsInAppUnits() const override;
virtual LayoutDeviceIntRect Bounds() const override;
/**
* Return boundaries in screen coordinates in CSS pixels.
*/
virtual nsIntRect BoundsInCSSPixels() const;
/**
* Return boundaries rect relative the bounding frame.
*/

View file

@ -619,6 +619,41 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCache(
return IPC_OK();
}
mozilla::ipc::IPCResult DocAccessibleParent::RecvSelectedAccessiblesChanged(
nsTArray<uint64_t>&& aSelectedIDs, nsTArray<uint64_t>&& aUnselectedIDs) {
ACQUIRE_ANDROID_LOCK
if (mShutdown) {
return IPC_OK();
}
for (auto& id : aSelectedIDs) {
RemoteAccessible* remote = GetAccessible(id);
if (!remote) {
MOZ_ASSERT_UNREACHABLE("No remote found!");
continue;
}
remote->UpdateStateCache(states::SELECTED, true);
}
for (auto& id : aUnselectedIDs) {
RemoteAccessible* remote = GetAccessible(id);
if (!remote) {
MOZ_ASSERT_UNREACHABLE("No remote found!");
continue;
}
remote->UpdateStateCache(states::SELECTED, false);
}
if (nsCOMPtr<nsIObserverService> obsService =
services::GetObserverService()) {
obsService->NotifyObservers(nullptr, NS_ACCESSIBLE_CACHE_TOPIC, nullptr);
}
return IPC_OK();
}
mozilla::ipc::IPCResult DocAccessibleParent::RecvAccessiblesWillMove(
nsTArray<uint64_t>&& aIDs) {
for (uint64_t id : aIDs) {

View file

@ -138,6 +138,10 @@ class DocAccessibleParent : public RemoteAccessible,
const mozilla::a11y::CacheUpdateType& aUpdateType,
nsTArray<CacheData>&& aData, const bool& aFinal) override;
virtual mozilla::ipc::IPCResult RecvSelectedAccessiblesChanged(
nsTArray<uint64_t>&& aSelectedIDs,
nsTArray<uint64_t>&& aUnselectedIDs) override;
virtual mozilla::ipc::IPCResult RecvAccessiblesWillMove(
nsTArray<uint64_t>&& aIDs) override;

View file

@ -457,7 +457,7 @@ void RemoteAccessibleBase<Derived>::ApplyScrollOffset(nsRect& aBounds) const {
}
template <class Derived>
nsRect RemoteAccessibleBase<Derived>::GetBoundsInAppUnits() const {
nsRect RemoteAccessibleBase<Derived>::BoundsInAppUnits() const {
dom::CanonicalBrowsingContext* cbc =
static_cast<dom::BrowserParent*>(mDoc->Manager())
->GetBrowsingContext()

View file

@ -181,7 +181,7 @@ class RemoteAccessibleBase : public Accessible, public HyperTextAccessibleBase {
virtual LayoutDeviceIntRect Bounds() const override;
nsRect GetBoundsInAppUnits() const;
virtual nsRect BoundsInAppUnits() const override;
virtual uint64_t State() override;

View file

@ -202,7 +202,7 @@ Accessible* ChildAtPoint(
int32_t aX, int32_t aY,
LocalAccessible::EWhichChildAtPoint aWhichChild) override;
LayoutDeviceIntRect Bounds() const override;
nsIntRect BoundsInCSSPixels();
virtual nsIntRect BoundsInCSSPixels() const override;
void Language(nsString& aLocale);
void DocType(nsString& aType);

View file

@ -135,6 +135,11 @@ parent:
*/
async Cache(CacheUpdateType aUpdateType, CacheData[] aData, bool aFinal);
/*
* Lists of accessibles that either gained or lost a selected state.
*/
async SelectedAccessiblesChanged(uint64_t[] aSelectedIDs, uint64_t[] aUnselectedIDs);
/*
* Tell the parent process that the given Accessibles are about to be moved
* via subsequent hide and show events.

View file

@ -989,7 +989,11 @@ LayoutDeviceIntRect RemoteAccessible::Bounds() const {
return rect;
}
nsIntRect RemoteAccessible::BoundsInCSSPixels() {
nsIntRect RemoteAccessible::BoundsInCSSPixels() const {
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
return RemoteAccessibleBase<RemoteAccessible>::BoundsInCSSPixels();
}
nsIntRect rect;
Unused << mDoc->SendExtentsInCSSPixels(mID, &rect.x, &rect.y, &rect.width,
&rect.height);

View file

@ -102,6 +102,11 @@ parent:
*/
async Cache(CacheUpdateType aUpdateType, CacheData[] aData, bool aFinal);
/*
* Lists of accessibles that either gained or lost a selected state.
*/
async SelectedAccessiblesChanged(uint64_t[] aSelectedIDs, uint64_t[] aUnselectedIDs);
/*
* Tell the parent process that the given Accessibles are about to be moved
* via subsequent hide and show events.

View file

@ -252,7 +252,11 @@ LayoutDeviceIntRect RemoteAccessible::Bounds() const {
return rect;
}
nsIntRect RemoteAccessible::BoundsInCSSPixels() {
nsIntRect RemoteAccessible::BoundsInCSSPixels() const {
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
return RemoteAccessibleBase<RemoteAccessible>::BoundsInCSSPixels();
}
RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
if (!custom) {
return nsIntRect();

View file

@ -254,3 +254,46 @@ addAccessibleTask(
remoteIframe: !isWinNoCache,
}
);
// ////////////////////////////////////////////////////////////////////////
// multiselect with coalesced selection event
addAccessibleTask(
`<select id="listbox" size="4" multiple="true">
<option id="item1">option1</option>
<option id="item2">option2</option>
<option id="item3">option3</option>
<option id="item4">option4</option>
<option id="item5">option5</option>
<option id="item6">option6</option>
<option id="item7">option7</option>
<option id="item8">option8</option>
<option id="item9">option9</option>
</select>`,
async function(browser, docAcc) {
info("select@size='4' multiselect with coalesced selection event");
let select = findAccessibleChildByID(docAcc, "listbox", [
nsIAccessibleSelectable,
]);
await testMultiSelectable(
select,
[
"item1",
"item2",
"item3",
"item4",
"item5",
"item6",
"item7",
"item8",
"item9",
],
"select@size='4' multiselect with coalesced selection event "
);
},
{
chrome: false,
topLevel: true,
iframe: false,
remoteIframe: false,
}
);

View file

@ -65,30 +65,25 @@ async function testMultiSelectable(widget, selectableChildren, msg = "") {
promise = multipleSelectionChanged(widget, selectableChildren, true);
let success = widget.selectAll();
ok(success, `${msg}: selectAll success`);
let coalesced = await promise;
if (isRemote && coalesced && isCacheEnabled) {
todo_is(
widget.selectedItemCount,
await promise;
if (isRemote && isCacheEnabled) {
await untilCacheIs(
() => widget.selectedItemCount,
selectableChildren.length,
"Bug 1755377: Coalesced SELECTION_WITHIN doesn't update cache"
"Selection cache updated"
);
// We bail early here because the cache is out of sync.
return;
}
testSelectableSelection(widget, selectableChildren, `${msg}: selectAll`);
promise = multipleSelectionChanged(widget, selectableChildren, false);
widget.unselectAll();
coalesced = await promise;
if (isRemote && coalesced && isCacheEnabled) {
todo_is(
widget.selectedItemCount,
await promise;
if (isRemote && isCacheEnabled) {
await untilCacheIs(
() => widget.selectedItemCount,
0,
"Coalesced SELECTION_WITHIN doesn't update cache"
"Selection cache updated"
);
// We bail early here because the cache is out of sync.
return;
}
testSelectableSelection(widget, [], `${msg}: selectAll`);
}

View file

@ -435,13 +435,7 @@ xpcAccessible::GetBounds(int32_t* aX, int32_t* aY, int32_t* aWidth,
if (!IntlGeneric()) return NS_ERROR_FAILURE;
LayoutDeviceIntRect rect;
if (LocalAccessible* acc = IntlGeneric()->AsLocal()) {
rect = acc->Bounds();
} else {
rect = IntlGeneric()->AsRemote()->Bounds();
}
LayoutDeviceIntRect rect = IntlGeneric()->Bounds();
rect.GetRect(aX, aY, aWidth, aHeight);
return NS_OK;
}
@ -462,13 +456,7 @@ xpcAccessible::GetBoundsInCSSPixels(int32_t* aX, int32_t* aY, int32_t* aWidth,
return NS_ERROR_FAILURE;
}
nsIntRect rect;
if (LocalAccessible* acc = IntlGeneric()->AsLocal()) {
rect = acc->BoundsInCSSPixels();
} else {
rect = IntlGeneric()->AsRemote()->BoundsInCSSPixels();
}
nsIntRect rect = IntlGeneric()->BoundsInCSSPixels();
rect.GetRect(aX, aY, aWidth, aHeight);
return NS_OK;
}

View file

@ -27,9 +27,6 @@ class AboutPrivateBrowsingChild extends RemotePageChild {
super.actorCreated();
let window = this.contentWindow;
Cu.exportFunction(this.PrivateBrowsingFeatureConfig.bind(this), window, {
defineAs: "PrivateBrowsingFeatureConfig",
});
Cu.exportFunction(this.PrivateBrowsingRecordClick.bind(this), window, {
defineAs: "PrivateBrowsingRecordClick",
});
@ -48,10 +45,9 @@ class AboutPrivateBrowsingChild extends RemotePageChild {
}
PrivateBrowsingRecordClick(source) {
const experiment =
lazy.ExperimentAPI.getExperimentMetaData({
featureId: "privatebrowsing",
}) || lazy.ExperimentAPI.getExperimentMetaData({ featureId: "pbNewtab" });
const experiment = lazy.ExperimentAPI.getExperimentMetaData({
featureId: "pbNewtab",
});
if (experiment) {
Services.telemetry.recordEvent("aboutprivatebrowsing", "click", source);
}
@ -66,19 +62,4 @@ class AboutPrivateBrowsingChild extends RemotePageChild {
PrivateBrowsingExposureTelemetry() {
lazy.NimbusFeatures.pbNewtab.recordExposureEvent({ once: false });
}
PrivateBrowsingFeatureConfig() {
const config = lazy.NimbusFeatures.privatebrowsing.getAllVariables() || {};
lazy.NimbusFeatures.privatebrowsing.recordExposureEvent();
// Format urls if any are defined
["infoLinkUrl", "promoLinkUrl"].forEach(key => {
if (config[key]) {
config[key] = Services.urlFormatter.formatURL(config[key]);
}
});
return Cu.cloneInto(config, this.contentWindow);
}
}

View file

@ -4,8 +4,6 @@
"use strict";
Cu.importGlobalProperties(["fetch"]);
var EXPORTED_SYMBOLS = ["AboutProtectionsParent"];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"

View file

@ -115,6 +115,8 @@ class ClickHandlerParent extends JSWindowActorParent {
csp: data.csp ? lazy.E10SUtils.deserializeCSP(data.csp) : null,
frameID: data.frameID,
openerBrowser: browser,
// The child ensures that untrusted events have a valid user activation.
hasValidUserGestureActivation: true,
};
// The new tab/window must use the same userContextId.

View file

@ -1011,9 +1011,6 @@ pref("plugins.show_infobar", false);
pref("plugin.default.state", 1);
#endif
// Enables the download and use of the flash blocklists.
pref("plugins.flashBlock.enabled", true);
// Prefer HTML5 video over Flash content, and don't
// load plugin instances with no src declared.
// These prefs are documented in details on all.js.
@ -1223,8 +1220,6 @@ pref("browser.bookmarks.editDialog.maxRecentFolders", 7);
// just save on Accept, once the project is complete.
pref("browser.bookmarks.editDialog.delayedApply.enabled", false);
pref("dom.ipc.shims.enabledWarnings", false);
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
// This controls the strength of the Windows content process sandbox for
// testing purposes. This will require a restart.
@ -1609,6 +1604,8 @@ pref("browser.aboutwelcome.enabled", true);
// Used to set multistage welcome UX
pref("browser.aboutwelcome.screens", "");
pref("browser.aboutwelcome.skipFocus", true);
// Used to enable template for MR 2022 Onboarding
pref("browser.aboutwelcome.templateMR", false);
// The pref that controls if the What's New panel is enabled.
pref("browser.messaging-system.whatsNewPanel.enabled", true);

View file

@ -176,8 +176,8 @@ panelview[mainview] > .panel-header {
}
#tabbrowser-tabs[hasadjacentnewtabbutton]:not([overflow="true"]) ~ #new-tab-button,
#tabbrowser-tabs[overflow="true"] > #tabbrowser-arrowscrollbox > #tabs-newtab-button,
#tabbrowser-tabs:not([hasadjacentnewtabbutton]) > #tabbrowser-arrowscrollbox > #tabs-newtab-button,
#tabbrowser-tabs[overflow="true"] > #tabbrowser-arrowscrollbox > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button,
#tabbrowser-tabs:not([hasadjacentnewtabbutton]) > #tabbrowser-arrowscrollbox > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button,
#TabsToolbar[customizing="true"] #tabs-newtab-button {
display: none;
}

View file

@ -1508,11 +1508,13 @@ function _loadURI(browser, uri, params = {}) {
userContextId,
csp,
remoteTypeOverride,
hasValidUserGestureActivation,
} = params || {};
let loadFlags =
params.loadFlags || params.flags || Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
let hasValidUserGestureActivation =
hasValidUserGestureActivation ??=
document.hasValidTransientUserGestureActivation;
if (!triggeringPrincipal) {
throw new Error("Must load with a triggering Principal");
}
@ -2245,7 +2247,7 @@ var gBrowserInit = {
});
} catch (e) {}
} else if (window.arguments.length >= 3) {
// window.arguments[1]: unused (bug 871161)
// window.arguments[1]: extraOptions (nsIPropertyBag)
// [2]: referrerInfo (nsIReferrerInfo)
// [3]: postData (nsIInputStream)
// [4]: allowThirdPartyFixup (bool)
@ -2260,23 +2262,50 @@ var gBrowserInit = {
window.arguments[5] != undefined
? window.arguments[5]
: Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
loadURI(
uriToLoad,
window.arguments[2] || null,
window.arguments[3] || null,
window.arguments[4] || false,
userContextId,
// pass the origin principal (if any) and force its use to create
// an initial about:blank viewer if present:
window.arguments[6],
window.arguments[7],
!!window.arguments[6],
window.arguments[8],
// TODO fix allowInheritPrincipal to default to false.
// Default to true unless explicitly set to false because of bug 1475201.
window.arguments[9] !== false,
window.arguments[10]
);
let hasValidUserGestureActivation = undefined;
let fromExternal = undefined;
if (window.arguments[1]) {
if (!(window.arguments[1] instanceof Ci.nsIPropertyBag2)) {
throw new Error(
"window.arguments[1] must be null or Ci.nsIPropertyBag2!"
);
}
let extraOptions = window.arguments[1];
if (extraOptions.hasKey("hasValidUserGestureActivation")) {
hasValidUserGestureActivation = extraOptions.getPropertyAsBool(
"hasValidUserGestureActivation"
);
}
if (extraOptions.hasKey("fromExternal")) {
fromExternal = extraOptions.getPropertyAsBool("fromExternal");
}
}
try {
openLinkIn(uriToLoad, "current", {
referrerInfo: window.arguments[2] || null,
postData: window.arguments[3] || null,
allowThirdPartyFixup: window.arguments[4] || false,
userContextId,
// pass the origin principal (if any) and force its use to create
// an initial about:blank viewer if present:
originPrincipal: window.arguments[6],
originStoragePrincipal: window.arguments[7],
triggeringPrincipal: window.arguments[8],
// TODO fix allowInheritPrincipal to default to false.
// Default to true unless explicitly set to false because of bug 1475201.
allowInheritPrincipal: window.arguments[9] !== false,
csp: window.arguments[10],
forceAboutBlankViewerInCurrent: !!window.arguments[6],
hasValidUserGestureActivation,
fromExternal,
});
} catch (e) {
Cu.reportError(e);
}
window.focus();
} else {
// Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
@ -6272,13 +6301,18 @@ nsBrowserAccess.prototype = {
// Pass all params to openDialog to ensure that "url" isn't passed through
// loadOneOrMoreURIs, which splits based on "|"
try {
let extraOptions = Cc[
"@mozilla.org/hash-property-bag;1"
].createInstance(Ci.nsIWritablePropertyBag2);
extraOptions.setPropertyAsBool("fromExternal", isExternal);
openDialog(
AppConstants.BROWSER_CHROME_URL,
"_blank",
features,
// window.arguments
url,
null,
extraOptions,
null,
null,
null,

View file

@ -55,12 +55,15 @@
# the current structure that we may want to revisit.
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" style="min-width: 1px;" clicktoscroll="true" scrolledtostart="true" scrolledtoend="true">
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="true" visuallyselected="true" fadein="true"/>
<toolbarbutton id="tabs-newtab-button"
class="toolbarbutton-1"
command="cmd_newNavigatorTab"
onclick="checkForMiddleClick(this, event);"
tooltip="dynamic-shortcut-tooltip"/>
<spacer class="closing-tabs-spacer" style="width: 0;"/>
<hbox id="tabbrowser-arrowscrollbox-periphery">
<toolbartabstop/>
<toolbarbutton id="tabs-newtab-button"
class="toolbarbutton-1"
command="cmd_newNavigatorTab"
onclick="checkForMiddleClick(this, event);"
tooltip="dynamic-shortcut-tooltip"/>
<spacer class="closing-tabs-spacer" style="width: 0;"/>
</hbox>
</arrowscrollbox>
<html:span id="tabbrowser-tab-a11y-desc" hidden="true"/>
</tabs>

View file

@ -1309,6 +1309,7 @@ class nsContextMenu {
triggeringPrincipal: this.principal,
csp: this.csp,
frameID: this.contentData.frameID,
hasValidUserGestureActivation: true,
};
for (let p in extra) {
params[p] = extra[p];

View file

@ -1012,12 +1012,11 @@
return this.querySelector("#tabs-newtab-button");
}
// Accessor for tabs. arrowScrollbox has two non-tab elements at the
// end, everything else is <tab>s
// Accessor for tabs. arrowScrollbox has a container for non-tab elements
// at the end, everything else is <tab>s.
get allTabs() {
let children = Array.from(this.arrowScrollbox.children);
children.pop();
children.pop();
return children;
}
@ -1032,8 +1031,8 @@
let { arrowScrollbox } = this;
if (node == null) {
// we have a toolbarbutton and a space at the end of the scrollbox
node = arrowScrollbox.lastChild.previousSibling;
// We have a container for non-tab elements at the end of the scrollbox.
node = arrowScrollbox.lastChild;
}
return arrowScrollbox.insertBefore(tab, node);
}

View file

@ -84,7 +84,7 @@ tabpanels {
pointer-events: none;
}
#tabbrowser-arrowscrollbox:not(:hover) > .closing-tabs-spacer {
#tabbrowser-arrowscrollbox:not(:hover) > #tabbrowser-arrowscrollbox-periphery > .closing-tabs-spacer {
transition: width .15s ease-out;
}

View file

@ -409,12 +409,17 @@ function openLinkIn(url, where, params) {
);
wuri.data = url;
let charset = null;
if (aCharset) {
charset = Cc["@mozilla.org/supports-string;1"].createInstance(
Ci.nsISupportsString
let extraOptions = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
Ci.nsIWritablePropertyBag2
);
if (params.hasValidUserGestureActivation !== undefined) {
extraOptions.setPropertyAsBool(
"hasValidUserGestureActivation",
params.hasValidUserGestureActivation
);
charset.data = "charset=" + aCharset;
}
if (params.fromExternal !== undefined) {
extraOptions.setPropertyAsBool("fromExternal", params.fromExternal);
}
var allowThirdPartyFixupSupports = Cc[
@ -428,7 +433,7 @@ function openLinkIn(url, where, params) {
userContextIdSupports.data = aUserContextId;
sa.appendElement(wuri);
sa.appendElement(charset);
sa.appendElement(extraOptions);
sa.appendElement(aReferrerInfo);
sa.appendElement(aPostData);
sa.appendElement(allowThirdPartyFixupSupports);
@ -579,6 +584,9 @@ function openLinkIn(url, where, params) {
if (aForceAllowDataURI) {
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
}
if (params.fromExternal) {
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
}
let { URI_INHERITS_SECURITY_CONTEXT } = Ci.nsIProtocolHandler;
if (
@ -600,6 +608,7 @@ function openLinkIn(url, where, params) {
referrerInfo: aReferrerInfo,
postData: aPostData,
userContextId: aUserContextId,
hasValidUserGestureActivation: params.hasValidUserGestureActivation,
});
if (aResolveOnContentBrowserReady) {
aResolveOnContentBrowserReady(targetBrowser);
@ -636,6 +645,7 @@ function openLinkIn(url, where, params) {
csp: aCsp,
focusUrlBar,
openerBrowser: params.openerBrowser,
fromExternal: params.fromExternal,
});
targetBrowser = tabUsedForLoad.linkedBrowser;

View file

@ -250,12 +250,17 @@ function openBrowserWindow(
});
args = [uriArray];
} else {
let extraOptions = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
Ci.nsIWritablePropertyBag2
);
extraOptions.setPropertyAsBool("fromExternal", true);
// Always pass at least 3 arguments to avoid the "|"-splitting behavior,
// ie. avoid the loadOneOrMoreURIs function.
// Also, we need to pass the triggering principal.
args = [
urlOrUrlList,
null, // charset
extraOptions,
null, // refererInfo
postData,
undefined, // allowThirdPartyFixup; this would be `false` but that

View file

@ -17,11 +17,13 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const { E10SUtils } = ChromeUtils.import(
"resource://gre/modules/E10SUtils.jsm"
);
const lazy = {};
XPCOMUtils.defineLazyModuleGetters(lazy, {
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
LoginBreaches: "resource:///modules/LoginBreaches.jsm",
LoginHelper: "resource://gre/modules/LoginHelper.jsm",
LoginExport: "resource://gre/modules/LoginExport.jsm",
@ -69,8 +71,7 @@ const PRIMARY_PASSWORD_NOTIFICATION_ID = "primary-password-login-required";
// about:logins will always use the privileged content process,
// even if it is disabled for other consumers such as about:newtab.
const EXPECTED_ABOUTLOGINS_REMOTE_TYPE =
lazy.E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE;
const EXPECTED_ABOUTLOGINS_REMOTE_TYPE = E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE;
let _gPasswordRemaskTimeout = null;
const convertSubjectToLogin = subject => {
subject.QueryInterface(Ci.nsILoginMetaInfo).QueryInterface(Ci.nsILoginInfo);

View file

@ -260,7 +260,7 @@ this.windows = class extends ExtensionAPIPersistent {
}
}
args.appendElement(null); // unused
args.appendElement(null); // extraOptions
args.appendElement(null); // referrerInfo
args.appendElement(null); // postData
args.appendElement(null); // allowThirdPartyFixup

View file

@ -107,8 +107,10 @@ add_task(async function test_sessions_get_recently_closed_tabs() {
await extension.startup();
let sessionUpdatePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab);
// Test with a closed tab.
BrowserTestUtils.removeTab(tab);
await sessionUpdatePromise;
extension.sendMessage("check-sessions");
let recentlyClosed = await extension.awaitMessage("recentlyClosed");

View file

@ -46,6 +46,7 @@ async function openFirefoxViewTab(w = window) {
assertFirefoxViewTab(w);
is(w.gBrowser.tabContainer.selectedIndex, 0, "Firefox View tab is selected");
await BrowserTestUtils.browserLoaded(w.gFirefoxViewTab.linkedBrowser);
return w.gFirefoxViewTab;
}
function closeFirefoxViewTab(w = window) {
@ -121,18 +122,21 @@ add_task(async function undo_close_tab() {
"about:about"
);
await TestUtils.waitForTick();
let sessionUpdatePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab);
gBrowser.removeTab(tab);
await TestUtils.waitForTick();
await sessionUpdatePromise;
is(
SessionStore.getClosedTabCount(window),
1,
"Closing about:about added to the closed tab count"
);
await openFirefoxViewTab();
let viewTab = await openFirefoxViewTab();
await TestUtils.waitForTick();
sessionUpdatePromise = BrowserTestUtils.waitForSessionStoreUpdate(viewTab);
closeFirefoxViewTab();
await TestUtils.waitForTick();
await sessionUpdatePromise;
is(
SessionStore.getClosedTabCount(window),
1,

View file

@ -26,6 +26,21 @@ async function close_tab(tab) {
await sessionStorePromise;
}
async function open_then_close(url) {
let { updatePromise } = await BrowserTestUtils.withNewTab(
url,
async browser => {
return {
updatePromise: BrowserTestUtils.waitForSessionStoreUpdate({
linkedBrowser: browser,
}),
};
}
);
await updatePromise;
return TestUtils.topicObserved("sessionstore-closed-objects-changed");
}
function clearHistory() {
Services.obs.notifyObservers(null, "browser:purge-session-history");
}
@ -86,7 +101,12 @@ add_task(async function test_empty_list() {
});
add_task(async function test_list_ordering() {
const existingData = SessionStore.getClosedTabCount(window);
Services.obs.notifyObservers(null, "browser:purge-session-history");
is(
SessionStore.getClosedTabCount(window),
0,
"Closed tab count after purging session history"
);
await BrowserTestUtils.withNewTab(
{
@ -95,9 +115,8 @@ add_task(async function test_list_ordering() {
},
async browser => {
const { document } = browser.contentWindow;
const closedObjectsChanged = TestUtils.topicObserved(
"sessionstore-closed-objects-changed"
);
const closedObjectsChanged = () =>
TestUtils.topicObserved("sessionstore-closed-objects-changed");
const tab1 = await add_new_tab(URLs[0]);
const tab2 = await add_new_tab(URLs[1]);
@ -106,13 +125,13 @@ add_task(async function test_list_ordering() {
gBrowser.selectedTab = tab3;
await close_tab(tab3);
await closedObjectsChanged;
await closedObjectsChanged();
await close_tab(tab2);
await closedObjectsChanged;
await closedObjectsChanged();
await close_tab(tab1);
await closedObjectsChanged;
await closedObjectsChanged();
const tabsList = document.querySelector("ol.closed-tabs-list");
await BrowserTestUtils.waitForMutationCondition(
@ -121,9 +140,9 @@ add_task(async function test_list_ordering() {
() => tabsList.children.length > 1
);
ok(
document.querySelector("ol.closed-tabs-list").children.length ===
3 + existingData,
is(
document.querySelector("ol.closed-tabs-list").children.length,
3,
"recently-closed-tabs-list should have one list item"
);
@ -146,8 +165,22 @@ add_task(async function test_list_ordering() {
});
add_task(async function test_max_list_items() {
// the tabs opened from the previous test provide seed data
const mockMaxTabsLength = SessionStore.getClosedTabCount(window);
Services.obs.notifyObservers(null, "browser:purge-session-history");
is(
SessionStore.getClosedTabCount(window),
0,
"Closed tab count after purging session history"
);
await open_then_close(URLs[0]);
await open_then_close(URLs[1]);
await open_then_close(URLs[2]);
// Seed the closed tabs count. We've assured that we've opened and
// closed at least three tabs because of the calls to open_then_close
// above.
let mockMaxTabsLength = 3;
await BrowserTestUtils.withNewTab(
{
gBrowser,
@ -175,19 +208,12 @@ add_task(async function test_max_list_items() {
},
});
ok(
document.querySelector("ol.closed-tabs-list").childNodes.length ===
mockMaxTabsLength,
is(
document.querySelector("ol.closed-tabs-list").childNodes.length,
mockMaxTabsLength,
`recently-closed-tabs-list should have ${mockMaxTabsLength} list items`
);
ok(
document
.querySelector("ol.closed-tabs-list")
.firstChild.textContent.includes("about:firefoxview"),
"first list item in recently-closed-tabs-list is from previous test (session store)"
);
const closedObjectsChanged = TestUtils.topicObserved(
"sessionstore-closed-objects-changed"
);
@ -203,9 +229,9 @@ add_task(async function test_max_list_items() {
"first list item in recently-closed-tabs-list should have been updated"
);
ok(
document.querySelector("ol.closed-tabs-list").childNodes.length ===
mockMaxTabsLength,
is(
document.querySelector("ol.closed-tabs-list").childNodes.length,
mockMaxTabsLength,
`recently-closed-tabs-list should still have ${mockMaxTabsLength} list items`
);
}

View file

@ -9,9 +9,12 @@ var EXPORTED_SYMBOLS = ["Qihoo360seMigrationUtils"];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { MigrationUtils } = ChromeUtils.import(
"resource:///modules/MigrationUtils.jsm"
);
const lazy = {};
XPCOMUtils.defineLazyModuleGetters(lazy, {
MigrationUtils: "resource:///modules/MigrationUtils.jsm",
PlacesUIUtils: "resource:///modules/PlacesUIUtils.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
Sqlite: "resource://gre/modules/Sqlite.jsm",
@ -32,7 +35,7 @@ function Bookmarks(aProfileFolder) {
this._file = file;
}
Bookmarks.prototype = {
type: lazy.MigrationUtils.resourceTypes.BOOKMARKS,
type: MigrationUtils.resourceTypes.BOOKMARKS,
get exists() {
return this._file.exists() && this._file.isReadable();
@ -105,10 +108,7 @@ Bookmarks.prototype = {
if (toolbarBMs.length) {
let parentGuid = lazy.PlacesUtils.bookmarks.toolbarGuid;
await lazy.MigrationUtils.insertManyBookmarksWrapper(
toolbarBMs,
parentGuid
);
await MigrationUtils.insertManyBookmarksWrapper(toolbarBMs, parentGuid);
lazy.PlacesUIUtils.maybeToggleBookmarkToolbarVisibilityAfterMigration();
}
})().then(

View file

@ -11,8 +11,6 @@
var EXPORTED_SYMBOLS = ["ChromeMacOSLoginCrypto"];
Cu.importGlobalProperties(["crypto"]);
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);

View file

@ -19,10 +19,13 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const { MigratorPrototype } = ChromeUtils.import(
"resource:///modules/MigrationUtils.jsm"
);
const lazy = {};
XPCOMUtils.defineLazyModuleGetters(lazy, {
ChromeMigrationUtils: "resource:///modules/ChromeMigrationUtils.jsm",
MigratorPrototype: "resource:///modules/MigrationUtils.jsm",
MigrationUtils: "resource:///modules/MigrationUtils.jsm",
NetUtil: "resource://gre/modules/NetUtil.jsm",
OS: "resource://gre/modules/osfile.jsm",
@ -76,7 +79,7 @@ function ChromeProfileMigrator() {
this._chromeUserDataPathSuffix = "Chrome";
}
ChromeProfileMigrator.prototype = Object.create(lazy.MigratorPrototype);
ChromeProfileMigrator.prototype = Object.create(MigratorPrototype);
ChromeProfileMigrator.prototype._keychainServiceName = "Chrome Safe Storage";
ChromeProfileMigrator.prototype._keychainAccountName = "Chrome";

View file

@ -11,8 +11,6 @@
var EXPORTED_SYMBOLS = ["ChromeWindowsLoginCrypto"];
Cu.importGlobalProperties(["atob", "crypto"]);
const { ChromeMigrationUtils } = ChromeUtils.import(
"resource:///modules/ChromeMigrationUtils.jsm"
);

View file

@ -31,11 +31,7 @@ ChromeUtils.defineModuleGetter(
"WindowsRegistry",
"resource://gre/modules/WindowsRegistry.jsm"
);
ChromeUtils.defineModuleGetter(
lazy,
"ctypes",
"resource://gre/modules/ctypes.jsm"
);
const { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm");
const EDGE_COOKIE_PATH_OPTIONS = ["", "#!001\\", "#!002\\"];
const EDGE_COOKIES_SUFFIX = "MicrosoftEdge\\Cookies";
@ -57,15 +53,15 @@ const WEB_CREDENTIALS_VAULT_ID = [
];
const wintypes = {
BOOL: lazy.ctypes.int,
DWORD: lazy.ctypes.uint32_t,
DWORDLONG: lazy.ctypes.uint64_t,
CHAR: lazy.ctypes.char,
PCHAR: lazy.ctypes.char.ptr,
LPCWSTR: lazy.ctypes.char16_t.ptr,
PDWORD: lazy.ctypes.uint32_t.ptr,
VOIDP: lazy.ctypes.voidptr_t,
WORD: lazy.ctypes.uint16_t,
BOOL: ctypes.int,
DWORD: ctypes.uint32_t,
DWORDLONG: ctypes.uint64_t,
CHAR: ctypes.char,
PCHAR: ctypes.char.ptr,
LPCWSTR: ctypes.char16_t.ptr,
PDWORD: ctypes.uint32_t.ptr,
VOIDP: ctypes.voidptr_t,
WORD: ctypes.uint16_t,
};
// TODO: Bug 1202978 - Refactor MSMigrationUtils ctypes helpers
@ -74,7 +70,7 @@ function CtypesKernelHelpers() {
this._functions = {};
this._libs = {};
this._structs.SYSTEMTIME = new lazy.ctypes.StructType("SYSTEMTIME", [
this._structs.SYSTEMTIME = new ctypes.StructType("SYSTEMTIME", [
{ wYear: wintypes.WORD },
{ wMonth: wintypes.WORD },
{ wDayOfWeek: wintypes.WORD },
@ -85,17 +81,17 @@ function CtypesKernelHelpers() {
{ wMilliseconds: wintypes.WORD },
]);
this._structs.FILETIME = new lazy.ctypes.StructType("FILETIME", [
this._structs.FILETIME = new ctypes.StructType("FILETIME", [
{ dwLowDateTime: wintypes.DWORD },
{ dwHighDateTime: wintypes.DWORD },
]);
try {
this._libs.kernel32 = lazy.ctypes.open("Kernel32");
this._libs.kernel32 = ctypes.open("Kernel32");
this._functions.FileTimeToSystemTime = this._libs.kernel32.declare(
"FileTimeToSystemTime",
lazy.ctypes.winapi_abi,
ctypes.winapi_abi,
wintypes.BOOL,
this._structs.FILETIME.ptr,
this._structs.SYSTEMTIME.ptr
@ -142,7 +138,7 @@ CtypesKernelHelpers.prototype = {
systemTime.address()
);
if (result == 0) {
throw new Error(lazy.ctypes.winLastError);
throw new Error(ctypes.winLastError);
}
// System time is in UTC, so we use Date.UTC to get milliseconds from epoch,
@ -165,11 +161,11 @@ function CtypesVaultHelpers() {
this._structs = {};
this._functions = {};
this._structs.GUID = new lazy.ctypes.StructType("GUID", [
this._structs.GUID = new ctypes.StructType("GUID", [
{ id: wintypes.DWORD.array(4) },
]);
this._structs.VAULT_ITEM_ELEMENT = new lazy.ctypes.StructType(
this._structs.VAULT_ITEM_ELEMENT = new ctypes.StructType(
"VAULT_ITEM_ELEMENT",
[
// not documented
@ -187,7 +183,7 @@ function CtypesVaultHelpers() {
]
);
this._structs.VAULT_ELEMENT = new lazy.ctypes.StructType("VAULT_ELEMENT", [
this._structs.VAULT_ELEMENT = new ctypes.StructType("VAULT_ELEMENT", [
// vault item schemaId
{ schemaId: this._structs.GUID },
// a pointer to the name of the browser VAULT_ITEM_ELEMENT
@ -212,11 +208,11 @@ function CtypesVaultHelpers() {
]);
try {
this._vaultcliLib = lazy.ctypes.open("vaultcli.dll");
this._vaultcliLib = ctypes.open("vaultcli.dll");
this._functions.VaultOpenVault = this._vaultcliLib.declare(
"VaultOpenVault",
lazy.ctypes.winapi_abi,
ctypes.winapi_abi,
wintypes.DWORD,
// GUID
this._structs.GUID.ptr,
@ -227,7 +223,7 @@ function CtypesVaultHelpers() {
);
this._functions.VaultEnumerateItems = this._vaultcliLib.declare(
"VaultEnumerateItems",
lazy.ctypes.winapi_abi,
ctypes.winapi_abi,
wintypes.DWORD,
// Vault Handle
wintypes.VOIDP,
@ -236,18 +232,18 @@ function CtypesVaultHelpers() {
// Items Count
wintypes.PDWORD,
// Items
lazy.ctypes.voidptr_t
ctypes.voidptr_t
);
this._functions.VaultCloseVault = this._vaultcliLib.declare(
"VaultCloseVault",
lazy.ctypes.winapi_abi,
ctypes.winapi_abi,
wintypes.DWORD,
// Vault Handle
wintypes.VOIDP
);
this._functions.VaultGetItem = this._vaultcliLib.declare(
"VaultGetItem",
lazy.ctypes.winapi_abi,
ctypes.winapi_abi,
wintypes.DWORD,
// Vault Handle
wintypes.VOIDP,
@ -268,7 +264,7 @@ function CtypesVaultHelpers() {
);
this._functions.VaultFree = this._vaultcliLib.declare(
"VaultFree",
lazy.ctypes.winapi_abi,
ctypes.winapi_abi,
wintypes.DWORD,
// Memory
this._structs.VAULT_ELEMENT.ptr

View file

@ -12,7 +12,6 @@ const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const lazy = {};
XPCOMUtils.defineLazyGlobalGetters(lazy, ["fetch"]);
XPCOMUtils.defineLazyModuleGetters(lazy, {
SnippetsTestMessageProvider:
"resource://activity-stream/lib/SnippetsTestMessageProvider.jsm",
@ -192,7 +191,7 @@ const MessageLoaderUtils = {
let response;
try {
response = await lazy.fetch(provider.url, {
response = await fetch(provider.url, {
headers,
credentials: "omit",
});

View file

@ -13,6 +13,12 @@ const { XPCOMUtils } = ChromeUtils.import(
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const { NewTabUtils } = ChromeUtils.import(
"resource://gre/modules/NewTabUtils.jsm"
);
const { ShellService } = ChromeUtils.import(
"resource:///modules/ShellService.jsm"
);
const lazy = {};
@ -20,9 +26,7 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
ASRouterPreferences: "resource://activity-stream/lib/ASRouterPreferences.jsm",
AddonManager: "resource://gre/modules/AddonManager.jsm",
ClientEnvironment: "resource://normandy/lib/ClientEnvironment.jsm",
NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
ProfileAge: "resource://gre/modules/ProfileAge.jsm",
ShellService: "resource:///modules/ShellService.jsm",
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm",
AttributionCode: "resource:///modules/AttributionCode.jsm",
TargetingContext: "resource://messaging-system/targeting/Targeting.jsm",
@ -116,7 +120,7 @@ XPCOMUtils.defineLazyServiceGetters(lazy, {
const FXA_USERNAME_PREF = "services.sync.username";
const { activityStreamProvider: asProvider } = lazy.NewTabUtils;
const { activityStreamProvider: asProvider } = NewTabUtils;
const FXA_ATTACHED_CLIENTS_UPDATE_INTERVAL = 4 * 60 * 60 * 1000; // Four hours
const FRECENT_SITES_UPDATE_INTERVAL = 6 * 60 * 60 * 1000; // Six hours
@ -265,7 +269,7 @@ const QueryCache = {
"doesAppNeedPin",
null,
FRECENT_SITES_UPDATE_INTERVAL,
lazy.ShellService
ShellService
),
},
};
@ -477,7 +481,7 @@ const TargetingGetters = {
},
get isDefaultBrowser() {
try {
return lazy.ShellService.isDefaultBrowser();
return ShellService.isDefaultBrowser();
} catch (e) {}
return null;
},
@ -498,7 +502,7 @@ const TargetingGetters = {
return QueryCache.queries.RecentBookmarks.get();
},
get pinnedSites() {
return lazy.NewTabUtils.pinnedLinks.links.map(site =>
return NewTabUtils.pinnedLinks.links.map(site =>
site
? {
url: site.url,

View file

@ -1,8 +1,9 @@
const lazy = {};
/* 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/. */
const lazy = {};
ChromeUtils.defineModuleGetter(
lazy,
"IndexedDB",

View file

@ -10,8 +10,6 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const lazy = {};
XPCOMUtils.defineLazyGlobalGetters(lazy, ["fetch"]);
XPCOMUtils.defineLazyModuleGetters(lazy, {
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
RemoteL10n: "resource://activity-stream/lib/RemoteL10n.jsm",
@ -881,7 +879,7 @@ const CFRPageActions = {
async _fetchLatestAddonVersion(id) {
let url = null;
try {
const response = await lazy.fetch(`${ADDONS_API_URL}/${id}/`, {
const response = await fetch(`${ADDONS_API_URL}/${id}/`, {
credentials: "omit",
});
if (response.status !== 204 && response.ok) {

View file

@ -3,9 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const lazy = {};
ChromeUtils.defineModuleGetter(
lazy,
@ -21,7 +18,6 @@ const { setTimeout, clearTimeout } = ChromeUtils.import(
"resource://gre/modules/Timer.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGlobalGetters(lazy, ["fetch"]);
const { actionTypes: at, actionCreators: ac } = ChromeUtils.import(
"resource://activity-stream/common/Actions.jsm"
);
@ -287,7 +283,7 @@ class DiscoveryStreamFeed {
const controller = new AbortController();
const { signal } = controller;
const fetchPromise = lazy.fetch(endpoint, {
const fetchPromise = fetch(endpoint, {
...options,
credentials: "omit",
signal,

View file

@ -18,11 +18,6 @@ ChromeUtils.defineModuleGetter(
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyGlobalGetters(lazy, ["fetch"]);
const { BasePromiseWorker } = ChromeUtils.import(
"resource://gre/modules/PromiseWorker.jsm"
@ -67,7 +62,7 @@ class PersonalityProvider {
}
const server = Services.prefs.getCharPref("services.settings.server");
const serverInfo = await (
await lazy.fetch(`${server}/`, {
await fetch(`${server}/`, {
credentials: "omit",
})
).json();

View file

@ -135,80 +135,95 @@ class _RemoteImages {
* then the promise will resolve to null.
*/
async patchMessage(message, replaceWith = "imageURL") {
try {
if (!!message && !!message.imageId) {
const { imageId } = message;
const blobURL = await this.load(imageId);
if (!!message && !!message.imageId) {
const { imageId } = message;
const urls = await this.load(imageId);
if (urls.size) {
const blobURL = urls.get(imageId);
delete message.imageId;
message[replaceWith] = blobURL;
return () => this.unload(blobURL);
return () => this.unload(urls);
}
return null;
} catch (e) {
Cu.reportError(
`RemoteImages Could not patch message with imageId "${message.imageId}": ${e}`
);
return null;
}
return null;
}
/**
* Load a remote image.
* Load remote images.
*
* If the image has not been previously downloaded then the image will be
* If the images have not been previously downloaded, then they will be
* downloaded from RemoteSettings.
*
* @param imageId The unique image ID.
* @param {...string} imageIds The image IDs to load.
*
* @throws This method throws if the image cannot be loaded.
* @returns {object} An object mapping image Ids to blob: URLs.
* If an image could not be loaded, it will not be present
* in the returned object.
*
* @returns A promise that resolves with a blob URL for the given image, or
* rejects with an error.
*
* After the caller is finished with the image, they must call
* |RemoteImages.unload()| on the returned URL.
* After the caller is finished with the images, they must call
* |RemoteImages.unload()| on the object.
*/
load(imageId) {
load(...imageIds) {
return this.withDb(async db => {
const recordId = this.#getRecordId(imageId);
// Deduplicate repeated imageIds by using a Map.
const urls = new Map(imageIds.map(key => [key, undefined]));
let blob;
if (db.data.images[recordId]) {
// We have previously fetched this image, we can load it from disk.
try {
blob = await this.#readFromDisk(db, recordId);
} catch (e) {
if (
!(
e instanceof Components.Exception &&
e.name === "NS_ERROR_FILE_NOT_FOUND"
)
) {
throw e;
await Promise.all(
Array.from(urls.keys()).map(async imageId => {
try {
urls.set(imageId, await this.#loadImpl(db, imageId));
} catch (e) {
Cu.reportError(`Could not load image ID ${imageId}: ${e}`);
urls.delete(imageId);
}
}
})
);
// Fall back to downloading if we cannot read it from disk.
}
if (typeof blob === "undefined") {
blob = await this.#download(db, recordId);
}
return URL.createObjectURL(blob);
return urls;
});
}
async #loadImpl(db, imageId) {
const recordId = this.#getRecordId(imageId);
let blob;
if (db.data.images[recordId]) {
// We have previously fetched this image, we can load it from disk.
try {
blob = await this.#readFromDisk(db, recordId);
} catch (e) {
if (
!(
e instanceof Components.Exception &&
e.name === "NS_ERROR_FILE_NOT_FOUND"
)
) {
throw e;
}
}
// Fall back to downloading if we cannot read it from disk.
}
if (typeof blob === "undefined") {
blob = await this.#download(db, recordId);
}
return URL.createObjectURL(blob);
}
/**
* Unload a URL returned by RemoteImages
* Unload URLs returned by RemoteImages
*
* @param url The URL to unload.
* @param {Map<string, string>} urls The result of calling |RemoteImages.load()|.
**/
unload(url) {
URL.revokeObjectURL(url);
unload(urls) {
for (const url of urls.keys()) {
URL.revokeObjectURL(url);
}
}
/**

View file

@ -11,8 +11,6 @@ const { XPCOMUtils } = ChromeUtils.import(
const lazy = {};
XPCOMUtils.defineLazyGlobalGetters(lazy, ["fetch"]);
ChromeUtils.defineModuleGetter(
lazy,
"BackgroundPageThumbs",
@ -63,7 +61,7 @@ const Screenshots = {
// Blob URIs for the screenshots.
const imgPath = lazy.PageThumbs.getThumbnailPath(url);
const filePathResponse = await lazy.fetch(`file://${imgPath}`);
const filePathResponse = await fetch(`file://${imgPath}`);
const fileContents = await filePathResponse.blob();
// Check if the file is empty, which indicates there isn't actually a

View file

@ -2,15 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const lazy = {};
XPCOMUtils.defineLazyGlobalGetters(lazy, ["fetch"]);
const TIPPYTOP_PATH = "chrome://activity-stream/content/data/content/tippytop/";
const TIPPYTOP_JSON_PATH =
"chrome://activity-stream/content/data/content/tippytop/top_sites.json";
@ -43,7 +36,7 @@ class TippyTopProvider {
// Load the Tippy Top sites from the json manifest.
try {
for (const site of await (
await lazy.fetch(TIPPYTOP_JSON_PATH, {
await fetch(TIPPYTOP_JSON_PATH, {
credentials: "omit",
})
).json()) {

View file

@ -74,8 +74,6 @@ ChromeUtils.defineModuleGetter(
"resource://gre/modules/Region.jsm"
);
XPCOMUtils.defineLazyGlobalGetters(lazy, ["fetch"]);
XPCOMUtils.defineLazyGetter(lazy, "log", () => {
const { Logger } = ChromeUtils.import(
"resource://messaging-system/lib/Logger.jsm"
@ -186,7 +184,7 @@ class ContileIntegration {
}
try {
let url = Services.prefs.getStringPref(CONTILE_ENDPOINT_PREF);
const response = await lazy.fetch(url, { credentials: "omit" });
const response = await fetch(url, { credentials: "omit" });
if (!response.ok) {
lazy.log.warn(
`Contile endpoint returned unexpected status: ${response.status}`

View file

@ -3,15 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { NewTabUtils } = ChromeUtils.import(
"resource://gre/modules/NewTabUtils.jsm"
);
const lazy = {};
XPCOMUtils.defineLazyGlobalGetters(lazy, ["fetch"]);
const { actionTypes: at, actionCreators: ac } = ChromeUtils.import(
"resource://activity-stream/common/Actions.jsm"
@ -29,6 +24,7 @@ const { PersistentCache } = ChromeUtils.import(
"resource://activity-stream/lib/PersistentCache.jsm"
);
const lazy = {};
ChromeUtils.defineModuleGetter(
lazy,
"pktApi",
@ -196,7 +192,7 @@ class TopStoriesFeed {
return null;
}
try {
const response = await lazy.fetch(this.stories_endpoint, {
const response = await fetch(this.stories_endpoint, {
credentials: "omit",
});
if (!response.ok) {
@ -296,7 +292,7 @@ class TopStoriesFeed {
return null;
}
try {
const response = await lazy.fetch(this.topics_endpoint, {
const response = await fetch(this.topics_endpoint, {
credentials: "omit",
});
if (!response.ok) {

View file

@ -14,8 +14,6 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const RS_SERVER_PREF = "services.settings.server";
Cu.importGlobalProperties(["fetch"]);
const RemoteImagesTestUtils = {
/**
* Serve a mock Remote Settings server with content for Remote Images
@ -26,70 +24,72 @@ const RemoteImagesTestUtils = {
* @returns A promise yielding a cleanup function. This function will stop the
* internal HTTP server and clean up all Remote Images state.
*/
async serveRemoteImages(imageInfo) {
const { filename, recordId, mimetype, hash, url, size } = imageInfo;
async serveRemoteImages(...imageInfos) {
const server = new HttpServer();
server.start(-1);
const baseURL = `http://localhost:${server.identity.primaryPort}/`;
const arrayBuffer = await fetch(url, { credentials: "omit" }).then(rsp =>
rsp.arrayBuffer()
);
for (const imageInfo of imageInfos) {
const { filename, recordId, mimetype, hash, url, size } = imageInfo;
server.registerPathHandler("/v1/", (request, response) => {
response.write(
JSON.stringify({
capabilities: {
attachments: {
base_url: `${baseURL}cdn`,
},
},
})
const arrayBuffer = await fetch(url, { credentials: "omit" }).then(rsp =>
rsp.arrayBuffer()
);
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setStatusLine(null, 200, "OK");
});
server.registerPathHandler(
`/v1/buckets/main/collections/ms-images/records/${recordId}`,
(request, response) => {
server.registerPathHandler("/v1/", (request, response) => {
response.write(
JSON.stringify({
data: {
attachment: {
filename,
location: `main/ms-images/${recordId}`,
hash,
mimetype,
size,
capabilities: {
attachments: {
base_url: `${baseURL}cdn`,
},
},
id: "image-id",
last_modified: Date.now(),
})
);
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setStatusLine(null, 200, "OK");
}
);
});
server.registerPathHandler(
`/cdn/main/ms-images/${recordId}`,
async (request, response) => {
const stream = Cc[
"@mozilla.org/io/arraybuffer-input-stream;1"
].createInstance(Ci.nsIArrayBufferInputStream);
stream.setData(arrayBuffer, 0, arrayBuffer.byteLength);
server.registerPathHandler(
`/v1/buckets/main/collections/ms-images/records/${recordId}`,
(request, response) => {
response.write(
JSON.stringify({
data: {
attachment: {
filename,
location: `main/ms-images/${recordId}`,
hash,
mimetype,
size,
},
},
id: "image-id",
last_modified: Date.now(),
})
);
response.bodyOutputStream.writeFrom(stream, size);
response.setHeader("Content-Type", mimetype);
response.setStatusLine(null, 200, "OK");
}
);
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setStatusLine(null, 200, "OK");
}
);
server.registerPathHandler(
`/cdn/main/ms-images/${recordId}`,
async (request, response) => {
const stream = Cc[
"@mozilla.org/io/arraybuffer-input-stream;1"
].createInstance(Ci.nsIArrayBufferInputStream);
stream.setData(arrayBuffer, 0, arrayBuffer.byteLength);
response.bodyOutputStream.writeFrom(stream, size);
response.setHeader("Content-Type", mimetype);
response.setStatusLine(null, 200, "OK");
}
);
}
Services.prefs.setCharPref(RS_SERVER_PREF, `${baseURL}v1`);
@ -177,6 +177,16 @@ const RemoteImagesTestUtils = {
url: "chrome://browser/content/aboutRobots-icon.png",
size: 7599,
},
Mountain: {
filename: "mountain.svg",
recordId: "mountain",
mimetype: "image/svg+xml",
hash: "96902f3d784e1b5e49547c543a5c121442c64b180deb2c38246fada1d14597ac",
url:
"chrome://activity-stream/content/data/content/assets/remote/mountain.svg",
size: 1650,
},
},
};

View file

@ -6,6 +6,9 @@
const { BrowserTestUtils } = ChromeUtils.import(
"resource://testing-common/BrowserTestUtils.jsm"
);
const { Downloader } = ChromeUtils.import(
"resource://services-settings/Attachments.jsm"
);
const {
RemoteImages,
REMOTE_IMAGES_PATH,
@ -24,21 +27,16 @@ function dbWriteFinished(db) {
add_setup(RemoteImagesTestUtils.wipeCache);
add_task(async function test_remoteImages_load() {
registerCleanupFunction(RemoteImagesTestUtils.wipeCache);
const imageInfo = RemoteImagesTestUtils.images.AboutRobots;
registerCleanupFunction(
await RemoteImagesTestUtils.serveRemoteImages(imageInfo)
);
async function runLoadTest(recordId, imageId) {
const urls = await RemoteImages.load(imageId);
Assert.equal(urls.size, 1, "RemogeImages.load() returns one result");
async function runLoadTest(imageId) {
const url = await RemoteImages.load(imageId);
const url = urls.get(imageId);
Assert.ok(url.startsWith("blob:"), "RemoteImages.load() returns blob URL");
Assert.ok(
await IOUtils.exists(
PathUtils.join(REMOTE_IMAGES_PATH, imageInfo.recordId)
),
await IOUtils.exists(PathUtils.join(REMOTE_IMAGES_PATH, recordId)),
"RemoteImages caches the image"
);
@ -62,19 +60,26 @@ add_task(async function test_remoteImages_load() {
"Data read from blob: URL matches expected"
);
RemoteImages.unload(url);
RemoteImages.unload(urls);
}
info("Loading a RemoteImage with a record ID");
await runLoadTest(imageInfo.recordId);
const stop = await RemoteImagesTestUtils.serveRemoteImages(imageInfo);
info("Loading a RemoteImage with a legacy image ID (record ID + extension)");
await runLoadTest(`${imageInfo.recordId}.png`);
try {
info("Loading a RemoteImage with a record ID");
await runLoadTest(imageInfo.recordId, imageInfo.recordId);
info(
"Loading a RemoteImage with a legacy image ID (record ID + extension)"
);
await runLoadTest(imageInfo.recordId, `${imageInfo.recordId}.png`);
} finally {
await stop();
await RemoteImagesTestUtils.wipeCache();
}
});
add_task(async function test_remoteImages_load_fallback() {
registerCleanupFunction(RemoteImagesTestUtils.wipeCache);
const imageInfo = RemoteImagesTestUtils.images.AboutRobots;
const origDbContent = {
version: 1,
@ -85,99 +90,138 @@ add_task(async function test_remoteImages_load_fallback() {
await IOUtils.writeJSON(REMOTE_IMAGES_DB_PATH, origDbContent);
registerCleanupFunction(
await RemoteImagesTestUtils.serveRemoteImages(imageInfo)
);
const stop = await RemoteImagesTestUtils.serveRemoteImages(imageInfo);
const url = await RemoteImages.load(imageInfo.recordId);
RemoteImages.unload(url);
try {
const urls = await RemoteImages.load(imageInfo.recordId);
RemoteImages.unload(urls);
await RemoteImages.withDb(async db => {
Assert.ok(
imageInfo.recordId in db.data.images,
"RemoteImages DB entry present"
);
await RemoteImages.withDb(async db => {
Assert.ok(
imageInfo.recordId in db.data.images,
"RemoteImages DB entry present"
);
Assert.notDeepEqual(
db.data,
origDbContent,
"RemoteImages DB changed after load()"
);
Assert.notDeepEqual(
db.data,
origDbContent,
"RemoteImages DB changed after load()"
);
await dbWriteFinished(db);
await dbWriteFinished(db);
const onDisk = await IOUtils.readJSON(REMOTE_IMAGES_DB_PATH);
Assert.deepEqual(
db.data,
onDisk,
"RemoteImages DB was saved to disk after load() falled back to download"
);
});
const onDisk = await IOUtils.readJSON(REMOTE_IMAGES_DB_PATH);
Assert.deepEqual(
db.data,
onDisk,
"RemoteImages DB was saved to disk after load() falled back to download"
);
});
} finally {
await stop();
await RemoteImagesTestUtils.wipeCache();
}
});
add_task(async function test_remoteImages_expire() {
registerCleanupFunction(RemoteImagesTestUtils.wipeCache);
const THIRTY_ONE_DAYS = 31 * 24 * 60 * 60;
const IMAGE_INFO = RemoteImagesTestUtils.images.AboutRobots;
await RemoteImages.reset();
try {
await RemoteImagesTestUtils.writeImage(IMAGE_INFO);
await IOUtils.writeJSON(REMOTE_IMAGES_DB_PATH, {
version: 1,
images: {
...RemoteImagesTestUtils.dbEntryFor(
IMAGE_INFO,
Date.now() - THIRTY_ONE_DAYS
),
},
});
await RemoteImagesTestUtils.writeImage(IMAGE_INFO);
await IOUtils.writeJSON(REMOTE_IMAGES_DB_PATH, {
version: 1,
images: {
...RemoteImagesTestUtils.dbEntryFor(
IMAGE_INFO,
Date.now() - THIRTY_ONE_DAYS
),
},
});
await RemoteImagesTestUtils.triggerCleanup();
await RemoteImages.withDb(async db => {
Assert.deepEqual(db.data.images, [], "RemoteImages should have no images");
Assert.ok(
!(await IOUtils.exists(
PathUtils.join(REMOTE_IMAGES_PATH, IMAGE_INFO.recordId)
)),
"Image should have been deleted during cleanup"
);
});
await RemoteImagesTestUtils.triggerCleanup();
await RemoteImages.withDb(async db => {
Assert.deepEqual(
db.data.images,
[],
"RemoteImages should have no images"
);
Assert.ok(
!(await IOUtils.exists(
PathUtils.join(REMOTE_IMAGES_PATH, IMAGE_INFO.recordId)
)),
"Image should have been deleted during cleanup"
);
});
} finally {
await RemoteImagesTestUtils.wipeCache();
}
});
add_task(async function test_remoteImages_migrate() {
registerCleanupFunction(RemoteImagesTestUtils.wipeCache);
await RemoteImages.reset();
await IOUtils.remove(REMOTE_IMAGES_DB_PATH);
await RemoteImagesTestUtils.writeImage(
RemoteImagesTestUtils.images.AboutRobots,
RemoteImagesTestUtils.images.AboutRobots.filename
);
await RemoteImages.withDb(async db => {
const children = await IOUtils.getChildren(REMOTE_IMAGES_PATH);
Assert.deepEqual(
children,
[],
"RemoteImages migration should delete all images."
try {
await IOUtils.remove(REMOTE_IMAGES_DB_PATH);
await RemoteImagesTestUtils.writeImage(
RemoteImagesTestUtils.images.AboutRobots,
RemoteImagesTestUtils.images.AboutRobots.filename
);
await dbWriteFinished(db);
const fromDisk = await IOUtils.readJSON(REMOTE_IMAGES_DB_PATH);
await RemoteImages.withDb(async db => {
const children = await IOUtils.getChildren(REMOTE_IMAGES_PATH);
Assert.deepEqual(
children,
[],
"RemoteImages migration should delete all images."
);
Assert.deepEqual(
fromDisk,
db.data,
"RemoteImages DB data should match on-disk contents"
);
await dbWriteFinished(db);
const fromDisk = await IOUtils.readJSON(REMOTE_IMAGES_DB_PATH);
Assert.equal(db.data.version, 1, "RemoteImages DB version should be 1");
Assert.deepEqual(
db.data.images,
{},
"RemoteImages DB should have no entries"
);
});
Assert.deepEqual(
fromDisk,
db.data,
"RemoteImages DB data should match on-disk contents"
);
Assert.equal(db.data.version, 1, "RemoteImages DB version should be 1");
Assert.deepEqual(
db.data.images,
{},
"RemoteImages DB should have no entries"
);
});
} finally {
await RemoteImagesTestUtils.wipeCache();
}
});
add_task(async function test_remoteImages_load_dedup() {
const imageInfo = RemoteImagesTestUtils.images.AboutRobots;
const sandbox = sinon.createSandbox();
const downloadSpy = sandbox.spy(Downloader.prototype, "downloadAsBytes");
const images = ["about-robots", "about-robots", "about-robots"];
const stop = await RemoteImagesTestUtils.serveRemoteImages(imageInfo);
try {
const results = await RemoteImages.load(...images);
RemoteImages.unload(results);
Assert.equal(
results.size,
1,
"RemoteImages.load doesn't return duplicates"
);
Assert.ok(
downloadSpy.calledOnce,
"RemoteImages.load doesn't download duplicates"
);
} finally {
await stop();
await RemoteImagesTestUtils.triggerCleanup();
sandbox.restore();
}
});

View file

@ -214,56 +214,71 @@ add_task(async function test_remoteL10n_content() {
add_task(async function test_remote_images_logo() {
const imageInfo = RemoteImagesTestUtils.images.AboutRobots;
const cleanup = await RemoteImagesTestUtils.serveRemoteImages(imageInfo);
const stop = await RemoteImagesTestUtils.serveRemoteImages(imageInfo);
registerCleanupFunction(cleanup);
try {
const message = await getMessage("SPOTLIGHT_MESSAGE_93");
message.content.logo = { imageId: imageInfo.recordId };
const message = await getMessage("SPOTLIGHT_MESSAGE_93");
message.content.logo = { imageId: imageInfo.recordId };
const dispatchStub = sinon.stub();
const browser = BrowserWindowTracker.getTopWindow().gBrowser
.selectedBrowser;
const dispatchStub = sinon.stub();
const browser = BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
await showAndWaitForDialog(
{ message, browser, dispatchStub },
async win => {
await win.document.mozSubdialogReady;
await showAndWaitForDialog({ message, browser, dispatchStub }, async win => {
await win.document.mozSubdialogReady;
const logo = win.document.querySelector(".logo");
const logo = win.document.querySelector(".logo");
ok(
logo.src.startsWith("blob:"),
"RemoteImages loaded a blob: URL in Spotlight"
);
ok(
logo.src.startsWith("blob:"),
"RemoteImages loaded a blob: URL in Spotlight"
win.document.getElementById("secondary").click();
}
);
win.document.getElementById("secondary").click();
});
} finally {
await stop();
}
});
add_task(async function test_remoteImages_fail() {
const imageInfo = RemoteImagesTestUtils.images.AboutRobots;
registerCleanupFunction(
await RemoteImagesTestUtils.serveRemoteImages(imageInfo)
);
const stop = await RemoteImagesTestUtils.serveRemoteImages(imageInfo);
const message = await getMessage("SPOTLIGHT_MESSAGE_93");
message.content.logo = { imageId: "bogus" };
try {
const message = await getMessage("SPOTLIGHT_MESSAGE_93");
message.content.logo = { imageId: "bogus" };
const dispatchStub = sinon.stub();
const browser = BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
const dispatchStub = sinon.stub();
const browser = BrowserWindowTracker.getTopWindow().gBrowser
.selectedBrowser;
await showAndWaitForDialog({ message, browser, dispatchStub }, async win => {
await win.document.mozSubdialogReady;
await showAndWaitForDialog(
{ message, browser, dispatchStub },
async win => {
await win.document.mozSubdialogReady;
const logo = win.document.querySelector(".logo");
const logo = win.document.querySelector(".logo");
Assert.ok(!logo.src.startsWith("blob:"), "RemoteImages did not patch URL");
Assert.equal(
logo.style.visibility,
"hidden",
"Spotlight hid image with missing URL"
Assert.ok(
!logo.src.startsWith("blob:"),
"RemoteImages did not patch URL"
);
Assert.equal(
logo.style.visibility,
"hidden",
"Spotlight hid image with missing URL"
);
win.document.getElementById("secondary").click();
}
);
win.document.getElementById("secondary").click();
});
} finally {
await stop();
}
});
add_task(async function test_contentExpanded() {

View file

@ -6,8 +6,6 @@
var EXPORTED_SYMBOLS = ["PageDataSchema"];
Cu.importGlobalProperties(["fetch"]);
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);

View file

@ -10,13 +10,15 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { EventEmitter } = ChromeUtils.import(
"resource://gre/modules/EventEmitter.jsm"
);
const lazy = {};
XPCOMUtils.defineLazyModuleGetters(lazy, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
EventEmitter: "resource://gre/modules/EventEmitter.jsm",
HiddenFrame: "resource://gre/modules/HiddenFrame.jsm",
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
});
@ -270,7 +272,7 @@ class PageDataCache {
* the format defined by the schemas at `browser/components/pagedata/schemas`.
*/
const PageDataService = new (class PageDataService extends lazy.EventEmitter {
const PageDataService = new (class PageDataService extends EventEmitter {
/**
* Caches page data discovered from browsers.
*

View file

@ -7,11 +7,13 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { EventEmitter } = ChromeUtils.import(
"resource://gre/modules/EventEmitter.jsm"
);
const lazy = {};
XPCOMUtils.defineLazyModuleGetters(lazy, {
EventEmitter: "resource://gre/modules/EventEmitter.jsm",
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
FilterAdult: "resource://activity-stream/lib/FilterAdult.jsm",
PlacesUIUtils: "resource:///modules/PlacesUIUtils.jsm",
@ -75,7 +77,7 @@ XPCOMUtils.defineLazyGetter(lazy, "logConsole", function() {
* This component is intentionally decoupled from where the context comes from
* so it can be unit tested.
*/
class SnapshotSelector extends lazy.EventEmitter {
class SnapshotSelector extends EventEmitter {
/**
* All of the active selectors.
*/
@ -274,7 +276,12 @@ class SnapshotSelector extends lazy.EventEmitter {
lazy.logConsole.debug(
`Found ${key} recommendations:`,
recommendations.map(r => r.snapshot.url)
recommendations.map(
r =>
`${r.snapshot.url} (score: ${r.score}${
r.data ? ", data: " + JSON.stringify(r.data) : ""
})`
)
);
return { recommendations, weight };

View file

@ -32,6 +32,9 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
* The recommended snapshot.
* @property {number} score
* The score for this snapshot.
* @property {object} [data]
* An optional object containing data used to calculate the score, printed
* as part of logs for debugging purposes.
*/
/**
@ -885,7 +888,7 @@ const Snapshots = new (class Snapshots {
interactionCounts.min = Math.min(interactionCounts.min, interactions);
return {
snapshot: this.#translateRow(row),
interactions,
data: { interactions },
};
});
@ -896,7 +899,7 @@ const Snapshots = new (class Snapshots {
// For now instead we assign a score based on the number of interactions
// with the page during `snapshot_timeofday_limit_days`.
entries.forEach(e => {
e.score = this.timeOfDayScore(e.interactions, interactionCounts);
e.score = this.timeOfDayScore(e.data.interactions, interactionCounts);
});
return entries;
}

View file

@ -245,27 +245,21 @@ async function handlePromoOnPreload(message) {
}
}
async function setupFeatureConfig() {
async function setupMessageConfig() {
let config = null;
let message = null;
let hideDefault = window.PrivateBrowsingShouldHideDefault();
try {
config = window.PrivateBrowsingFeatureConfig();
let response = await window.ASRouterMessage({
type: "PBNEWTAB_MESSAGE_REQUEST",
data: { hideDefault: !!hideDefault },
});
message = response?.message;
config = message?.content;
config.messageId = message?.id;
} catch (e) {}
if (!Object.keys(config).length) {
let hideDefault = window.PrivateBrowsingShouldHideDefault();
try {
let response = await window.ASRouterMessage({
type: "PBNEWTAB_MESSAGE_REQUEST",
data: { hideDefault: !!hideDefault },
});
message = response?.message;
config = message?.content;
config.messageId = message?.id;
} catch (e) {}
}
await renderInfo(config);
let hasRendered = await renderPromo(config);
if (hasRendered && message) {
@ -290,7 +284,7 @@ document.addEventListener("DOMContentLoaded", function() {
// We don't do this setup until now, because we don't want to record any impressions until we're
// sure we're actually running a private window, not just about:privatebrowsing in a normal window.
setupFeatureConfig();
setupMessageConfig();
// Set up the private search banner.
const privateSearchBanner = document.getElementById("search-banner");

View file

@ -8,10 +8,10 @@ add_task(async function test_experiment_plain_text() {
const defaultMessageContent = (await PanelTestProvider.getMessages()).find(
m => m.template === "pb_newtab"
).content;
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
enabled: true,
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: "PB_NEWTAB_MESSAGING_SYSTEM",
template: "pb_newtab",
content: {
...defaultMessageContent,
infoTitle: "Hello world",
infoTitleEnabled: true,
@ -22,6 +22,10 @@ add_task(async function test_experiment_plain_text() {
promoLinkText: "Promo link",
promoLinkUrl: "https://test.com",
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
let { win, tab } = await openTabAndWaitForRender();
@ -57,53 +61,17 @@ add_task(async function test_experiment_plain_text() {
await doExperimentCleanup();
});
add_task(async function test_experiment_fluent() {
const defaultMessageContent = (await PanelTestProvider.getMessages()).find(
m => m.template === "pb_newtab"
).content;
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
enabled: true,
value: {
...defaultMessageContent,
infoBody: "fluent:about-private-browsing-info-title",
promoLinkText: "fluent:about-private-browsing-prominent-cta",
promoLinkUrl: "https://test.com",
},
});
let { win, tab } = await openTabAndWaitForRender();
await SpecialPowers.spawn(tab, [], async function() {
const infoBody = content.document.getElementById("info-body");
const promoLink = content.document.getElementById(
"private-browsing-vpn-link"
);
// Check experiment values are rendered
is(
infoBody.textContent,
"Youre in a Private Window",
"should render infoBody with fluent"
);
is(
promoLink.textContent,
"Stay private with Mozilla VPN",
"should render promoLinkText with fluent"
);
});
await BrowserTestUtils.closeWindow(win);
await doExperimentCleanup();
});
add_task(async function test_experiment_info_disabled() {
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
enabled: true,
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: "PB_NEWTAB_MESSAGING_SYSTEM",
template: "pb_newtab",
content: {
infoEnabled: false,
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
let { win, tab } = await openTabAndWaitForRender();
@ -121,12 +89,16 @@ add_task(async function test_experiment_info_disabled() {
});
add_task(async function test_experiment_promo_disabled() {
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
enabled: true,
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: "PB_NEWTAB_MESSAGING_SYSTEM",
template: "pb_newtab",
content: {
promoEnabled: false,
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
let { win, tab } = await openTabAndWaitForRender();
@ -145,15 +117,19 @@ add_task(async function test_experiment_promo_disabled() {
add_task(async function test_experiment_format_urls() {
const LOCALE = Services.locale.appLocaleAsBCP47;
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
enabled: true,
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: "PB_NEWTAB_MESSAGING_SYSTEM",
template: "pb_newtab",
content: {
infoEnabled: true,
promoEnabled: true,
infoLinkUrl: "http://foo.mozilla.com/%LOCALE%",
promoLinkUrl: "http://bar.mozilla.com/%LOCALE%",
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
let { win, tab } = await openTabAndWaitForRender();
@ -176,13 +152,17 @@ add_task(async function test_experiment_format_urls() {
});
add_task(async function test_experiment_click_info_telemetry() {
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
enabled: true,
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: "PB_NEWTAB_MESSAGING_SYSTEM_CLICK_INFO_TELEM",
template: "pb_newtab",
content: {
infoEnabled: true,
infoLinkUrl: "http://example.com",
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
// Required for `mach test --verify`
@ -207,13 +187,17 @@ add_task(async function test_experiment_click_info_telemetry() {
});
add_task(async function test_experiment_click_promo_telemetry() {
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
enabled: true,
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: `PB_NEWTAB_MESSAGING_SYSTEM_PROMO_TELEM_${Math.random()}`,
template: "pb_newtab",
content: {
promoEnabled: true,
promoLinkUrl: "http://example.com",
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
let { win, tab } = await openTabAndWaitForRender();
@ -240,13 +224,15 @@ add_task(async function test_experiment_bottom_promo() {
const defaultMessageContent = (await PanelTestProvider.getMessages()).find(
m => m.template === "pb_newtab"
).content;
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: "PB_NEWTAB_MESSAGING_SYSTEM",
template: "pb_newtab",
content: {
...defaultMessageContent,
enabled: true,
promoEnabled: true,
promoLinkType: "button",
promoLinkUrl: "http://example.com",
promoLinkUrl: "http://bar.example.com/%LOCALE%",
promoSectionStyle: "bottom",
promoHeader: "Need more privacy?",
infoTitleEnabled: true,
@ -254,6 +240,10 @@ add_task(async function test_experiment_bottom_promo() {
promoImageLarge: "",
promoImageSmall: "chrome://browser/content/assets/vpn-logo.svg",
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
let { win, tab } = await openTabAndWaitForRender();
@ -277,7 +267,7 @@ add_task(async function test_experiment_bottom_promo() {
);
ok(
!content.document.querySelector("#private-browsing-vpn-text"),
"Should not render promo title if promoTitleEnabled is true"
"Should not render promo title if promoTitleEnabled is false"
);
ok(
content.document.querySelector("#info-title"),
@ -297,11 +287,12 @@ add_task(async function test_experiment_below_search_promo() {
const defaultMessageContent = (await PanelTestProvider.getMessages()).find(
m => m.template === "pb_newtab"
).content;
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: "PB_NEWTAB_MESSAGING_SYSTEM",
template: "pb_newtab",
content: {
...defaultMessageContent,
enabled: true,
promoEnabled: true,
promoLinkType: "button",
promoLinkUrl: "http://example.com",
promoSectionStyle: "below-search",
@ -312,6 +303,10 @@ add_task(async function test_experiment_below_search_promo() {
promoImageSmall: "chrome://browser/content/assets/vpn-logo.svg",
infoTitleEnabled: false,
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
let { win, tab } = await openTabAndWaitForRender();
@ -356,11 +351,12 @@ add_task(async function test_experiment_top_promo() {
const defaultMessageContent = (await PanelTestProvider.getMessages()).find(
m => m.template === "pb_newtab"
).content;
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "privatebrowsing",
value: {
let doExperimentCleanup = await setupMSExperimentWithMessage({
id: `PB_NEWTAB_MESSAGING_SYSTEM_DISMISS_${Math.random()}`,
template: "pb_newtab",
content: {
...defaultMessageContent,
enabled: true,
promoEnabled: true,
promoLinkType: "button",
promoLinkUrl: "http://example.com",
promoSectionStyle: "top",
@ -371,6 +367,10 @@ add_task(async function test_experiment_top_promo() {
promoImageSmall: "chrome://browser/content/assets/vpn-logo.svg",
infoTitleEnabled: false,
},
// Priority ensures this message is picked over the one in
// OnboardingMessageProvider
priority: 5,
targeting: "true",
});
let { win, tab } = await openTabAndWaitForRender();

View file

@ -3,7 +3,7 @@
function handleRequest(req, resp) {
resp.setHeader("Content-Type", "text/html", false);
if (req.hasHeader("Origin")) {
if (req.hasHeader("Origin") && req.getHeader("Origin") != "null") {
resp.write("error");
return;
}

View file

@ -230,6 +230,9 @@ const { XPCOMUtils } = ChromeUtils.import(
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const { GlobalState } = ChromeUtils.import(
"resource:///modules/sessionstore/GlobalState.jsm"
);
const lazy = {};
@ -248,7 +251,6 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
DevToolsShim: "chrome://devtools-startup/content/DevToolsShim.jsm",
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
GlobalState: "resource:///modules/sessionstore/GlobalState.jsm",
HomePage: "resource:///modules/HomePage.jsm",
PrivacyFilter: "resource://gre/modules/sessionstore/PrivacyFilter.jsm",
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
@ -606,7 +608,7 @@ var SessionStoreInternal = {
"nsISupportsWeakReference",
]),
_globalState: new lazy.GlobalState(),
_globalState: new GlobalState(),
// A counter to be used to generate a unique ID for each closed tab or window.
_nextClosedId: 0,

View file

@ -33,66 +33,62 @@ addNonCoopTask(
async function test_restore_text_data_subframes(aURL) {
// Add a new tab.
let tab = BrowserTestUtils.addTab(gBrowser, aURL);
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, aURL);
// "Type in" some random values.
await SpecialPowers.spawn(tab.linkedBrowser, [], async function() {
function typeText(aTextField, aValue) {
aTextField.value = aValue;
await setPropertyOfFormField(
tab.linkedBrowser,
"#out1",
"value",
Date.now().toString(16)
);
let event = aTextField.ownerDocument.createEvent("UIEvents");
event.initUIEvent("input", true, true, aTextField.ownerGlobal, 0);
aTextField.dispatchEvent(event);
}
typeText(content.document.getElementById("out1"), Date.now().toString(16));
typeText(content.document.getElementsByName("1|#out2")[0], Math.random());
await SpecialPowers.spawn(content.frames[0], [], async function() {
await SpecialPowers.spawn(content.frames[1], [], async function() {
function typeText2(aTextField, aValue) {
aTextField.value = aValue;
await setPropertyOfFormField(
tab.linkedBrowser,
"input[name='1|#out2']",
"value",
Math.random()
);
let event = aTextField.ownerDocument.createEvent("UIEvents");
event.initUIEvent("input", true, true, aTextField.ownerGlobal, 0);
aTextField.dispatchEvent(event);
}
typeText2(content.document.getElementById("in1"), new Date());
});
});
});
await setPropertyOfFormField(
tab.linkedBrowser.browsingContext.children[0].children[1],
"#in1",
"value",
new Date()
);
// Duplicate the tab.
let tab2 = gBrowser.duplicateTab(tab);
let browser2 = tab2.linkedBrowser;
await promiseTabRestored(tab2);
isnot(
await getPropertyOfFormField(browser2, "#out1", "value"),
await getPropertyOfFormField(
browser2.browsingContext.children[1],
"#out1",
"value"
),
"text isn't reused for frames"
);
isnot(
await getPropertyOfFormField(browser2, "input[name='1|#out2']", "value"),
"",
"text containing | and # is correctly restored"
);
is(
await getPropertyOfFormField(
browser2.browsingContext.children[1],
"#out2",
"value"
),
"",
"id prefixes can't be faked"
);
// Query a few values from the top and its child frames.
await SpecialPowers.spawn(tab2.linkedBrowser, [], async function() {
let out1Val = await SpecialPowers.spawn(
content.frames[1],
[],
async function() {
return content.document.getElementById("out1").value;
}
);
Assert.notEqual(
content.document.getElementById("out1").value,
out1Val,
"text isn't reused for frames"
);
Assert.notEqual(
content.document.getElementsByName("1|#out2")[0].value,
"",
"text containing | and # is correctly restored"
);
let out2Val = await SpecialPowers.spawn(
content.frames[1],
[],
async function() {
return content.document.getElementById("out2").value;
}
);
Assert.equal(out2Val, "", "id prefixes can't be faked");
// Bug 588077
// XXX(farre): disabling this, because it started passing more heavily on Windows.
/*
@ -107,19 +103,17 @@ async function test_restore_text_data_subframes(aURL) {
);
todo_is(in1ValFrame0_1, "", "id prefixes aren't mixed up");
*/
let in1ValFrame1_0 = await SpecialPowers.spawn(
content.frames[1],
[],
async function() {
return SpecialPowers.spawn(content.frames[0], [], async function() {
return content.document.getElementById("in1").value;
});
}
);
Assert.equal(in1ValFrame1_0, "", "id prefixes aren't mixed up");
});
is(
await getPropertyOfFormField(
browser2.browsingContext.children[1].children[0],
"#in1",
"value"
),
"",
"id prefixes aren't mixed up"
);
// Cleanup.
gBrowser.removeTab(tab2);
gBrowser.removeTab(tab);

View file

@ -17,8 +17,6 @@ const { XPCOMUtils } = ChromeUtils.import(
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
XPCOMUtils.defineLazyModuleGetters(this, {
ProfileAge: "resource://gre/modules/ProfileAge.jsm",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",

View file

@ -28,8 +28,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
});
XPCOMUtils.defineLazyGlobalGetters(this, ["crypto", "fetch"]);
const TIMESTAMP_TEMPLATE = "%YYYYMMDDHH%";
const TIMESTAMP_LENGTH = 10;
const TIMESTAMP_REGEXP = /^\d{10}$/;

View file

@ -8,7 +8,6 @@ This is the nascent documentation of the Firefox front-end code.
:maxdepth: 2
urlbar/index
/toolkit/mozapps/update/docs/BackgroundUpdates
BrowserUsageTelemetry
CommandLineParameters
components/enterprisepolicies/docs/index

View file

@ -165,7 +165,7 @@ const AVAILABLE_SHIMS = [
types: ["image", "imageset", "xmlhttprequest"],
},
],
onlyIfDFPIActive: true,
onlyIfBlockedByETP: true,
},
{
id: "AdSafeProtectedGoogleIMAAdapter",
@ -545,7 +545,7 @@ const AVAILABLE_SHIMS = [
types: ["image", "imageset", "xmlhttprequest"],
},
],
onlyIfDFPIActive: true,
onlyIfBlockedByETP: true,
},
{
id: "Vidible",

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Web Compatibility Interventions",
"description": "Urgent post-release fixes for web compatibility.",
"version": "102.11.0",
"version": "102.13.0",
"applications": {
"gecko": {
"id": "webcompat@mozilla.org",

View file

@ -174,3 +174,14 @@ if (window[window.GoogleAnalyticsObject || "ga"]?.loaded === undefined) {
// Run dataLayer.hide.end to handle asynchide (bug 1628151)
run(window.dataLayer?.hide?.end);
}
if (!window?.gaplugins?.Linker) {
window.gaplugins = window.gaplugins || {};
window.gaplugins.Linker = class {
autoLink() {}
decorate(url) {
return url;
}
passthrough() {}
};
}

View file

@ -123,7 +123,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "477713442405d727148d74b07fe5de3cac5ffbac"
"revision": "ab457d20536cdad54f18c6f6e6cebfee7f5b4a6a"
},
"bg": {
"pin": false,
@ -159,7 +159,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "483ebc0eec582865c896a82ad12cfb0c0c3dba3b"
"revision": "dbbc175612ace7929bb0cf161ce9d823eafb3004"
},
"bo": {
"pin": false,
@ -483,7 +483,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "f2fe1f5df117080bdcb664ad545c7619ddd2070a"
"revision": "40b5590086e9b32742f2fa3db7c80437139e6eb0"
},
"es-CL": {
"pin": false,
@ -555,7 +555,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "d5ec66c46af2a98a4bd25df5c994c08291fac0de"
"revision": "3b129b698a2f30a1c8dae7f8968786b0ee08135c"
},
"eu": {
"pin": false,
@ -627,7 +627,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "036521c5740106d4349400b81fe3fa1e2f7d0a43"
"revision": "af0706d0cf385ac9436c67055804860f9e94001c"
},
"fr": {
"pin": false,
@ -663,7 +663,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c00b44f074b8ad9b622f1daab871d54d2d1645ee"
"revision": "e3b53c4c7a7d49418d6b12d40128aae0b513410a"
},
"ga-IE": {
"pin": false,
@ -951,7 +951,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "65370babd8731f8278b79ea0b74f465f4dc39887"
"revision": "714abf1ab272afd53ab6bea729d1bda22f6441da"
},
"ja": {
"pin": false,
@ -1011,7 +1011,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "8e6fbf4edc5bd5f6daafbba7d4e3fe5558b79407"
"revision": "9f1681ad30765dc1098e0668de59d953ab732a5a"
},
"kk": {
"pin": false,
@ -1317,7 +1317,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c395fc5b6bb54bdb75275dcde13a2b9f8e0fc60f"
"revision": "afef0210f7e634d6e548c8d022e5b2a53861cf0a"
},
"nn-NO": {
"pin": false,
@ -1335,7 +1335,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "4598fb2e432dd8a22069fd6c16a0119ffc86f33e"
"revision": "28bdd662868540209fdad943df879806528b1693"
},
"oc": {
"pin": false,
@ -1353,7 +1353,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "a2795507470ca965d783a8fdf04522b79aca3170"
"revision": "bb392bb97d78d2a5d680fb4c0529fa4eee6cc312"
},
"pa-IN": {
"pin": false,
@ -1371,7 +1371,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "613a0f7506b0bd3a289eb841ccad4b8b6d8a2c53"
"revision": "d049479fe4de64b8e5af760f1dd9e0b985f04700"
},
"pl": {
"pin": false,
@ -1407,7 +1407,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "222b020e3b81acc865482d5431df6c7f42780d93"
"revision": "3f34c89e3f254b86bee63146c79c6336c77a61e3"
},
"pt-PT": {
"pin": false,
@ -1425,7 +1425,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "198b02d912931955c81337a225cc8898cbb6e0d7"
"revision": "012095d45e7dfedde3f2ae924005db743bec4926"
},
"rm": {
"pin": false,
@ -1605,7 +1605,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "28103aabc4f3ac18218cd3b446f5c4f014a06c4a"
"revision": "f08c322f36f1ce75ed553fad2c6274d707635ef6"
},
"son": {
"pin": false,
@ -1767,7 +1767,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "7973fb73283f5649e7e3a573aa1114f46663e6e8"
"revision": "1af51f1f890cd94aed334bd335f5dfac56076c56"
},
"tl": {
"pin": false,
@ -1803,7 +1803,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "fd0e0955e3f64b76f3989740f738ca61639f9938"
"revision": "acfcc1ead9c1a6e216a7208fa6052c0573a1b334"
},
"trs": {
"pin": false,
@ -1893,7 +1893,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "acddeae5f5a6744f7b4bece74d8360d9d1aaa4fc"
"revision": "c9537a6c9ddd734253e6ac6d64e2f9eb60d0648e"
},
"wo": {
"pin": false,
@ -1947,7 +1947,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "26c5b9170419a95f54cfa6a80fdb52d557a32256"
"revision": "ccdf7081c85960340e57b23c5bf31bc057f64cf3"
},
"zh-TW": {
"pin": false,

View file

@ -4,8 +4,6 @@
"use strict";
Cu.importGlobalProperties(["fetch"]);
var EXPORTED_SYMBOLS = [
"PartnerLinkAttribution",
"CONTEXTUAL_SERVICES_PING_TYPES",

View file

@ -683,7 +683,7 @@
/* Firefox View button */
:is(#firefox-view-button, #wrapper-firefox-view-button) + #tabbrowser-tabs {
:root:not([privatebrowsingmode=temporary]) :is(#firefox-view-button, #wrapper-firefox-view-button) + #tabbrowser-tabs {
border-inline-start: 1px solid color-mix(in srgb, currentColor 25%, transparent);
padding-inline-start: calc(var(--tab-overflow-pinned-tabs-width) + 4px);
margin-inline-start: 4px;

View file

@ -186,13 +186,13 @@ toolbar .toolbarbutton-1:not([disabled=true]):is([open],[checked],:hover:active)
}
/* Keyboard focus styling */
.titlebar-button:focus-visible,
#PersonalToolbar .toolbarbutton-1:focus-visible,
findbar toolbarbutton.tabbable:focus-visible,
toolbarbutton.bookmark-item:not(.subviewbutton):focus-visible,
toolbar:not(#PersonalToolbar) .toolbarbutton-1:focus-visible > .toolbarbutton-icon,
toolbar:not(#PersonalToolbar) .toolbarbutton-1:focus-visible > .toolbarbutton-text,
toolbar:not(#PersonalToolbar) .toolbarbutton-1:focus-visible > .toolbarbutton-badge-stack {
color: inherit;
outline: var(--focus-outline);
outline-offset: var(--focus-outline-inset);
}

View file

@ -36,7 +36,7 @@ allprojects {
topsrcdir = gradle.mozconfig.topsrcdir
topobjdir = gradle.mozconfig.topobjdir
gleanVersion = "50.0.1"
gleanVersion = "50.1.0"
if (gleanVersion != getRustVersionFor("glean")) {
throw new StopExecutionException("Mismatched Glean version, expected: ${gleanVersion}," +
" found ${getRustVersionFor("glean")}")

View file

@ -20,16 +20,38 @@ option(
set_config("MOZ_UPDATER", True, when="--enable-updater")
set_define("MOZ_UPDATER", True, when="--enable-updater")
# Verify MAR signatures
# Updates that do not verify signatures
# ==============================================================
option("--disable-verify-mar", help="Disable verifying MAR signatures")
option(
"--enable-unverified-updates",
default=False,
help="Enable application update without verifying MAR or updater binary signatures",
)
@depends("--enable-unverified-updates", "--enable-compile-environment")
def disable_unverified_updates(unverified_updates, compile_environment):
if unverified_updates:
if not compile_environment:
die("--enable-unverified-updates requires --enable-compile-environment")
return not unverified_updates
set_define(
"MOZ_VERIFY_MAR_SIGNATURE", depends_if("--enable-verify-mar")(lambda _: True)
"MOZ_VERIFY_MAR_SIGNATURE",
depends_if(disable_unverified_updates)(lambda _: True),
)
set_config(
"MOZ_VERIFY_MAR_SIGNATURE", depends_if("--enable-verify-mar")(lambda _: True)
"MOZ_VERIFY_MAR_SIGNATURE",
True,
depends_if(disable_unverified_updates)(lambda _: True),
)
set_config(
"DISABLE_UPDATER_AUTHENTICODE_CHECK",
True,
depends_if("--enable-unverified-updates")(lambda _: True),
)
# Maintenance service (Windows only)

View file

@ -0,0 +1,17 @@
[package]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview999"
edition = "2018"
license = "MPL-2.0"
[lib]
path = "lib.rs"
[dependencies.wasi]
version = "0.11"
default-features = false
[features]
default = ["wasi/default"]
rustc-dep-of-std = ["wasi/rustc-dep-of-std"]
std = ["wasi/std"]

5
build/rust/wasi/lib.rs Normal file
View file

@ -0,0 +1,5 @@
/* 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/. */
pub use wasi::*;

View file

@ -105,17 +105,6 @@ class SourcesTree extends Component {
);
}
if (
nextProps.selectedSource &&
nextProps.selectedSource != selectedSource
) {
const highlightItems = getDirectories(
nextProps.selectedSource,
sourceTree
);
this.setState({ highlightItems });
}
// NOTE: do not run this every time a source is clicked,
// only when a new source is added
if (nextProps.sources != this.props.sources) {
@ -128,9 +117,43 @@ class SourcesTree extends Component {
sourceTree,
});
if (update) {
this.setState(update);
this.setState({
uncollapsedTree: update.uncollapsedTree,
sourceTree: update.sourceTree,
getParent: update.getParent,
});
}
}
// Execute this *after* the call to updateTree in case the selected source
// just got added in the props.
if (
nextProps.selectedSource &&
nextProps.selectedSource != selectedSource
) {
const highlightItems = getDirectories(
nextProps.selectedSource,
// Ensure querying latest state, in case updateTree updated the source tree
this.state.sourceTree
);
this.setState({ highlightItems });
// Also, it can happen that the source is selected before it is registered in the tree,
// In which case, this previous line would select the root item.
// So check if we have a selectedSource and we are on root and we got new sources,
// to try to update the selected item in the ManagedTree
} else if (
nextProps.selectedSource &&
this.state.highlightItems &&
this.state.highlightItems[0].name == "root"
) {
const highlightItems = getDirectories(
nextProps.selectedSource,
// Ensure querying latest state, in case updateTree updated the source tree
this.state.sourceTree
);
this.setState({ highlightItems });
}
}
selectItem = item => {

View file

@ -34,8 +34,8 @@ add_task(async function() {
await waitForPaused(dbg);
await waitForSelectedSource(dbg, "content_script.js");
ok(
findElementWithSelector(dbg, ".sources-list .focused"),
await waitFor(
() => findElementWithSelector(dbg, ".sources-list .focused"),
"Source is focused"
);
assertPausedAtSourceAndLine(

View file

@ -393,19 +393,14 @@ add_task(async function testSourceTreeWithWebExtensionContentScript() {
let dbg = await initDebugger("doc-content-script-sources.html");
// Let some time for unexpected source to appear
await wait(1000);
// Bug 1761975 - While the content script doesn't show up,
// the internals of WebExtension codebase appear in the debugger...
await waitForSourcesInSourceTree(dbg, ["ExtensionContent.jsm"]);
await waitForSourcesInSourceTree(dbg, []);
await dbg.toolbox.closeToolbox();
info("With the chrome preference, the content script shows up");
await pushPref("devtools.chrome.enabled", true);
const toolbox = await openToolboxForTab(gBrowser.selectedTab, "jsdebugger");
dbg = createDebuggerContext(toolbox);
await waitForSourcesInSourceTree(dbg, [
"content_script.js",
"ExtensionContent.jsm",
]);
await waitForSourcesInSourceTree(dbg, ["content_script.js"]);
await selectSource(dbg, "content_script.js");
ok(
findElementWithSelector(dbg, ".sources-list .focused"),
@ -445,7 +440,6 @@ add_task(async function testSourceTreeNamesForWebExtensions() {
"Test content script extension",
"Test content script extension is labeled properly"
);
is(getLabel(dbg, 3), "resource://gre", "resource://gre is labeled properly");
await dbg.toolbox.closeToolbox();
await extension.unload();

View file

@ -58,6 +58,11 @@ const MessageState = overrides =>
// List of all the messages added to the console. Unlike other properties, this Map
// will be mutated on state changes for performance reasons.
mutableMessagesById: new Map(),
// Array of message ids, in chronological order. We use a dedicated property to store
// the order (instead of relying on the order of insertion in mutableMessagesById)
// as we might receive messages that need to be inserted at a specific index. Doing
// so on the Map can be costly, especially when the Map holds lots of messages.
mutableMessagesOrder: [],
// List of elements matching the selector of CSS Warning messages(populated
// on-demand via the UI).
cssMessagesMatchingElements: new Map(),
@ -103,6 +108,7 @@ function cloneState(state) {
warningGroupsById: new Map(state.warningGroupsById),
// no need to mutate the properties below as they're not directly triggering re-render
mutableMessagesById: state.mutableMessagesById,
mutableMessagesOrder: state.mutableMessagesOrder,
currentGroup: state.currentGroup,
lastMessageId: state.lastMessageId,
};
@ -167,8 +173,6 @@ function addMessage(newMessage, state, filtersState, prefsState, uiState) {
newMessage.indent = parentGroups.length;
}
const removedIds = [];
// Check if the current message could be placed in a Warning Group.
// This needs to be done before setting the new message in mutableMessagesById so we have a
// proper message.
@ -261,21 +265,25 @@ function addMessage(newMessage, state, filtersState, prefsState, uiState) {
// If the new message isn't the "oldest" one, then we need to insert it at the right
// position in the message map.
if (isUnsorted) {
const entries = Array.from(state.mutableMessagesById.entries());
const newMessageIndex = entries.findIndex(
entry => entry[1].timeStamp > addedMessage.timeStamp
);
// This shouldn't happen as `isUnsorted` would only be true if the last message is
// younger than the added message.
if (newMessageIndex === -1) {
state.mutableMessagesById.set(addedMessage.id, addedMessage);
} else {
entries.splice(newMessageIndex, 0, [addedMessage.id, addedMessage]);
state.mutableMessagesById = new Map(entries);
let newMessageIndex = 0;
// This is can be on a hot path, so we're not using `findIndex`, which could be slow.
// Furthermore, there's a high chance the message beed to be inserted somewhere at the
// end of the list, so we loop through mutableMessagesOrder in reverse order.
for (let i = state.mutableMessagesOrder.length - 1; i >= 0; i--) {
const message = state.mutableMessagesById.get(
state.mutableMessagesOrder[i]
);
if (message.timeStamp <= addedMessage.timeStamp) {
newMessageIndex = i + 1;
break;
}
}
state.mutableMessagesOrder.splice(newMessageIndex, 0, addedMessage.id);
} else {
state.mutableMessagesById.set(addedMessage.id, addedMessage);
state.mutableMessagesOrder.push(addedMessage.id);
}
state.mutableMessagesById.set(addedMessage.id, addedMessage);
if (newMessage.type === "trace") {
// We want the stacktrace to be open by default.
@ -322,16 +330,20 @@ function addMessage(newMessage, state, filtersState, prefsState, uiState) {
} else if (isUnsorted) {
// If the new message wasn't the "oldest" one, then we need to insert its id at
// the right position in the array.
const index = state.visibleMessages.findIndex(
id => state.mutableMessagesById.get(id).timeStamp > newMessage.timeStamp
);
// If the index wasn't found, it means the new message is the oldest of the visible
// messages, so we can directly push it into the array.
if (index == -1) {
state.visibleMessages.push(newMessage.id);
} else {
state.visibleMessages.splice(index, 0, newMessage.id);
// This is can be on a hot path, so we're not using `findIndex`, which could be slow.
// Furthermore, there's a high chance the message beed to be inserted somewhere at the
// end of the list, so we loop through visibleMessages in reverse order.
let index = 0;
for (let i = state.visibleMessages.length - 1; i >= 0; i--) {
const id = state.visibleMessages[i];
if (
state.mutableMessagesById.get(id).timeStamp <= newMessage.timeStamp
) {
index = i + 1;
break;
}
}
state.visibleMessages.splice(index, 0, newMessage.id);
} else {
state.visibleMessages.push(newMessage.id);
}
@ -347,7 +359,7 @@ function addMessage(newMessage, state, filtersState, prefsState, uiState) {
state.networkMessagesUpdateById[newMessage.actor] = newMessage;
}
return removeMessagesFromState(state, removedIds);
return state;
}
// eslint-disable-next-line complexity
@ -465,7 +477,8 @@ function messages(
if (isGroupType(currMessage.type) || isWarningGroup(currMessage)) {
// We want to make its children visible
const messagesToShow = [];
for (const [id, message] of mutableMessagesById) {
for (const id of state.mutableMessagesOrder) {
const message = mutableMessagesById.get(id);
if (
!visibleMessages.includes(message.id) &&
((isWarningGroup(currMessage) && !!getWarningGroupType(message)) ||
@ -495,18 +508,6 @@ function messages(
...visibleMessages.slice(insertIndex),
];
}
// If the current message is a network event, mark it as opened-once,
// so HTTP details are not fetched again the next time the user
// opens the log.
if (currMessage.source == "network") {
openState.mutableMessagesById = new Map(mutableMessagesById).set(
action.id,
{
...currMessage,
}
);
}
return openState;
case constants.MESSAGE_CLOSE:
@ -631,7 +632,8 @@ function messages(
}
let needSort = false;
for (const [msgId, message] of state.mutableMessagesById) {
for (const msgId of state.mutableMessagesOrder) {
const message = state.mutableMessagesById.get(msgId);
const warningGroupType = getWarningGroupType(message);
if (warningGroupType) {
const warningGroupMessageId = getParentWarningGroupMessageId(message);
@ -714,6 +716,7 @@ function setVisibleMessages({
}) {
const {
mutableMessagesById,
mutableMessagesOrder,
visibleMessages,
messagesUiById,
} = messagesState;
@ -722,7 +725,8 @@ function setVisibleMessages({
const matchedGroups = new Set();
const filtered = getDefaultFiltersCounter();
mutableMessagesById.forEach((message, msgId) => {
mutableMessagesOrder.forEach(msgId => {
const message = mutableMessagesById.get(msgId);
const groupParentId = message.groupId;
let hasMatchedAncestor = false;
const ancestors = [];
@ -877,7 +881,8 @@ function limitTopLevelMessageCount(newState, logLimit) {
const removedMessagesId = [];
let cleaningGroup = false;
for (const [id, message] of newState.mutableMessagesById) {
for (const id of newState.mutableMessagesOrder) {
const message = newState.mutableMessagesById.get(id);
// If we were cleaning a group and the current message does not have
// a groupId, we're done cleaning.
if (cleaningGroup === true && !message.groupId) {
@ -962,7 +967,13 @@ function removeMessagesFromState(state, removedMessagesIds) {
return res;
}, {});
removedMessagesIds.forEach(id => state.mutableMessagesById.delete(id));
removedMessagesIds.forEach(id => {
state.mutableMessagesById.delete(id);
state.mutableMessagesOrder.splice(
state.mutableMessagesOrder.indexOf(id),
1
);
});
if (state.messagesUiById.find(isInRemovedId)) {
state.messagesUiById = state.messagesUiById.filter(

View file

@ -81,8 +81,8 @@ function clonePacket(packet) {
* @return {Message} - The message, or undefined if the index does not exists in the map.
*/
function getMessageAt(state, index) {
const messages = getMutableMessagesById(state);
return messages.get([...messages.keys()][index]);
const messageMap = getMutableMessagesById(state);
return messageMap.get(state.messages.mutableMessagesOrder[index]);
}
/**
@ -102,7 +102,7 @@ function getFirstMessage(state) {
* @return {Message} - The last message, or undefined if there are no message in store.
*/
function getLastMessage(state) {
const lastIndex = getMutableMessagesById(state).size - 1;
const lastIndex = state.messages.mutableMessagesOrder.length - 1;
return getMessageAt(state, lastIndex);
}

View file

@ -320,6 +320,7 @@ describe("Message reducer:", () => {
expect(getAllCssMessagesMatchingElements(state).size).toBe(0);
expect(getCurrentGroup(state)).toBe(null);
expect(getAllRepeatById(state)).toEqual({});
expect(state.messages.mutableMessagesOrder).toEqual([]);
});
it("cleans the repeatsById object when messages are pruned", () => {
@ -383,6 +384,9 @@ describe("Message reducer:", () => {
expect(getLastMessage(getState()).parameters[0]).toBe(
`message num ${logLimit + 2}`
);
const { mutableMessagesOrder } = getState().messages;
expect(mutableMessagesOrder.length).toBe(logLimit);
});
it("properly limits number of messages when there are nested groups", () => {
@ -421,9 +425,12 @@ describe("Message reducer:", () => {
const visibleMessages = getVisibleMessages(getState());
const messages = getMutableMessagesById(getState());
const { mutableMessagesOrder } = getState().messages;
expect(messages.size).toBe(logLimit);
expect(visibleMessages.length).toBe(logLimit);
expect(mutableMessagesOrder.length).toBe(logLimit);
expect(messages.get(visibleMessages[0]).parameters[0]).toBe(`message-0`);
expect(messages.get(visibleMessages[logLimit - 1]).parameters[0]).toBe(
`message-${logLimit - 1}`
@ -648,6 +655,73 @@ describe("Message reducer:", () => {
});
});
describe("mutableMessagesOrder", () => {
it("adds a message to an empty store", () => {
const { dispatch, getState } = setupStore();
const packet = stubPackets.get("console.log('foobar', 'test')");
dispatch(actions.messagesAdd([packet]));
const { mutableMessagesOrder } = getState().messages;
expect(mutableMessagesOrder.length).toBe(1);
expect(mutableMessagesOrder[0]).toBe(
// Don't get getMessageIndexAt/getFirstMessage since it relies on mutableMessagesOrder
[...getMutableMessagesById(getState()).keys()][0]
);
});
it("reorder messages", () => {
const { dispatch, getState } = setupStore();
const naNpacket = stubPackets.get("console.log(NaN)");
dispatch(actions.messagesAdd([naNpacket]));
// Add a message that has a shorter timestamp than the previous one, and thus, should
// be displayed before
const nullPacket = clonePacket(stubPackets.get("console.log(null)"));
nullPacket.message.timeStamp = naNpacket.message.timeStamp - 10;
dispatch(actions.messagesAdd([nullPacket]));
// Add a message that should be display between the 2 previous messages
const undefinedPacket = clonePacket(
stubPackets.get("console.log(undefined)")
);
undefinedPacket.message.timeStamp = naNpacket.message.timeStamp - 5;
dispatch(actions.messagesAdd([undefinedPacket]));
const { mutableMessagesOrder } = getState().messages;
const [nanMessage, nullMessage, undefinedMessage] = [
...getMutableMessagesById(getState()).values(),
];
const visibleMessages = getVisibleMessages(getState());
// Checking that messages in the Map are the expected ones
expect(nanMessage.parameters[0].type).toBe("NaN");
expect(nullMessage.parameters[0].type).toBe("null");
expect(undefinedMessage.parameters[0].type).toBe("undefined");
// Check that mutableMessagesOrder has the message ids in the chronological order
expect(mutableMessagesOrder).toEqual([
nullMessage.id,
undefinedMessage.id,
nanMessage.id,
]);
// Since we didn't filtered anything, visibleMessages should be similar to mutableMessagesOrder
expect(mutableMessagesOrder).toEqual(visibleMessages);
// Check that visibleMessages is computed from mutableMessagesOrder when filtering
dispatch(actions.filterToggle("log"));
expect(getVisibleMessages(getState())).toEqual([]);
dispatch(actions.filterToggle("log"));
expect(getVisibleMessages(getState())).toEqual([
nullMessage.id,
undefinedMessage.id,
nanMessage.id,
]);
});
});
describe("expandedMessageIds", () => {
it("opens console.trace messages when they are added", () => {
const { dispatch, getState } = setupStore();
@ -1157,8 +1231,10 @@ describe("Message reducer:", () => {
dispatch(actions.messageRemove(secondTraceMessage.id));
const messages = getMutableMessagesById(getState());
const { mutableMessagesOrder } = getState().messages;
// The messages was removed
expect(messages.size).toBe(3);
expect(mutableMessagesOrder.length).toBe(3);
// Its id was removed from the messagesUI property as well
expanded = getAllMessagesUiById(getState());

View file

@ -2056,6 +2056,31 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
this._shouldEmitNewSource = false;
},
/**
* Filtering function to filter out sources for which we don't want to notify/create
* source actors
*
* @param {Debugger.Source} source
* The source to accept or ignore
* @param Boolean
* True, if we want to create a source actor.
*/
_acceptSource(source) {
// We have some spurious source created by ExtensionContent.jsm when debugging tabs.
// These sources are internal stuff injected by WebExt codebase to implement content
// scripts. We can't easily ignore them from Debugger API, so ignore them
// when debugging a tab (i.e. browser-element). As we still want to debug them
// from the browser toolbox.
if (
this._parent.sessionContext.type == "browser-element" &&
source.url.endsWith("ExtensionContent.jsm")
) {
return false;
}
return true;
},
/**
* Add the provided source to the server cache.
*
@ -2063,6 +2088,10 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
* The source that will be stored.
*/
_addSource(source) {
if (!this._acceptSource(source)) {
return;
}
// Preloaded WebExtension content scripts may be cached internally by
// ExtensionContent.jsm and ThreadActor would ignore them on a page reload
// because it finds them in the _debuggerSourcesSeen WeakSet,

View file

@ -23,6 +23,9 @@ const {
} = require("devtools/shared/specs/targets/window-global");
const { tabDescriptorSpec } = require("devtools/shared/specs/descriptors/tab");
const Targets = require("devtools/server/actors/targets/index");
const {
createContentProcessSessionContext,
} = require("devtools/server/actors/watcher/session-context");
var gTestGlobals = new Set();
DevToolsServer.addTestGlobal = function(global) {
@ -150,6 +153,8 @@ const TestTargetActor = protocol.ActorClassWithSpec(windowGlobalTargetSpec, {
initialize: function(conn, global) {
protocol.Actor.prototype.initialize.call(this, conn);
this.conn = conn;
this.sessionContext = createContentProcessSessionContext();
this._global = global;
this._global.wrappedJSObject = global;
this.threadActor = new ThreadActor(this, this._global);

View file

@ -49,6 +49,7 @@ The plugin implements the following rules:
eslint-plugin-mozilla/reject-addtask-only
eslint-plugin-mozilla/reject-chromeutils-import-params
eslint-plugin-mozilla/reject-global-this
eslint-plugin-mozilla/reject-globalThis-modification
eslint-plugin-mozilla/reject-importGlobalProperties
eslint-plugin-mozilla/reject-osfile
eslint-plugin-mozilla/reject-relative-requires

View file

@ -0,0 +1,19 @@
reject-globalThis-modification
==============================
Reject any modification to ``globalThis`` inside the system modules.
``globalThis`` is the shared global inside the system modules, and modification
on it is visible from all modules, and it shouldn't be done unless it's really
necessary.
Examples of incorrect code for this rule:
-----------------------------------------
.. code-block:: js
globalThis.foo = 10;
Object.defineProperty(globalThis, "bar", { value: 20});
XPCOMUtils.defineLazyModuleGetters(globalThis, {
Services: "resource://gre/modules/Services.jsm",
});

View file

@ -5796,8 +5796,8 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
if (WindowContext* windowContext =
mBrowsingContext->GetCurrentWindowContext()) {
SessionStoreChild::From(windowContext->GetWindowGlobalChild())
->SendResetSessionStore(
mBrowsingContext, mBrowsingContext->GetSessionStoreEpoch());
->ResetSessionStore(mBrowsingContext,
mBrowsingContext->GetSessionStoreEpoch());
}
}
}
@ -6538,11 +6538,14 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
if (WindowContext* windowContext =
mBrowsingContext->GetCurrentWindowContext()) {
// TODO(farre): File bug: From a user perspective this would probably be
// just fine to run off the change listener timer. Turns out that a flush
// is needed. Several tests depend on this behaviour. Could potentially be
// an optimization for later. See Bug 1756995.
SessionStoreChangeListener::FlushAllSessionStoreData(windowContext);
using Change = SessionStoreChangeListener::Change;
// We've finished loading the page and now we want to collect all the
// session store state that the page is initialized with.
SessionStoreChangeListener::CollectSessionStoreData(
windowContext,
EnumSet<Change>(Change::Input, Change::Scroll, Change::SessionHistory,
Change::WireFrame));
}
}
@ -11463,6 +11466,7 @@ nsresult nsDocShell::UpdateURLAndHistory(Document* aDocument, nsIURI* aNewURI,
UpdateActiveEntry(false,
/* aPreviousScrollPos = */ Some(scrollPos), aNewURI,
/* aOriginalURI = */ nullptr,
/* aReferrerInfo = */ nullptr,
/* aTriggeringPrincipal = */ aDocument->NodePrincipal(),
csp, title, scrollRestorationIsManual, aData,
uriWasModified);
@ -11505,12 +11509,17 @@ nsresult nsDocShell::UpdateURLAndHistory(Document* aDocument, nsIURI* aNewURI,
// in our case. We could also set it to aNewURI, with the same result.
// We don't use aTitle here, see bug 544535.
nsString title;
nsCOMPtr<nsIReferrerInfo> referrerInfo;
if (mActiveEntry) {
title = mActiveEntry->GetTitle();
referrerInfo = mActiveEntry->GetReferrerInfo();
} else {
referrerInfo = nullptr;
}
UpdateActiveEntry(
true, /* aPreviousScrollPos = */ Nothing(), aNewURI, aNewURI,
aDocument->NodePrincipal(), aDocument->GetCsp(), title,
/* aReferrerInfo = */ referrerInfo, aDocument->NodePrincipal(),
aDocument->GetCsp(), title,
mActiveEntry && mActiveEntry->GetScrollRestorationIsManual(), aData,
uriWasModified);
} else {
@ -11930,10 +11939,10 @@ nsresult nsDocShell::AddToSessionHistory(
void nsDocShell::UpdateActiveEntry(
bool aReplace, const Maybe<nsPoint>& aPreviousScrollPos, nsIURI* aURI,
nsIURI* aOriginalURI, nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp, const nsAString& aTitle,
bool aScrollRestorationIsManual, nsIStructuredCloneContainer* aData,
bool aURIWasModified) {
nsIURI* aOriginalURI, nsIReferrerInfo* aReferrerInfo,
nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
const nsAString& aTitle, bool aScrollRestorationIsManual,
nsIStructuredCloneContainer* aData, bool aURIWasModified) {
MOZ_ASSERT(mozilla::SessionHistoryInParent());
MOZ_ASSERT(aURI, "uri is null");
MOZ_ASSERT(mLoadType == LOAD_PUSHSTATE,
@ -11962,6 +11971,7 @@ void nsDocShell::UpdateActiveEntry(
aURI, aTriggeringPrincipal, nullptr, nullptr, aCsp, mContentTypeHint);
}
mActiveEntry->SetOriginalURI(aOriginalURI);
mActiveEntry->SetReferrerInfo(aReferrerInfo);
mActiveEntry->SetTitle(aTitle);
mActiveEntry->SetStateData(static_cast<nsStructuredCloneContainer*>(aData));
mActiveEntry->SetURIWasModified(aURIWasModified);

View file

@ -640,10 +640,10 @@ class nsDocShell final : public nsDocLoader,
void UpdateActiveEntry(
bool aReplace, const mozilla::Maybe<nsPoint>& aPreviousScrollPos,
nsIURI* aURI, nsIURI* aOriginalURI, nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp, const nsAString& aTitle,
bool aScrollRestorationIsManual, nsIStructuredCloneContainer* aData,
bool aURIWasModified);
nsIURI* aURI, nsIURI* aOriginalURI, nsIReferrerInfo* aReferrerInfo,
nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
const nsAString& aTitle, bool aScrollRestorationIsManual,
nsIStructuredCloneContainer* aData, bool aURIWasModified);
nsresult AddChildSHEntry(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
int32_t aChildOffset, uint32_t aLoadType,

View file

@ -71,6 +71,11 @@ class SessionHistoryInfo {
mResultPrincipalURI = aResultPrincipalURI;
}
nsIReferrerInfo* GetReferrerInfo() { return mReferrerInfo; }
void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
mReferrerInfo = aReferrerInfo;
}
bool HasPostData() const { return mPostData; }
already_AddRefed<nsIInputStream> GetPostData() const;
void SetPostData(nsIInputStream* aPostData);

View file

@ -0,0 +1,13 @@
<script>
let bc = new BroadcastChannel("bug1743353");
bc.addEventListener("message", ({ data }) => {
if (data == "next") {
location = "file_bug1773192_2.html";
} else if (data == "close") {
window.close();
}
});
window.addEventListener("pageshow", () => {
bc.postMessage({ location: location.href, referrer: document.referrer });
});
</script>

View file

@ -0,0 +1,13 @@
<html>
<head>
<meta http-equiv="Cache-Control" content="no-cache, no-store">
<meta name="referrer" content="same-origin">
</head>
<body>
<form method="POST" action="file_bug1773192_3.sjs"></form>
<script>
history.replaceState({}, "", document.referrer);
document.forms[0].submit();
</script>
</body>
</html>

View file

@ -0,0 +1,3 @@
function handleRequest(request, response) {
response.write("<script>history.back();</script>");
}

View file

@ -140,6 +140,11 @@ support-files =
[test_bug1747033.html]
support-files =
file_bug1747033.sjs
[test_bug1773192.html]
support-files =
file_bug1773192_1.html
file_bug1773192_2.html
file_bug1773192_3.sjs
[test_close_onpagehide_by_history_back.html]
[test_close_onpagehide_by_window_close.html]
[test_compressed_multipart.html]

View file

@ -0,0 +1,61 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test referrer with going back</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<script>
SimpleTest.waitForExplicitFinish();
// file_bug1773192_1.html will send a message with some data on pageshow.
function waitForData(bc) {
return new Promise(resolve => {
bc.addEventListener(
"message",
({ data }) => {
resolve(data);
},
{ once: true }
);
});
}
async function runTest() {
let bc = new BroadcastChannel("bug1743353");
let getData = waitForData(bc);
window.open("file_bug1773192_1.html", "", "noreferrer");
await getData.then(({ referrer }) => {
is(referrer, "", "Referrer should be empty at first.");
});
getData = waitForData(bc);
// When file_bug1773192_1.html receives this message it will navigate to
// file_bug1773192_2.html. file_bug1773192_2.html removes itself from
// history with replaceState and submits a form with the POST method to
// file_bug1773192_3.sjs. file_bug1773192_3.sjs goes back in history.
// We should end up back at file_bug1773192_1.html, which will send a
// message with some data on pageshow.
bc.postMessage("next");
await getData.then(({ location, referrer }) => {
let firstURL = new URL("file_bug1773192_1.html", location).toString();
is(location, firstURL, "Location should be the first page again.");
is(referrer, firstURL, "Referrer should also be the first page.");
});
bc.postMessage("close");
SimpleTest.finish();
}
</script>
</head>
<body onload="runTest();">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</html>

View file

@ -1442,7 +1442,6 @@ Document::Document(const char* aContentType)
mViewportFit(ViewportFitType::Auto),
mSubDocuments(nullptr),
mHeaderData(nullptr),
mFlashClassification(FlashClassification::Unknown),
mServoRestyleRootDirtyBits(0),
mThrowOnDynamicMarkupInsertionCounter(0),
mIgnoreOpensDuringUnloadCounter(0),
@ -4302,11 +4301,6 @@ bool Document::GetAllowPlugins() {
}
}
FlashClassification classification = DocumentFlashClassification();
if (classification == FlashClassification::Denied) {
return false;
}
return true;
}
@ -16610,52 +16604,6 @@ bool Document::IsExtensionPage() const {
BasePrincipal::Cast(NodePrincipal())->AddonPolicy();
}
/**
* Retrieves the classification of the Flash plugins in the document based on
* the classification lists. For more information, see
* toolkit/components/url-classifier/flash-block-lists.rst
*/
FlashClassification Document::DocumentFlashClassification() {
// Disable flash blocking when fission is enabled(See Bug 1584931).
const auto fnIsFlashBlockingEnabled = [] {
return StaticPrefs::plugins_flashBlock_enabled() && !FissionAutostart();
};
// If neither pref is on, skip the null-principal and principal URI checks.
if (!StaticPrefs::plugins_http_https_only() && !fnIsFlashBlockingEnabled()) {
return FlashClassification::Unknown;
}
if (!NodePrincipal()->GetIsContentPrincipal()) {
return FlashClassification::Denied;
}
if (StaticPrefs::plugins_http_https_only()) {
// Only allow plugins for documents from an HTTP/HTTPS origin. This should
// allow dependent data: URIs to load plugins, but not:
// * chrome documents
// * "bare" data: loads
// * FTP/gopher/file
if (!(NodePrincipal()->SchemeIs("http") ||
NodePrincipal()->SchemeIs("https"))) {
return FlashClassification::Denied;
}
}
// If flash blocking is disabled, it is equivalent to all sites being
// on neither list.
if (!fnIsFlashBlockingEnabled()) {
return FlashClassification::Unknown;
}
if (mFlashClassification == FlashClassification::Unknown) {
mFlashClassification = DocumentFlashClassificationInternal();
}
return mFlashClassification;
}
void Document::AddResizeObserver(ResizeObserver& aObserver) {
if (!mResizeObserverController) {
mResizeObserverController = MakeUnique<ResizeObserverController>(this);
@ -16692,123 +16640,6 @@ void Document::ScheduleResizeObserversNotification() const {
mResizeObserverController->ScheduleNotification();
}
/**
* Initializes |mIsThirdPartyForFlashClassifier| if necessary and returns its
* value. The value returned represents whether this document should be
* considered Third-Party.
*
* A top-level document cannot be a considered Third-Party; only subdocuments
* may. For a subdocument to be considered Third-Party, it must meet ANY ONE
* of the following requirements:
* - The document's parent is Third-Party
* - The document has a different scheme (http/https) than its parent document
* - The document's domain and subdomain do not match those of its parent
* document.
*
* If there is an error in determining whether the document is Third-Party,
* it will be assumed to be Third-Party for security reasons.
*/
bool Document::IsThirdPartyForFlashClassifier() {
if (mIsThirdPartyForFlashClassifier.isSome()) {
return mIsThirdPartyForFlashClassifier.value();
}
BrowsingContext* browsingContext = this->GetBrowsingContext();
if (!browsingContext) {
mIsThirdPartyForFlashClassifier.emplace(true);
return mIsThirdPartyForFlashClassifier.value();
}
if (browsingContext->IsTop()) {
mIsThirdPartyForFlashClassifier.emplace(false);
return mIsThirdPartyForFlashClassifier.value();
}
nsCOMPtr<Document> parentDocument = GetInProcessParentDocument();
if (!parentDocument) {
// Failure
mIsThirdPartyForFlashClassifier.emplace(true);
return mIsThirdPartyForFlashClassifier.value();
}
if (parentDocument->IsThirdPartyForFlashClassifier()) {
mIsThirdPartyForFlashClassifier.emplace(true);
return mIsThirdPartyForFlashClassifier.value();
}
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
nsCOMPtr<nsIPrincipal> parentPrincipal = parentDocument->GetPrincipal();
bool principalsMatch = false;
nsresult rv = principal->Equals(parentPrincipal, &principalsMatch);
if (NS_WARN_IF(NS_FAILED(rv))) {
// Failure
mIsThirdPartyForFlashClassifier.emplace(true);
return mIsThirdPartyForFlashClassifier.value();
}
if (!principalsMatch) {
mIsThirdPartyForFlashClassifier.emplace(true);
return mIsThirdPartyForFlashClassifier.value();
}
// Fall-through. Document is not a Third-Party Document.
mIsThirdPartyForFlashClassifier.emplace(false);
return mIsThirdPartyForFlashClassifier.value();
}
FlashClassification Document::DocumentFlashClassificationInternal() {
FlashClassification classification = FlashClassification::Unknown;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(GetChannel());
if (httpChannel) {
nsIHttpChannel::FlashPluginState state = nsIHttpChannel::FlashPluginUnknown;
httpChannel->GetFlashPluginState(&state);
// Allow unknown children to inherit allowed status from parent, but do not
// allow denied children to do so.
if (state == nsIHttpChannel::FlashPluginDeniedInSubdocuments &&
IsThirdPartyForFlashClassifier()) {
return FlashClassification::Denied;
}
if (state == nsIHttpChannel::FlashPluginDenied) {
return FlashClassification::Denied;
}
if (state == nsIHttpChannel::FlashPluginAllowed) {
classification = FlashClassification::Allowed;
}
}
if (IsTopLevelContentDocument()) {
return classification;
}
Document* parentDocument = GetInProcessParentDocument();
if (!parentDocument) {
return FlashClassification::Denied;
}
FlashClassification parentClassification =
parentDocument->DocumentFlashClassification();
if (parentClassification == FlashClassification::Denied) {
return FlashClassification::Denied;
}
// Allow unknown children to inherit allowed status from parent, but
// do not allow denied children to do so.
if (classification == FlashClassification::Unknown &&
parentClassification == FlashClassification::Allowed) {
return FlashClassification::Allowed;
}
return classification;
}
void Document::ClearStaleServoData() {
DocumentStyleRootIterator iter(this);
while (Element* root = iter.GetNextStyleRoot()) {

View file

@ -3757,10 +3757,6 @@ class Document : public nsINode,
// determine if it belongs to a tracker.
bool IsScriptTracking(JSContext* aCx) const;
// For more information on Flash classification, see
// toolkit/components/url-classifier/flash-block-lists.rst
FlashClassification DocumentFlashClassification();
// ResizeObserver usage.
void AddResizeObserver(ResizeObserver&);
void RemoveResizeObserver(ResizeObserver&);
@ -3886,11 +3882,7 @@ class Document : public nsINode,
// stored in parent iframe or container's browsingContext (cross process)
already_AddRefed<mozilla::dom::FeaturePolicy> GetParentFeaturePolicy();
FlashClassification DocumentFlashClassificationInternal();
public:
bool IsThirdPartyForFlashClassifier();
const OriginTrials& Trials() const { return mTrials; }
private:
@ -5089,14 +5081,6 @@ class Document : public nsINode,
class HeaderData;
UniquePtr<HeaderData> mHeaderData;
// For determining if this is a flash document which should be
// blocked based on its principal.
FlashClassification mFlashClassification;
// Do not use this value directly. Call the |IsThirdPartyForFlashClassifier()|
// method, which caches its result here.
Maybe<bool> mIsThirdPartyForFlashClassifier;
nsRevocableEventPtr<nsRunnableMethod<Document, void, false>>
mPendingTitleChangeEvent;

View file

@ -16,8 +16,6 @@ if (DEBUG) {
var EXPORTED_SYMBOLS = ["IndexedDBHelper"];
Cu.importGlobalProperties(["indexedDB"]);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
function getErrorName(err) {

View file

@ -185,4 +185,11 @@ RefPtr<GenericPromise> ClientHandle::OnDetach() {
return mDetachPromise;
}
void ClientHandle::EvictFromBFCache() {
ClientEvictBFCacheArgs args;
StartOp(
std::move(args), [](const ClientOpResult& aResult) {},
[](const ClientOpResult& aResult) {});
}
} // namespace mozilla::dom

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