summaryrefslogtreecommitdiffstats
path: root/dom/base
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base')
-rw-r--r--dom/base/BodyUtil.cpp4
-rw-r--r--dom/base/CharacterData.cpp27
-rw-r--r--dom/base/CharacterData.h2
-rw-r--r--dom/base/ChromeUtils.cpp108
-rw-r--r--dom/base/ChromeUtils.h3
-rw-r--r--dom/base/ContentProcessMessageManager.cpp3
-rw-r--r--dom/base/DOMParser.cpp10
-rw-r--r--dom/base/DOMRequest.cpp256
-rw-r--r--dom/base/DOMRequest.h103
-rw-r--r--dom/base/DOMRequestHelper.sys.mjs335
-rw-r--r--dom/base/DirectionalityUtils.cpp745
-rw-r--r--dom/base/DirectionalityUtils.h5
-rw-r--r--dom/base/Document.cpp149
-rw-r--r--dom/base/Document.h38
-rw-r--r--dom/base/DocumentFragment.h2
-rw-r--r--dom/base/Element.cpp135
-rw-r--r--dom/base/Element.h44
-rw-r--r--dom/base/EventSource.cpp3
-rw-r--r--dom/base/FlushType.h2
-rw-r--r--dom/base/FragmentOrElement.cpp48
-rw-r--r--dom/base/IDTracker.cpp25
-rw-r--r--dom/base/InProcessBrowserChildMessageManager.cpp24
-rw-r--r--dom/base/InProcessBrowserChildMessageManager.h3
-rw-r--r--dom/base/IndexedDBHelper.sys.mjs6
-rw-r--r--dom/base/MimeType.cpp14
-rw-r--r--dom/base/MimeType.h9
-rw-r--r--dom/base/Navigator.cpp3
-rw-r--r--dom/base/Navigator.h1
-rw-r--r--dom/base/RadioGroupContainer.cpp11
-rw-r--r--dom/base/RadioGroupContainer.h1
-rw-r--r--dom/base/ResizeObserver.cpp121
-rw-r--r--dom/base/ResizeObserver.h31
-rw-r--r--dom/base/Selection.cpp59
-rw-r--r--dom/base/ShadowRoot.cpp9
-rw-r--r--dom/base/StructuredCloneHolder.cpp121
-rw-r--r--dom/base/StructuredCloneHolder.h14
-rw-r--r--dom/base/StructuredCloneTags.h4
-rw-r--r--dom/base/UnbindContext.h35
-rw-r--r--dom/base/UseCounters.conf1
-rw-r--r--dom/base/crashtests/crashtests.list4
-rw-r--r--dom/base/moz.build6
-rw-r--r--dom/base/nsAttrValue.cpp4
-rw-r--r--dom/base/nsContentCID.h195
-rw-r--r--dom/base/nsContentUtils.cpp41
-rw-r--r--dom/base/nsContentUtils.h129
-rw-r--r--dom/base/nsCopySupport.cpp42
-rw-r--r--dom/base/nsDOMNavigationTiming.cpp3
-rw-r--r--dom/base/nsDOMWindowUtils.cpp1
-rw-r--r--dom/base/nsFocusManager.cpp107
-rw-r--r--dom/base/nsFocusManager.h30
-rw-r--r--dom/base/nsFrameLoader.cpp146
-rw-r--r--dom/base/nsFrameLoader.h9
-rw-r--r--dom/base/nsGlobalWindowInner.cpp33
-rw-r--r--dom/base/nsGlobalWindowInner.h13
-rw-r--r--dom/base/nsGlobalWindowOuter.cpp1
-rw-r--r--dom/base/nsIContent.h11
-rw-r--r--dom/base/nsIDOMRequestService.idl21
-rw-r--r--dom/base/nsINode.cpp27
-rw-r--r--dom/base/nsINode.h42
-rw-r--r--dom/base/nsIScriptableContentIterator.idl8
-rw-r--r--dom/base/nsImageLoadingContent.cpp14
-rw-r--r--dom/base/nsImageLoadingContent.h5
-rw-r--r--dom/base/nsJSEnvironment.cpp15
-rw-r--r--dom/base/nsObjectLoadingContent.cpp8
-rw-r--r--dom/base/nsObjectLoadingContent.h2
-rw-r--r--dom/base/nsTextNode.cpp19
-rw-r--r--dom/base/nsTextNode.h2
-rw-r--r--dom/base/nsWindowRoot.cpp2
-rw-r--r--dom/base/test/browser.toml10
-rw-r--r--dom/base/test/browser_object_attachment.js168
-rw-r--r--dom/base/test/chrome.toml3
-rw-r--r--dom/base/test/chrome/bug418986-1.js3
-rw-r--r--dom/base/test/chrome/chrome.toml4
-rw-r--r--dom/base/test/chrome/file_bug549682.xhtml10
-rw-r--r--dom/base/test/chrome/file_bug616841.xhtml2
-rw-r--r--dom/base/test/chrome/test_bug1339722.html4
-rw-r--r--dom/base/test/chrome/test_bug339494.xhtml2
-rw-r--r--dom/base/test/chrome/test_bug429785.xhtml2
-rw-r--r--dom/base/test/chrome/test_bug430050.xhtml2
-rw-r--r--dom/base/test/chrome/test_chromeOuterWindowID.xhtml2
-rw-r--r--dom/base/test/chrome/test_swapFrameLoaders.xhtml25
-rw-r--r--dom/base/test/chrome/title_window.xhtml4
-rw-r--r--dom/base/test/chrome/window_nsITextInputProcessor.xhtml4
-rw-r--r--dom/base/test/chrome/window_swapFrameLoaders.xhtml223
-rw-r--r--dom/base/test/common_postMessages.js2
-rw-r--r--dom/base/test/file_bug1008126_worker.js2
-rw-r--r--dom/base/test/file_bug945152_worker.js1
-rw-r--r--dom/base/test/file_focus_shadow_dom.html24
-rw-r--r--dom/base/test/file_img_attachment.jpgbin0 -> 2711 bytes
-rw-r--r--dom/base/test/file_img_attachment.jpg^headers^1
-rw-r--r--dom/base/test/file_img_object_attachment.html6
-rw-r--r--dom/base/test/file_pdf_attachment.pdfbin0 -> 1568 bytes
-rw-r--r--dom/base/test/file_pdf_attachment.pdf^headers^2
-rw-r--r--dom/base/test/file_pdf_object_attachment.html6
-rw-r--r--dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml2
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-navigation-history-race.js2
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js2
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-api.html22
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html2
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-bug-1798219.html2
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-denied.html2
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html2
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-esc-exit.html4
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-shadowdom.html2
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-svg-element.html2
-rw-r--r--dom/base/test/fullscreen/fullscreen.xhtml2
-rw-r--r--dom/base/test/fullscreen/fullscreen_helpers.js4
-rw-r--r--dom/base/test/fullscreen/test_fullscreen-api.html2
-rw-r--r--dom/base/test/fullscreen/test_fullscreen_modal.html11
-rw-r--r--dom/base/test/gtest/TestMimeType.cpp142
-rw-r--r--dom/base/test/meta_viewport/viewport_helpers.js1
-rw-r--r--dom/base/test/mochitest.toml5
-rw-r--r--dom/base/test/test_domrequest.html233
-rw-r--r--dom/base/test/test_domrequesthelper.xhtml549
-rw-r--r--dom/base/test/test_focus_radio.html90
-rw-r--r--dom/base/test/unit/test_error_codes.js2
-rw-r--r--dom/base/test/useractivation/file_clipboard_common.js8
-rw-r--r--dom/base/test/useractivation/test_popup_blocker_async_callback.html2
-rw-r--r--dom/base/test/useractivation/test_useractivation_scrollbar.html2
-rw-r--r--dom/base/use_counter_metrics.yaml34
120 files changed, 1722 insertions, 3375 deletions
diff --git a/dom/base/BodyUtil.cpp b/dom/base/BodyUtil.cpp
index e5d86a3c36..e8de3d18ec 100644
--- a/dom/base/BodyUtil.cpp
+++ b/dom/base/BodyUtil.cpp
@@ -267,7 +267,7 @@ class MOZ_STACK_CLASS FormDataParser {
}
// Determine boundary from mimetype.
- UniquePtr<CMimeType> parsed = CMimeType::Parse(mMixedCaseMimeType);
+ RefPtr<CMimeType> parsed = CMimeType::Parse(mMixedCaseMimeType);
if (!parsed) {
return false;
}
@@ -422,7 +422,7 @@ already_AddRefed<FormData> BodyUtil::ConsumeFormData(
if (isValidUrlEncodedMimeType) {
RefPtr<FormData> fd = new FormData(aParent);
DebugOnly<bool> status = URLParams::Parse(
- aStr, [&fd](const nsAString& aName, const nsAString& aValue) {
+ aStr, true, [&fd](const nsAString& aName, const nsAString& aValue) {
ErrorResult rv;
fd->Append(aName, aValue, rv);
MOZ_ASSERT(!rv.Failed());
diff --git a/dom/base/CharacterData.cpp b/dom/base/CharacterData.cpp
index b4809a0293..eccf9fe4d9 100644
--- a/dom/base/CharacterData.cpp
+++ b/dom/base/CharacterData.cpp
@@ -11,32 +11,22 @@
#include "mozilla/dom/CharacterData.h"
-#include "mozilla/DebugOnly.h"
-
#include "mozilla/AsyncEventDispatcher.h"
-#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/BindContext.h"
#include "mozilla/dom/Element.h"
-#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/MutationObservers.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/Document.h"
+#include "mozilla/dom/UnbindContext.h"
#include "nsReadableUtils.h"
#include "mozilla/InternalMutationEvent.h"
-#include "nsCOMPtr.h"
-#include "nsDOMString.h"
-#include "nsChangeHint.h"
-#include "nsCOMArray.h"
#include "mozilla/dom/DirectionalityUtils.h"
-#include "nsCCUncollectableMarker.h"
#include "mozAutoDocUpdate.h"
#include "nsIContentInlines.h"
#include "nsTextNode.h"
#include "nsBidiUtils.h"
-#include "PLDHashTable.h"
#include "mozilla/Sprintf.h"
#include "nsWindowSizes.h"
-#include "nsWrapperCacheInlines.h"
#if defined(ACCESSIBILITY) && defined(DEBUG)
# include "nsAccessibilityService.h"
@@ -478,13 +468,14 @@ nsresult CharacterData::BindToTree(BindContext& aContext, nsINode& aParent) {
return NS_OK;
}
-void CharacterData::UnbindFromTree(bool aNullParent) {
+void CharacterData::UnbindFromTree(UnbindContext& aContext) {
// Unset frame flags; if we need them again later, they'll get set again.
UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE);
- HandleShadowDOMRelatedRemovalSteps(aNullParent);
+ const bool nullParent = aContext.IsUnbindRoot(this);
+ HandleShadowDOMRelatedRemovalSteps(nullParent);
- if (aNullParent) {
+ if (nullParent) {
if (GetParent()) {
NS_RELEASE(mParent);
} else {
@@ -495,15 +486,13 @@ void CharacterData::UnbindFromTree(bool aNullParent) {
ClearInDocument();
SetIsConnected(false);
- if (aNullParent || !mParent->IsInShadowTree()) {
+ if (nullParent || !mParent->IsInShadowTree()) {
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// Begin keeping track of our subtree root.
- SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
- }
+ SetSubtreeRootPointer(nullParent ? this : mParent->SubtreeRoot());
- if (nsExtendedContentSlots* slots = GetExistingExtendedContentSlots()) {
- if (aNullParent || !mParent->IsInShadowTree()) {
+ if (nsExtendedContentSlots* slots = GetExistingExtendedContentSlots()) {
slots->mContainingShadow = nullptr;
}
}
diff --git a/dom/base/CharacterData.h b/dom/base/CharacterData.h
index 8e008b134b..50ff159eef 100644
--- a/dom/base/CharacterData.h
+++ b/dom/base/CharacterData.h
@@ -106,7 +106,7 @@ class CharacterData : public nsIContent {
// Implementation for nsIContent
nsresult BindToTree(BindContext&, nsINode& aParent) override;
- void UnbindFromTree(bool aNullParent = true) override;
+ void UnbindFromTree(UnbindContext&) override;
const nsTextFragment* GetText() override { return &mText; }
uint32_t TextLength() const final { return TextDataLength(); }
diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp
index be06bb083a..0df1cd3c9b 100644
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -602,23 +602,6 @@ void ChromeUtils::Import(const GlobalObject& aGlobal,
aRetval.set(exports);
}
-static mozJSModuleLoader* GetContextualESLoader(
- const Optional<bool>& aLoadInDevToolsLoader, JSObject* aGlobal) {
- RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
- // We should load the module in the DevTools loader if:
- // - ChromeUtils.importESModule's `loadInDevToolsLoader` option is true, or,
- // - if the callsite is from a module loaded in the DevTools loader and
- // `loadInDevToolsLoader` isn't an explicit false.
- bool shouldUseDevToolsLoader =
- (aLoadInDevToolsLoader.WasPassed() && aLoadInDevToolsLoader.Value()) ||
- (devToolsModuleloader && !aLoadInDevToolsLoader.WasPassed() &&
- devToolsModuleloader->IsLoaderGlobal(aGlobal));
- if (shouldUseDevToolsLoader) {
- return mozJSModuleLoader::GetOrCreateDevToolsLoader();
- }
- return mozJSModuleLoader::Get();
-}
-
static mozJSModuleLoader* GetModuleLoaderForCurrentGlobal(
JSContext* aCx, const GlobalObject& aGlobal,
Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
@@ -629,7 +612,7 @@ static mozJSModuleLoader* GetModuleLoaderForCurrentGlobal(
return mozJSModuleLoader::Get();
}
if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global)) {
- return mozJSModuleLoader::GetOrCreateDevToolsLoader();
+ return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
}
if (loader::NonSharedGlobalSyncModuleLoaderScope::IsActive()) {
@@ -681,7 +664,7 @@ static mozJSModuleLoader* GetModuleLoaderForOptions(
Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
aMaybeSyncLoaderScope) {
if (!aOptions.mGlobal.WasPassed()) {
- return GetContextualESLoader(aOptions.mLoadInDevToolsLoader, aGlobal.Get());
+ return mozJSModuleLoader::Get();
}
switch (aOptions.mGlobal.Value()) {
@@ -689,7 +672,7 @@ static mozJSModuleLoader* GetModuleLoaderForOptions(
return mozJSModuleLoader::Get();
case ImportESModuleTargetGlobal::Devtools:
- return mozJSModuleLoader::GetOrCreateDevToolsLoader();
+ return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
case ImportESModuleTargetGlobal::Contextual: {
if (!NS_IsMainThread()) {
@@ -700,7 +683,7 @@ static mozJSModuleLoader* GetModuleLoaderForOptions(
RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
if (devToolsModuleloader &&
devToolsModuleloader->IsLoaderGlobal(aGlobal.Get())) {
- return mozJSModuleLoader::GetOrCreateDevToolsLoader();
+ return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
}
return mozJSModuleLoader::Get();
}
@@ -715,7 +698,8 @@ static mozJSModuleLoader* GetModuleLoaderForOptions(
}
static bool ValidateImportOptions(
- JSContext* aCx, const ImportESModuleOptionsDictionary& aOptions) {
+ JSContext* aCx, const GlobalObject& aGlobal,
+ const ImportESModuleOptionsDictionary& aOptions) {
if (!NS_IsMainThread() &&
(!aOptions.mGlobal.WasPassed() ||
(aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Current &&
@@ -727,12 +711,17 @@ static bool ValidateImportOptions(
return false;
}
- if (aOptions.mGlobal.WasPassed() &&
- aOptions.mLoadInDevToolsLoader.WasPassed()) {
- JS_ReportErrorASCII(aCx,
- "global option and loadInDevToolsLoader option "
- "cannot be used at the same time");
- return false;
+ if (NS_IsMainThread()) {
+ nsCOMPtr<nsIGlobalObject> global =
+ do_QueryInterface(aGlobal.GetAsSupports());
+
+ if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global) &&
+ !aOptions.mGlobal.WasPassed()) {
+ JS_ReportErrorASCII(aCx,
+ "ChromeUtils.importESModule: global option is "
+ "required in DevTools distinct global");
+ return false;
+ }
}
return true;
@@ -745,7 +734,7 @@ void ChromeUtils::ImportESModule(
JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
JSContext* cx = aGlobal.Context();
- if (!ValidateImportOptions(cx, aOptions)) {
+ if (!ValidateImportOptions(cx, aGlobal, aOptions)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
@@ -789,21 +778,11 @@ void ChromeUtils::ImportESModule(
class EncodedOptions {
public:
explicit EncodedOptions(const ImportESModuleOptionsDictionary& aOptions) {
- uint32_t globalFlag = 0;
if (aOptions.mGlobal.WasPassed()) {
- globalFlag = uint32_t(aOptions.mGlobal.Value()) + 1;
- }
-
- uint32_t devtoolsFlag = 0;
- if (aOptions.mLoadInDevToolsLoader.WasPassed()) {
- if (aOptions.mLoadInDevToolsLoader.Value()) {
- devtoolsFlag = DevToolsFlag_True;
- } else {
- devtoolsFlag = DevToolsFlag_False;
- }
+ mValue = uint32_t(aOptions.mGlobal.Value()) + 1;
+ } else {
+ mValue = 0;
}
-
- mValue = globalFlag | devtoolsFlag;
}
explicit EncodedOptions(uint32_t aValue) : mValue(aValue) {}
@@ -811,37 +790,14 @@ class EncodedOptions {
int32_t toInt32() const { return int32_t(mValue); }
void DecodeInto(ImportESModuleOptionsDictionary& aOptions) {
- uint32_t globalFlag = mValue & GlobalFlag_Mask;
- if (globalFlag == 0) {
+ if (mValue == 0) {
aOptions.mGlobal.Reset();
} else {
- aOptions.mGlobal.Construct(ImportESModuleTargetGlobal(globalFlag - 1));
- }
-
- uint32_t devtoolsFlag = mValue & DevToolsFlag_Mask;
- switch (devtoolsFlag) {
- case DevToolsFlag_NotPassed:
- aOptions.mLoadInDevToolsLoader.Reset();
- break;
- case DevToolsFlag_False:
- aOptions.mLoadInDevToolsLoader.Construct(false);
- break;
- case DevToolsFlag_True:
- aOptions.mLoadInDevToolsLoader.Construct(true);
- break;
- default:
- MOZ_CRASH("Unknown DevToolsFlag");
+ aOptions.mGlobal.Construct(ImportESModuleTargetGlobal(mValue - 1));
}
}
private:
- static constexpr uint32_t GlobalFlag_Mask = 0xF;
-
- static constexpr uint32_t DevToolsFlag_NotPassed = 0x00;
- static constexpr uint32_t DevToolsFlag_False = 0x10;
- static constexpr uint32_t DevToolsFlag_True = 0x20;
- static constexpr uint32_t DevToolsFlag_Mask = 0x0F0;
-
uint32_t mValue = 0;
};
@@ -1017,10 +973,6 @@ static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
ImportESModuleOptionsDictionary options;
encodedOptions.DecodeInto(options);
- if (!ValidateImportOptions(aCx, options)) {
- return false;
- }
-
GlobalObject global(aCx, callee);
Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
@@ -1198,6 +1150,11 @@ void ChromeUtils::DefineESModuleGetters(
return;
}
+ if (!ValidateImportOptions(cx, global, aOptions)) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+
EncodedOptions encodedOptions(aOptions);
JS::Rooted<JS::PropertyKey> prop(cx);
@@ -1411,7 +1368,8 @@ void ChromeUtils::ClearStyleSheetCache(GlobalObject&) {
static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
// Max is the value of the last enum, not the length, so add one.
static_assert(
- WebIDLProcTypeValues::Count == static_cast<size_t>(ProcType::Max) + 1,
+ static_cast<size_t>(MaxContiguousEnumValue<WebIDLProcType>::value) ==
+ static_cast<size_t>(ProcType::Max),
"In order for this static cast to be okay, "
"WebIDLProcType must match ProcType exactly");
@@ -2118,9 +2076,9 @@ unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) {
void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal,
nsTArray<nsCString>& aNames) {
aNames.Clear();
- for (size_t i = 0; i < WebIDLUtilityActorNameValues::Count; ++i) {
- auto idlName = static_cast<UtilityActorName>(i);
- aNames.AppendElement(WebIDLUtilityActorNameValues::GetString(idlName));
+ for (UtilityActorName idlName :
+ MakeWebIDLEnumeratedRange<WebIDLUtilityActorName>()) {
+ aNames.AppendElement(GetEnumString(idlName));
}
}
diff --git a/dom/base/ChromeUtils.h b/dom/base/ChromeUtils.h
index 804fc44e4a..4c2d043ecb 100644
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -129,8 +129,7 @@ class ChromeUtils {
static bool IsOriginAttributesEqualIgnoringFPD(
const dom::OriginAttributesDictionary& aA,
const dom::OriginAttributesDictionary& aB) {
- return aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser &&
- aA.mUserContextId == aB.mUserContextId &&
+ return aA.mUserContextId == aB.mUserContextId &&
aA.mPrivateBrowsingId == aB.mPrivateBrowsingId;
}
diff --git a/dom/base/ContentProcessMessageManager.cpp b/dom/base/ContentProcessMessageManager.cpp
index 7fe9f4c2c7..7661d1036f 100644
--- a/dom/base/ContentProcessMessageManager.cpp
+++ b/dom/base/ContentProcessMessageManager.cpp
@@ -6,7 +6,6 @@
#include "ContentProcessMessageManager.h"
-#include "nsContentCID.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/MessageManagerBinding.h"
#include "mozilla/dom/ParentProcessMessageManager.h"
@@ -31,7 +30,7 @@ ContentProcessMessageManager::~ContentProcessMessageManager() {
ContentProcessMessageManager* ContentProcessMessageManager::Get() {
nsCOMPtr<nsIMessageSender> service =
- do_GetService(NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID);
+ do_GetService("@mozilla.org/childprocessmessagemanager;1");
if (!service) {
return nullptr;
}
diff --git a/dom/base/DOMParser.cpp b/dom/base/DOMParser.cpp
index 87bac20093..b3cf6ba04b 100644
--- a/dom/base/DOMParser.cpp
+++ b/dom/base/DOMParser.cpp
@@ -181,12 +181,10 @@ already_AddRefed<Document> DOMParser::ParseFromStream(nsIInputStream* aStream,
// Create a fake channel
nsCOMPtr<nsIChannel> parserChannel;
- NS_NewInputStreamChannel(
- getter_AddRefs(parserChannel), mDocumentURI,
- nullptr, // aStream
- mPrincipal, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
- nsIContentPolicy::TYPE_OTHER,
- nsDependentCSubstring(SupportedTypeValues::GetString(aType)));
+ NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI,
+ nullptr, // aStream
+ mPrincipal, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+ nsIContentPolicy::TYPE_OTHER, GetEnumString(aType));
if (NS_WARN_IF(!parserChannel)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
diff --git a/dom/base/DOMRequest.cpp b/dom/base/DOMRequest.cpp
deleted file mode 100644
index 93c1d75d89..0000000000
--- a/dom/base/DOMRequest.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DOMRequest.h"
-
-#include "DOMException.h"
-#include "nsThreadUtils.h"
-#include "mozilla/HoldDropJSObjects.h"
-#include "mozilla/ErrorResult.h"
-#include "mozilla/dom/Event.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/dom/ScriptSettings.h"
-#include "jsfriendapi.h"
-#include "nsContentUtils.h"
-
-using mozilla::dom::AnyCallback;
-using mozilla::dom::AutoJSAPI;
-using mozilla::dom::DOMException;
-using mozilla::dom::DOMRequest;
-using mozilla::dom::DOMRequestService;
-using mozilla::dom::Promise;
-using mozilla::dom::RootingCx;
-
-DOMRequest::DOMRequest(nsPIDOMWindowInner* aWindow)
- : DOMEventTargetHelper(aWindow),
- mResult(JS::UndefinedValue()),
- mDone(false) {}
-
-DOMRequest::DOMRequest(nsIGlobalObject* aGlobal)
- : DOMEventTargetHelper(aGlobal),
- mResult(JS::UndefinedValue()),
- mDone(false) {}
-
-DOMRequest::~DOMRequest() { mozilla::DropJSObjects(this); }
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED_WITH_JS_MEMBERS(DOMRequest,
- DOMEventTargetHelper,
- (mError, mPromise),
- (mResult))
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMRequest)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-NS_IMPL_ADDREF_INHERITED(DOMRequest, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(DOMRequest, DOMEventTargetHelper)
-
-/* virtual */
-JSObject* DOMRequest::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) {
- return DOMRequest_Binding::Wrap(aCx, this, aGivenProto);
-}
-
-void DOMRequest::FireSuccess(JS::Handle<JS::Value> aResult) {
- NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
- NS_ASSERTION(!mError, "mError shouldn't have been set!");
- NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
-
- mDone = true;
- if (aResult.isGCThing()) {
- RootResultVal();
- }
- mResult = aResult;
-
- FireEvent(u"success"_ns, false, false);
-
- if (mPromise) {
- mPromise->MaybeResolve(mResult);
- }
-}
-
-void DOMRequest::FireError(const nsAString& aError) {
- NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
- NS_ASSERTION(!mError, "mError shouldn't have been set!");
- NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
-
- mDone = true;
- // XXX Error code chosen arbitrarily
- mError = DOMException::Create(NS_ERROR_DOM_UNKNOWN_ERR,
- NS_ConvertUTF16toUTF8(aError));
-
- FireEvent(u"error"_ns, true, true);
-
- if (mPromise) {
- mPromise->MaybeRejectBrokenly(mError);
- }
-}
-
-void DOMRequest::FireError(nsresult aError) {
- NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
- NS_ASSERTION(!mError, "mError shouldn't have been set!");
- NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
-
- mDone = true;
- mError = DOMException::Create(aError);
-
- FireEvent(u"error"_ns, true, true);
-
- if (mPromise) {
- mPromise->MaybeRejectBrokenly(mError);
- }
-}
-
-void DOMRequest::FireDetailedError(DOMException& aError) {
- NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
- NS_ASSERTION(!mError, "mError shouldn't have been set!");
- NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
-
- mDone = true;
- mError = &aError;
-
- FireEvent(u"error"_ns, true, true);
-
- if (mPromise) {
- mPromise->MaybeRejectBrokenly(mError);
- }
-}
-
-void DOMRequest::FireEvent(const nsAString& aType, bool aBubble,
- bool aCancelable) {
- if (NS_FAILED(CheckCurrentGlobalCorrectness())) {
- return;
- }
-
- RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
- event->InitEvent(aType, aBubble, aCancelable);
- event->SetTrusted(true);
-
- DispatchEvent(*event);
-}
-
-void DOMRequest::RootResultVal() { mozilla::HoldJSObjects(this); }
-
-void DOMRequest::Then(JSContext* aCx, AnyCallback* aResolveCallback,
- AnyCallback* aRejectCallback,
- JS::MutableHandle<JS::Value> aRetval,
- mozilla::ErrorResult& aRv) {
- if (!mPromise) {
- mPromise = Promise::Create(DOMEventTargetHelper::GetParentObject(), aRv);
- if (aRv.Failed()) {
- return;
- }
- if (mDone) {
- // Since we create mPromise lazily, it's possible that the DOMRequest
- // object has already fired its success/error event. In that case we
- // should manually resolve/reject mPromise here. mPromise will take care
- // of calling the callbacks on |promise| as needed.
- if (mError) {
- mPromise->MaybeRejectBrokenly(mError);
- } else {
- mPromise->MaybeResolve(mResult);
- }
- }
- }
-
- // Just use the global of the Promise itself as the callee global.
- JS::Rooted<JSObject*> global(aCx, mPromise->PromiseObj());
- global = JS::GetNonCCWObjectGlobal(global);
- mPromise->Then(aCx, global, aResolveCallback, aRejectCallback, aRetval, aRv);
-}
-
-NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService)
-
-NS_IMETHODIMP
-DOMRequestService::CreateRequest(mozIDOMWindow* aWindow,
- DOMRequest** aRequest) {
- MOZ_ASSERT(NS_IsMainThread());
- NS_ENSURE_STATE(aWindow);
- auto* win = nsPIDOMWindowInner::From(aWindow);
- RefPtr<DOMRequest> req = new DOMRequest(win);
- req.forget(aRequest);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DOMRequestService::FireSuccess(DOMRequest* aRequest,
- JS::Handle<JS::Value> aResult) {
- NS_ENSURE_STATE(aRequest);
- aRequest->FireSuccess(aResult);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DOMRequestService::FireError(DOMRequest* aRequest, const nsAString& aError) {
- NS_ENSURE_STATE(aRequest);
- aRequest->FireError(aError);
-
- return NS_OK;
-}
-
-class FireSuccessAsyncTask : public mozilla::Runnable {
- FireSuccessAsyncTask(DOMRequest* aRequest, const JS::Value& aResult)
- : mozilla::Runnable("FireSuccessAsyncTask"),
- mReq(aRequest),
- mResult(RootingCx(), aResult) {}
-
- public:
- // Due to the fact that initialization can fail during shutdown (since we
- // can't fetch a js context), set up an initiatization function to make sure
- // we can return the failure appropriately
- static nsresult Dispatch(DOMRequest* aRequest, const JS::Value& aResult) {
- RefPtr<FireSuccessAsyncTask> asyncTask =
- new FireSuccessAsyncTask(aRequest, aResult);
- MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(asyncTask));
- return NS_OK;
- }
-
- NS_IMETHOD
- Run() override {
- mReq->FireSuccess(
- JS::Handle<JS::Value>::fromMarkedLocation(mResult.address()));
- return NS_OK;
- }
-
- private:
- RefPtr<DOMRequest> mReq;
- JS::PersistentRooted<JS::Value> mResult;
-};
-
-class FireErrorAsyncTask : public mozilla::Runnable {
- public:
- FireErrorAsyncTask(DOMRequest* aRequest, const nsAString& aError)
- : mozilla::Runnable("FireErrorAsyncTask"),
- mReq(aRequest),
- mError(aError) {}
-
- NS_IMETHOD
- Run() override {
- mReq->FireError(mError);
- return NS_OK;
- }
-
- private:
- RefPtr<DOMRequest> mReq;
- nsString mError;
-};
-
-NS_IMETHODIMP
-DOMRequestService::FireSuccessAsync(DOMRequest* aRequest,
- JS::Handle<JS::Value> aResult) {
- NS_ENSURE_STATE(aRequest);
- return FireSuccessAsyncTask::Dispatch(aRequest, aResult);
-}
-
-NS_IMETHODIMP
-DOMRequestService::FireErrorAsync(DOMRequest* aRequest,
- const nsAString& aError) {
- NS_ENSURE_STATE(aRequest);
- nsCOMPtr<nsIRunnable> asyncTask = new FireErrorAsyncTask(aRequest, aError);
- MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(asyncTask));
- return NS_OK;
-}
diff --git a/dom/base/DOMRequest.h b/dom/base/DOMRequest.h
deleted file mode 100644
index b0e7c23112..0000000000
--- a/dom/base/DOMRequest.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_domrequest_h__
-#define mozilla_dom_domrequest_h__
-
-#include "nsIDOMRequestService.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/DOMEventTargetHelper.h"
-#include "mozilla/dom/DOMException.h"
-#include "mozilla/dom/DOMRequestBinding.h"
-
-#include "nsCOMPtr.h"
-
-namespace mozilla {
-
-class ErrorResult;
-
-namespace dom {
-
-class AnyCallback;
-class Promise;
-
-class DOMRequest : public DOMEventTargetHelper {
- protected:
- JS::Heap<JS::Value> mResult;
- RefPtr<DOMException> mError;
- RefPtr<Promise> mPromise;
- bool mDone;
-
- public:
- NS_DECL_ISUPPORTS_INHERITED
-
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DOMRequest,
- DOMEventTargetHelper)
-
- // WrapperCache
- nsPIDOMWindowInner* GetParentObject() const { return GetOwner(); }
-
- virtual JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- // WebIDL Interface
- DOMRequestReadyState ReadyState() const {
- return mDone ? DOMRequestReadyState::Done : DOMRequestReadyState::Pending;
- }
-
- void GetResult(JSContext*, JS::MutableHandle<JS::Value> aRetval) const {
- NS_ASSERTION(mDone || mResult.isUndefined(),
- "Result should be undefined when pending");
- aRetval.set(mResult);
- }
-
- DOMException* GetError() const {
- NS_ASSERTION(mDone || !mError, "Error should be null when pending");
- return mError;
- }
-
- IMPL_EVENT_HANDLER(success)
- IMPL_EVENT_HANDLER(error)
-
- void Then(JSContext* aCx, AnyCallback* aResolveCallback,
- AnyCallback* aRejectCallback, JS::MutableHandle<JS::Value> aRetval,
- mozilla::ErrorResult& aRv);
-
- void FireSuccess(JS::Handle<JS::Value> aResult);
- void FireError(const nsAString& aError);
- void FireError(nsresult aError);
- void FireDetailedError(DOMException& aError);
-
- explicit DOMRequest(nsPIDOMWindowInner* aWindow);
- explicit DOMRequest(nsIGlobalObject* aGlobal);
-
- protected:
- virtual ~DOMRequest();
-
- void FireEvent(const nsAString& aType, bool aBubble, bool aCancelable);
-
- void RootResultVal();
-};
-
-class DOMRequestService final : public nsIDOMRequestService {
- ~DOMRequestService() = default;
-
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIDOMREQUESTSERVICE
-
- // No one should call this but the factory.
- static already_AddRefed<DOMRequestService> FactoryCreate() {
- return MakeAndAddRef<DOMRequestService>();
- }
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#define DOMREQUEST_SERVICE_CONTRACTID "@mozilla.org/dom/dom-request-service;1"
-
-#endif // mozilla_dom_domrequest_h__
diff --git a/dom/base/DOMRequestHelper.sys.mjs b/dom/base/DOMRequestHelper.sys.mjs
deleted file mode 100644
index 832c06c4de..0000000000
--- a/dom/base/DOMRequestHelper.sys.mjs
+++ /dev/null
@@ -1,335 +0,0 @@
-/* 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/. */
-
-/**
- * Helper object for APIs that deal with DOMRequests and Promises.
- * It allows objects inheriting from it to create and keep track of DOMRequests
- * and Promises objects in the common scenario where requests are created in
- * the child, handed out to content and delivered to the parent within an async
- * message (containing the identifiers of these requests). The parent may send
- * messages back as answers to different requests and the child will use this
- * helper to get the right request object. This helper also takes care of
- * releasing the requests objects when the window goes out of scope.
- *
- * DOMRequestIPCHelper also deals with message listeners, allowing to add them
- * to the child side of frame and process message manager and removing them
- * when needed.
- */
-export function DOMRequestIpcHelper() {
- // _listeners keeps a list of messages for which we added a listener and the
- // kind of listener that we added (strong or weak). It's an object of this
- // form:
- // {
- // "message1": true,
- // "messagen": false
- // }
- //
- // where each property is the name of the message and its value is a boolean
- // that indicates if the listener is weak or not.
- this._listeners = null;
- this._requests = null;
- this._window = null;
-}
-
-DOMRequestIpcHelper.prototype = {
- /**
- * An object which "inherits" from DOMRequestIpcHelper and declares its own
- * queryInterface method MUST implement Ci.nsISupportsWeakReference.
- */
- QueryInterface: ChromeUtils.generateQI([
- "nsISupportsWeakReference",
- "nsIObserver",
- ]),
-
- /**
- * 'aMessages' is expected to be an array of either:
- * - objects of this form:
- * {
- * name: "messageName",
- * weakRef: false
- * }
- * where 'name' is the message identifier and 'weakRef' a boolean
- * indicating if the listener should be a weak referred one or not.
- *
- * - or only strings containing the message name, in which case the listener
- * will be added as a strong reference by default.
- */
- addMessageListeners(aMessages) {
- if (!aMessages) {
- return;
- }
-
- if (!this._listeners) {
- this._listeners = {};
- }
-
- if (!Array.isArray(aMessages)) {
- aMessages = [aMessages];
- }
-
- aMessages.forEach(aMsg => {
- let name = aMsg.name || aMsg;
- // If the listener is already set and it is of the same type we just
- // increase the count and bail out. If it is not of the same type,
- // we throw an exception.
- if (this._listeners[name] != undefined) {
- if (!!aMsg.weakRef == this._listeners[name].weakRef) {
- this._listeners[name].count++;
- return;
- }
- throw Components.Exception("", Cr.NS_ERROR_FAILURE);
- }
-
- aMsg.weakRef
- ? Services.cpmm.addWeakMessageListener(name, this)
- : Services.cpmm.addMessageListener(name, this);
- this._listeners[name] = {
- weakRef: !!aMsg.weakRef,
- count: 1,
- };
- });
- },
-
- /**
- * 'aMessages' is expected to be a string or an array of strings containing
- * the message names of the listeners to be removed.
- */
- removeMessageListeners(aMessages) {
- if (!this._listeners || !aMessages) {
- return;
- }
-
- if (!Array.isArray(aMessages)) {
- aMessages = [aMessages];
- }
-
- aMessages.forEach(aName => {
- if (this._listeners[aName] == undefined) {
- return;
- }
-
- // Only remove the listener really when we don't have anybody that could
- // be waiting on a message.
- if (!--this._listeners[aName].count) {
- this._listeners[aName].weakRef
- ? Services.cpmm.removeWeakMessageListener(aName, this)
- : Services.cpmm.removeMessageListener(aName, this);
- delete this._listeners[aName];
- }
- });
- },
-
- /**
- * Initialize the helper adding the corresponding listeners to the messages
- * provided as the second parameter.
- *
- * 'aMessages' is expected to be an array of either:
- *
- * - objects of this form:
- * {
- * name: 'messageName',
- * weakRef: false
- * }
- * where 'name' is the message identifier and 'weakRef' a boolean
- * indicating if the listener should be a weak referred one or not.
- *
- * - or only strings containing the message name, in which case the listener
- * will be added as a strong referred one by default.
- */
- initDOMRequestHelper(aWindow, aMessages) {
- // Query our required interfaces to force a fast fail if they are not
- // provided. These calls will throw if the interface is not available.
- this.QueryInterface(Ci.nsISupportsWeakReference);
- this.QueryInterface(Ci.nsIObserver);
-
- if (aMessages) {
- this.addMessageListeners(aMessages);
- }
-
- this._id = this._getRandomId();
-
- this._window = aWindow;
- if (this._window) {
- // We don't use this.innerWindowID, but other classes rely on it.
- this.innerWindowID = this._window.windowGlobalChild.innerWindowId;
- }
-
- this._destroyed = false;
-
- Services.obs.addObserver(
- this,
- "inner-window-destroyed",
- /* weak-ref */ true
- );
- },
-
- destroyDOMRequestHelper() {
- if (this._destroyed) {
- return;
- }
-
- this._destroyed = true;
-
- Services.obs.removeObserver(this, "inner-window-destroyed");
-
- if (this._listeners) {
- Object.keys(this._listeners).forEach(aName => {
- this._listeners[aName].weakRef
- ? Services.cpmm.removeWeakMessageListener(aName, this)
- : Services.cpmm.removeMessageListener(aName, this);
- });
- }
-
- this._listeners = null;
- this._requests = null;
-
- // Objects inheriting from DOMRequestIPCHelper may have an uninit function.
- if (this.uninit) {
- this.uninit();
- }
-
- this._window = null;
- },
-
- observe(aSubject, aTopic, aData) {
- if (aTopic !== "inner-window-destroyed") {
- return;
- }
-
- let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
- if (wId != this.innerWindowID) {
- return;
- }
-
- this.destroyDOMRequestHelper();
- },
-
- getRequestId(aRequest) {
- if (!this._requests) {
- this._requests = {};
- }
-
- let id = "id" + this._getRandomId();
- this._requests[id] = aRequest;
- return id;
- },
-
- getPromiseResolverId(aPromiseResolver) {
- // Delegates to getRequest() since the lookup table is agnostic about
- // storage.
- return this.getRequestId(aPromiseResolver);
- },
-
- getRequest(aId) {
- if (this._requests && this._requests[aId]) {
- return this._requests[aId];
- }
- return undefined;
- },
-
- getPromiseResolver(aId) {
- // Delegates to getRequest() since the lookup table is agnostic about
- // storage.
- return this.getRequest(aId);
- },
-
- removeRequest(aId) {
- if (this._requests && this._requests[aId]) {
- delete this._requests[aId];
- }
- },
-
- removePromiseResolver(aId) {
- // Delegates to getRequest() since the lookup table is agnostic about
- // storage.
- this.removeRequest(aId);
- },
-
- takeRequest(aId) {
- if (!this._requests || !this._requests[aId]) {
- return null;
- }
- let request = this._requests[aId];
- delete this._requests[aId];
- return request;
- },
-
- takePromiseResolver(aId) {
- // Delegates to getRequest() since the lookup table is agnostic about
- // storage.
- return this.takeRequest(aId);
- },
-
- _getRandomId() {
- return Services.uuid.generateUUID().toString();
- },
-
- createRequest() {
- // If we don't have a valid window object, throw.
- if (!this._window) {
- console.error(
- "DOMRequestHelper trying to create a DOMRequest without a valid window, failing."
- );
- throw Components.Exception("", Cr.NS_ERROR_FAILURE);
- }
- return Services.DOMRequest.createRequest(this._window);
- },
-
- /**
- * createPromise() creates a new Promise, with `aPromiseInit` as the
- * PromiseInit callback. The promise constructor is obtained from the
- * reference to window owned by this DOMRequestIPCHelper.
- */
- createPromise(aPromiseInit) {
- // If we don't have a valid window object, throw.
- if (!this._window) {
- console.error(
- "DOMRequestHelper trying to create a Promise without a valid window, failing."
- );
- throw Components.Exception("", Cr.NS_ERROR_FAILURE);
- }
- return new this._window.Promise(aPromiseInit);
- },
-
- /**
- * createPromiseWithId() creates a new Promise, accepting a callback
- * which is immediately called with the generated resolverId.
- */
- createPromiseWithId(aCallback) {
- return this.createPromise((aResolve, aReject) => {
- let resolverId = this.getPromiseResolverId({
- resolve: aResolve,
- reject: aReject,
- });
- aCallback(resolverId);
- });
- },
-
- forEachRequest(aCallback) {
- if (!this._requests) {
- return;
- }
-
- Object.keys(this._requests).forEach(aKey => {
- if (this._window.DOMRequest.isInstance(this.getRequest(aKey))) {
- aCallback(aKey);
- }
- });
- },
-
- forEachPromiseResolver(aCallback) {
- if (!this._requests) {
- return;
- }
-
- Object.keys(this._requests).forEach(aKey => {
- if (
- "resolve" in this.getPromiseResolver(aKey) &&
- "reject" in this.getPromiseResolver(aKey)
- ) {
- aCallback(aKey);
- }
- });
- },
-};
diff --git a/dom/base/DirectionalityUtils.cpp b/dom/base/DirectionalityUtils.cpp
index 46229cfbd3..dd427c61b1 100644
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -5,8 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
- Implementation description from https://etherpad.mozilla.org/dir-auto
-
Static case
===========
When we see a new content node with @dir=auto from the parser, we set the
@@ -45,23 +43,8 @@
I will call this algorithm "upward propagation".
- Each text node should maintain a list of elements which have their
- directionality determined by the first strong character of that text node.
- This is useful to make dynamic changes more efficient. One way to implement
- this is to have a per-document hash table mapping a text node to a set of
- elements. I'll call this data structure TextNodeDirectionalityMap. The
- algorithm for appending a new text node above needs to update this data
- structure.
-
- *IMPLEMENTATION NOTE*
- In practice, the implementation uses two per-node properties:
-
- dirAutoSetBy, which is set on a node with auto-directionality, and points to
- the textnode that contains the strong character which determines the
- directionality of the node.
-
- textNodeDirectionalityMap, which is set on a text node and points to a hash
- table listing the nodes whose directionality is determined by the text node.
+ Each text node keeps a flag if it might determine the directionality of any
+ ancestor. This is useful to make dynamic changes more efficient.
Handling dynamic changes
========================
@@ -90,16 +73,15 @@
(I'll call this the "downward propagation algorithm".) by walking the child
subtree in tree order. Note that an element with @dir=auto should not affect
other elements in its document with @dir=auto. So there is no need to walk up
- the parent chain in this case. TextNodeDirectionalityMap needs to be updated
- as appropriate.
+ the parent chain in this case.
3a. When the dir attribute is set to any valid value on an element that didn't
have a valid dir attribute before, this means that any descendant of that
element will not affect the directionality of any of its ancestors. So we need
- to check whether any text node descendants of the element are listed in
- TextNodeDirectionalityMap, and whether the elements whose direction they set
- are ancestors of the element. If so, we need to rerun the downward propagation
- algorithm for those ancestors.
+ to check whether any text node descendants of the element can set the dir of
+ any ancestor, and whether the elements whose direction they set are ancestors
+ of the element. If so, we need to rerun the downward propagation algorithm for
+ those ancestors. That's done by OnSetDirAttr.
4. When the dir attribute is changed from auto to something else (including
the case where it gets removed) on a textarea or an input element with
@@ -118,80 +100,29 @@
should still retain the same flag.)
* We resolve the directionality of the element based on the value of the @dir
attribute on the element itself or its parent element.
- TextNodeDirectionalityMap needs to be updated as appropriate.
5a. When the dir attribute is removed or set to an invalid value on any
element (except a bdi element) with the NodeAncestorHasDirAuto flag which
previously had a valid dir attribute, it might have a text node descendant
that did not previously affect the directionality of any of its ancestors but
- should now begin to affect them. We run the following algorithm:
- * Walk up the parent chain from the element.
- * For any element that appears in the TextNodeDirectionalityMap, remove the
- element from the map and rerun the downward propagation algorithm
- (see section 3).
- * If we reach an element without either of the NodeHasDirAuto or
- NodeAncestorHasDirAuto flags, abort the parent chain walk.
+ should now begin to affect them. We run OnSetDirAttr.
6. When an element with @dir=auto is added to the document, we should handle
it similar to the case 2/3 above.
7. When an element with NodeHasDirAuto or NodeAncestorHasDirAuto is
removed from the document, we should handle it similar to the case 4/5 above,
- except that we don't need to handle anything in the child subtree. We should
- also remove all of the occurrences of that node and its descendants from
- TextNodeDirectionalityMap. (This is the conceptual description of what needs
- to happen but in the implementation UnbindFromTree is going to be called on
- all of the descendants so we don't need to descend into the child subtree).
+ except that we don't need to handle anything in the child subtree.
8. When the contents of a text node is changed either from script or by the
- user, we need to run the following algorithm:
- * If the change has happened after the first character with strong
- directionality in the text node, do nothing.
- * If the text node is a child of a bdi, script or style element, do nothing.
- * If the text node belongs to a textarea with NodeHasDirAuto, we need to
- update the directionality of the textarea.
- * Grab a list of elements affected by this text node from
- TextNodeDirectionalityMap and re-resolve the directionality of each one of
- them based on the new contents of the text node.
- * If the text node does not exist in TextNodeDirectionalityMap, and it has the
- NodeAncestorHasDirAuto flag set, this could potentially be a text node
- which is going to start affecting the directionality of its parent @dir=auto
- elements. In this case, we need to fall back to the (potentially expensive)
- "upward propagation algorithm". The TextNodeDirectionalityMap data structure
- needs to be update during this algorithm.
- * If the new contents of the text node do not have any strong characters, and
- the old contents used to, and the text node used to exist in
- TextNodeDirectionalityMap and it has the NodeAncestorHasDirAuto flag set,
- the elements associated with this text node inside TextNodeDirectionalityMap
- will now get their directionality from another text node. In this case, for
- each element in the list retrieved from TextNodeDirectionalityMap, run the
- downward propagation algorithm (section 3), and remove the text node from
- TextNodeDirectionalityMap.
-
- 9. When a new text node is injected into a document, we need to run the
- following algorithm:
- * If the contents of the text node do not have any characters with strong
- direction, do nothing.
- * If the text node is a child of a bdi, script or style element, do nothing.
- * If the text node is appended to a textarea element with NodeHasDirAuto, we
- need to update the directionality of the textarea.
- * If the text node has NodeAncestorHasDirAuto, we need to run the "upward
- propagation algorithm". The TextNodeDirectionalityMap data structure needs to
- be update during this algorithm.
-
- 10. When a text node is removed from a document, we need to run the following
- algorithm:
- * If the contents of the text node do not have any characters with strong
- direction, do nothing.
- * If the text node is a child of a bdi, script or style element, do nothing.
- * If the text node is removed from a textarea element with NodeHasDirAuto,
- set the directionality to "ltr". (This is what the spec currently says, but
- I'm filing a spec bug to get it fixed -- the directionality should depend on
- the parent element here.)
- * If the text node has NodeAncestorHasDirAuto, we need to look at the list
- of elements being affected by this text node from TextNodeDirectionalityMap,
- run the "downward propagation algorithm" (section 3) for each one of them,
- while updating TextNodeDirectionalityMap along the way.
+ user, we need to run TextNode{WillChange,Changed}Direction, see inline docs
+ for details.
+
+ 9. When a new text node is injected into a document, we need to run
+ SetDirectionFromNewTextNode.
+
+ 10. When a text node is removed from a document, we need to run
+ ResetDirectionSetByTextNode.
11. If the value of the @dir attribute on a bdi element is changed to an
invalid value (or if it's removed), determine the new directionality similar
@@ -210,18 +141,16 @@
#include "nsIContent.h"
#include "nsIContentInlines.h"
#include "mozilla/dom/Document.h"
-#include "mozilla/AutoRestore.h"
-#include "mozilla/DebugOnly.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/dom/UnbindContext.h"
#include "mozilla/intl/UnicodeProperties.h"
#include "nsUnicodeProperties.h"
#include "nsTextFragment.h"
#include "nsAttrValue.h"
#include "nsTextNode.h"
-#include "nsCheapSets.h"
namespace mozilla {
@@ -230,75 +159,53 @@ using mozilla::dom::HTMLInputElement;
using mozilla::dom::HTMLSlotElement;
using mozilla::dom::ShadowRoot;
-static nsIContent* GetParentOrHostOrSlot(
- const nsIContent* aContent, bool* aCrossedShadowBoundary = nullptr) {
+static nsIContent* GetParentOrHostOrSlot(const nsIContent* aContent) {
if (HTMLSlotElement* slot = aContent->GetAssignedSlot()) {
- if (aCrossedShadowBoundary) {
- *aCrossedShadowBoundary = true;
- }
return slot;
}
-
- nsIContent* parent = aContent->GetParent();
- if (parent) {
+ if (nsIContent* parent = aContent->GetParent()) {
return parent;
}
-
- const ShadowRoot* sr = ShadowRoot::FromNode(aContent);
- if (sr) {
- if (aCrossedShadowBoundary) {
- *aCrossedShadowBoundary = true;
- }
- return sr->Host();
+ if (const ShadowRoot* sr = ShadowRoot::FromNode(aContent)) {
+ return sr->GetHost();
}
-
return nullptr;
}
-static bool AncestorChainCrossesShadowBoundary(nsIContent* aDescendant,
- nsIContent* aAncestor) {
- bool crossedShadowBoundary = false;
- nsIContent* content = aDescendant;
- while (content && content != aAncestor) {
- content = GetParentOrHostOrSlot(content, &crossedShadowBoundary);
- if (crossedShadowBoundary) {
- return true;
- }
- }
-
- return false;
-}
-
/**
- * Returns true if aElement is one of the elements whose text content should not
- * affect its own direction, nor the direction of ancestors with dir=auto.
+ * Returns true if aElement is one of the elements whose text content should
+ * affect its own direction, or the direction of ancestors with dir=auto.
*
* Note that this does not include <bdi>, whose content does affect its own
* direction when it has dir=auto (which it has by default), so one needs to
- * test for it separately, e.g. with DoesNotAffectDirectionOfAncestors.
+ * test for it separately, e.g. with AffectsDirectionOfAncestors.
* It *does* include textarea, because even if a textarea has dir=auto, it has
* unicode-bidi: plaintext and is handled automatically in bidi resolution.
* It also includes `input`, because it takes the `dir` value from its value
* attribute, instead of the child nodes.
*/
-static bool DoesNotParticipateInAutoDirection(const nsIContent* aContent) {
- mozilla::dom::NodeInfo* nodeInfo = aContent->NodeInfo();
- return ((!aContent->IsHTMLElement() || nodeInfo->Equals(nsGkAtoms::script) ||
- nodeInfo->Equals(nsGkAtoms::style) ||
- nodeInfo->Equals(nsGkAtoms::input) ||
- nodeInfo->Equals(nsGkAtoms::textarea) ||
- aContent->IsInNativeAnonymousSubtree())) &&
- !aContent->IsShadowRoot();
+static bool ParticipatesInAutoDirection(const nsIContent* aContent) {
+ if (aContent->IsInNativeAnonymousSubtree()) {
+ return false;
+ }
+ if (aContent->IsShadowRoot()) {
+ return true;
+ }
+ dom::NodeInfo* ni = aContent->NodeInfo();
+ return ni->NamespaceID() == kNameSpaceID_XHTML &&
+ !ni->Equals(nsGkAtoms::script) && !ni->Equals(nsGkAtoms::style) &&
+ !ni->Equals(nsGkAtoms::input) && !ni->Equals(nsGkAtoms::textarea);
}
/**
- * Returns true if aElement is one of the element whose text content should not
- * affect the direction of ancestors with dir=auto (though it may affect its own
- * direction, e.g. <bdi>)
+ * Returns true if aElement is one of the element whose text should affect the
+ * direction of ancestors with dir=auto (though note that even if it returns
+ * false it may affect its own direction, e.g. <bdi> or dir=auto itself)
*/
-static bool DoesNotAffectDirectionOfAncestors(const Element* aElement) {
- return (DoesNotParticipateInAutoDirection(aElement) ||
- aElement->IsHTMLElement(nsGkAtoms::bdi) || aElement->HasFixedDir());
+static bool AffectsDirectionOfAncestors(const Element* aElement) {
+ return ParticipatesInAutoDirection(aElement) &&
+ !aElement->IsHTMLElement(nsGkAtoms::bdi) && !aElement->HasFixedDir() &&
+ !aElement->HasDirAuto();
}
/**
@@ -318,11 +225,15 @@ static Directionality GetDirectionFromChar(uint32_t ch) {
}
}
-inline static bool NodeAffectsDirAutoAncestor(nsIContent* aTextNode) {
+inline static bool TextChildrenAffectDirAutoAncestor(nsIContent* aContent) {
+ return ParticipatesInAutoDirection(aContent) &&
+ aContent->NodeOrAncestorHasDirAuto();
+}
+
+inline static bool NodeAffectsDirAutoAncestor(nsTextNode* aTextNode) {
nsIContent* parent = GetParentOrHostOrSlot(aTextNode);
- return (parent && !DoesNotParticipateInAutoDirection(parent) &&
- parent->NodeOrAncestorHasDirAuto() &&
- !aTextNode->IsInNativeAnonymousSubtree());
+ return parent && TextChildrenAffectDirAutoAncestor(parent) &&
+ !aTextNode->IsInNativeAnonymousSubtree();
}
Directionality GetDirectionFromText(const char16_t* aText,
@@ -394,11 +305,11 @@ static Directionality GetDirectionFromText(const mozilla::dom::Text* aTextNode,
}
static nsTextNode* WalkDescendantsAndGetDirectionFromText(
- nsINode* aRoot, nsINode* aSkip, Directionality* aDirectionality) {
+ nsINode* aRoot, Directionality* aDirectionality) {
nsIContent* child = aRoot->GetFirstChild();
while (child) {
if ((child->IsElement() &&
- DoesNotAffectDirectionOfAncestors(child->AsElement())) ||
+ !AffectsDirectionOfAncestors(child->AsElement())) ||
child->GetAssignedSlot()) {
child = child->GetNextNonChildNode(aRoot);
continue;
@@ -409,19 +320,16 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText(
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
nsIContent* assignedNode = assignedNodes[i]->AsContent();
if (assignedNode->NodeType() == nsINode::TEXT_NODE) {
- auto text = static_cast<nsTextNode*>(assignedNode);
- if (assignedNode != aSkip) {
- Directionality textNodeDir = GetDirectionFromText(text);
- if (textNodeDir != Directionality::Unset) {
- *aDirectionality = textNodeDir;
- return text;
- }
+ auto* text = static_cast<nsTextNode*>(assignedNode);
+ Directionality textNodeDir = GetDirectionFromText(text);
+ if (textNodeDir != Directionality::Unset) {
+ *aDirectionality = textNodeDir;
+ return text;
}
} else if (assignedNode->IsElement() &&
- !DoesNotAffectDirectionOfAncestors(
- assignedNode->AsElement())) {
+ AffectsDirectionOfAncestors(assignedNode->AsElement())) {
nsTextNode* text = WalkDescendantsAndGetDirectionFromText(
- assignedNode, aSkip, aDirectionality);
+ assignedNode, aDirectionality);
if (text) {
return text;
}
@@ -429,8 +337,8 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText(
}
}
- if (child->NodeType() == nsINode::TEXT_NODE && child != aSkip) {
- auto text = static_cast<nsTextNode*>(child);
+ if (child->NodeType() == nsINode::TEXT_NODE) {
+ auto* text = static_cast<nsTextNode*>(child);
Directionality textNodeDir = GetDirectionFromText(text);
if (textNodeDir != Directionality::Unset) {
*aDirectionality = textNodeDir;
@@ -447,17 +355,14 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText(
* Set the directionality of a node with dir=auto as defined in
* http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#the-directionality
*
- * @param[in] changedNode If we call this method because the content of a text
- * node is about to change, pass in the changed node, so that we
- * know not to return it
* @return the text node containing the character that determined the direction
*/
-static nsTextNode* WalkDescendantsSetDirectionFromText(
- Element* aElement, bool aNotify, nsINode* aChangedNode = nullptr) {
+static nsTextNode* WalkDescendantsSetDirectionFromText(Element* aElement,
+ bool aNotify) {
MOZ_ASSERT(aElement, "Must have an element");
MOZ_ASSERT(aElement->HasDirAuto(), "Element must have dir=auto");
- if (DoesNotParticipateInAutoDirection(aElement)) {
+ if (!ParticipatesInAutoDirection(aElement)) {
return nullptr;
}
@@ -465,8 +370,8 @@ static nsTextNode* WalkDescendantsSetDirectionFromText(
// Check the text in Shadow DOM.
if (ShadowRoot* shadowRoot = aElement->GetShadowRoot()) {
- nsTextNode* text = WalkDescendantsAndGetDirectionFromText(
- shadowRoot, aChangedNode, &textNodeDir);
+ nsTextNode* text =
+ WalkDescendantsAndGetDirectionFromText(shadowRoot, &textNodeDir);
if (text) {
aElement->SetDirectionality(textNodeDir, aNotify);
return text;
@@ -474,8 +379,8 @@ static nsTextNode* WalkDescendantsSetDirectionFromText(
}
// Check the text in light DOM.
- nsTextNode* text = WalkDescendantsAndGetDirectionFromText(
- aElement, aChangedNode, &textNodeDir);
+ nsTextNode* text =
+ WalkDescendantsAndGetDirectionFromText(aElement, &textNodeDir);
if (text) {
aElement->SetDirectionality(textNodeDir, aNotify);
return text;
@@ -487,194 +392,6 @@ static nsTextNode* WalkDescendantsSetDirectionFromText(
return nullptr;
}
-class nsTextNodeDirectionalityMap {
- static void nsTextNodeDirectionalityMapDtor(void* aObject,
- nsAtom* aPropertyName,
- void* aPropertyValue,
- void* aData) {
- nsINode* textNode = static_cast<nsINode*>(aObject);
- textNode->ClearHasTextNodeDirectionalityMap();
-
- nsTextNodeDirectionalityMap* map =
- reinterpret_cast<nsTextNodeDirectionalityMap*>(aPropertyValue);
- map->EnsureMapIsClear();
- delete map;
- }
-
- public:
- explicit nsTextNodeDirectionalityMap(nsINode* aTextNode)
- : mElementToBeRemoved(nullptr) {
- MOZ_ASSERT(aTextNode, "Null text node");
- MOZ_COUNT_CTOR(nsTextNodeDirectionalityMap);
- aTextNode->SetProperty(nsGkAtoms::textNodeDirectionalityMap, this,
- nsTextNodeDirectionalityMapDtor);
- aTextNode->SetHasTextNodeDirectionalityMap();
- }
-
- MOZ_COUNTED_DTOR(nsTextNodeDirectionalityMap)
-
- static void nsTextNodeDirectionalityMapPropertyDestructor(
- void* aObject, nsAtom* aProperty, void* aPropertyValue, void* aData) {
- nsTextNode* textNode = static_cast<nsTextNode*>(aPropertyValue);
- nsTextNodeDirectionalityMap* map = GetDirectionalityMap(textNode);
- if (map) {
- map->RemoveEntryForProperty(static_cast<Element*>(aObject));
- }
- NS_RELEASE(textNode);
- }
-
- void AddEntry(nsTextNode* aTextNode, Element* aElement) {
- if (!mElements.Contains(aElement)) {
- mElements.Put(aElement);
- NS_ADDREF(aTextNode);
- aElement->SetProperty(nsGkAtoms::dirAutoSetBy, aTextNode,
- nsTextNodeDirectionalityMapPropertyDestructor);
- aElement->SetHasDirAutoSet();
- }
- }
-
- void RemoveEntry(nsTextNode* aTextNode, Element* aElement) {
- NS_ASSERTION(mElements.Contains(aElement),
- "element already removed from map");
-
- mElements.Remove(aElement);
- aElement->ClearHasDirAutoSet();
- aElement->RemoveProperty(nsGkAtoms::dirAutoSetBy);
- }
-
- void RemoveEntryForProperty(Element* aElement) {
- if (mElementToBeRemoved != aElement) {
- mElements.Remove(aElement);
- }
- aElement->ClearHasDirAutoSet();
- }
-
- private:
- nsCheapSet<nsPtrHashKey<Element>> mElements;
- // Only used for comparison.
- Element* mElementToBeRemoved;
-
- static nsTextNodeDirectionalityMap* GetDirectionalityMap(nsINode* aTextNode) {
- MOZ_ASSERT(aTextNode->NodeType() == nsINode::TEXT_NODE,
- "Must be a text node");
- nsTextNodeDirectionalityMap* map = nullptr;
-
- if (aTextNode->HasTextNodeDirectionalityMap()) {
- map = static_cast<nsTextNodeDirectionalityMap*>(
- aTextNode->GetProperty(nsGkAtoms::textNodeDirectionalityMap));
- }
-
- return map;
- }
-
- static nsCheapSetOperator SetNodeDirection(nsPtrHashKey<Element>* aEntry,
- void* aDir) {
- aEntry->GetKey()->SetDirectionality(
- *reinterpret_cast<Directionality*>(aDir), true);
- return OpNext;
- }
-
- struct nsTextNodeDirectionalityMapAndElement {
- nsTextNodeDirectionalityMap* mMap;
- nsCOMPtr<nsINode> mNode;
- };
-
- static nsCheapSetOperator ResetNodeDirection(nsPtrHashKey<Element>* aEntry,
- void* aData) {
- // run the downward propagation algorithm
- // and remove the text node from the map
- nsTextNodeDirectionalityMapAndElement* data =
- static_cast<nsTextNodeDirectionalityMapAndElement*>(aData);
- nsINode* oldTextNode = data->mNode;
- Element* rootNode = aEntry->GetKey();
- nsTextNode* newTextNode = nullptr;
- if (rootNode->GetParentNode() && rootNode->HasDirAuto()) {
- newTextNode =
- WalkDescendantsSetDirectionFromText(rootNode, true, oldTextNode);
- }
-
- AutoRestore<Element*> restore(data->mMap->mElementToBeRemoved);
- data->mMap->mElementToBeRemoved = rootNode;
- if (newTextNode) {
- nsINode* oldDirAutoSetBy = static_cast<nsTextNode*>(
- rootNode->GetProperty(nsGkAtoms::dirAutoSetBy));
- if (oldDirAutoSetBy == newTextNode) {
- // We're already registered.
- return OpNext;
- }
- nsTextNodeDirectionalityMap::AddEntryToMap(newTextNode, rootNode);
- } else {
- rootNode->ClearHasDirAutoSet();
- rootNode->RemoveProperty(nsGkAtoms::dirAutoSetBy);
- }
- return OpRemove;
- }
-
- static nsCheapSetOperator TakeEntries(nsPtrHashKey<Element>* aEntry,
- void* aData) {
- AutoTArray<Element*, 8>* entries =
- static_cast<AutoTArray<Element*, 8>*>(aData);
- entries->AppendElement(aEntry->GetKey());
- return OpRemove;
- }
-
- public:
- uint32_t UpdateAutoDirection(Directionality aDir) {
- return mElements.EnumerateEntries(SetNodeDirection, &aDir);
- }
-
- void ResetAutoDirection(nsINode* aTextNode) {
- nsTextNodeDirectionalityMapAndElement data = {this, aTextNode};
- mElements.EnumerateEntries(ResetNodeDirection, &data);
- }
-
- void EnsureMapIsClear() {
- AutoRestore<Element*> restore(mElementToBeRemoved);
- AutoTArray<Element*, 8> entries;
- mElements.EnumerateEntries(TakeEntries, &entries);
- for (Element* el : entries) {
- el->ClearHasDirAutoSet();
- el->RemoveProperty(nsGkAtoms::dirAutoSetBy);
- }
- }
-
- static void RemoveElementFromMap(nsTextNode* aTextNode, Element* aElement) {
- if (aTextNode->HasTextNodeDirectionalityMap()) {
- GetDirectionalityMap(aTextNode)->RemoveEntry(aTextNode, aElement);
- }
- }
-
- static void AddEntryToMap(nsTextNode* aTextNode, Element* aElement) {
- nsTextNodeDirectionalityMap* map = GetDirectionalityMap(aTextNode);
- if (!map) {
- map = new nsTextNodeDirectionalityMap(aTextNode);
- }
-
- map->AddEntry(aTextNode, aElement);
- }
-
- static uint32_t UpdateTextNodeDirection(nsINode* aTextNode,
- Directionality aDir) {
- MOZ_ASSERT(aTextNode->HasTextNodeDirectionalityMap(),
- "Map missing in UpdateTextNodeDirection");
- return GetDirectionalityMap(aTextNode)->UpdateAutoDirection(aDir);
- }
-
- static void ResetTextNodeDirection(nsTextNode* aTextNode,
- nsTextNode* aChangedTextNode) {
- MOZ_ASSERT(aTextNode->HasTextNodeDirectionalityMap(),
- "Map missing in ResetTextNodeDirection");
- RefPtr<nsTextNode> textNode = aTextNode;
- GetDirectionalityMap(textNode)->ResetAutoDirection(aChangedTextNode);
- }
-
- static void EnsureMapIsClearFor(nsINode* aTextNode) {
- if (aTextNode->HasTextNodeDirectionalityMap()) {
- GetDirectionalityMap(aTextNode)->EnsureMapIsClear();
- }
- }
-};
-
Directionality GetParentDirectionality(const Element* aElement) {
if (nsIContent* parent = GetParentOrHostOrSlot(aElement)) {
if (ShadowRoot* shadow = ShadowRoot::FromNode(parent)) {
@@ -729,7 +446,7 @@ static inline bool IsBoundary(const Element& aElement) {
static void SetDirectionalityOnDescendantsInternal(nsINode* aNode,
Directionality aDir,
bool aNotify) {
- if (Element* element = Element::FromNode(aNode)) {
+ if (auto* element = Element::FromNode(aNode)) {
if (ShadowRoot* shadow = element->GetShadowRoot()) {
SetDirectionalityOnDescendantsInternal(shadow, aDir, aNotify);
}
@@ -778,66 +495,37 @@ void SetDirectionalityOnDescendants(Element* aElement, Directionality aDir,
}
static void ResetAutoDirection(Element* aElement, bool aNotify) {
- if (aElement->HasDirAutoSet()) {
- // If the parent has the DirAutoSet flag, its direction is determined by
- // some text node descendant.
- // Remove it from the map and reset its direction by the downward
- // propagation algorithm
- nsTextNode* setByNode = static_cast<nsTextNode*>(
- aElement->GetProperty(nsGkAtoms::dirAutoSetBy));
- if (setByNode) {
- nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode, aElement);
- }
- }
-
- if (aElement->HasDirAuto()) {
- nsTextNode* setByNode =
- WalkDescendantsSetDirectionFromText(aElement, aNotify);
- if (setByNode) {
- nsTextNodeDirectionalityMap::AddEntryToMap(setByNode, aElement);
- }
- SetDirectionalityOnDescendants(aElement, aElement->GetDirectionality(),
- aNotify);
+ MOZ_ASSERT(aElement->HasDirAuto());
+ nsTextNode* setByNode =
+ WalkDescendantsSetDirectionFromText(aElement, aNotify);
+ if (setByNode) {
+ setByNode->SetMaySetDirAuto();
}
+ SetDirectionalityOnDescendants(aElement, aElement->GetDirectionality(),
+ aNotify);
}
/**
- * Walk the parent chain of a text node whose dir attribute has been removed and
- * reset the direction of any of its ancestors which have dir=auto and whose
- * directionality is determined by a text node descendant.
+ * Walk the parent chain of a text node whose dir attribute has been removed or
+ * added and reset the direction of any of its ancestors which have dir=auto and
+ * whose directionality is determined by a text node descendant.
*/
void WalkAncestorsResetAutoDirection(Element* aElement, bool aNotify) {
- nsTextNode* setByNode;
- nsIContent* parent = GetParentOrHostOrSlot(aElement);
- while (parent && parent->NodeOrAncestorHasDirAuto()) {
- if (!parent->IsElement()) {
- parent = GetParentOrHostOrSlot(parent);
+ for (nsIContent* parent = GetParentOrHostOrSlot(aElement);
+ parent && parent->NodeOrAncestorHasDirAuto();
+ parent = GetParentOrHostOrSlot(parent)) {
+ auto* parentElement = Element::FromNode(*parent);
+ if (!parentElement || !parentElement->HasDirAuto()) {
continue;
}
-
- Element* parentElement = parent->AsElement();
- if (parent->HasDirAutoSet()) {
- // If the parent has the DirAutoSet flag, its direction is determined by
- // some text node descendant.
- // Remove it from the map and reset its direction by the downward
- // propagation algorithm
- setByNode = static_cast<nsTextNode*>(
- parent->GetProperty(nsGkAtoms::dirAutoSetBy));
- if (setByNode) {
- nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode,
- parentElement);
- }
- }
- if (parentElement->HasDirAuto()) {
- setByNode = WalkDescendantsSetDirectionFromText(parentElement, aNotify);
- if (setByNode) {
- nsTextNodeDirectionalityMap::AddEntryToMap(setByNode, parentElement);
- }
- SetDirectionalityOnDescendants(
- parentElement, parentElement->GetDirectionality(), aNotify);
- break;
+ nsTextNode* setByNode =
+ WalkDescendantsSetDirectionFromText(parentElement, aNotify);
+ if (setByNode) {
+ setByNode->SetMaySetDirAuto();
}
- parent = GetParentOrHostOrSlot(parent);
+ SetDirectionalityOnDescendants(parentElement,
+ parentElement->GetDirectionality(), aNotify);
+ break;
}
}
@@ -901,26 +589,6 @@ void SlotStateChanged(HTMLSlotElement* aSlot, bool aAllAssignedNodesChanged) {
}
}
-void WalkDescendantsResetAutoDirection(Element* aElement) {
- nsIContent* child = aElement->GetFirstChild();
- while (child) {
- if (child->IsElement() && child->AsElement()->HasDirAuto()) {
- child = child->GetNextNonChildNode(aElement);
- continue;
- }
-
- if (child->NodeType() == nsINode::TEXT_NODE &&
- child->HasTextNodeDirectionalityMap()) {
- nsTextNodeDirectionalityMap::ResetTextNodeDirection(
- static_cast<nsTextNode*>(child), nullptr);
- // Don't call nsTextNodeDirectionalityMap::EnsureMapIsClearFor(child)
- // since ResetTextNodeDirection may have kept elements in child's
- // DirectionalityMap.
- }
- child = child->GetNextNode(aElement);
- }
-}
-
static void SetAncestorHasDirAutoOnDescendants(nsINode* aRoot);
static void MaybeSetAncestorHasDirAutoOnShadowDOM(nsINode* aNode) {
@@ -938,7 +606,7 @@ static void SetAncestorHasDirAutoOnDescendants(nsINode* aRoot) {
nsIContent* child = aRoot->GetFirstChild();
while (child) {
if (child->IsElement() &&
- DoesNotAffectDirectionOfAncestors(child->AsElement())) {
+ !AffectsDirectionOfAncestors(child->AsElement())) {
child = child->GetNextNonChildNode(aRoot);
continue;
}
@@ -961,20 +629,20 @@ static void SetAncestorHasDirAutoOnDescendants(nsINode* aRoot) {
}
void WalkDescendantsSetDirAuto(Element* aElement, bool aNotify) {
- // Only test for DoesNotParticipateInAutoDirection -- in other words, if
- // aElement is a <bdi> which is having its dir attribute set to auto (or
+ // Only test for ParticipatesInAutoDirection -- in other words, if aElement is
+ // a <bdi> which is having its dir attribute set to auto (or
// removed or set to an invalid value, which are equivalent to dir=auto for
// <bdi>, we *do* want to set AncestorHasDirAuto on its descendants, unlike
// in SetDirOnBind where we don't propagate AncestorHasDirAuto to a <bdi>
// being bound to an existing node with dir=auto.
- if (!DoesNotParticipateInAutoDirection(aElement) &&
+ if (ParticipatesInAutoDirection(aElement) &&
!aElement->AncestorHasDirAuto()) {
SetAncestorHasDirAutoOnDescendants(aElement);
}
nsTextNode* textNode = WalkDescendantsSetDirectionFromText(aElement, aNotify);
if (textNode) {
- nsTextNodeDirectionalityMap::AddEntryToMap(textNode, aElement);
+ textNode->SetMaySetDirAuto();
}
}
@@ -1022,98 +690,67 @@ void WalkDescendantsClearAncestorDirAuto(nsIContent* aContent) {
}
}
-void SetAncestorDirectionIfAuto(nsTextNode* aTextNode, Directionality aDir,
- bool aNotify = true) {
- MOZ_ASSERT(aTextNode->NodeType() == nsINode::TEXT_NODE,
- "Must be a text node");
+struct DirAutoElementResult {
+ Element* mElement = nullptr;
+ // This is false when we hit the top of the ancestor chain without finding a
+ // dir=auto element or an element with a fixed direction. This is useful when
+ // processing node removals, since we might need to look at the subtree we're
+ // removing from.
+ bool mAnswerIsDefinitive = false;
+};
- bool crossedShadowBoundary = false;
- nsIContent* parent = GetParentOrHostOrSlot(aTextNode, &crossedShadowBoundary);
- while (parent && parent->NodeOrAncestorHasDirAuto()) {
- if (!parent->IsElement()) {
- parent = GetParentOrHostOrSlot(parent, &crossedShadowBoundary);
+static DirAutoElementResult FindDirAutoElementFrom(nsIContent* aContent) {
+ for (nsIContent* parent = aContent;
+ parent && parent->NodeOrAncestorHasDirAuto();
+ parent = GetParentOrHostOrSlot(parent)) {
+ auto* parentElement = Element::FromNode(*parent);
+ if (!parentElement) {
continue;
}
-
- Element* parentElement = parent->AsElement();
- if (DoesNotParticipateInAutoDirection(parentElement) ||
+ if (!ParticipatesInAutoDirection(parentElement) ||
parentElement->HasFixedDir()) {
- break;
+ return {nullptr, true};
}
-
if (parentElement->HasDirAuto()) {
- bool resetDirection = false;
- nsTextNode* directionWasSetByTextNode = static_cast<nsTextNode*>(
- parent->GetProperty(nsGkAtoms::dirAutoSetBy));
-
- if (!parent->HasDirAutoSet()) {
- // Fast path if parent's direction is not yet set by any descendant
- MOZ_ASSERT(!directionWasSetByTextNode,
- "dirAutoSetBy property should be null");
- resetDirection = true;
- } else {
- // If parent's direction is already set, we need to know if
- // aTextNode is before or after the text node that had set it.
- // We will walk parent's descendants in tree order starting from
- // aTextNode to optimize for the most common case where text nodes are
- // being appended to tree.
- if (!directionWasSetByTextNode) {
- resetDirection = true;
- } else if (directionWasSetByTextNode != aTextNode) {
- if (crossedShadowBoundary || AncestorChainCrossesShadowBoundary(
- directionWasSetByTextNode, parent)) {
- // Need to take the slow path when the path from either the old or
- // new text node to the dir=auto element crosses shadow boundary.
- ResetAutoDirection(parentElement, aNotify);
- return;
- }
-
- nsIContent* child = aTextNode->GetNextNode(parent);
- while (child) {
- if (child->IsElement() &&
- DoesNotAffectDirectionOfAncestors(child->AsElement())) {
- child = child->GetNextNonChildNode(parent);
- continue;
- }
-
- if (child == directionWasSetByTextNode) {
- // we found the node that set the element's direction after our
- // text node, so we need to reset the direction
- resetDirection = true;
- break;
- }
-
- child = child->GetNextNode(parent);
- }
- }
- }
-
- if (resetDirection) {
- if (directionWasSetByTextNode) {
- nsTextNodeDirectionalityMap::RemoveElementFromMap(
- directionWasSetByTextNode, parentElement);
- }
- parentElement->SetDirectionality(aDir, aNotify);
- nsTextNodeDirectionalityMap::AddEntryToMap(aTextNode, parentElement);
- SetDirectionalityOnDescendants(parentElement, aDir, aNotify);
- }
+ return {parentElement, true};
+ }
+ }
+ return {nullptr, false};
+}
- // Since we found an element with dir=auto, we can stop walking the
- // parent chain: none of its ancestors will have their direction set by
- // any of its descendants.
- return;
+static DirAutoElementResult FindDirAutoElementForText(nsTextNode* aTextNode) {
+ MOZ_ASSERT(aTextNode->NodeType() == nsINode::TEXT_NODE,
+ "Must be a text node");
+ return FindDirAutoElementFrom(GetParentOrHostOrSlot(aTextNode));
+}
+
+static DirAutoElementResult SetAncestorDirectionIfAuto(nsTextNode* aTextNode,
+ Directionality aDir,
+ bool aNotify = true) {
+ auto result = FindDirAutoElementForText(aTextNode);
+ if (Element* parentElement = result.mElement) {
+ if (parentElement->GetDirectionality() == aDir) {
+ // If we know that the directionality is already correct, we don't need to
+ // reset it. But we might be responsible for the directionality of
+ // parentElement.
+ MOZ_ASSERT(aDir != Directionality::Unset);
+ aTextNode->SetMaySetDirAuto();
+ } else {
+ // Otherwise recompute the directionality of parentElement.
+ ResetAutoDirection(parentElement, aNotify);
}
- parent = GetParentOrHostOrSlot(parent, &crossedShadowBoundary);
}
+ return result;
}
bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir,
uint32_t aOffset) {
if (!NodeAffectsDirAutoAncestor(aTextNode)) {
- nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode);
return false;
}
+ // If the change has happened after the first character with strong
+ // directionality in the text node, do nothing.
uint32_t firstStrong;
*aOldDir = GetDirectionFromText(aTextNode, &firstStrong);
return (aOffset <= firstStrong);
@@ -1121,29 +758,17 @@ bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir,
void TextNodeChangedDirection(nsTextNode* aTextNode, Directionality aOldDir,
bool aNotify) {
+ MOZ_ASSERT(NodeAffectsDirAutoAncestor(aTextNode), "Caller should check");
Directionality newDir = GetDirectionFromText(aTextNode);
- if (newDir == Directionality::Unset) {
- if (aOldDir != Directionality::Unset &&
- aTextNode->HasTextNodeDirectionalityMap()) {
- // This node used to have a strong directional character but no
- // longer does. ResetTextNodeDirection() will re-resolve the
- // directionality of any elements whose directionality was
- // determined by this node.
- nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode);
- }
- } else {
- // This node has a strong directional character. If it has a
- // TextNodeDirectionalityMap property, it already determines the
- // directionality of some element(s), so call UpdateTextNodeDirection to
- // reresolve their directionality. If it has no map, or if
- // UpdateTextNodeDirection returns zero, indicating that the map is
- // empty, call SetAncestorDirectionIfAuto to find ancestor elements
- // which should have their directionality determined by this node.
- if (aTextNode->HasTextNodeDirectionalityMap() &&
- nsTextNodeDirectionalityMap::UpdateTextNodeDirection(aTextNode,
- newDir)) {
- return;
- }
+ if (newDir == aOldDir) {
+ return;
+ }
+ // If the old directionality is Unset, we might determine now dir=auto
+ // ancestor direction now, even if we don't have the MaySetDirAuto flag.
+ //
+ // Otherwise we used to have a strong directionality and either no longer
+ // does, or it changed. We might need to reset the direction.
+ if (aOldDir == Directionality::Unset || aTextNode->MaySetDirAuto()) {
SetAncestorDirectionIfAuto(aTextNode, newDir, aNotify);
}
}
@@ -1164,17 +789,39 @@ void SetDirectionFromNewTextNode(nsTextNode* aTextNode) {
}
}
-void ResetDirectionSetByTextNode(nsTextNode* aTextNode) {
- if (!NodeAffectsDirAutoAncestor(aTextNode)) {
- nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode);
+void ResetDirectionSetByTextNode(nsTextNode* aTextNode,
+ dom::UnbindContext& aContext) {
+ MOZ_ASSERT(!aTextNode->IsInComposedDoc(), "Should be disconnected already");
+ if (!aTextNode->MaySetDirAuto()) {
+ return;
+ }
+ auto result = FindDirAutoElementForText(aTextNode);
+ if (result.mAnswerIsDefinitive) {
+ // The dir=auto element is in our (now detached) subtree. We're done, as
+ // nothing really changed for our purposes.
+ return;
+ }
+ MOZ_ASSERT(!result.mElement);
+ // The dir=auto element might have been on the element we're unbinding from.
+ // In any case, this text node is clearly no longer what determines its
+ // directionality.
+ aTextNode->ClearMaySetDirAuto();
+ auto* unboundFrom =
+ nsIContent::FromNodeOrNull(aContext.GetOriginalSubtreeParent());
+ if (!unboundFrom || !TextChildrenAffectDirAutoAncestor(unboundFrom)) {
return;
}
Directionality dir = GetDirectionFromText(aTextNode);
- if (dir != Directionality::Unset &&
- aTextNode->HasTextNodeDirectionalityMap()) {
- nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode);
+ if (dir == Directionality::Unset) {
+ return;
+ }
+
+ result = FindDirAutoElementFrom(unboundFrom);
+ if (!result.mElement || result.mElement->GetDirectionality() != dir) {
+ return;
}
+ ResetAutoDirection(result.mElement, /* aNotify = */ true);
}
void SetDirectionalityFromValue(Element* aElement, const nsAString& value,
@@ -1192,26 +839,15 @@ void SetDirectionalityFromValue(Element* aElement, const nsAString& value,
void OnSetDirAttr(Element* aElement, const nsAttrValue* aNewValue,
bool hadValidDir, bool hadDirAuto, bool aNotify) {
- if (aElement->IsHTMLElement(nsGkAtoms::input) ||
- aElement->IsHTMLElement(nsGkAtoms::textarea)) {
+ if (aElement->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea)) {
return;
}
if (aElement->AncestorHasDirAuto()) {
- if (!hadValidDir) {
- // The element is a descendant of an element with dir = auto, is
- // having its dir attribute set, and previously didn't have a valid dir
- // attribute.
- // Check whether any of its text node descendants determine the
- // direction of any of its ancestors, and redetermine their direction
- WalkDescendantsResetAutoDirection(aElement);
- } else if (!aElement->HasValidDir()) {
- // The element is a descendant of an element with dir = auto and is
- // having its dir attribute removed or set to an invalid value.
- // Reset the direction of any of its ancestors whose direction is
- // determined by a text node descendant
- WalkAncestorsResetAutoDirection(aElement, aNotify);
- }
+ // The element is a descendant of an element with dir = auto, is having its
+ // dir attribute changed. Reset the direction of any of its ancestors whose
+ // direction might be determined by a text node descendant
+ WalkAncestorsResetAutoDirection(aElement, aNotify);
} else if (hadDirAuto && !aElement->HasDirAuto()) {
// The element isn't a descendant of an element with dir = auto, and is
// having its dir attribute set to something other than auto.
@@ -1231,11 +867,6 @@ void OnSetDirAttr(Element* aElement, const nsAttrValue* aNewValue,
if (aElement->HasDirAuto()) {
WalkDescendantsSetDirAuto(aElement, aNotify);
} else {
- if (aElement->HasDirAutoSet()) {
- nsTextNode* setByNode = static_cast<nsTextNode*>(
- aElement->GetProperty(nsGkAtoms::dirAutoSetBy));
- nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode, aElement);
- }
SetDirectionalityOnDescendants(
aElement, RecomputeDirectionality(aElement, aNotify), aNotify);
}
@@ -1244,7 +875,7 @@ void OnSetDirAttr(Element* aElement, const nsAttrValue* aNewValue,
void SetDirOnBind(Element* aElement, nsIContent* aParent) {
// Set the AncestorHasDirAuto flag, unless this element shouldn't affect
// ancestors that have dir=auto
- if (!DoesNotParticipateInAutoDirection(aElement) &&
+ if (ParticipatesInAutoDirection(aElement) &&
!aElement->IsHTMLElement(nsGkAtoms::bdi) && aParent &&
aParent->NodeOrAncestorHasDirAuto()) {
aElement->SetAncestorHasDirAuto();
@@ -1265,12 +896,6 @@ void SetDirOnBind(Element* aElement, nsIContent* aParent) {
}
void ResetDir(Element* aElement) {
- if (aElement->HasDirAutoSet()) {
- nsTextNode* setByNode = static_cast<nsTextNode*>(
- aElement->GetProperty(nsGkAtoms::dirAutoSetBy));
- nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode, aElement);
- }
-
if (!aElement->HasDirAuto()) {
RecomputeDirectionality(aElement, false);
}
diff --git a/dom/base/DirectionalityUtils.h b/dom/base/DirectionalityUtils.h
index 17cec80485..0012a1d4be 100644
--- a/dom/base/DirectionalityUtils.h
+++ b/dom/base/DirectionalityUtils.h
@@ -18,6 +18,7 @@ class nsTextNode;
namespace mozilla::dom {
class Element;
class HTMLSlotElement;
+struct UnbindContext;
} // namespace mozilla::dom
namespace mozilla {
@@ -133,10 +134,8 @@ void SetDirectionFromNewTextNode(nsTextNode* aTextNode);
/**
* When a text node is removed from a document, find any ancestors whose
* directionality it determined and redetermine their directionality
- *
- * @param aTextNode the text node
*/
-void ResetDirectionSetByTextNode(nsTextNode* aTextNode);
+void ResetDirectionSetByTextNode(nsTextNode*, dom::UnbindContext&);
/**
* Set the directionality of an element according to the directionality of the
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index 819cd8c11d..4e9286a91e 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -104,6 +104,7 @@
#include "mozilla/SMILTimeContainer.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Components.h"
+#include "mozilla/SVGUtils.h"
#include "mozilla/ServoStyleConsts.h"
#include "mozilla/ServoTypes.h"
#include "mozilla/SizeOfState.h"
@@ -1399,6 +1400,7 @@ Document::Document(const char* aContentType)
mShouldResistFingerprinting(false),
mCloningForSVGUse(false),
mAllowDeclarativeShadowRoots(false),
+ mSuspendDOMNotifications(false),
mXMLDeclarationBits(0),
mOnloadBlockCount(0),
mWriteLevel(0),
@@ -1430,7 +1432,6 @@ Document::Document(const char* aContentType)
mHttpsOnlyStatus(nsILoadInfo::HTTPS_ONLY_UNINITIALIZED),
mViewportType(Unknown),
mViewportFit(ViewportFitType::Auto),
- mSubDocuments(nullptr),
mHeaderData(nullptr),
mServoRestyleRootDirtyBits(0),
mThrowOnDynamicMarkupInsertionCounter(0),
@@ -2333,7 +2334,6 @@ Document::~Document() {
// Kill the subdocument map, doing this will release its strong
// references, if any.
- delete mSubDocuments;
mSubDocuments = nullptr;
nsAutoScriptBlocker scriptBlocker;
@@ -2505,7 +2505,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLazyLoadObserver)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLastRememberedSizeObserver)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElementsObservedForLastRememberedSize)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOrientationPendingPromise)
@@ -2627,7 +2627,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSecurityInfo)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLazyLoadObserver)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mLastRememberedSizeObserver)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mElementsObservedForLastRememberedSize);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentL10n)
@@ -2687,7 +2687,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document)
tmp->mStyleSheetSetList = nullptr;
}
- delete tmp->mSubDocuments;
tmp->mSubDocuments = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameRequestManager)
@@ -2848,7 +2847,6 @@ void Document::DisconnectNodeTree() {
// Delete references to sub-documents and kill the subdocument map,
// if any. This is not strictly needed, but makes the node tree
// teardown a bit faster.
- delete mSubDocuments;
mSubDocuments = nullptr;
bool oldVal = mInUnlinkOrDeletion;
@@ -6319,9 +6317,11 @@ void Document::DeferredContentEditableCountChange(Element* aElement) {
if (aElement) {
if (RefPtr<HTMLEditor> htmlEditor = GetHTMLEditor()) {
nsCOMPtr<nsIInlineSpellChecker> spellChecker;
- rv = htmlEditor->GetInlineSpellChecker(false,
- getter_AddRefs(spellChecker));
- NS_ENSURE_SUCCESS_VOID(rv);
+ DebugOnly<nsresult> rvIgnored = htmlEditor->GetInlineSpellChecker(
+ false, getter_AddRefs(spellChecker));
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rvIgnored),
+ "EditorBase::GetInlineSpellChecker() failed, but ignored");
if (spellChecker &&
aElement->InclusiveDescendantMayNeedSpellchecking(htmlEditor)) {
@@ -7205,7 +7205,8 @@ nsresult Document::SetSubDocumentFor(Element* aElement, Document* aSubDoc) {
PLDHashTable::HashVoidPtrKeyStub, PLDHashTable::MatchEntryStub,
PLDHashTable::MoveEntryStub, SubDocClearEntry, SubDocInitEntry};
- mSubDocuments = new PLDHashTable(&hash_table_ops, sizeof(SubDocMapEntry));
+ mSubDocuments =
+ MakeUnique<PLDHashTable>(&hash_table_ops, sizeof(SubDocMapEntry));
}
// Add a mapping to the hash table
@@ -12394,7 +12395,8 @@ already_AddRefed<nsIURI> Document::ResolvePreloadImage(
void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr,
ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet,
- bool aLinkPreload, uint64_t aEarlyHintPreloaderId) {
+ bool aLinkPreload, uint64_t aEarlyHintPreloaderId,
+ const nsAString& aFetchPriority) {
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL |
nsContentUtils::CORSModeToLoadImageFlags(
Element::StringToCORSMode(aCrossOriginAttr));
@@ -12415,7 +12417,8 @@ void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr,
nsresult rv = nsContentUtils::LoadImage(
aUri, static_cast<nsINode*>(this), this, NodePrincipal(), 0, referrerInfo,
nullptr /* no observer */, loadFlags, initiator, getter_AddRefs(request),
- policyType, false /* urgent */, aLinkPreload, aEarlyHintPreloaderId);
+ policyType, false /* urgent */, aLinkPreload, aEarlyHintPreloaderId,
+ nsGenericHTMLElement::ToFetchPriority(aFetchPriority));
// Pin image-reference to avoid evicting it from the img-cache before
// the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
@@ -12428,7 +12431,8 @@ void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr,
void Document::MaybePreLoadImage(nsIURI* aUri,
const nsAString& aCrossOriginAttr,
ReferrerPolicyEnum aReferrerPolicy,
- bool aIsImgSet, bool aLinkPreload) {
+ bool aIsImgSet, bool aLinkPreload,
+ const nsAString& aFetchPriority) {
const CORSMode corsMode = dom::Element::StringToCORSMode(aCrossOriginAttr);
if (aLinkPreload) {
// Check if the image was already preloaded in this document to avoid
@@ -12437,7 +12441,7 @@ void Document::MaybePreLoadImage(nsIURI* aUri,
PreloadHashKey::CreateAsImage(aUri, NodePrincipal(), corsMode);
if (!mPreloadService.PreloadExists(key)) {
PreLoadImage(aUri, aCrossOriginAttr, aReferrerPolicy, aIsImgSet,
- aLinkPreload, 0);
+ aLinkPreload, 0, aFetchPriority);
}
return;
}
@@ -12451,7 +12455,7 @@ void Document::MaybePreLoadImage(nsIURI* aUri,
// Image not in cache - trigger preload
PreLoadImage(aUri, aCrossOriginAttr, aReferrerPolicy, aIsImgSet, aLinkPreload,
- 0);
+ 0, aFetchPriority);
}
void Document::MaybePreconnect(nsIURI* aOrigURI, mozilla::CORSMode aCORSMode) {
@@ -14751,6 +14755,10 @@ void Document::TopLayerPush(Element& aElement) {
const bool modal = aElement.State().HasState(ElementState::MODAL);
TopLayerPop(aElement);
+ if (nsIFrame* f = aElement.GetPrimaryFrame()) {
+ f->MarkNeedsDisplayItemRebuild();
+ }
+
mTopLayer.AppendElement(do_GetWeakReference(&aElement));
NS_ASSERTION(GetTopLayerTop() == &aElement, "Should match");
@@ -14804,6 +14812,9 @@ Element* Document::TopLayerPop(FunctionRef<bool(Element*)> aPredicate) {
nsCOMPtr<Element> element(do_QueryReferent(mTopLayer[i]));
if (element && aPredicate(element)) {
removedElement = element;
+ if (nsIFrame* f = element->GetPrimaryFrame()) {
+ f->MarkNeedsDisplayItemRebuild();
+ }
mTopLayer.RemoveElementAt(i);
break;
}
@@ -14818,6 +14829,12 @@ Element* Document::TopLayerPop(FunctionRef<bool(Element*)> aPredicate) {
while (!mTopLayer.IsEmpty()) {
Element* element = GetTopLayerTop();
if (!element || element->GetComposedDoc() != this) {
+ if (element) {
+ if (nsIFrame* f = element->GetPrimaryFrame()) {
+ f->MarkNeedsDisplayItemRebuild();
+ }
+ }
+
mTopLayer.RemoveLastElement();
} else {
// The top element of the stack is now an in-doc element. Return here.
@@ -16432,27 +16449,79 @@ DOMIntersectionObserver& Document::EnsureLazyLoadObserver() {
return *mLazyLoadObserver;
}
-ResizeObserver& Document::EnsureLastRememberedSizeObserver() {
- if (!mLastRememberedSizeObserver) {
- mLastRememberedSizeObserver =
- ResizeObserver::CreateLastRememberedSizeObserver(*this);
- }
- return *mLastRememberedSizeObserver;
-}
-
void Document::ObserveForLastRememberedSize(Element& aElement) {
if (NS_WARN_IF(!IsActive())) {
return;
}
- // Options are initialized with ResizeObserverBoxOptions::Content_box by
- // default, which is what we want.
- static ResizeObserverOptions options;
- EnsureLastRememberedSizeObserver().Observe(aElement, options);
+ mElementsObservedForLastRememberedSize.Insert(&aElement);
}
void Document::UnobserveForLastRememberedSize(Element& aElement) {
- if (mLastRememberedSizeObserver) {
- mLastRememberedSizeObserver->Unobserve(aElement);
+ mElementsObservedForLastRememberedSize.Remove(&aElement);
+}
+
+void Document::UpdateLastRememberedSizes() {
+ auto shouldRemoveElement = [&](auto* element) {
+ if (element->GetComposedDoc() != this) {
+ element->RemoveLastRememberedBSize();
+ element->RemoveLastRememberedISize();
+ return true;
+ }
+ return !element->GetPrimaryFrame();
+ };
+
+ for (auto it = mElementsObservedForLastRememberedSize.begin(),
+ end = mElementsObservedForLastRememberedSize.end();
+ it != end; ++it) {
+ if (shouldRemoveElement(*it)) {
+ mElementsObservedForLastRememberedSize.Remove(it);
+ continue;
+ }
+ const auto element = *it;
+ MOZ_ASSERT(element->GetComposedDoc() == this);
+ nsIFrame* frame = element->GetPrimaryFrame();
+ MOZ_ASSERT(frame);
+
+ // As for ResizeObserver, skip nodes hidden `content-visibility`.
+ if (frame->IsHiddenByContentVisibilityOnAnyAncestor()) {
+ continue;
+ }
+
+ MOZ_ASSERT(!frame->IsLineParticipant() || frame->IsReplaced(),
+ "Should have unobserved non-replaced inline.");
+ MOZ_ASSERT(!frame->HidesContent(),
+ "Should have unobserved element skipping its contents.");
+ const nsStylePosition* stylePos = frame->StylePosition();
+ const WritingMode wm = frame->GetWritingMode();
+ bool canUpdateBSize = stylePos->ContainIntrinsicBSize(wm).HasAuto();
+ bool canUpdateISize = stylePos->ContainIntrinsicISize(wm).HasAuto();
+ MOZ_ASSERT(canUpdateBSize || !element->HasLastRememberedBSize(),
+ "Should have removed the last remembered block size.");
+ MOZ_ASSERT(canUpdateISize || !element->HasLastRememberedISize(),
+ "Should have removed the last remembered inline size.");
+ MOZ_ASSERT(canUpdateBSize || canUpdateISize,
+ "Should have unobserved if we can't update any size.");
+
+ AutoTArray<LogicalPixelSize, 1> contentSizeList =
+ ResizeObserver::CalculateBoxSize(element,
+ ResizeObserverBoxOptions::Content_box,
+ /* aForceFragmentHandling */ true);
+ MOZ_ASSERT(!contentSizeList.IsEmpty());
+
+ if (canUpdateBSize) {
+ float bSize = 0;
+ for (const auto& current : contentSizeList) {
+ bSize += current.BSize();
+ }
+ element->SetLastRememberedBSize(bSize);
+ }
+ if (canUpdateISize) {
+ float iSize = 0;
+ for (const auto& current : contentSizeList) {
+ iSize = std::max(iSize, current.ISize());
+ }
+ element->SetLastRememberedISize(iSize);
+ }
}
}
@@ -17103,13 +17172,7 @@ bool Document::IsExtensionPage() const {
void Document::AddResizeObserver(ResizeObserver& aObserver) {
MOZ_ASSERT(!mResizeObservers.Contains(&aObserver));
- // Insert internal ResizeObservers before scripted ones, since they may have
- // observable side-effects and we don't want to expose the insertion time.
- if (aObserver.HasNativeCallback()) {
- mResizeObservers.InsertElementAt(0, &aObserver);
- } else {
- mResizeObservers.AppendElement(&aObserver);
- }
+ mResizeObservers.AppendElement(&aObserver);
}
void Document::RemoveResizeObserver(ResizeObserver& aObserver) {
@@ -17164,6 +17227,18 @@ void Document::DetermineProximityToViewportAndNotifyResizeObservers() {
// sub-documents or ancestors, so flushing layout for the whole browsing
// context tree makes sure we don't miss anyone.
FlushLayoutForWholeBrowsingContextTree(*this);
+
+ // Last remembered sizes are recorded "at the time that ResizeObserver
+ // events are determined and delivered".
+ // https://drafts.csswg.org/css-sizing-4/#last-remembered
+ //
+ // We do it right after layout to make sure sizes are up-to-date. If we do
+ // it after determining the proximities to viewport of
+ // 'content-visibility: auto' nodes, and if one of such node ever becomes
+ // relevant to the user, then we would be incorrectly recording the size
+ // of its rendering when it was skipping its content.
+ UpdateLastRememberedSizes();
+
if (PresShell* presShell = GetPresShell()) {
auto result = presShell->DetermineProximityToViewport();
if (result.mHadInitialDetermination) {
@@ -18627,7 +18702,7 @@ nsIPrincipal* Document::EffectiveStoragePrincipal() const {
}
// Calling StorageAllowedForDocument will notify the ContentBlockLog. This
- // loads TrackingDBService.jsm, which in turn pulls in osfile.jsm, making us
+ // loads TrackingDBService.sys.mjs, making us potentially
// fail // browser/base/content/test/performance/browser_startup.js. To avoid
// that, we short-circuit the check here by allowing storage access to system
// and addon principles, avoiding the test-failure.
diff --git a/dom/base/Document.h b/dom/base/Document.h
index 6a2bd55a9c..a52c61addf 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -57,7 +57,6 @@
#include "mozilla/dom/LargestContentfulPaint.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/WakeLockBinding.h"
-#include "mozilla/glean/GleanMetrics.h"
#include "nsAtom.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
@@ -320,6 +319,9 @@ enum BFCacheStatus {
};
} // namespace dom
+namespace glean::perf {
+struct PageLoadExtra;
+}
} // namespace mozilla
namespace mozilla::net {
@@ -2930,10 +2932,11 @@ class Document : public nsINode,
*/
void MaybePreLoadImage(nsIURI* uri, const nsAString& aCrossOriginAttr,
ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet,
- bool aLinkPreload);
+ bool aLinkPreload, const nsAString& aFetchPriority);
void PreLoadImage(nsIURI* uri, const nsAString& aCrossOriginAttr,
ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet,
- bool aLinkPreload, uint64_t aEarlyHintPreloaderId);
+ bool aLinkPreload, uint64_t aEarlyHintPreloaderId,
+ const nsAString& aFetchPriority);
/**
* Called by images to forget an image preload when they start doing
@@ -3722,12 +3725,12 @@ class Document : public nsINode,
DOMIntersectionObserver* GetLazyLoadObserver() { return mLazyLoadObserver; }
DOMIntersectionObserver& EnsureLazyLoadObserver();
- ResizeObserver* GetLastRememberedSizeObserver() {
- return mLastRememberedSizeObserver;
+ bool HasElementsWithLastRememberedSize() const {
+ return !mElementsObservedForLastRememberedSize.IsEmpty();
}
- ResizeObserver& EnsureLastRememberedSizeObserver();
void ObserveForLastRememberedSize(Element&);
void UnobserveForLastRememberedSize(Element&);
+ void UpdateLastRememberedSizes();
// Dispatch a runnable related to the document.
nsresult Dispatch(already_AddRefed<nsIRunnable>&& aRunnable) const;
@@ -3875,6 +3878,17 @@ class Document : public nsINode,
void SetAllowDeclarativeShadowRoots(bool aAllowDeclarativeShadowRoots);
bool AllowsDeclarativeShadowRoots() const;
+ void SuspendDOMNotifications() {
+ MOZ_ASSERT(IsHTMLDocument(),
+ "Currently suspending DOM notifications is supported only on "
+ "HTML documents.");
+ mSuspendDOMNotifications = true;
+ }
+
+ void ResumeDOMNotifications() { mSuspendDOMNotifications = false; }
+
+ bool DOMNotificationsSuspended() const { return mSuspendDOMNotifications; }
+
protected:
RefPtr<DocumentL10n> mDocumentL10n;
@@ -4866,6 +4880,8 @@ class Document : public nsINode,
bool mAllowDeclarativeShadowRoots : 1;
+ bool mSuspendDOMNotifications : 1;
+
// The fingerprinting protections overrides for this document. The value will
// override the default enabled fingerprinting protections for this document.
// This will only get populated if these is one that comes from the local
@@ -5125,7 +5141,11 @@ class Document : public nsINode,
// https://drafts.csswg.org/css-round-display/#viewport-fit-descriptor
ViewportFitType mViewportFit;
- PLDHashTable* mSubDocuments;
+ // XXXdholbert This should really be modernized to a nsTHashMap or similar,
+ // though note that the modernization will need to take care to also convert
+ // the special hash_table_ops logic (e.g. how SubDocClearEntry clears the
+ // parent document as part of cleaning up an entry in this table).
+ UniquePtr<PLDHashTable> mSubDocuments;
class HeaderData;
UniquePtr<HeaderData> mHeaderData;
@@ -5162,9 +5182,9 @@ class Document : public nsINode,
RefPtr<DOMIntersectionObserver> mLazyLoadObserver;
- // ResizeObserver for storing and removing the last remembered size.
+ // Elements observed for a last remembered size.
// @see {@link https://drafts.csswg.org/css-sizing-4/#last-remembered}
- RefPtr<ResizeObserver> mLastRememberedSizeObserver;
+ nsTHashSet<RefPtr<Element>> mElementsObservedForLastRememberedSize;
// Stack of top layer elements.
nsTArray<nsWeakPtr> mTopLayer;
diff --git a/dom/base/DocumentFragment.h b/dom/base/DocumentFragment.h
index 4b1c11c480..9b8cc69673 100644
--- a/dom/base/DocumentFragment.h
+++ b/dom/base/DocumentFragment.h
@@ -66,7 +66,7 @@ class DocumentFragment : public FragmentOrElement {
return NS_ERROR_NOT_IMPLEMENTED;
}
- virtual void UnbindFromTree(bool aNullParent) override {
+ virtual void UnbindFromTree(UnbindContext&) override {
NS_ASSERTION(false, "Trying to unbind a fragment from a tree");
}
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index f653363f48..be31000278 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -54,7 +54,6 @@
#include "mozilla/PresShellForwards.h"
#include "mozilla/ReflowOutput.h"
#include "mozilla/RelativeTo.h"
-#include "mozilla/ScrollOrigin.h"
#include "mozilla/ScrollTypes.h"
#include "mozilla/ServoStyleConsts.h"
#include "mozilla/ServoStyleConstsInlines.h"
@@ -106,6 +105,7 @@
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/Text.h"
+#include "mozilla/dom/UnbindContext.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/XULCommandEvent.h"
#include "mozilla/dom/nsCSPContext.h"
@@ -113,6 +113,7 @@
#include "mozilla/gfx/BaseRect.h"
#include "mozilla/gfx/BaseSize.h"
#include "mozilla/gfx/Matrix.h"
+#include "mozilla/widget/Screen.h"
#include "nsAtom.h"
#include "nsAttrName.h"
#include "nsAttrValueInlines.h"
@@ -161,7 +162,6 @@
#include "nsIInterfaceRequestor.h"
#include "nsIMemoryReporter.h"
#include "nsIPrincipal.h"
-#include "nsIScreenManager.h"
#include "nsIScriptError.h"
#include "nsIScrollableFrame.h"
#include "nsISpeculativeConnect.h"
@@ -780,8 +780,6 @@ void Element::ScrollIntoView(const ScrollIntoViewOptions& aOptions) {
return WhereToScroll::Center;
case ScrollLogicalPosition::End:
return WhereToScroll::End;
- case ScrollLogicalPosition::EndGuard_:
- MOZ_FALLTHROUGH_ASSERT("Unexpected block direction value");
case ScrollLogicalPosition::Nearest:
break;
}
@@ -1048,20 +1046,13 @@ int32_t Element::ScreenY() {
}
already_AddRefed<nsIScreen> Element::GetScreen() {
- nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
- if (!frame) {
- return nullptr;
+ // Flush layout to guarantee that frames are created if needed, and preserve
+ // behavior.
+ Unused << GetPrimaryFrame(FlushType::Frames);
+ if (nsIWidget* widget = nsContentUtils::WidgetForContent(this)) {
+ return widget->GetWidgetScreen();
}
- nsCOMPtr<nsIScreenManager> screenMgr =
- do_GetService("@mozilla.org/gfx/screenmanager;1");
- if (!screenMgr) {
- return nullptr;
- }
- nsPresContext* pc = frame->PresContext();
- const CSSIntRect rect = frame->GetScreenRect();
- DesktopRect desktopRect = rect * pc->CSSToDevPixelScale() /
- pc->DeviceContext()->GetDesktopToDeviceScale();
- return screenMgr->ScreenForRect(DesktopIntRect::Round(desktopRect));
+ return nullptr;
}
already_AddRefed<DOMRect> Element::GetBoundingClientRect() {
@@ -1722,8 +1713,7 @@ already_AddRefed<nsIHTMLCollection> Element::GetElementsByClassName(
}
Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const {
- const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
- if (slots) {
+ if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElements.Get(aAttr);
if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl)) {
// If reflectedTarget's explicitly set attr-element |attrEl| is
@@ -1774,16 +1764,56 @@ void Element::ClearExplicitlySetAttrElement(nsAtom* aAttr) {
}
void Element::ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement) {
+#ifdef ACCESSIBILITY
+ nsAccessibilityService* accService = GetAccService();
+#endif
+ // Accessibility requires that no other attribute changes occur between
+ // AttrElementWillChange and AttrElementChanged. Scripts could cause
+ // this, so don't let them run here. We do this even if accessibility isn't
+ // running so that the JS behavior is consistent regardless of accessibility.
+ // Otherwise, JS might be able to use this difference to determine whether
+ // accessibility is running, which would be a privacy concern.
+ nsAutoScriptBlocker scriptBlocker;
if (aElement) {
+#ifdef ACCESSIBILITY
+ if (accService) {
+ accService->NotifyAttrElementWillChange(this, aAttr);
+ }
+#endif
SetAttr(aAttr, EmptyString(), IgnoreErrors());
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
slots->mExplicitlySetAttrElements.InsertOrUpdate(
aAttr, do_GetWeakReference(aElement));
+#ifdef ACCESSIBILITY
+ if (accService) {
+ accService->NotifyAttrElementChanged(this, aAttr);
+ }
+#endif
return;
}
+#ifdef ACCESSIBILITY
+ if (accService) {
+ accService->NotifyAttrElementWillChange(this, aAttr);
+ }
+#endif
ClearExplicitlySetAttrElement(aAttr);
UnsetAttr(aAttr, IgnoreErrors());
+#ifdef ACCESSIBILITY
+ if (accService) {
+ accService->NotifyAttrElementChanged(this, aAttr);
+ }
+#endif
+}
+
+Element* Element::GetExplicitlySetAttrElement(nsAtom* aAttr) const {
+ if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
+ nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElements.Get(aAttr);
+ if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl)) {
+ return attrEl;
+ }
+ }
+ return nullptr;
}
void Element::GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements) {
@@ -1958,7 +1988,8 @@ nsresult Element::BindToTree(BindContext& aContext, nsINode& aParent) {
return NS_OK;
}
-bool WillDetachFromShadowOnUnbind(const Element& aElement, bool aNullParent) {
+static bool WillDetachFromShadowOnUnbind(const Element& aElement,
+ bool aNullParent) {
// If our parent still is in a shadow tree by now, and we're not removing
// ourselves from it, then we're still going to be in a shadow tree after
// this.
@@ -1966,12 +1997,14 @@ bool WillDetachFromShadowOnUnbind(const Element& aElement, bool aNullParent) {
(aNullParent || !aElement.GetParent()->IsInShadowTree());
}
-void Element::UnbindFromTree(bool aNullParent) {
- HandleShadowDOMRelatedRemovalSteps(aNullParent);
+void Element::UnbindFromTree(UnbindContext& aContext) {
+ const bool nullParent = aContext.IsUnbindRoot(this);
+
+ HandleShadowDOMRelatedRemovalSteps(nullParent);
if (HasFlag(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR) &&
!IsHTMLElement(nsGkAtoms::datalist)) {
- if (aNullParent) {
+ if (nullParent) {
UnsetFlags(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR);
} else {
nsIContent* parent = GetParent();
@@ -1983,7 +2016,7 @@ void Element::UnbindFromTree(bool aNullParent) {
}
const bool detachingFromShadow =
- WillDetachFromShadowOnUnbind(*this, aNullParent);
+ WillDetachFromShadowOnUnbind(*this, nullParent);
// Make sure to only remove from the ID table if our subtree root is actually
// changing.
if (IsInUncomposedDoc() || detachingFromShadow) {
@@ -2033,7 +2066,7 @@ void Element::UnbindFromTree(bool aNullParent) {
data->ClearAllAnimationCollections();
}
- if (aNullParent) {
+ if (nullParent) {
if (GetParent()) {
RefPtr<nsINode> p;
p.swap(mParent);
@@ -2071,15 +2104,13 @@ void Element::UnbindFromTree(bool aNullParent) {
ClearElementCreatedFromPrototypeAndHasUnmodifiedL10n();
}
- if (aNullParent || !mParent->IsInShadowTree()) {
+ if (nullParent || !mParent->IsInShadowTree()) {
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// Begin keeping track of our subtree root.
- SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
- }
+ SetSubtreeRootPointer(nullParent ? this : mParent->SubtreeRoot());
- if (nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
- if (aNullParent || !mParent->IsInShadowTree()) {
+ if (nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
slots->mContainingShadow = nullptr;
}
}
@@ -2103,11 +2134,10 @@ void Element::UnbindFromTree(bool aNullParent) {
}
if (HasLastRememberedBSize() || HasLastRememberedISize()) {
- // Need to remove the last remembered size at the next ResizeObserver
- // opportunity, so observe the element. But if already observed, we still
- // want the callback to be invoked even if the size was already 0x0, so
- // unobserve it first.
- document->UnobserveForLastRememberedSize(*this);
+ // Make sure the element is observed so that remembered sizes are kept
+ // until the next time "ResizeObserver events are determined and
+ // delivered". See "Disconnected element" tests from
+ // css/css-sizing/contain-intrinsic-size/auto-006.html
document->ObserveForLastRememberedSize(*this);
}
}
@@ -2121,9 +2151,7 @@ void Element::UnbindFromTree(bool aNullParent) {
for (nsIContent* child = GetFirstChild(); child;
child = child->GetNextSibling()) {
- // Note that we pass false for aNullParent here, since we don't want
- // the kids to forget us.
- child->UnbindFromTree(false);
+ child->UnbindFromTree(aContext);
}
MutationObservers::NotifyParentChainChanged(this);
@@ -2751,6 +2779,12 @@ bool Element::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
return true;
}
+ if (aAttribute == nsGkAtoms::aria_activedescendant) {
+ // String in aria-activedescendant is an id, so store as an atom.
+ aResult.ParseAtom(aValue);
+ return true;
+ }
+
if (aAttribute == nsGkAtoms::id) {
// Store id as an atom. id="" means that the element has no id,
// not that it has an emptystring as the id.
@@ -2805,6 +2839,8 @@ void Element::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
if (ShadowRoot* shadow = GetParent()->GetShadowRoot()) {
shadow->MaybeReassignContent(*this);
}
+ } else if (aName == nsGkAtoms::aria_activedescendant) {
+ ClearExplicitlySetAttrElement(aName);
}
}
}
@@ -2856,6 +2892,11 @@ void Element::OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
ElementCallbackType::eAttributeChanged, this, args, definition);
}
}
+
+ if (aNamespaceID == kNameSpaceID_None &&
+ aName == nsGkAtoms::aria_activedescendant) {
+ ClearExplicitlySetAttrElement(aName);
+ }
}
EventListenerManager* Element::GetEventListenerManagerForAttr(nsAtom* aAttrName,
@@ -3397,14 +3438,6 @@ nsresult Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) {
void Element::GetLinkTarget(nsAString& aTarget) { aTarget.Truncate(); }
-static nsStaticAtom* const sPropertiesToTraverseAndUnlink[] = {
- nsGkAtoms::dirAutoSetBy, nullptr};
-
-// static
-nsStaticAtom* const* Element::HTMLSVGPropertiesToTraverseAndUnlink() {
- return sPropertiesToTraverseAndUnlink;
-}
-
nsresult Element::CopyInnerTo(Element* aDst, ReparseAttributes aReparse) {
nsresult rv = aDst->mAttrs.EnsureCapacityToClone(mAttrs);
NS_ENSURE_SUCCESS(rv, rv);
@@ -5048,4 +5081,14 @@ void Element::SetHTMLUnsafe(const nsAString& aHTML) {
nsContentUtils::SetHTMLUnsafe(this, this, aHTML);
}
+bool Element::BlockingContainsRender() const {
+ const nsAttrValue* attrValue = GetParsedAttr(nsGkAtoms::blocking);
+ if (!attrValue || !StaticPrefs::dom_element_blocking_enabled()) {
+ return false;
+ }
+ MOZ_ASSERT(attrValue->Type() == nsAttrValue::eAtomArray,
+ "Checking blocking attribute on element that doesn't parse it?");
+ return attrValue->Contains(nsGkAtoms::render, eIgnoreCase);
+}
+
} // namespace mozilla::dom
diff --git a/dom/base/Element.h b/dom/base/Element.h
index 6c717bfc88..40a8052aef 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -90,7 +90,6 @@ class nsIDOMXULSelectControlElement;
class nsIDOMXULSelectControlItemElement;
class nsIFrame;
class nsIHTMLCollection;
-class nsIMozBrowserFrame;
class nsIPrincipal;
class nsIScreen;
class nsIScrollableFrame;
@@ -244,6 +243,15 @@ class Grid;
SetOrRemoveNullableStringAttr(nsGkAtoms::attr, aValue, aRv); \
}
+#define REFLECT_NULLABLE_ELEMENT_ATTR(method, attr) \
+ Element* Get##method() const { \
+ return GetAttrAssociatedElement(nsGkAtoms::attr); \
+ } \
+ \
+ void Set##method(Element* aElement) { \
+ ExplicitlySetAttrElement(nsGkAtoms::attr, aElement); \
+ }
+
class Element : public FragmentOrElement {
public:
#ifdef MOZILLA_INTERNAL_API
@@ -459,22 +467,13 @@ class Element : public FragmentOrElement {
virtual bool IsInteractiveHTMLContent() const;
/**
- * Returns |this| as an nsIMozBrowserFrame* if the element is a frame or
- * iframe element.
- *
- * We have this method, rather than using QI, so that we can use it during
- * the servo traversal, where we can't QI DOM nodes because of non-thread-safe
- * refcounts.
- */
- virtual nsIMozBrowserFrame* GetAsMozBrowserFrame() { return nullptr; }
-
- /**
* Is the attribute named aAttribute a mapped attribute?
*/
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const;
nsresult BindToTree(BindContext&, nsINode& aParent) override;
- void UnbindFromTree(bool aNullParent = true) override;
+ void UnbindFromTree(UnbindContext&) override;
+ using nsIContent::UnbindFromTree;
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
static void MapNoAttributesInto(mozilla::MappedDeclarationsBuilder&);
@@ -658,8 +657,13 @@ class Element : public FragmentOrElement {
REFLECT_NULLABLE_DOMSTRING_ATTR(Role, role)
// AriaAttributes
+ REFLECT_NULLABLE_ELEMENT_ATTR(AriaActiveDescendantElement,
+ aria_activedescendant)
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaAtomic, aria_atomic)
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaAutoComplete, aria_autocomplete)
+ REFLECT_NULLABLE_DOMSTRING_ATTR(AriaBrailleLabel, aria_braillelabel)
+ REFLECT_NULLABLE_DOMSTRING_ATTR(AriaBrailleRoleDescription,
+ aria_brailleroledescription)
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaBusy, aria_busy)
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaChecked, aria_checked)
REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColCount, aria_colcount)
@@ -1107,8 +1111,6 @@ class Element : public FragmentOrElement {
return FindAttributeDependence(aAttribute, aMaps, N);
}
- static nsStaticAtom* const* HTMLSVGPropertiesToTraverseAndUnlink();
-
MOZ_CAN_RUN_SCRIPT virtual void HandleInvokeInternal(nsAtom* aAction,
ErrorResult& aRv) {}
@@ -1245,6 +1247,16 @@ class Element : public FragmentOrElement {
void ClearExplicitlySetAttrElement(nsAtom*);
+ /**
+ * Gets the attribute element for the given attribute.
+ * https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#explicitly-set-attr-element
+ * Unlike GetAttrAssociatedElement, this returns the target even if it isn't
+ * a descendant of any of this element's shadow-including ancestors. It also
+ * doesn't attempt to retrieve an element using a string id set in the content
+ * attribute.
+ */
+ Element* GetExplicitlySetAttrElement(nsAtom* aAttr) const;
+
PseudoStyleType GetPseudoElementType() const {
nsresult rv = NS_OK;
auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv);
@@ -1332,6 +1344,10 @@ class Element : public FragmentOrElement {
void GetLoading(nsAString& aValue) const;
bool ParseLoadingAttribute(const nsAString& aValue, nsAttrValue& aResult);
+ // https://html.spec.whatwg.org/#potentially-render-blocking
+ virtual bool IsPotentiallyRenderBlocking() { return false; }
+ bool BlockingContainsRender() const;
+
// Shadow DOM v1
enum class ShadowRootDeclarative : bool { No, Yes };
diff --git a/dom/base/EventSource.cpp b/dom/base/EventSource.cpp
index 52cb13f097..f70db487dd 100644
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -849,7 +849,8 @@ EventSourceImpl::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
aStatusCode != NS_ERROR_NET_PARTIAL_TRANSFER &&
aStatusCode != NS_ERROR_NET_TIMEOUT_EXTERNAL &&
aStatusCode != NS_ERROR_PROXY_CONNECTION_REFUSED &&
- aStatusCode != NS_ERROR_DNS_LOOKUP_QUEUE_FULL) {
+ aStatusCode != NS_ERROR_DNS_LOOKUP_QUEUE_FULL &&
+ aStatusCode != NS_ERROR_INVALID_CONTENT_ENCODING) {
DispatchFailConnection();
return NS_ERROR_ABORT;
}
diff --git a/dom/base/FlushType.h b/dom/base/FlushType.h
index 04a253c534..c90cbbd16f 100644
--- a/dom/base/FlushType.h
+++ b/dom/base/FlushType.h
@@ -40,7 +40,7 @@ enum class FlushType : uint8_t {
// Flush type strings that will be displayed in the profiler
// clang-format off
-const EnumeratedArray<FlushType, FlushType::Count, const char*>
+const EnumeratedArray<FlushType, const char*, size_t(FlushType::Count)>
kFlushTypeNames = {
"",
"Event",
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index 9811ce5ace..87fd81bfa3 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -16,11 +16,11 @@
#include "mozilla/dom/FragmentOrElement.h"
#include "DOMIntersectionObserver.h"
#include "mozilla/AsyncEventDispatcher.h"
-#include "mozilla/DeclarationBlock.h"
#include "mozilla/EffectSet.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/ElementAnimationData.h"
+#include "mozilla/DeclarationBlock.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/mozInlineSpellChecker.h"
#include "mozilla/PresShell.h"
@@ -30,39 +30,31 @@
#include "mozilla/URLExtraData.h"
#include "mozilla/dom/Attr.h"
#include "mozilla/dom/RadioGroupContainer.h"
+#include "mozilla/dom/UnbindContext.h"
#include "nsDOMAttributeMap.h"
#include "nsAtom.h"
#include "mozilla/dom/NodeInfo.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/ScriptLoader.h"
-#include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "nsIControllers.h"
#include "nsIDocumentEncoder.h"
#include "nsFocusManager.h"
-#include "nsIScriptGlobalObject.h"
#include "nsNetUtil.h"
#include "nsIFrame.h"
#include "nsIAnonymousContentCreator.h"
#include "nsPresContext.h"
-#include "nsStyleConsts.h"
#include "nsString.h"
-#include "nsUnicharUtils.h"
-#include "nsDOMCID.h"
#include "nsDOMCSSAttrDeclaration.h"
#include "nsNameSpaceManager.h"
#include "nsContentList.h"
#include "nsDOMTokenList.h"
#include "nsError.h"
-#include "nsDOMString.h"
#include "nsXULElement.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozilla/MouseEvents.h"
-#include "nsAttrValueOrString.h"
-#include "nsQueryObject.h"
-#include "nsFrameSelection.h"
#ifdef DEBUG
# include "nsRange.h"
#endif
@@ -73,7 +65,6 @@
#include "nsGkAtoms.h"
#include "nsContentUtils.h"
#include "nsTextFragment.h"
-#include "nsContentCID.h"
#include "nsWindowSizes.h"
#include "nsIWidget.h"
@@ -82,12 +73,10 @@
#include "nsGenericHTMLElement.h"
#include "nsContentCreatorFunctions.h"
#include "nsView.h"
-#include "nsViewManager.h"
#include "nsIScrollableFrame.h"
#include "ChildIterator.h"
-#include "nsTextNode.h"
#include "mozilla/dom/NodeListBinding.h"
-
+#include "mozilla/dom/MutationObservers.h"
#include "nsCCUncollectableMarker.h"
#include "mozAutoDocUpdate.h"
@@ -97,16 +86,12 @@
#include "nsWrapperCacheInlines.h"
#include "nsCycleCollector.h"
#include "xpcpublic.h"
-#include "mozilla/Telemetry.h"
-
-#include "mozilla/CORSMode.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/SVGUseElement.h"
-#include "nsStyledElement.h"
#include "nsIContentInlines.h"
#include "nsChildContentList.h"
#include "mozilla/BloomFilter.h"
@@ -169,6 +154,11 @@ nsIContent* nsIContent::FindFirstNonChromeOnlyAccessContent() const {
return nullptr;
}
+void nsIContent::UnbindFromTree() {
+ UnbindContext context(*this);
+ UnbindFromTree(context);
+}
+
// https://dom.spec.whatwg.org/#dom-slotable-assignedslot
HTMLSlotElement* nsIContent::GetAssignedSlotByMode() const {
/**
@@ -1337,14 +1327,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
Element* elem = tmp->AsElement();
elem->UnlinkIntersectionObservers();
}
-
- if (tmp->IsHTMLElement() || tmp->IsSVGElement()) {
- nsStaticAtom* const* props =
- Element::HTMLSVGPropertiesToTraverseAndUnlink();
- for (uint32_t i = 0; props[i]; ++i) {
- tmp->RemoveProperty(props[i]);
- }
- }
}
// Unlink child content (and unbind our subtree).
@@ -1815,15 +1797,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
}
}
}
- if (tmp->IsHTMLElement() || tmp->IsSVGElement()) {
- nsStaticAtom* const* props =
- Element::HTMLSVGPropertiesToTraverseAndUnlink();
- for (uint32_t i = 0; props[i]; ++i) {
- nsISupports* property =
- static_cast<nsISupports*>(tmp->GetProperty(props[i]));
- cb.NoteXPCOMChild(property);
- }
- }
}
if (tmp->IsElement()) {
Element* element = tmp->AsElement();
@@ -2029,6 +2002,7 @@ void FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML,
}
if (doc->IsHTMLDocument()) {
+ doc->SuspendDOMNotifications();
nsAtom* contextLocalName = parseContext->NodeInfo()->NameAtom();
int32_t contextNameSpaceID = parseContext->GetNameSpaceID();
@@ -2036,6 +2010,10 @@ void FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML,
aError = nsContentUtils::ParseFragmentHTML(
aInnerHTML, target, contextLocalName, contextNameSpaceID,
doc->GetCompatibilityMode() == eCompatibility_NavQuirks, true);
+ doc->ResumeDOMNotifications();
+ if (target->GetFirstChild()) {
+ MutationObservers::NotifyContentAppended(target, target->GetFirstChild());
+ }
mb.NodesAdded();
// HTML5 parser has notified, but not fired mutation events.
nsContentUtils::FireMutationEventsForDirectParsing(doc, target,
diff --git a/dom/base/IDTracker.cpp b/dom/base/IDTracker.cpp
index 4db592534d..813aa44e11 100644
--- a/dom/base/IDTracker.cpp
+++ b/dom/base/IDTracker.cpp
@@ -132,13 +132,30 @@ void IDTracker::ResetWithLocalRef(Element& aFrom, const nsAString& aLocalRef,
bool aWatch) {
MOZ_ASSERT(nsContentUtils::IsLocalRefURL(aLocalRef));
- nsAutoCString ref;
- if (!AppendUTF16toUTF8(Substring(aLocalRef, 1), ref, mozilla::fallible)) {
+ auto ref = Substring(aLocalRef, 1);
+ if (ref.IsEmpty()) {
Unlink();
return;
}
- NS_UnescapeURL(ref);
- RefPtr<nsAtom> idAtom = NS_Atomize(ref);
+
+ nsAutoCString utf8Ref;
+ if (!AppendUTF16toUTF8(ref, utf8Ref, mozilla::fallible)) {
+ Unlink();
+ return;
+ }
+
+ // Only unescape ASCII characters; if we were to unescape arbitrary bytes,
+ // we'd potentially end up with invalid UTF-8.
+ nsAutoCString unescaped;
+ bool appended;
+ if (NS_FAILED(NS_UnescapeURL(utf8Ref.BeginReading(), utf8Ref.Length(),
+ esc_OnlyASCII | esc_AlwaysCopy, unescaped,
+ appended, mozilla::fallible))) {
+ Unlink();
+ return;
+ }
+
+ RefPtr<nsAtom> idAtom = NS_Atomize(unescaped);
ResetWithID(aFrom, idAtom, aWatch);
}
diff --git a/dom/base/InProcessBrowserChildMessageManager.cpp b/dom/base/InProcessBrowserChildMessageManager.cpp
index 191ec9f7b5..830c57591b 100644
--- a/dom/base/InProcessBrowserChildMessageManager.cpp
+++ b/dom/base/InProcessBrowserChildMessageManager.cpp
@@ -13,7 +13,6 @@
#include "nsFrameLoaderOwner.h"
#include "nsQueryObject.h"
#include "xpcpublic.h"
-#include "nsIMozBrowserFrame.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/ChromeMessageSender.h"
#include "mozilla/dom/Document.h"
@@ -100,15 +99,6 @@ InProcessBrowserChildMessageManager::InProcessBrowserChildMessageManager(
mOwner(aOwner),
mChromeMessageManager(aChrome) {
mozilla::HoldJSObjects(this);
-
- // If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our
- // GetEventTargetParent implementation.
- nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
- if (browserFrame) {
- mIsBrowserFrame = browserFrame->GetReallyIsBrowser();
- } else {
- mIsBrowserFrame = false;
- }
}
InProcessBrowserChildMessageManager::~InProcessBrowserChildMessageManager() {
@@ -236,19 +226,7 @@ void InProcessBrowserChildMessageManager::GetEventTargetParent(
return;
}
- if (mIsBrowserFrame &&
- (!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
- if (mOwner) {
- if (nsPIDOMWindowInner* innerWindow =
- mOwner->OwnerDoc()->GetInnerWindow()) {
- // 'this' is already a "chrome handler", so we consider window's
- // parent target to be part of that same part of the event path.
- aVisitor.SetParentTarget(innerWindow->GetParentTarget(), false);
- }
- }
- } else {
- aVisitor.SetParentTarget(mOwner, false);
- }
+ aVisitor.SetParentTarget(mOwner, false);
}
class nsAsyncScriptLoad : public Runnable {
diff --git a/dom/base/InProcessBrowserChildMessageManager.h b/dom/base/InProcessBrowserChildMessageManager.h
index b12e84290f..4064a6d65b 100644
--- a/dom/base/InProcessBrowserChildMessageManager.h
+++ b/dom/base/InProcessBrowserChildMessageManager.h
@@ -108,9 +108,6 @@ class InProcessBrowserChildMessageManager final
RefPtr<nsDocShell> mDocShell;
bool mLoadingScript;
- // Is this the message manager for an in-process <iframe mozbrowser>? This
- // affects where events get sent, so it affects GetEventTargetParent.
- bool mIsBrowserFrame;
bool mPreventEventsEscaping;
// We keep a strong reference to the frameloader after we've started
diff --git a/dom/base/IndexedDBHelper.sys.mjs b/dom/base/IndexedDBHelper.sys.mjs
index a36b211c0a..a9a6b39786 100644
--- a/dom/base/IndexedDBHelper.sys.mjs
+++ b/dom/base/IndexedDBHelper.sys.mjs
@@ -9,7 +9,7 @@ if (DEBUG) {
dump("-*- IndexedDBHelper: " + s + "\n");
};
} else {
- debug = function (s) {};
+ debug = function () {};
}
function getErrorName(err) {
@@ -70,7 +70,7 @@ IndexedDBHelper.prototype = {
debug("Opened database:" + self.dbName + " " + self.dbVersion);
}
self._db = event.target.result;
- self._db.onversionchange = function (event) {
+ self._db.onversionchange = function () {
if (DEBUG) {
debug("WARNING: DB modified from a different window.");
}
@@ -106,7 +106,7 @@ IndexedDBHelper.prototype = {
}
invokeCallbacks(getErrorName(aEvent.target.error));
};
- req.onblocked = function (aEvent) {
+ req.onblocked = function () {
if (DEBUG) {
debug("Opening database request is blocked.");
}
diff --git a/dom/base/MimeType.cpp b/dom/base/MimeType.cpp
index c5869b1d8a..da61489c1f 100644
--- a/dom/base/MimeType.cpp
+++ b/dom/base/MimeType.cpp
@@ -9,8 +9,8 @@
#include "nsUnicharUtils.h"
template <typename char_type>
-/* static */ mozilla::UniquePtr<TMimeType<char_type>>
-TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
+/* static */ RefPtr<TMimeType<char_type>> TMimeType<char_type>::Parse(
+ const nsTSubstring<char_type>& aMimeType) {
// See https://mimesniff.spec.whatwg.org/#parsing-a-mime-type
// Steps 1-2
@@ -85,8 +85,8 @@ TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
for (const char_type* c = subtypeStart; c < subtypeEnd; ++c) {
subtype.Append(ToLowerCaseASCII(*c));
}
- mozilla::UniquePtr<TMimeType<char_type>> mimeType(
- mozilla::MakeUnique<TMimeType<char_type>>(type, subtype));
+ RefPtr<TMimeType<char_type>> mimeType =
+ new TMimeType<char_type>(type, subtype);
// Step 11
while (pos < end) {
@@ -274,7 +274,7 @@ template <typename char_type>
static char_type kCHARSET[] = {'c', 'h', 'a', 'r', 's', 'e', 't'};
static nsTDependentSubstring<char_type> kCharset(kCHARSET, 7);
- mozilla::UniquePtr<TMimeType<char_type>> parsed;
+ RefPtr<TMimeType<char_type>> parsed;
nsTAutoString<char_type> prevContentType;
nsTAutoString<char_type> prevCharset;
@@ -398,9 +398,9 @@ void TMimeType<char_type>::SetParameterValue(
});
}
-template mozilla::UniquePtr<TMimeType<char16_t>> TMimeType<char16_t>::Parse(
+template RefPtr<TMimeType<char16_t>> TMimeType<char16_t>::Parse(
const nsTSubstring<char16_t>& aMimeType);
-template mozilla::UniquePtr<TMimeType<char>> TMimeType<char>::Parse(
+template RefPtr<TMimeType<char>> TMimeType<char>::Parse(
const nsTSubstring<char>& aMimeType);
template bool TMimeType<char16_t>::Parse(
const nsTSubstring<char16_t>& aMimeType,
diff --git a/dom/base/MimeType.h b/dom/base/MimeType.h
index 8c980c7f63..a8b23dfa9b 100644
--- a/dom/base/MimeType.h
+++ b/dom/base/MimeType.h
@@ -8,7 +8,6 @@
#define mozilla_dom_MimeType_h
#include "mozilla/TextUtils.h"
-#include "mozilla/UniquePtr.h"
#include "nsTHashMap.h"
#include "nsTArray.h"
@@ -26,6 +25,8 @@ struct HashKeyType<char> {
template <typename char_type>
class TMimeType final {
private:
+ ~TMimeType() = default;
+
class ParameterValue : public nsTString<char_type> {
public:
bool mRequiresQuoting;
@@ -48,8 +49,8 @@ class TMimeType final {
const nsTSubstring<char_type>& aSubtype)
: mType(aType), mSubtype(aSubtype) {}
- static mozilla::UniquePtr<TMimeType<char_type>> Parse(
- const nsTSubstring<char_type>& aStr);
+ static RefPtr<TMimeType<char_type>> Parse(
+ const nsTSubstring<char_type>& aMimeType);
// @param aMimeType - the mimetype string
// @param aOutEssence - will hold the value of the content-type
@@ -84,6 +85,8 @@ class TMimeType final {
// @param aValue - the value of the parameter
void SetParameterValue(const nsTSubstring<char_type>& aName,
const nsTSubstring<char_type>& aValue);
+
+ NS_INLINE_DECL_REFCOUNTING(TMimeType)
};
using MimeType = TMimeType<char16_t>;
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
index d4b04f8092..14a00b8ed8 100644
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -171,6 +171,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRServiceTest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharePromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXRSystem)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClipboard)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
void Navigator::Invalidate() {
@@ -254,6 +255,8 @@ void Navigator::Invalidate() {
mSharePromise = nullptr;
mWakeLock = nullptr;
+
+ mClipboard = nullptr;
}
void Navigator::GetUserAgent(nsAString& aUserAgent, CallerType aCallerType,
diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h
index 998328cfc6..e559dc4d6a 100644
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -39,7 +39,6 @@ class MediaDevices;
struct MediaStreamConstraints;
class ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
class ServiceWorkerContainer;
-class DOMRequest;
class CredentialsContainer;
class Clipboard;
class LockManager;
diff --git a/dom/base/RadioGroupContainer.cpp b/dom/base/RadioGroupContainer.cpp
index 1d5abb78c6..3bb4d7da20 100644
--- a/dom/base/RadioGroupContainer.cpp
+++ b/dom/base/RadioGroupContainer.cpp
@@ -131,6 +131,17 @@ nsresult RadioGroupContainer::GetNextRadioButton(
return NS_OK;
}
+HTMLInputElement* RadioGroupContainer::GetFirstRadioButton(
+ const nsAString& aName) {
+ nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
+ for (HTMLInputElement* radio : radioGroup->mRadioButtons.AsList()) {
+ if (!radio->Disabled()) {
+ return radio;
+ }
+ }
+ return nullptr;
+}
+
void RadioGroupContainer::AddToRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio,
nsIContent* aAncestor) {
diff --git a/dom/base/RadioGroupContainer.h b/dom/base/RadioGroupContainer.h
index 0c920c1c09..6331c71dd9 100644
--- a/dom/base/RadioGroupContainer.h
+++ b/dom/base/RadioGroupContainer.h
@@ -32,6 +32,7 @@ class RadioGroupContainer final {
nsresult GetNextRadioButton(const nsAString& aName, const bool aPrevious,
HTMLInputElement* aFocusedRadio,
HTMLInputElement** aRadioOut);
+ HTMLInputElement* GetFirstRadioButton(const nsAString& aName);
void AddToRadioGroup(const nsAString& aName, HTMLInputElement* aRadio,
nsIContent* aAncestor);
void RemoveFromRadioGroup(const nsAString& aName, HTMLInputElement* aRadio);
diff --git a/dom/base/ResizeObserver.cpp b/dom/base/ResizeObserver.cpp
index 77472179c8..4a8ffd4c76 100644
--- a/dom/base/ResizeObserver.cpp
+++ b/dom/base/ResizeObserver.cpp
@@ -66,16 +66,9 @@ static nsSize GetContentRectSize(const nsIFrame& aFrame) {
return aFrame.GetContentRectRelativeToSelf().Size();
}
-/**
- * Returns |aTarget|'s size in the form of gfx::Size (in pixels).
- * If the target is an SVG that does not participate in CSS layout,
- * its width and height are determined from bounding box.
- *
- * https://www.w3.org/TR/resize-observer-1/#calculate-box-size
- */
-static AutoTArray<LogicalPixelSize, 1> CalculateBoxSize(
+AutoTArray<LogicalPixelSize, 1> ResizeObserver::CalculateBoxSize(
Element* aTarget, ResizeObserverBoxOptions aBox,
- const ResizeObserver& aObserver) {
+ bool aForceFragmentHandling) {
nsIFrame* frame = aTarget->GetPrimaryFrame();
if (!frame) {
@@ -158,7 +151,7 @@ static AutoTArray<LogicalPixelSize, 1> CalculateBoxSize(
return CSSPixel::FromAppUnits(GetContentRectSize(*aFrame)).ToUnknownSize();
};
if (!StaticPrefs::dom_resize_observer_support_fragments() &&
- !aObserver.HasNativeCallback()) {
+ !aForceFragmentHandling) {
return {LogicalPixelSize(frame->GetWritingMode(), GetFrameSize(frame))};
}
AutoTArray<LogicalPixelSize, 1> size;
@@ -209,7 +202,7 @@ bool ResizeObservation::IsActive() const {
}
return mLastReportedSize !=
- CalculateBoxSize(mTarget, mObservedBox, *mObserver);
+ ResizeObserver::CalculateBoxSize(mTarget, mObservedBox);
}
void ResizeObservation::UpdateLastReportedSize(
@@ -221,23 +214,14 @@ void ResizeObservation::UpdateLastReportedSize(
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ResizeObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ResizeObserver)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner, mDocument, mActiveTargets,
- mObservationMap);
- if (tmp->mCallback.is<RefPtr<ResizeObserverCallback>>()) {
- ImplCycleCollectionTraverse(
- cb, tmp->mCallback.as<RefPtr<ResizeObserverCallback>>(), "mCallback",
- 0);
- }
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner, mDocument, mCallback,
+ mActiveTargets, mObservationMap);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ResizeObserver)
tmp->Disconnect();
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner, mDocument, mActiveTargets,
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner, mDocument, mCallback, mActiveTargets,
mObservationMap);
- if (tmp->mCallback.is<RefPtr<ResizeObserverCallback>>()) {
- ImplCycleCollectionUnlink(
- tmp->mCallback.as<RefPtr<ResizeObserverCallback>>());
- }
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -248,14 +232,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ResizeObserver)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
-ResizeObserver::ResizeObserver(Document& aDocument, NativeCallback aCallback)
- : mOwner(aDocument.GetInnerWindow()),
- mDocument(&aDocument),
- mCallback(aCallback) {
- MOZ_ASSERT(mOwner, "Need a non-null owner window");
- MOZ_ASSERT(mDocument == mOwner->GetExtantDoc());
-}
-
already_AddRefed<ResizeObserver> ResizeObserver::Constructor(
const GlobalObject& aGlobal, ResizeObserverCallback& aCb,
ErrorResult& aRv) {
@@ -361,12 +337,7 @@ void ResizeObserver::GatherActiveObservations(uint32_t aDepth) {
if (targetDepth > aDepth) {
mActiveTargets.AppendElement(observation);
} else {
- // This boolean is only used to indicate we will deliver resize loop error
- // notification later on. However, we don't want to do that for our
- // internal observers.
- if (!HasNativeCallback()) {
- mHasSkippedTargets = true;
- }
+ mHasSkippedTargets = true;
}
}
}
@@ -383,12 +354,12 @@ uint32_t ResizeObserver::BroadcastActiveObservations() {
for (auto& observation : mActiveTargets) {
Element* target = observation->Target();
- auto borderBoxSize =
- CalculateBoxSize(target, ResizeObserverBoxOptions::Border_box, *this);
- auto contentBoxSize =
- CalculateBoxSize(target, ResizeObserverBoxOptions::Content_box, *this);
- auto devicePixelContentBoxSize = CalculateBoxSize(
- target, ResizeObserverBoxOptions::Device_pixel_content_box, *this);
+ auto borderBoxSize = ResizeObserver::CalculateBoxSize(
+ target, ResizeObserverBoxOptions::Border_box);
+ auto contentBoxSize = ResizeObserver::CalculateBoxSize(
+ target, ResizeObserverBoxOptions::Content_box);
+ auto devicePixelContentBoxSize = ResizeObserver::CalculateBoxSize(
+ target, ResizeObserverBoxOptions::Device_pixel_content_box);
RefPtr<ResizeObserverEntry> entry =
new ResizeObserverEntry(mOwner, *target, borderBoxSize, contentBoxSize,
devicePixelContentBoxSize);
@@ -419,13 +390,8 @@ uint32_t ResizeObserver::BroadcastActiveObservations() {
}
}
- if (mCallback.is<RefPtr<ResizeObserverCallback>>()) {
- RefPtr<ResizeObserverCallback> callback(
- mCallback.as<RefPtr<ResizeObserverCallback>>());
- callback->Call(this, entries, *this);
- } else {
- mCallback.as<NativeCallback>()(entries, *this);
- }
+ RefPtr<ResizeObserverCallback> callback(mCallback);
+ callback->Call(this, entries, *this);
mActiveTargets.Clear();
mHasSkippedTargets = false;
@@ -524,61 +490,6 @@ void ResizeObserverEntry::SetDevicePixelContentSize(
}
}
-static void LastRememberedSizeCallback(
- const Sequence<OwningNonNull<ResizeObserverEntry>>& aEntries,
- ResizeObserver& aObserver) {
- for (const auto& entry : aEntries) {
- Element* target = entry->Target();
- if (!target->IsInComposedDoc()) {
- aObserver.Unobserve(*target);
- target->RemoveLastRememberedBSize();
- target->RemoveLastRememberedISize();
- continue;
- }
- nsIFrame* frame = target->GetPrimaryFrame();
- if (!frame) {
- aObserver.Unobserve(*target);
- continue;
- }
- MOZ_ASSERT(!frame->IsLineParticipant() || frame->IsReplaced(),
- "Should have unobserved non-replaced inline.");
- MOZ_ASSERT(!frame->HidesContent(),
- "Should have unobserved element skipping its contents.");
- const nsStylePosition* stylePos = frame->StylePosition();
- const WritingMode wm = frame->GetWritingMode();
- bool canUpdateBSize = stylePos->ContainIntrinsicBSize(wm).HasAuto();
- bool canUpdateISize = stylePos->ContainIntrinsicISize(wm).HasAuto();
- MOZ_ASSERT(canUpdateBSize || !target->HasLastRememberedBSize(),
- "Should have removed the last remembered block size.");
- MOZ_ASSERT(canUpdateISize || !target->HasLastRememberedISize(),
- "Should have removed the last remembered inline size.");
- MOZ_ASSERT(canUpdateBSize || canUpdateISize,
- "Should have unobserved if we can't update any size.");
- AutoTArray<RefPtr<ResizeObserverSize>, 1> contentSizeList;
- entry->GetContentBoxSize(contentSizeList);
- MOZ_ASSERT(!contentSizeList.IsEmpty());
- if (canUpdateBSize) {
- float bSize = 0;
- for (const auto& current : contentSizeList) {
- bSize += current->BlockSize();
- }
- target->SetLastRememberedBSize(bSize);
- }
- if (canUpdateISize) {
- float iSize = 0;
- for (const auto& current : contentSizeList) {
- iSize = std::max(iSize, current->InlineSize());
- }
- target->SetLastRememberedISize(iSize);
- }
- }
-}
-
-/* static */ already_AddRefed<ResizeObserver>
-ResizeObserver::CreateLastRememberedSizeObserver(Document& aDocument) {
- return do_AddRef(new ResizeObserver(aDocument, LastRememberedSizeCallback));
-}
-
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ResizeObserverSize, mOwner)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ResizeObserverSize)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ResizeObserverSize)
diff --git a/dom/base/ResizeObserver.h b/dom/base/ResizeObserver.h
index 6f1fc5b6cd..eaa0e1726d 100644
--- a/dom/base/ResizeObserver.h
+++ b/dom/base/ResizeObserver.h
@@ -121,9 +121,6 @@ class ResizeObservation final : public LinkedListElement<ResizeObservation> {
* https://drafts.csswg.org/resize-observer/#api
*/
class ResizeObserver final : public nsISupports, public nsWrapperCache {
- using NativeCallback = void (*)(
- const Sequence<OwningNonNull<ResizeObserverEntry>>&, ResizeObserver&);
- ResizeObserver(Document& aDocument, NativeCallback aCallback);
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -131,9 +128,7 @@ class ResizeObserver final : public nsISupports, public nsWrapperCache {
ResizeObserver(nsCOMPtr<nsPIDOMWindowInner>&& aOwner, Document* aDocument,
ResizeObserverCallback& aCb)
- : mOwner(std::move(aOwner)),
- mDocument(aDocument),
- mCallback(RefPtr<ResizeObserverCallback>(&aCb)) {
+ : mOwner(std::move(aOwner)), mDocument(aDocument), mCallback(&aCb) {
MOZ_ASSERT(mOwner, "Need a non-null owner window");
MOZ_ASSERT(mDocument, "Need a non-null doc");
MOZ_ASSERT(mDocument == mOwner->GetExtantDoc());
@@ -177,11 +172,6 @@ class ResizeObserver final : public nsISupports, public nsWrapperCache {
bool HasSkippedObservations() const { return mHasSkippedTargets; }
/**
- * Returns whether this is an internal ResizeObserver with a native callback.
- */
- bool HasNativeCallback() const { return mCallback.is<NativeCallback>(); }
-
- /**
* Invoke the callback function in JavaScript for all active observations
* and pass the sequence of ResizeObserverEntry so JavaScript can access them.
* The active observations' mLastReportedSize fields will be updated, and
@@ -191,8 +181,21 @@ class ResizeObserver final : public nsISupports, public nsWrapperCache {
*/
MOZ_CAN_RUN_SCRIPT uint32_t BroadcastActiveObservations();
- static already_AddRefed<ResizeObserver> CreateLastRememberedSizeObserver(
- Document&);
+ /**
+ * Returns |aTarget|'s size in the form of gfx::Size (in pixels).
+ * If the target is an SVG that does not participate in CSS layout,
+ * its width and height are determined from bounding box. Otherwise, the
+ * relevant box is determined according to the |aBox| parameter.
+ *
+ * If dom.resize_observer.support_fragments is enabled, or if
+ * |aForceFragmentHandling| is true then the function reports the size of all
+ * fragments, and not just the first one.
+ *
+ * https://www.w3.org/TR/resize-observer-1/#calculate-box-size
+ */
+ static AutoTArray<LogicalPixelSize, 1> CalculateBoxSize(
+ Element* aTarget, ResizeObserverBoxOptions aBox,
+ bool aForceFragmentHandling = false);
protected:
~ResizeObserver() { Disconnect(); }
@@ -200,7 +203,7 @@ class ResizeObserver final : public nsISupports, public nsWrapperCache {
nsCOMPtr<nsPIDOMWindowInner> mOwner;
// The window's document at the time of ResizeObserver creation.
RefPtr<Document> mDocument;
- Variant<RefPtr<ResizeObserverCallback>, NativeCallback> mCallback;
+ RefPtr<ResizeObserverCallback> mCallback;
nsTArray<RefPtr<ResizeObservation>> mActiveTargets;
// The spec uses a list to store the skipped targets. However, it seems what
// we want is to check if there are any skipped targets (i.e. existence).
diff --git a/dom/base/Selection.cpp b/dom/base/Selection.cpp
index a56e460cbf..69986e6b78 100644
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -46,7 +46,6 @@
#include "nsString.h"
#include "nsFrameSelection.h"
#include "nsISelectionListener.h"
-#include "nsContentCID.h"
#include "nsDeviceContext.h"
#include "nsIContent.h"
#include "nsIContentInlines.h"
@@ -817,7 +816,8 @@ void Selection::SetAnchorFocusRange(size_t aIndex) {
static int32_t CompareToRangeStart(const nsINode& aCompareNode,
uint32_t aCompareOffset,
- const AbstractRange& aRange) {
+ const AbstractRange& aRange,
+ nsContentUtils::NodeIndexCache* aCache) {
MOZ_ASSERT(aRange.GetStartContainer());
nsINode* start = aRange.GetStartContainer();
// If the nodes that we're comparing are not in the same document, assume that
@@ -831,7 +831,13 @@ static int32_t CompareToRangeStart(const nsINode& aCompareNode,
// The points are in the same subtree, hence there has to be an order.
return *nsContentUtils::ComparePoints(&aCompareNode, aCompareOffset, start,
- aRange.StartOffset());
+ aRange.StartOffset(), aCache);
+}
+
+static int32_t CompareToRangeStart(const nsINode& aCompareNode,
+ uint32_t aCompareOffset,
+ const AbstractRange& aRange) {
+ return CompareToRangeStart(aCompareNode, aCompareOffset, aRange, nullptr);
}
static int32_t CompareToRangeEnd(const nsINode& aCompareNode,
@@ -1463,10 +1469,49 @@ void Selection::StyledRanges::ReorderRangesIfNecessary() {
mInvalidStaticRanges.AppendElements(std::move(invalidStaticRanges));
}
if (domMutationHasHappened || mRangesMightHaveChanged) {
- mRanges.Sort([](const StyledRange& a, const StyledRange& b) -> int {
- return CompareToRangeStart(*a.mRange->GetStartContainer(),
- a.mRange->StartOffset(), *b.mRange);
- });
+ // This is hot code. Proceed with caution.
+ // This path uses a cache that keep the last 100 node/index combinations
+ // in a stack-allocated array to save up on expensive calls to
+ // nsINode::ComputeIndexOf() (which happen in
+ // nsContentUtils::ComparePoints()).
+ // The second expensive call here is the sort() below, which should be
+ // avoided if possible. Sorting can be avoided if the ranges are still in
+ // order. Checking the order is cheap compared to sorting (also, it fills up
+ // the cache, which is reused by the sort call).
+ nsContentUtils::NodeIndexCache cache;
+ bool rangeOrderHasChanged = false;
+ const nsINode* prevStartContainer = nullptr;
+ uint32_t prevStartOffset = 0;
+ for (const StyledRange& range : mRanges) {
+ const nsINode* startContainer = range.mRange->GetStartContainer();
+ uint32_t startOffset = range.mRange->StartOffset();
+ if (!prevStartContainer) {
+ prevStartContainer = startContainer;
+ prevStartOffset = startOffset;
+ continue;
+ }
+ // Calling ComparePoints here saves one call of
+ // AbstractRange::StartOffset() per iteration (which is surprisingly
+ // expensive).
+ const Maybe<int32_t> compareResult = nsContentUtils::ComparePoints(
+ startContainer, startOffset, prevStartContainer, prevStartOffset,
+ &cache);
+ // If the nodes are in different subtrees, the Maybe is empty.
+ // Since CompareToRangeStart pretends ranges to be ordered, this aligns
+ // to that behavior.
+ if (compareResult.valueOr(1) != 1) {
+ rangeOrderHasChanged = true;
+ break;
+ }
+ prevStartContainer = startContainer;
+ prevStartOffset = startOffset;
+ }
+ if (rangeOrderHasChanged) {
+ mRanges.Sort([&cache](const StyledRange& a, const StyledRange& b) -> int {
+ return CompareToRangeStart(*a.mRange->GetStartContainer(),
+ a.mRange->StartOffset(), *b.mRange, &cache);
+ });
+ }
mDocumentGeneration = currentDocumentGeneration;
mRangesMightHaveChanged = false;
}
diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp
index 64a1614aee..94db7bad85 100644
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -4,7 +4,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "mozilla/Preferences.h"
#include "mozilla/dom/BindContext.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/DocumentFragment.h"
@@ -17,8 +16,10 @@
#include "mozilla/dom/HTMLDetailsElement.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/HTMLSummaryElement.h"
+#include "mozilla/dom/MutationObservers.h"
#include "mozilla/dom/Text.h"
#include "mozilla/dom/TreeOrderedArrayInlines.h"
+#include "mozilla/dom/UnbindContext.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/IdentifierMapEntry.h"
#include "mozilla/PresShell.h"
@@ -26,7 +27,6 @@
#include "mozilla/ScopeExit.h"
#include "mozilla/ServoStyleRuleMap.h"
#include "mozilla/StyleSheet.h"
-#include "mozilla/StyleSheetInlines.h"
#include "mozilla/dom/StyleSheetList.h"
using namespace mozilla;
@@ -184,10 +184,13 @@ void ShadowRoot::Unbind() {
OwnerDoc()->RemoveComposedDocShadowRoot(*this);
}
+ UnbindContext context(*this);
for (nsIContent* child = GetFirstChild(); child;
child = child->GetNextSibling()) {
- child->UnbindFromTree(false);
+ child->UnbindFromTree(context);
}
+
+ MutationObservers::NotifyParentChainChanged(this);
}
void ShadowRoot::Unattach() {
diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp
index bf3945b1d7..f3e2bea46b 100644
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -34,6 +34,8 @@
#include "mozilla/dom/DOMTypes.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/DocGroup.h"
+#include "mozilla/dom/EncodedAudioChunk.h"
+#include "mozilla/dom/EncodedAudioChunkBinding.h"
#include "mozilla/dom/EncodedVideoChunk.h"
#include "mozilla/dom/EncodedVideoChunkBinding.h"
#include "mozilla/dom/File.h"
@@ -58,6 +60,7 @@
#include "mozilla/dom/TransformStream.h"
#include "mozilla/dom/TransformStreamBinding.h"
#include "mozilla/dom/VideoFrame.h"
+#include "mozilla/dom/AudioData.h"
#include "mozilla/dom/VideoFrameBinding.h"
#include "mozilla/dom/WebIDLSerializable.h"
#include "mozilla/dom/WritableStream.h"
@@ -399,6 +402,7 @@ void StructuredCloneHolder::Read(nsIGlobalObject* aGlobal, JSContext* aCx,
mClonedSurfaces.Clear();
mInputStreamArray.Clear();
mVideoFrames.Clear();
+ mEncodedAudioChunks.Clear();
mEncodedVideoChunks.Clear();
Clear();
}
@@ -1127,6 +1131,28 @@ JSObject* StructuredCloneHolder::CustomReadHandler(
}
}
+ if (StaticPrefs::dom_media_webcodecs_enabled() &&
+ aTag == SCTAG_DOM_AUDIODATA &&
+ CloneScope() == StructuredCloneScope::SameProcess &&
+ aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
+ JS::Rooted<JSObject*> global(aCx, mGlobal->GetGlobalJSObject());
+ if (AudioData_Binding::ConstructorEnabled(aCx, global)) {
+ return AudioData::ReadStructuredClone(aCx, mGlobal, aReader,
+ AudioData()[aIndex]);
+ }
+ }
+
+ if (StaticPrefs::dom_media_webcodecs_enabled() &&
+ aTag == SCTAG_DOM_ENCODEDAUDIOCHUNK &&
+ CloneScope() == StructuredCloneScope::SameProcess &&
+ aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
+ JS::Rooted<JSObject*> global(aCx, mGlobal->GetGlobalJSObject());
+ if (EncodedAudioChunk_Binding::ConstructorEnabled(aCx, global)) {
+ return EncodedAudioChunk::ReadStructuredClone(
+ aCx, mGlobal, aReader, EncodedAudioChunks()[aIndex]);
+ }
+ }
+
return ReadFullySerializableObjects(aCx, aReader, aTag, false);
}
@@ -1246,6 +1272,29 @@ bool StructuredCloneHolder::CustomWriteHandler(
}
}
+ // See if this is an AudioData object.
+ if (StaticPrefs::dom_media_webcodecs_enabled()) {
+ mozilla::dom::AudioData* audioData = nullptr;
+ if (NS_SUCCEEDED(UNWRAP_OBJECT(AudioData, &obj, audioData))) {
+ SameProcessScopeRequired(aSameProcessScopeRequired);
+ return CloneScope() == StructuredCloneScope::SameProcess
+ ? audioData->WriteStructuredClone(aWriter, this)
+ : false;
+ }
+ }
+
+ // See if this is a EncodedAudioChunk object.
+ if (StaticPrefs::dom_media_webcodecs_enabled()) {
+ EncodedAudioChunk* encodedAudioChunk = nullptr;
+ if (NS_SUCCEEDED(
+ UNWRAP_OBJECT(EncodedAudioChunk, &obj, encodedAudioChunk))) {
+ SameProcessScopeRequired(aSameProcessScopeRequired);
+ return CloneScope() == StructuredCloneScope::SameProcess
+ ? encodedAudioChunk->WriteStructuredClone(aWriter, this)
+ : false;
+ }
+ }
+
{
// We only care about streams, so ReflectorToISupportsStatic is fine.
nsCOMPtr<nsISupports> base = xpc::ReflectorToISupportsStatic(aObj);
@@ -1429,6 +1478,39 @@ StructuredCloneHolder::CustomReadTransferHandler(
return true;
}
+ if (StaticPrefs::dom_media_webcodecs_enabled() &&
+ aTag == SCTAG_DOM_AUDIODATA &&
+ CloneScope() == StructuredCloneScope::SameProcess &&
+ aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
+ MOZ_ASSERT(aContent);
+
+ JS::Rooted<JSObject*> globalObj(aCx, mGlobal->GetGlobalJSObject());
+ // aContent will be released in CustomFreeTransferHandler.
+ if (!AudioData_Binding::ConstructorEnabled(aCx, globalObj)) {
+ return false;
+ }
+
+ AudioData::TransferredData* data =
+ static_cast<AudioData::TransferredData*>(aContent);
+ nsCOMPtr<nsIGlobalObject> global = mGlobal;
+ RefPtr<mozilla::dom::AudioData> audioData =
+ AudioData::FromTransferred(global.get(), data);
+ // aContent will be released in CustomFreeTransferHandler if frame is null.
+ if (!audioData) {
+ return false;
+ }
+ delete data;
+ aContent = nullptr;
+
+ JS::Rooted<JS::Value> value(aCx);
+ if (!GetOrCreateDOMReflector(aCx, audioData, &value)) {
+ JS_ClearPendingException(aCx);
+ return false;
+ }
+ aReturnObject.set(&value.toObject());
+ return true;
+ }
+
return false;
}
@@ -1530,6 +1612,26 @@ StructuredCloneHolder::CustomWriteTransferHandler(
return true;
}
}
+ if (StaticPrefs::dom_media_webcodecs_enabled()) {
+ mozilla::dom::AudioData* audioData = nullptr;
+ rv = UNWRAP_OBJECT(AudioData, &obj, audioData);
+ if (NS_SUCCEEDED(rv)) {
+ MOZ_ASSERT(audioData);
+
+ *aExtraData = 0;
+ *aTag = SCTAG_DOM_AUDIODATA;
+ *aContent = nullptr;
+
+ UniquePtr<AudioData::TransferredData> data = audioData->Transfer();
+ if (!data) {
+ return false;
+ }
+ *aContent = data.release();
+ MOZ_ASSERT(*aContent);
+ *aOwnership = JS::SCTAG_TMO_CUSTOM;
+ return true;
+ }
+ }
}
{
@@ -1667,6 +1769,16 @@ void StructuredCloneHolder::CustomFreeTransferHandler(
}
return;
}
+ if (StaticPrefs::dom_media_webcodecs_enabled() &&
+ aTag == SCTAG_DOM_AUDIODATA &&
+ CloneScope() == StructuredCloneScope::SameProcess) {
+ if (aContent) {
+ AudioData::TransferredData* data =
+ static_cast<AudioData::TransferredData*>(aContent);
+ delete data;
+ }
+ return;
+ }
}
bool StructuredCloneHolder::CustomCanTransferHandler(
@@ -1750,6 +1862,15 @@ bool StructuredCloneHolder::CustomCanTransferHandler(
}
}
+ if (StaticPrefs::dom_media_webcodecs_enabled()) {
+ mozilla::dom::AudioData* audioData = nullptr;
+ nsresult rv = UNWRAP_OBJECT(AudioData, &obj, audioData);
+ if (NS_SUCCEEDED(rv)) {
+ SameProcessScopeRequired(aSameProcessScopeRequired);
+ return CloneScope() == StructuredCloneScope::SameProcess;
+ }
+ }
+
return false;
}
diff --git a/dom/base/StructuredCloneHolder.h b/dom/base/StructuredCloneHolder.h
index 206c3d3a25..d1d7cf7806 100644
--- a/dom/base/StructuredCloneHolder.h
+++ b/dom/base/StructuredCloneHolder.h
@@ -165,10 +165,12 @@ class StructuredCloneHolderBase {
};
class BlobImpl;
+class EncodedAudioChunkData;
class EncodedVideoChunkData;
class MessagePort;
class MessagePortIdentifier;
struct VideoFrameSerializedData;
+struct AudioDataSerializedData;
class StructuredCloneHolder : public StructuredCloneHolderBase {
public:
@@ -270,10 +272,16 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
nsTArray<VideoFrameSerializedData>& VideoFrames() { return mVideoFrames; }
+ nsTArray<AudioDataSerializedData>& AudioData() { return mAudioData; }
+
nsTArray<EncodedVideoChunkData>& EncodedVideoChunks() {
return mEncodedVideoChunks;
}
+ nsTArray<EncodedAudioChunkData>& EncodedAudioChunks() {
+ return mEncodedAudioChunks;
+ }
+
// Implementations of the virtual methods to allow cloning of objects which
// JS engine itself doesn't clone.
@@ -379,9 +387,15 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
// Used for cloning VideoFrame in the structured cloning algorithm.
nsTArray<VideoFrameSerializedData> mVideoFrames;
+ // Used for cloning AudioData in the structured cloning algorithm.
+ nsTArray<AudioDataSerializedData> mAudioData;
+
// Used for cloning EncodedVideoChunk in the structured cloning algorithm.
nsTArray<EncodedVideoChunkData> mEncodedVideoChunks;
+ // Used for cloning EncodedAudioChunk in the structured cloning algorithm.
+ nsTArray<EncodedAudioChunkData> mEncodedAudioChunks;
+
// This raw pointer is only set within ::Read() and is unset by the end.
nsIGlobalObject* MOZ_NON_OWNING_REF mGlobal;
diff --git a/dom/base/StructuredCloneTags.h b/dom/base/StructuredCloneTags.h
index 95233c62d7..bbc50d9f9d 100644
--- a/dom/base/StructuredCloneTags.h
+++ b/dom/base/StructuredCloneTags.h
@@ -157,6 +157,10 @@ enum StructuredCloneTags : uint32_t {
SCTAG_DOM_ENCODEDVIDEOCHUNK,
+ SCTAG_DOM_AUDIODATA,
+
+ SCTAG_DOM_ENCODEDAUDIOCHUNK,
+
// IMPORTANT: If you plan to add an new IDB tag, it _must_ be add before the
// "less stable" tags!
};
diff --git a/dom/base/UnbindContext.h b/dom/base/UnbindContext.h
new file mode 100644
index 0000000000..77505ba582
--- /dev/null
+++ b/dom/base/UnbindContext.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* State that is passed down to UnbindToTree. */
+
+#ifndef mozilla_dom_UnbindContext_h__
+#define mozilla_dom_UnbindContext_h__
+
+#include "mozilla/Attributes.h"
+#include "nsINode.h"
+
+namespace mozilla::dom {
+
+struct MOZ_STACK_CLASS UnbindContext final {
+ // The root of the subtree being unbound.
+ nsINode& Root() const { return mRoot; }
+ // Whether we're the root of the subtree being unbound.
+ bool IsUnbindRoot(const nsINode* aNode) const { return &mRoot == aNode; }
+ // The parent node of the subtree we're unbinding from.
+ nsINode* GetOriginalSubtreeParent() const { return mOriginalParent; }
+
+ explicit UnbindContext(nsINode& aRoot)
+ : mRoot(aRoot), mOriginalParent(aRoot.GetParentNode()) {}
+
+ private:
+ nsINode& mRoot;
+ nsINode* const mOriginalParent;
+};
+
+} // namespace mozilla::dom
+
+#endif
diff --git a/dom/base/UseCounters.conf b/dom/base/UseCounters.conf
index 67aa988176..86d782b476 100644
--- a/dom/base/UseCounters.conf
+++ b/dom/base/UseCounters.conf
@@ -74,7 +74,6 @@ custom onunderflow sets an element onunderflow event listener
// JavaScript feature usage
custom JS_asmjs uses asm.js
custom JS_wasm uses WebAssembly
-custom JS_late_weekday parses a Date with day of week in an unexpected position
custom JS_wasm_legacy_exceptions uses WebAssembly legacy exception-handling
// Console API
diff --git a/dom/base/crashtests/crashtests.list b/dom/base/crashtests/crashtests.list
index 7260a18878..864538ddf5 100644
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -220,7 +220,7 @@ load 1406109-1.html
load 1411473.html
load 1413815.html
load 1419799.html
-skip-if(!browserIsRemote) skip-if(geckoview) skip-if(geckoview&&isDebugBuild) skip-if(AddressSanitizer) skip-if(ThreadSanitizer) pref(dom.disable_open_during_load,false) load 1419902.html # skip on non e10s loads, Bug 1419902. Bug 1563013 for GV+WR. Bug 1524493 GV+debug. Bug 1573281 asan
+skip-if(geckoview) skip-if(geckoview&&isDebugBuild) skip-if(AddressSanitizer) skip-if(ThreadSanitizer) pref(dom.disable_open_during_load,false) load 1419902.html # skip Bug 1419902. Bug 1563013 for GV+WR. Bug 1524493 GV+debug. Bug 1573281 asan
load 1422883.html
load 1428053.html
load 1441029.html
@@ -250,7 +250,7 @@ load 1555786.html
load 1577191.html
load eventSource_invalid_scheme_worker_shutdown.html
load 1291535.html
-skip-if(!isDebugBuild||xulRuntime.OS!="Linux") load 1611853.html
+skip-if(!isDebugBuild||!gtkWidget) load 1611853.html
load 1619322.html
asserts(0-2) load 1623918.html # May hit an assertion if the <input> element's anonymous tree hasn't been flushed when IMEContentObserver handles focus
load 1656925.html
diff --git a/dom/base/moz.build b/dom/base/moz.build
index 14c9f9dd96..ef1780f161 100644
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -22,7 +22,6 @@ include("/tools/fuzzing/libfuzzer-config.mozbuild")
XPIDL_SOURCES += [
"mozIDOMWindow.idl",
"nsIContentPolicy.idl",
- "nsIDOMRequestService.idl",
"nsIDroppedLinkHandler.idl",
"nsIEventSourceEventService.idl",
"nsIImageLoadingContent.idl",
@@ -51,7 +50,6 @@ EXPORTS += [
"nsAttrValueInlines.h",
"nsCaseTreatment.h",
"nsChildContentList.h",
- "nsContentCID.h",
"nsContentCreatorFunctions.h",
"nsContentList.h",
"nsContentListDeclarations.h",
@@ -187,7 +185,6 @@ EXPORTS.mozilla.dom += [
"DOMPoint.h",
"DOMQuad.h",
"DOMRect.h",
- "DOMRequest.h",
"DOMStringList.h",
"DOMTokenListSupportedTokens.h",
"Element.h",
@@ -283,6 +280,7 @@ EXPORTS.mozilla.dom += [
"TreeOrderedArrayInlines.h",
"TreeWalker.h",
"UIDirectionManager.h",
+ "UnbindContext.h",
"UseCounterMetrics.h",
"UserActivation.h",
"ViewportMetaData.h",
@@ -345,7 +343,6 @@ UNIFIED_SOURCES += [
"DOMPoint.cpp",
"DOMQuad.cpp",
"DOMRect.cpp",
- "DOMRequest.cpp",
"DOMStringList.cpp",
"Element.cpp",
"EventSource.cpp",
@@ -545,7 +542,6 @@ if CONFIG["TARGET_CPU"].startswith("ppc"):
EXTRA_JS_MODULES += [
"ContentAreaDropListener.sys.mjs",
- "DOMRequestHelper.sys.mjs",
"IndexedDBHelper.sys.mjs",
"LocationHelper.sys.mjs",
"ProcessSelector.sys.mjs",
diff --git a/dom/base/nsAttrValue.cpp b/dom/base/nsAttrValue.cpp
index ea7923fa0f..01efef2eb9 100644
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -15,11 +15,10 @@
#include "nsAttrValue.h"
#include "nsAttrValueInlines.h"
-#include "nsAtomHashKeys.h"
#include "nsUnicharUtils.h"
#include "mozilla/AttributeStyles.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/BloomFilter.h"
-#include "mozilla/CORSMode.h"
#include "mozilla/DeclarationBlock.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/ServoBindingTypes.h"
@@ -27,7 +26,6 @@
#include "mozilla/ShadowParts.h"
#include "mozilla/SVGAttrValueWrapper.h"
#include "mozilla/URLExtraData.h"
-#include "mozilla/dom/CSSRuleBinding.h"
#include "mozilla/dom/Document.h"
#include "nsContentUtils.h"
#include "nsReadableUtils.h"
diff --git a/dom/base/nsContentCID.h b/dom/base/nsContentCID.h
deleted file mode 100644
index cda1cb4075..0000000000
--- a/dom/base/nsContentCID.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsContentCID_h__
-#define nsContentCID_h__
-
-// {972D8D8F-F0DA-11d4-9885-00C04FA0CF4B}
-#define NS_CONTENT_VIEWER_CID \
- { \
- 0x972d8d8f, 0xf0da, 0x11d4, { \
- 0x98, 0x85, 0x0, 0xc0, 0x4f, 0xa0, 0xcf, 0x4b \
- } \
- }
-
-// {FC886801-E768-11d4-9885-00C04FA0CF4B}
-#define NS_CONTENT_DOCUMENT_LOADER_FACTORY_CID \
- { \
- 0xfc886801, 0xe768, 0x11d4, { \
- 0x98, 0x85, 0x0, 0xc0, 0x4f, 0xa0, 0xcf, 0x4b \
- } \
- }
-
-#define NS_NAMESPACEMANAGER_CID \
- { /* d9783472-8fe9-11d2-9d3c-0060088f9ff7 */ \
- 0xd9783472, 0x8fe9, 0x11d2, { \
- 0x9d, 0x3c, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7 \
- } \
- }
-
-// {09F689E0-B4DA-11d2-A68B-00104BDE6048}
-#define NS_EVENTLISTENERMANAGER_CID \
- { \
- 0x9f689e0, 0xb4da, 0x11d2, { \
- 0xa6, 0x8b, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 \
- } \
- }
-
-// {64F300A1-C88C-11d3-97FB-00400553EEF0}
-#define NS_XBLSERVICE_CID \
- { \
- 0x64f300a1, 0xc88c, 0x11d3, { \
- 0x97, 0xfb, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 \
- } \
- }
-
-// {4aef38b7-6364-4e23-a5e7-12f837fbbd9c}
-#define NS_XMLCONTENTSERIALIZER_CID \
- { \
- 0x4aef38b7, 0x6364, 0x4e23, { \
- 0xa5, 0xe7, 0x12, 0xf8, 0x37, 0xfb, 0xbd, 0x9c \
- } \
- }
-
-// {e7c2aaf5-c11a-4954-9dbf-e28edec1fd91}
-#define NS_XHTMLCONTENTSERIALIZER_CID \
- { \
- 0xe7c2aaf5, 0xc11a, 0x4954, { \
- 0x9d, 0xbf, 0xe2, 0x8e, 0xde, 0xc1, 0xfd, 0x91 \
- } \
- }
-
-// {9d3f70da-86e9-11d4-95ec-00b0d03e37b7}
-#define NS_HTMLCONTENTSERIALIZER_CID \
- { \
- 0x9d3f70da, 0x86e9, 0x11d4, { \
- 0x95, 0xec, 0x00, 0xb0, 0xd0, 0x3e, 0x37, 0xb7 \
- } \
- }
-
-// {feca3c34-205e-4ae5-bd1c-03c686ff012b}
-#define MOZ_SANITIZINGHTMLSERIALIZER_CID \
- { \
- 0xfeca3c34, 0x205e, 0x4ae5, { \
- 0xbd, 0x1c, 0x03, 0xc6, 0x86, 0xff, 0x01, 0x2b \
- } \
- }
-
-// {6030f7ef-32ed-46a7-9a63-6a5d3f90445f}
-#define NS_PLAINTEXTSERIALIZER_CID \
- { \
- 0x6030f7ef, 0x32ed, 0x46a7, { \
- 0x9a, 0x63, 0x6a, 0x5d, 0x3f, 0x90, 0x44, 0x5f \
- } \
- }
-
-// {d4f2b600-b5c1-11d6-b483-cc97c63e567c}
-#define NS_HTMLFRAGMENTSINK_CID \
- { \
- 0xd4f2b600, 0xb5c1, 0x11d6, { \
- 0xb4, 0x83, 0xcc, 0x97, 0xc6, 0x3e, 0x56, 0x7c \
- } \
- }
-
-// {13111d00-ce81-11d6-8082-ecf3665af67c}
-#define NS_HTMLFRAGMENTSINK2_CID \
- { \
- 0x13111d00, 0xce81, 0x11d6, { \
- 0x80, 0x82, 0xec, 0xf3, 0x66, 0x5a, 0xf6, 0x7c \
- } \
- }
-
-// {4B664E54-72A2-4bbf-A5C2-66D4DC3066A0}
-#define NS_XMLFRAGMENTSINK_CID \
- { \
- 0x4b664e54, 0x72a2, 0x4bbf, { \
- 0xa5, 0xc2, 0x66, 0xd4, 0xdc, 0x30, 0x66, 0xa0 \
- } \
- }
-
-// {4DC30689-929D-425e-A709-082C6294E542}
-#define NS_XMLFRAGMENTSINK2_CID \
- { \
- 0x4dc30689, 0x929d, 0x425e, { \
- 0xa7, 0x9, 0x8, 0x2c, 0x62, 0x94, 0xe5, 0x42 \
- } \
- }
-
-// {3986B301-097C-11d3-BF87-00105A1B0627}
-#define NS_XULPOPUPLISTENER_CID \
- { \
- 0x3986b301, 0x97c, 0x11d3, { \
- 0xbf, 0x87, 0x0, 0x10, 0x5a, 0x1b, 0x6, 0x27 \
- } \
- }
-
-// {3D262D00-8B5A-11d2-8EB0-00805F29F370}
-#define NS_XULTEMPLATEBUILDER_CID \
- { \
- 0x3d262d00, 0x8b5a, 0x11d2, { \
- 0x8e, 0xb0, 0x0, 0x80, 0x5f, 0x29, 0xf3, 0x70 \
- } \
- }
-
-// {1abdcc96-1dd2-11b2-b520-f8f59cdd67bc}
-#define NS_XULTREEBUILDER_CID \
- { \
- 0x1abdcc96, 0x1dd2, 0x11b2, { \
- 0xb5, 0x20, 0xf8, 0xf5, 0x9c, 0xdd, 0x67, 0xbc \
- } \
- }
-
-#define NS_EVENTLISTENERSERVICE_CID \
- { /* baa34652-f1f1-4185-b224-244ee82a413a */ \
- 0xbaa34652, 0xf1f1, 0x4185, { \
- 0xb2, 0x24, 0x24, 0x4e, 0xe8, 0x2a, 0x41, 0x3a \
- } \
- }
-#define NS_EVENTLISTENERSERVICE_CONTRACTID "@mozilla.org/eventlistenerservice;1"
-
-#define NS_GLOBALMESSAGEMANAGER_CID \
- { /* 130b016f-fad7-4526-bc7f-827dabf79265 */ \
- 0x130b016f, 0xfad7, 0x4526, { \
- 0xbc, 0x7f, 0x82, 0x7d, 0xab, 0xf7, 0x92, 0x65 \
- } \
- }
-#define NS_GLOBALMESSAGEMANAGER_CONTRACTID "@mozilla.org/globalmessagemanager;1"
-
-#define NS_PARENTPROCESSMESSAGEMANAGER_CID \
- { /* 2a058404-fb85-44ec-8cfd-e8cbdc988dc1 */ \
- 0x2a058404, 0xfb85, 0x44ec, { \
- 0x8c, 0xfd, 0xe8, 0xcb, 0xdc, 0x98, 0x8d, 0xc1 \
- } \
- }
-#define NS_PARENTPROCESSMESSAGEMANAGER_CONTRACTID \
- "@mozilla.org/parentprocessmessagemanager;1"
-
-#define NS_CHILDPROCESSMESSAGEMANAGER_CID \
- { /* fe0ff7c3-8e97-448b-9a8a-86afdb9fbbb6 */ \
- 0xfe0ff7c3, 0x8e97, 0x448b, { \
- 0x9a, 0x8a, 0x86, 0xaf, 0xdb, 0x9f, 0xbb, 0xb6 \
- } \
- }
-#define NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID \
- "@mozilla.org/childprocessmessagemanager;1"
-
-// {08c6cc8b-cfb0-421d-b1f7-683ff2989681}
-#define THIRDPARTYUTIL_CID \
- { \
- 0x08c6cc8b, 0xcfb0, 0x421d, { \
- 0xb1, 0xf7, 0x68, 0x3f, 0xf2, 0x98, 0x96, 0x81 \
- } \
- }
-
-// {7B121F7E-EBE4-43AB-9410-DC9087A1DBA6}
-#define GECKO_MEDIA_PLUGIN_SERVICE_CID \
- { \
- 0x7B121F7E, 0xEBE4, 0x43AB, { \
- 0x94, 0x10, 0xDC, 0x90, 0x87, 0xA1, 0xDB, 0xA6 \
- } \
- }
-
-#endif /* nsContentCID_h__ */
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index d849b13927..c6f1687f73 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3027,13 +3027,15 @@ bool nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2,
}
/* static */
-Maybe<int32_t> nsContentUtils::ComparePoints(
- const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2,
- uint32_t aOffset2, ComparePointsCache* aParent1Cache) {
+Maybe<int32_t> nsContentUtils::ComparePoints(const nsINode* aParent1,
+ uint32_t aOffset1,
+ const nsINode* aParent2,
+ uint32_t aOffset2,
+ NodeIndexCache* aIndexCache) {
bool disconnected{false};
const int32_t order = ComparePoints_Deprecated(
- aParent1, aOffset1, aParent2, aOffset2, &disconnected, aParent1Cache);
+ aParent1, aOffset1, aParent2, aOffset2, &disconnected, aIndexCache);
if (disconnected) {
return Nothing();
}
@@ -3044,7 +3046,7 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
/* static */
int32_t nsContentUtils::ComparePoints_Deprecated(
const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2,
- uint32_t aOffset2, bool* aDisconnected, ComparePointsCache* aParent1Cache) {
+ uint32_t aOffset2, bool* aDisconnected, NodeIndexCache* aIndexCache) {
if (aParent1 == aParent2) {
return aOffset1 < aOffset2 ? -1 : aOffset1 > aOffset2 ? 1 : 0;
}
@@ -3089,10 +3091,15 @@ int32_t nsContentUtils::ComparePoints_Deprecated(
if (MOZ_UNLIKELY(child2->IsShadowRoot())) {
return 1;
}
- const Maybe<uint32_t> child1Index =
- aParent1Cache ? aParent1Cache->ComputeIndexOf(parent, child1)
- : parent->ComputeIndexOf(child1);
- const Maybe<uint32_t> child2Index = parent->ComputeIndexOf(child2);
+ Maybe<uint32_t> child1Index;
+ Maybe<uint32_t> child2Index;
+ if (aIndexCache) {
+ aIndexCache->ComputeIndicesOf(parent, child1, child2, child1Index,
+ child2Index);
+ } else {
+ child1Index = parent->ComputeIndexOf(child1);
+ child2Index = parent->ComputeIndexOf(child2);
+ }
if (MOZ_LIKELY(child1Index.isSome() && child2Index.isSome())) {
return *child1Index < *child2Index ? -1 : 1;
}
@@ -3110,7 +3117,9 @@ int32_t nsContentUtils::ComparePoints_Deprecated(
if (!pos1) {
const nsINode* child2 = parents2.ElementAt(--pos2);
- const Maybe<uint32_t> child2Index = parent->ComputeIndexOf(child2);
+ const Maybe<uint32_t> child2Index =
+ aIndexCache ? aIndexCache->ComputeIndexOf(parent, child2)
+ : parent->ComputeIndexOf(child2);
if (MOZ_UNLIKELY(NS_WARN_IF(child2Index.isNothing()))) {
return 1;
}
@@ -3119,8 +3128,8 @@ int32_t nsContentUtils::ComparePoints_Deprecated(
const nsINode* child1 = parents1.ElementAt(--pos1);
const Maybe<uint32_t> child1Index =
- aParent1Cache ? aParent1Cache->ComputeIndexOf(parent, child1)
- : parent->ComputeIndexOf(child1);
+ aIndexCache ? aIndexCache->ComputeIndexOf(parent, child1)
+ : parent->ComputeIndexOf(child1);
if (MOZ_UNLIKELY(NS_WARN_IF(child1Index.isNothing()))) {
return -1;
}
@@ -4004,7 +4013,8 @@ nsresult nsContentUtils::LoadImage(
int32_t aLoadFlags, const nsAString& initiatorType,
imgRequestProxy** aRequest, nsContentPolicyType aContentPolicyType,
bool aUseUrgentStartForChannel, bool aLinkPreload,
- uint64_t aEarlyHintPreloaderId) {
+ uint64_t aEarlyHintPreloaderId,
+ mozilla::dom::FetchPriority aFetchPriority) {
MOZ_ASSERT(aURI, "Must have a URI");
MOZ_ASSERT(aContext, "Must have a context");
MOZ_ASSERT(aLoadingDocument, "Must have a document");
@@ -4041,7 +4051,7 @@ nsresult nsContentUtils::LoadImage(
initiatorType, /* the load initiator */
aUseUrgentStartForChannel, /* urgent-start flag */
aLinkPreload, /* <link preload> initiator */
- aEarlyHintPreloaderId, aRequest);
+ aEarlyHintPreloaderId, aFetchPriority, aRequest);
}
// static
@@ -11426,6 +11436,7 @@ int32_t nsContentUtils::CompareTreePosition(const nsINode* aNode1,
nsIContent* nsContentUtils::AttachDeclarativeShadowRoot(nsIContent* aHost,
ShadowRootMode aMode,
+ bool aIsClonable,
bool aDelegatesFocus) {
RefPtr<Element> host = mozilla::dom::Element::FromNodeOrNull(aHost);
if (!host) {
@@ -11436,7 +11447,7 @@ nsIContent* nsContentUtils::AttachDeclarativeShadowRoot(nsIContent* aHost,
init.mMode = aMode;
init.mDelegatesFocus = aDelegatesFocus;
init.mSlotAssignment = SlotAssignmentMode::Named;
- init.mClonable = true;
+ init.mClonable = aIsClonable;
RefPtr shadowRoot = host->AttachShadow(init, IgnoreErrors(),
Element::ShadowRootDeclarative::Yes);
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 95744fe831..338fc097de 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -39,6 +39,7 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/FromParser.h"
+#include "mozilla/dom/FetchPriority.h"
#include "mozilla/fallible.h"
#include "mozilla/gfx/Point.h"
#include "nsCOMPtr.h"
@@ -545,26 +546,115 @@ class nsContentUtils {
mozilla::Maybe<uint32_t>* aNode1Index = nullptr,
mozilla::Maybe<uint32_t>* aNode2Index = nullptr);
- struct ComparePointsCache {
+ /**
+ * Cache implementation for ComparePoints().
+ *
+ * This cache keeps the last cache_size child/index combinations
+ * in a stack-allocated array for fast lookup.
+ * If the cache is full, the entries are overridden,
+ * starting from the oldest entry.
+ *
+ * Note: This cache does not observe invalidation. As soon as script has
+ * run, this cache must not be used anymore.
+ * Also, this cache uses raw pointers. Beware!
+ */
+ template <size_t cache_size>
+ struct ResizableNodeIndexCache {
+ /**
+ * Looks up or computes two indices in one loop.
+ */
+ void ComputeIndicesOf(const nsINode* aParent, const nsINode* aChild1,
+ const nsINode* aChild2,
+ mozilla::Maybe<uint32_t>& aChild1Index,
+ mozilla::Maybe<uint32_t>& aChild2Index) {
+ bool foundChild1 = false;
+ bool foundChild2 = false;
+ for (size_t cacheIndex = 0; cacheIndex < cache_size; ++cacheIndex) {
+ if (foundChild1 && foundChild2) {
+ return;
+ }
+ const nsINode* node = mNodes[cacheIndex];
+ if (!node) {
+ // reached the end of not-fully-populated cache.
+ break;
+ }
+ if (!foundChild1 && node == aChild1) {
+ aChild1Index = mIndices[cacheIndex];
+ foundChild1 = true;
+ continue;
+ }
+ if (!foundChild2 && node == aChild2) {
+ aChild2Index = mIndices[cacheIndex];
+ foundChild2 = true;
+ continue;
+ }
+ }
+ if (!foundChild1) {
+ aChild1Index = ComputeAndInsertIndexIntoCache(aParent, aChild1);
+ }
+ if (!foundChild2) {
+ aChild2Index = ComputeAndInsertIndexIntoCache(aParent, aChild2);
+ }
+ }
+ /**
+ * Looks up or computes child index.
+ */
mozilla::Maybe<uint32_t> ComputeIndexOf(const nsINode* aParent,
const nsINode* aChild) {
- if (aParent == mParent && aChild == mChild) {
- return mIndex;
+ for (size_t cacheIndex = 0; cacheIndex < cache_size; ++cacheIndex) {
+ const nsINode* node = mNodes[cacheIndex];
+ if (!node) {
+ break;
+ }
+ if (node == aChild) {
+ return mIndices[cacheIndex];
+ }
}
-
- mIndex = aParent->ComputeIndexOf(aChild);
- mParent = aParent;
- mChild = aChild;
- return mIndex;
+ return ComputeAndInsertIndexIntoCache(aParent, aChild);
}
private:
- const nsINode* mParent = nullptr;
- const nsINode* mChild = nullptr;
- mozilla::Maybe<uint32_t> mIndex;
+ /**
+ * Computes the index of aChild in aParent, inserts the index into the
+ * cache, and returns the index.
+ */
+ mozilla::Maybe<uint32_t> ComputeAndInsertIndexIntoCache(
+ const nsINode* aParent, const nsINode* aChild) {
+ mozilla::Maybe<uint32_t> childIndex = aParent->ComputeIndexOf(aChild);
+
+ mNodes[mNext] = aChild;
+ mIndices[mNext] = childIndex;
+
+ ++mNext;
+ if (mNext == cache_size) {
+ // the last element of the cache has been reached.
+ // set mNext to 0 to start overriding the oldest cache entries.
+ mNext = 0;
+ }
+ return childIndex;
+ }
+
+ /// Node storage. The array is initialized to null
+ /// by the empty initializer list.
+ const nsINode* mNodes[cache_size]{};
+
+ mozilla::Maybe<uint32_t> mIndices[cache_size];
+
+ /// The next element in the cache that will be written to.
+ /// If the cache is full (mNext == cache_size),
+ /// the oldest entries in the cache will be overridden,
+ /// ie. mNext will be set to 0.
+ size_t mNext{0};
};
/**
+ * Typedef with a reasonable default cache size.
+ * If Caches of different sizes are needed,
+ * ComparePoints would need to become templated.
+ */
+ using NodeIndexCache = ResizableNodeIndexCache<100>;
+
+ /**
* Utility routine to compare two "points", where a point is a node/offset
* pair.
* Pass a cache object as aParent1Cache if you expect to repeatedly
@@ -577,7 +667,7 @@ class nsContentUtils {
*/
static mozilla::Maybe<int32_t> ComparePoints(
const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2,
- uint32_t aOffset2, ComparePointsCache* aParent1Cache = nullptr);
+ uint32_t aOffset2, NodeIndexCache* aIndexCache = nullptr);
template <typename FPT, typename FRT, typename SPT, typename SRT>
static mozilla::Maybe<int32_t> ComparePoints(
const mozilla::RangeBoundaryBase<FPT, FRT>& aFirstBoundary,
@@ -592,13 +682,16 @@ class nsContentUtils {
* the result is 1, and the optional aDisconnected parameter
* is set to true.
*
- * Pass a cache object as aParent1Cache if you expect to repeatedly
- * call this function with the same value as aParent1.
+ * Pass a cache object as aIndexCache if you expect to repeatedly
+ * call this function.
+ * ComparePointsCache will store the last X (currently 100) node/index
+ * combinations in a stack-allocated array and does a lookup there
+ * before going into the expensive ComputeIndexOf() method.
*/
static int32_t ComparePoints_Deprecated(
const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2,
uint32_t aOffset2, bool* aDisconnected = nullptr,
- ComparePointsCache* aParent1Cache = nullptr);
+ NodeIndexCache* aIndexCache = nullptr);
template <typename FPT, typename FRT, typename SPT, typename SRT>
static int32_t ComparePoints_Deprecated(
const mozilla::RangeBoundaryBase<FPT, FRT>& aFirstBoundary,
@@ -1026,7 +1119,9 @@ class nsContentUtils {
nsContentPolicyType aContentPolicyType =
nsIContentPolicy::TYPE_INTERNAL_IMAGE,
bool aUseUrgentStartForChannel = false, bool aLinkPreload = false,
- uint64_t aEarlyHintPreloaderId = 0);
+ uint64_t aEarlyHintPreloaderId = 0,
+ mozilla::dom::FetchPriority aFetchPriority =
+ mozilla::dom::FetchPriority::Auto);
/**
* Obtain an image loader that respects the given document/channel's privacy
@@ -3438,7 +3533,7 @@ class nsContentUtils {
MOZ_CAN_RUN_SCRIPT_BOUNDARY
static nsIContent* AttachDeclarativeShadowRoot(
- nsIContent* aHost, mozilla::dom::ShadowRootMode aMode,
+ nsIContent* aHost, mozilla::dom::ShadowRootMode aMode, bool aIsClonable,
bool aDelegatesFocus);
private:
diff --git a/dom/base/nsCopySupport.cpp b/dom/base/nsCopySupport.cpp
index 4dc183d664..15c0cf4cf0 100644
--- a/dom/base/nsCopySupport.cpp
+++ b/dom/base/nsCopySupport.cpp
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCopySupport.h"
+#include "nsGlobalWindowInner.h"
#include "nsIDocumentEncoder.h"
#include "nsISupports.h"
#include "nsIContent.h"
@@ -38,7 +39,6 @@
#include "nsIImageLoadingContent.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsContentUtils.h"
-#include "nsContentCID.h"
#ifdef XP_WIN
# include "mozilla/StaticPrefs_clipboard.h"
@@ -714,6 +714,33 @@ static Element* GetElementOrNearestFlattenedTreeParentElement(nsINode* aNode) {
return nullptr;
}
+/**
+ * This class is used while processing clipboard paste event.
+ */
+class MOZ_RAII AutoHandlingPasteEvent final {
+ public:
+ explicit AutoHandlingPasteEvent(nsGlobalWindowInner* aWindow,
+ DataTransfer* aDataTransfer,
+ const EventMessage& aEventMessage,
+ const int32_t& aClipboardType) {
+ MOZ_ASSERT(aDataTransfer);
+ if (aWindow && aEventMessage == ePaste &&
+ aClipboardType == nsIClipboard::kGlobalClipboard) {
+ aWindow->SetCurrentPasteDataTransfer(aDataTransfer);
+ mInnerWindow = aWindow;
+ }
+ }
+
+ ~AutoHandlingPasteEvent() {
+ if (mInnerWindow) {
+ mInnerWindow->SetCurrentPasteDataTransfer(nullptr);
+ }
+ }
+
+ private:
+ RefPtr<nsGlobalWindowInner> mInnerWindow;
+};
+
bool nsCopySupport::FireClipboardEvent(EventMessage aEventMessage,
int32_t aClipboardType,
PresShell* aPresShell,
@@ -791,9 +818,16 @@ bool nsCopySupport::FireClipboardEvent(EventMessage aEventMessage,
InternalClipboardEvent evt(true, originalEventMessage);
evt.mClipboardData = clipboardData;
- RefPtr<nsPresContext> presContext = presShell->GetPresContext();
- EventDispatcher::Dispatch(targetElement, presContext, &evt, nullptr,
- &status);
+ {
+ AutoHandlingPasteEvent autoHandlingPasteEvent(
+ nsGlobalWindowInner::Cast(doc->GetInnerWindow()), clipboardData,
+ aEventMessage, aClipboardType);
+
+ RefPtr<nsPresContext> presContext = presShell->GetPresContext();
+ EventDispatcher::Dispatch(targetElement, presContext, &evt, nullptr,
+ &status);
+ }
+
// If the event was cancelled, don't do the clipboard operation
doDefault = (status != nsEventStatus_eConsumeNoDefault);
}
diff --git a/dom/base/nsDOMNavigationTiming.cpp b/dom/base/nsDOMNavigationTiming.cpp
index ec70d2b1ac..c174153531 100644
--- a/dom/base/nsDOMNavigationTiming.cpp
+++ b/dom/base/nsDOMNavigationTiming.cpp
@@ -7,12 +7,11 @@
#include "nsDOMNavigationTiming.h"
#include "GeckoProfiler.h"
-#include "ipc/IPCMessageUtilsSpecializations.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
+#include "mozilla/glean/GleanMetrics.h"
#include "mozilla/dom/Document.h"
-#include "mozilla/dom/PerformanceNavigation.h"
#include "mozilla/ipc/IPDLParamTraits.h"
#include "mozilla/ipc/URIUtils.h"
#include "nsCOMPtr.h"
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
index 692b94e9bd..9bc8340b90 100644
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -897,6 +897,7 @@ nsresult nsDOMWindowUtils::SendTouchEventCommon(
return NS_ERROR_UNEXPECTED;
}
WidgetTouchEvent event(true, msg, widget);
+ event.mFlags.mIsSynthesizedForTests = true;
event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
nsPresContext* presContext = GetPresContext();
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
index 08a2641333..5a4cf78d65 100644
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -3358,7 +3358,7 @@ nsresult nsFocusManager::DetermineElementToMoveFocus(
}
return GetNextTabbableContent(presShell, startContent, nullptr,
startContent, true, 1, false, false,
- aNavigateByKey, false, aNextContent);
+ aNavigateByKey, false, false, aNextContent);
}
if (aType == MOVEFOCUS_LAST) {
if (!aStartContent) {
@@ -3366,7 +3366,7 @@ nsresult nsFocusManager::DetermineElementToMoveFocus(
}
return GetNextTabbableContent(presShell, startContent, nullptr,
startContent, false, 0, false, false,
- aNavigateByKey, false, aNextContent);
+ aNavigateByKey, false, false, aNextContent);
}
bool forward = (aType == MOVEFOCUS_FORWARD || aType == MOVEFOCUS_FORWARDDOC ||
@@ -3537,7 +3537,7 @@ nsresult nsFocusManager::DetermineElementToMoveFocus(
MOZ_KnownLive(skipOriginalContentCheck ? nullptr
: originalStartContent.get()),
startContent, forward, tabIndex, ignoreTabIndex,
- forDocumentNavigation, aNavigateByKey, false,
+ forDocumentNavigation, aNavigateByKey, false, false,
getter_AddRefs(nextFocus));
NS_ENSURE_SUCCESS(rv, rv);
if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
@@ -3660,15 +3660,16 @@ nsresult nsFocusManager::DetermineElementToMoveFocus(
// If the focus started in this window outside a popup however, we should
// continue by looping around to the end again.
if (forDocumentNavigation && (forward || mayFocusRoot || popupFrame)) {
- // HTML content documents can have their root element focused (a focus
- // ring appears around the entire content area frame). This root
- // appears in the tab order before all of the elements in the document.
- // Chrome documents however cannot be focused directly, so instead we
- // focus the first focusable element within the window.
+ // HTML content documents can have their root element focused by
+ // pressing F6(a focus ring appears around the entire content area
+ // frame). This root appears in the tab order before all of the elements
+ // in the document. Chrome documents however cannot be focused directly,
+ // so instead we focus the first focusable element within the window.
// For example, the urlbar.
RefPtr<Element> rootElementForFocus =
GetRootForFocus(piWindow, doc, true, true);
- return FocusFirst(rootElementForFocus, aNextContent);
+ return FocusFirst(rootElementForFocus, aNextContent,
+ true /* aReachedToEndForDocumentNavigation */);
}
// Once we have hit the top-level and have iterated to the end again, we
@@ -3889,7 +3890,7 @@ nsIContent* nsFocusManager::GetNextTabbableContentInScope(
nsIContent* aOwner, nsIContent* aStartContent,
nsIContent* aOriginalStartContent, bool aForward, int32_t aCurrentTabIndex,
bool aIgnoreTabIndex, bool aForDocumentNavigation, bool aNavigateByKey,
- bool aSkipOwner) {
+ bool aSkipOwner, bool aReachedToEndForDocumentNavigation) {
MOZ_ASSERT(
IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner),
"Scope owner should be host, slot or an open popover with invoker set.");
@@ -3972,6 +3973,7 @@ nsIContent* nsFocusManager::GetNextTabbableContentInScope(
if (TryToMoveFocusToSubDocument(iterContent, aOriginalStartContent,
aForward, aForDocumentNavigation,
aNavigateByKey,
+ aReachedToEndForDocumentNavigation,
getter_AddRefs(elementInFrame))) {
return elementInFrame;
}
@@ -3984,7 +3986,8 @@ nsIContent* nsFocusManager::GetNextTabbableContentInScope(
nsIContent* contentToFocus = GetNextTabbableContentInScope(
iterContent, iterContent, aOriginalStartContent, aForward,
aForward ? 1 : 0, aIgnoreTabIndex, aForDocumentNavigation,
- aNavigateByKey, false /* aSkipOwner */);
+ aNavigateByKey, false /* aSkipOwner */,
+ aReachedToEndForDocumentNavigation);
if (contentToFocus) {
return contentToFocus;
}
@@ -4024,7 +4027,8 @@ nsIContent* nsFocusManager::GetNextTabbableContentInScope(
nsIContent* nsFocusManager::GetNextTabbableContentInAncestorScopes(
nsIContent* aStartOwner, nsCOMPtr<nsIContent>& aStartContent /* inout */,
nsIContent* aOriginalStartContent, bool aForward, int32_t* aCurrentTabIndex,
- bool* aIgnoreTabIndex, bool aForDocumentNavigation, bool aNavigateByKey) {
+ bool* aIgnoreTabIndex, bool aForDocumentNavigation, bool aNavigateByKey,
+ bool aReachedToEndForDocumentNavigation) {
MOZ_ASSERT(aStartOwner == FindScopeOwner(aStartContent),
"aStartOWner should be the scope owner of aStartContent");
MOZ_ASSERT(IsHostOrSlot(aStartOwner), "scope owner should be host or slot");
@@ -4043,7 +4047,7 @@ nsIContent* nsFocusManager::GetNextTabbableContentInAncestorScopes(
nsIContent* contentToFocus = GetNextTabbableContentInScope(
owner, startContent, aOriginalStartContent, aForward, tabIndex,
tabIndex < 0, aForDocumentNavigation, aNavigateByKey,
- false /* aSkipOwner */);
+ false /* aSkipOwner */, aReachedToEndForDocumentNavigation);
if (contentToFocus) {
return contentToFocus;
}
@@ -4089,7 +4093,8 @@ nsresult nsFocusManager::GetNextTabbableContent(
PresShell* aPresShell, nsIContent* aRootContent,
nsIContent* aOriginalStartContent, nsIContent* aStartContent, bool aForward,
int32_t aCurrentTabIndex, bool aIgnoreTabIndex, bool aForDocumentNavigation,
- bool aNavigateByKey, bool aSkipPopover, nsIContent** aResultContent) {
+ bool aNavigateByKey, bool aSkipPopover,
+ bool aReachedToEndForDocumentNavigation, nsIContent** aResultContent) {
*aResultContent = nullptr;
if (!aStartContent) {
@@ -4109,7 +4114,7 @@ nsresult nsFocusManager::GetNextTabbableContent(
nsIContent* contentToFocus = GetNextTabbableContentInScope(
startContent, startContent, aOriginalStartContent, aForward, 1,
aIgnoreTabIndex, aForDocumentNavigation, aNavigateByKey,
- true /* aSkipOwner */);
+ true /* aSkipOwner */, aReachedToEndForDocumentNavigation);
if (contentToFocus) {
NS_ADDREF(*aResultContent = contentToFocus);
return NS_OK;
@@ -4125,7 +4130,7 @@ nsresult nsFocusManager::GetNextTabbableContent(
nsIContent* contentToFocus = GetNextTabbableContentInScope(
popover, popover, aOriginalStartContent, aForward, 1,
aIgnoreTabIndex, aForDocumentNavigation, aNavigateByKey,
- true /* aSkipOwner */);
+ true /* aSkipOwner */, aReachedToEndForDocumentNavigation);
if (contentToFocus) {
NS_ADDREF(*aResultContent = contentToFocus);
return NS_OK;
@@ -4140,7 +4145,7 @@ nsresult nsFocusManager::GetNextTabbableContent(
nsIContent* contentToFocus = GetNextTabbableContentInAncestorScopes(
owner, startContent /* inout */, aOriginalStartContent, aForward,
&aCurrentTabIndex, &aIgnoreTabIndex, aForDocumentNavigation,
- aNavigateByKey);
+ aNavigateByKey, aReachedToEndForDocumentNavigation);
if (contentToFocus) {
NS_ADDREF(*aResultContent = contentToFocus);
return NS_OK;
@@ -4185,7 +4190,8 @@ nsresult nsFocusManager::GetNextTabbableContent(
nsIContent* contentToFocus = GetNextTabbableContentInScope(
iterStartContent, iterStartContent, aOriginalStartContent,
aForward, aForward ? 1 : 0, aIgnoreTabIndex,
- aForDocumentNavigation, aNavigateByKey, true /* aSkipOwner */);
+ aForDocumentNavigation, aNavigateByKey, true /* aSkipOwner */,
+ aReachedToEndForDocumentNavigation);
if (contentToFocus) {
NS_ADDREF(*aResultContent = contentToFocus);
return NS_OK;
@@ -4276,7 +4282,8 @@ nsresult nsFocusManager::GetNextTabbableContent(
(aIgnoreTabIndex || aCurrentTabIndex == tabIndex)) {
nsresult rv = GetNextTabbableContent(
aPresShell, rootElement, nullptr, invokerContent, true,
- tabIndex, false, false, aNavigateByKey, true, aResultContent);
+ tabIndex, false, false, aNavigateByKey, true,
+ aReachedToEndForDocumentNavigation, aResultContent);
if (NS_SUCCEEDED(rv) && *aResultContent) {
return rv;
}
@@ -4298,7 +4305,7 @@ nsresult nsFocusManager::GetNextTabbableContent(
nsIContent* contentToFocus = GetNextTabbableContentInScope(
popover, popover, aOriginalStartContent, aForward, 0,
aIgnoreTabIndex, aForDocumentNavigation, aNavigateByKey,
- true /* aSkipOwner */);
+ true /* aSkipOwner */, aReachedToEndForDocumentNavigation);
if (contentToFocus) {
NS_ADDREF(*aResultContent = contentToFocus);
@@ -4340,7 +4347,8 @@ nsresult nsFocusManager::GetNextTabbableContent(
// want to locate the first content, not the first document.
nsresult rv = GetNextTabbableContent(
aPresShell, currentContent, nullptr, currentContent, true, 1,
- false, false, aNavigateByKey, false, aResultContent);
+ false, false, aNavigateByKey, false,
+ aReachedToEndForDocumentNavigation, aResultContent);
if (NS_SUCCEEDED(rv) && *aResultContent) {
return rv;
}
@@ -4368,7 +4376,7 @@ nsresult nsFocusManager::GetNextTabbableContent(
currentTopLevelScopeOwner, currentTopLevelScopeOwner,
aOriginalStartContent, aForward, aForward ? 1 : 0,
aIgnoreTabIndex, aForDocumentNavigation, aNavigateByKey,
- true /* aSkipOwner */);
+ true /* aSkipOwner */, aReachedToEndForDocumentNavigation);
if (contentToFocus) {
NS_ADDREF(*aResultContent = contentToFocus);
return NS_OK;
@@ -4469,7 +4477,8 @@ nsresult nsFocusManager::GetNextTabbableContent(
// frame. If so, navigate into the child frame instead.
if (TryToMoveFocusToSubDocument(
currentContent, aOriginalStartContent, aForward,
- aForDocumentNavigation, aNavigateByKey, aResultContent)) {
+ aForDocumentNavigation, aNavigateByKey,
+ aReachedToEndForDocumentNavigation, aResultContent)) {
MOZ_ASSERT(*aResultContent);
return NS_OK;
}
@@ -4485,6 +4494,24 @@ nsresult nsFocusManager::GetNextTabbableContent(
NS_ADDREF(*aResultContent = currentContent);
return NS_OK;
}
+ } else if (currentContent && aReachedToEndForDocumentNavigation &&
+ StaticPrefs::dom_disable_tab_focus_to_root_element() &&
+ nsContentUtils::IsChromeDoc(
+ currentContent->GetComposedDoc())) {
+ // aReachedToEndForDocumentNavigation is true means
+ // 1. This is a document navigation (VK_F6)
+ // 2. This is the top-level document (Note that we may start from
+ // a subdocument)
+ // 3. We've searched through the this top-level document already
+ if (!GetRootForChildDocument(currentContent)) {
+ // We'd like to focus the first focusable element of this
+ // top-level chrome document.
+ if (currentContent == aRootContent ||
+ currentContent != startContent) {
+ NS_ADDREF(*aResultContent = currentContent);
+ return NS_OK;
+ }
+ }
}
}
} else if (aOriginalStartContent &&
@@ -4522,13 +4549,14 @@ nsresult nsFocusManager::GetNextTabbableContent(
if (aCurrentTabIndex == (aForward ? 0 : 1)) {
// if going backwards, the canvas should be focused once the beginning
// has been reached, so get the root element.
- if (!aForward) {
+ if (!aForward && !StaticPrefs::dom_disable_tab_focus_to_root_element()) {
nsCOMPtr<nsPIDOMWindowOuter> window = GetCurrentWindow(aRootContent);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
RefPtr<Element> docRoot = GetRootForFocus(
window, aRootContent->GetComposedDoc(), false, true);
- FocusFirst(docRoot, aResultContent);
+ FocusFirst(docRoot, aResultContent,
+ false /* aReachedToEndForDocumentNavigation */);
}
break;
}
@@ -4556,7 +4584,8 @@ bool nsFocusManager::TryDocumentNavigation(nsIContent* aCurrentContent,
// the frameset's frames and locate the first focusable frame.
if (!rootElementForChildDocument->IsHTMLElement(nsGkAtoms::frameset)) {
*aCheckSubDocument = false;
- Unused << FocusFirst(rootElementForChildDocument, aResultContent);
+ Unused << FocusFirst(rootElementForChildDocument, aResultContent,
+ false /* aReachedToEndForDocumentNavigation */);
return *aResultContent != nullptr;
}
} else {
@@ -4571,12 +4600,12 @@ bool nsFocusManager::TryDocumentNavigation(nsIContent* aCurrentContent,
bool nsFocusManager::TryToMoveFocusToSubDocument(
nsIContent* aCurrentContent, nsIContent* aOriginalStartContent,
bool aForward, bool aForDocumentNavigation, bool aNavigateByKey,
- nsIContent** aResultContent) {
+ bool aReachedToEndForDocumentNavigation, nsIContent** aResultContent) {
Document* doc = aCurrentContent->GetComposedDoc();
NS_ASSERTION(doc, "content not in document");
Document* subdoc = doc->GetSubDocumentFor(aCurrentContent);
if (subdoc && !subdoc->EventHandlingSuppressed()) {
- if (aForward) {
+ if (aForward && !StaticPrefs::dom_disable_tab_focus_to_root_element()) {
// When tabbing forward into a frame, return the root
// frame so that the canvas becomes focused.
if (nsCOMPtr<nsPIDOMWindowOuter> subframe = subdoc->GetWindow()) {
@@ -4592,11 +4621,19 @@ bool nsFocusManager::TryToMoveFocusToSubDocument(
nsresult rv = GetNextTabbableContent(
subPresShell, rootElement, aOriginalStartContent, rootElement,
aForward, (aForward ? 1 : 0), false, aForDocumentNavigation,
- aNavigateByKey, false, aResultContent);
+ aNavigateByKey, false, aReachedToEndForDocumentNavigation,
+ aResultContent);
NS_ENSURE_SUCCESS(rv, false);
if (*aResultContent) {
return true;
}
+ if (rootElement->IsEditable() &&
+ StaticPrefs::dom_disable_tab_focus_to_root_element()) {
+ // Only move to the root element with a valid reason
+ *aResultContent = rootElement;
+ NS_ADDREF(*aResultContent);
+ return true;
+ }
}
}
}
@@ -4711,7 +4748,8 @@ int32_t nsFocusManager::GetNextTabIndex(nsIContent* aParent,
}
nsresult nsFocusManager::FocusFirst(Element* aRootElement,
- nsIContent** aNextContent) {
+ nsIContent** aNextContent,
+ bool aReachedToEndForDocumentNavigation) {
if (!aRootElement) {
return NS_OK;
}
@@ -4741,9 +4779,12 @@ nsresult nsFocusManager::FocusFirst(Element* aRootElement,
// tabbable item so that the first item is focused. Note that we
// always go forward and not back here.
if (RefPtr<PresShell> presShell = doc->GetPresShell()) {
- return GetNextTabbableContent(presShell, aRootElement, nullptr,
- aRootElement, true, 1, false, false, true,
- false, aNextContent);
+ return GetNextTabbableContent(
+ presShell, aRootElement, nullptr, aRootElement, true, 1, false,
+ StaticPrefs::dom_disable_tab_focus_to_root_element()
+ ? aReachedToEndForDocumentNavigation
+ : false,
+ true, false, aReachedToEndForDocumentNavigation, aNextContent);
}
}
}
diff --git a/dom/base/nsFocusManager.h b/dom/base/nsFocusManager.h
index 6e5c761f4c..4fb9d05e1c 100644
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -578,6 +578,10 @@ class nsFocusManager final : public nsIFocusManager,
* aSkipOwner to skip owner while searching. The flag is set when caller is
* |GetNextTabbableContent| in order to let caller handle owner.
*
+ * aReachedToEndForDocumentNavigation is true when this is a document
+ * navigation and the focus algorithm has reached to the end of the top-level
+ * document.
+ *
* NOTE:
* Consider the method searches downwards in flattened subtree
* rooted at aOwner.
@@ -586,7 +590,8 @@ class nsFocusManager final : public nsIFocusManager,
nsIContent* aOwner, nsIContent* aStartContent,
nsIContent* aOriginalStartContent, bool aForward,
int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
- bool aForDocumentNavigation, bool aNavigateByKey, bool aSkipOwner);
+ bool aForDocumentNavigation, bool aNavigateByKey, bool aSkipOwner,
+ bool aReachedToEndForDocumentNavigation);
/**
* Retrieve the next tabbable element in scope including aStartContent
@@ -619,6 +624,10 @@ class nsFocusManager final : public nsIFocusManager,
* aNavigateByKey to move focus by keyboard as a side effect of computing the
* next target.
*
+ * aReachedToEndForDocumentNavigation is true when this is a document
+ * navigation and the focus algorithm has reached to the end of the top-level
+ * document.
+ *
* NOTE:
* Consider the method searches upwards in all shadow host- or slot-rooted
* flattened subtrees that contains aStartContent as non-root, except
@@ -628,7 +637,8 @@ class nsFocusManager final : public nsIFocusManager,
nsIContent* aStartOwner, nsCOMPtr<nsIContent>& aStartContent /* inout */,
nsIContent* aOriginalStartContent, bool aForward,
int32_t* aCurrentTabIndex, bool* aIgnoreTabIndex,
- bool aForDocumentNavigation, bool aNavigateByKey);
+ bool aForDocumentNavigation, bool aNavigateByKey,
+ bool aReachedToEndForDocumentNavigation);
/**
* Retrieve the next tabbable element within a document, using focusability
@@ -663,13 +673,17 @@ class nsFocusManager final : public nsIFocusManager,
*
* aNavigateByKey to move focus by keyboard as a side effect of computing the
* next target.
+ *
+ * aReachedToEndForDocumentNavigation is true when this is a document
+ * navigation and the focus algorithm has reached to the end of the top-level
+ * document.
*/
MOZ_CAN_RUN_SCRIPT nsresult GetNextTabbableContent(
mozilla::PresShell* aPresShell, nsIContent* aRootContent,
nsIContent* aOriginalStartContent, nsIContent* aStartContent,
bool aForward, int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
bool aForDocumentNavigation, bool aNavigateByKey, bool aSkipPopover,
- nsIContent** aResultContent);
+ bool aReachedToEndForDocumentNavigation, nsIContent** aResultContent);
/**
* Get the next tabbable image map area and returns it.
@@ -699,9 +713,13 @@ class nsFocusManager final : public nsIFocusManager,
* Focus the first focusable content within the document with a root node of
* aRootContent. For content documents, this will be aRootContent itself, but
* for chrome documents, this will locate the next focusable content.
+ *
+ * aReachedToEndForDocumentNavigation is true when the focus algorithm has
+ * reached to the end of the top-level document.
*/
- MOZ_CAN_RUN_SCRIPT nsresult FocusFirst(mozilla::dom::Element* aRootContent,
- nsIContent** aNextContent);
+ MOZ_CAN_RUN_SCRIPT nsresult
+ FocusFirst(mozilla::dom::Element* aRootContent, nsIContent** aNextContent,
+ bool aReachedToEndForDocumentNavigation);
/**
* Retrieves and returns the root node from aDocument to be focused. Will
@@ -761,7 +779,7 @@ class nsFocusManager final : public nsIFocusManager,
MOZ_CAN_RUN_SCRIPT bool TryToMoveFocusToSubDocument(
nsIContent* aCurrentContent, nsIContent* aOriginalStartContent,
bool aForward, bool aForDocumentNavigation, bool aNavigateByKey,
- nsIContent** aResultContent);
+ bool aReachedToEndForDocumentNavigation, nsIContent** aResultContent);
// Sets the focused BrowsingContext and, if appropriate, syncs it to
// other processes.
diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp
index a40bc427dd..eca528f258 100644
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -39,7 +39,6 @@
#include "nsSubDocumentFrame.h"
#include "nsError.h"
#include "nsIAppWindow.h"
-#include "nsIMozBrowserFrame.h"
#include "nsIScriptError.h"
#include "nsGlobalWindowInner.h"
#include "nsGlobalWindowOuter.h"
@@ -262,13 +261,6 @@ static bool IsTopContent(BrowsingContext* aParent, Element* aOwner) {
return false;
}
- // If we have a (deprecated) mozbrowser element, we want to start a new
- // BrowsingContext tree regardless of whether the parent is chrome or content.
- nsCOMPtr<nsIMozBrowserFrame> mozbrowser = aOwner->GetAsMozBrowserFrame();
- if (mozbrowser && mozbrowser->GetReallyIsBrowser()) {
- return true;
- }
-
if (aParent->IsContent()) {
// If we're already in content, we may still want to create a new
// BrowsingContext tree if our element is a xul browser element with a
@@ -365,17 +357,8 @@ static bool InitialLoadIsRemote(Element* aOwner) {
return false;
}
- // If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
- // fall back to the default.
- nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(aOwner);
- bool isMozBrowserFrame = browserFrame && browserFrame->GetReallyIsBrowser();
- if (isMozBrowserFrame && !aOwner->HasAttr(nsGkAtoms::remote)) {
- return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
- }
-
- // Otherwise, we're remote if we have "remote=true" and we're either a
- // browser frame or a XUL element.
- return (isMozBrowserFrame || aOwner->GetNameSpaceID() == kNameSpaceID_XUL) &&
+ // Otherwise, we're remote if we have "remote=true" and we're a XUL element.
+ return (aOwner->GetNameSpaceID() == kNameSpaceID_XUL) &&
aOwner->AttrValueIs(kNameSpaceID_None, nsGkAtoms::remote,
nsGkAtoms::_true, eCaseMatters);
}
@@ -706,12 +689,6 @@ nsresult nsFrameLoader::ReallyStartLoadingInternal() {
// Default flags:
int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
-
- // Flags for browser frame:
- if (OwnerIsMozBrowserFrame()) {
- flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
- nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
- }
loadState->SetLoadFlags(flags);
loadState->SetFirstParty(false);
@@ -875,14 +852,6 @@ static bool CheckDocShellType(mozilla::dom::Element* aOwnerContent,
bool isContent = aOwnerContent->AttrValueIs(kNameSpaceID_None, aAtom,
nsGkAtoms::content, eIgnoreCase);
- if (!isContent) {
- nsCOMPtr<nsIMozBrowserFrame> mozbrowser =
- aOwnerContent->GetAsMozBrowserFrame();
- if (mozbrowser) {
- mozbrowser->GetMozbrowser(&isContent);
- }
- }
-
if (isContent) {
return aDocShell->ItemType() == nsIDocShellTreeItem::typeContent;
}
@@ -1156,7 +1125,6 @@ bool nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
if (nsCOMPtr<nsIObserverService> os = services::GetObserverService()) {
os->NotifyObservers(ToSupports(this), "remote-browser-shown", nullptr);
}
- ProcessPriorityManager::RemoteBrowserFrameShown(this);
}
} else {
nsIntRect dimensions;
@@ -1329,14 +1297,6 @@ nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
return NS_ERROR_NOT_IMPLEMENTED;
}
- // Destroy browser frame scripts for content leaving a frame with browser API
- if (OwnerIsMozBrowserFrame() && !aOther->OwnerIsMozBrowserFrame()) {
- DestroyBrowserFrameScripts();
- }
- if (!OwnerIsMozBrowserFrame() && aOther->OwnerIsMozBrowserFrame()) {
- aOther->DestroyBrowserFrameScripts();
- }
-
otherBrowserParent->SetBrowserDOMWindow(browserDOMWindow);
browserParent->SetBrowserDOMWindow(otherBrowserDOMWindow);
@@ -1405,10 +1365,6 @@ nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
ourPresShell->BackingScaleFactorChanged();
otherPresShell->BackingScaleFactorChanged();
- // Initialize browser API if needed now that owner content has changed.
- InitializeBrowserAPI();
- aOther->InitializeBrowserAPI();
-
mInSwap = aOther->mInSwap = false;
// Send an updated tab context since owner content type may have changed.
@@ -1536,13 +1492,8 @@ nsresult nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
return NS_ERROR_NOT_IMPLEMENTED;
}
- bool ourFullscreenAllowed = ourContent->IsXULElement() ||
- (OwnerIsMozBrowserFrame() &&
- ourContent->HasAttr(nsGkAtoms::allowfullscreen));
- bool otherFullscreenAllowed =
- otherContent->IsXULElement() ||
- (aOther->OwnerIsMozBrowserFrame() &&
- otherContent->HasAttr(nsGkAtoms::allowfullscreen));
+ bool ourFullscreenAllowed = ourContent->IsXULElement();
+ bool otherFullscreenAllowed = otherContent->IsXULElement();
if (ourFullscreenAllowed != otherFullscreenAllowed) {
return NS_ERROR_NOT_IMPLEMENTED;
}
@@ -1732,14 +1683,6 @@ nsresult nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
return rv;
}
- // Destroy browser frame scripts for content leaving a frame with browser API
- if (OwnerIsMozBrowserFrame() && !aOther->OwnerIsMozBrowserFrame()) {
- DestroyBrowserFrameScripts();
- }
- if (!OwnerIsMozBrowserFrame() && aOther->OwnerIsMozBrowserFrame()) {
- aOther->DestroyBrowserFrameScripts();
- }
-
// Now move the docshells to the right docshell trees. Note that this
// resets their treeowners to null.
ourParentItem->RemoveChild(ourDocshell);
@@ -1837,10 +1780,6 @@ nsresult nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
ourFrame->PresShell()->BackingScaleFactorChanged();
otherFrame->PresShell()->BackingScaleFactorChanged();
- // Initialize browser API if needed now that owner content has changed
- InitializeBrowserAPI();
- aOther->InitializeBrowserAPI();
-
return NS_OK;
}
@@ -2174,11 +2113,6 @@ void nsFrameLoader::SetOwnerContent(Element* aContent) {
}
}
-bool nsFrameLoader::OwnerIsMozBrowserFrame() {
- nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
- return browserFrame ? browserFrame->GetReallyIsBrowser() : false;
-}
-
nsIContent* nsFrameLoader::GetParentObject() const { return mOwnerContent; }
void nsFrameLoader::AssertSafeToInit() {
@@ -2338,16 +2272,7 @@ nsresult nsFrameLoader::MaybeCreateDocShell() {
MOZ_ALWAYS_SUCCEEDS(mPendingBrowsingContext->SetInitialSandboxFlags(
mPendingBrowsingContext->GetSandboxFlags()));
- if (OwnerIsMozBrowserFrame()) {
- // For inproc frames, set the docshell properties.
- nsAutoString name;
- if (mOwnerContent->GetAttr(nsGkAtoms::name, name)) {
- docShell->SetName(name);
- }
- }
-
ReallyLoadFrameScripts();
- InitializeBrowserAPI();
// Previously we would forcibly create the initial about:blank document for
// in-process content frames from a frame script which eagerly loaded in
@@ -2588,11 +2513,8 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
// Graphics initialization code relies on having a frame for the
// remote browser case, as we can be inside a popup, which is a different
// widget.
- //
- // FIXME: Ideally this should be unconditional, but we skip if for <iframe
- // mozbrowser> because the old RDM ui depends on current behavior, and the
- // mozbrowser frame code is scheduled for deletion, see bug 1574886.
- if (!OwnerIsMozBrowserFrame() && !mOwnerContent->GetPrimaryFrame()) {
+
+ if (!mOwnerContent->GetPrimaryFrame()) {
doc->FlushPendingNotifications(FlushType::Frames);
}
@@ -2647,12 +2569,11 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
mPendingBrowsingContext->InitSessionHistory();
}
- // <iframe mozbrowser> gets to skip these checks.
// iframes for JS plugins also get to skip these checks. We control the URL
// that gets loaded, but the load is triggered from the document containing
// the plugin.
// out of process iframes also get to skip this check.
- if (!OwnerIsMozBrowserFrame() && !XRE_IsContentProcess()) {
+ if (!XRE_IsContentProcess()) {
if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
// Allow three exceptions to this rule :
// - about:addons so it can load remote extension options pages
@@ -2817,7 +2738,6 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
}
ReallyLoadFrameScripts();
- InitializeBrowserAPI();
return true;
}
@@ -3053,7 +2973,7 @@ nsresult nsFrameLoader::EnsureMessageManager() {
return NS_OK;
}
- if (!mIsTopLevelContent && !OwnerIsMozBrowserFrame() && !IsRemoteFrame() &&
+ if (!mIsTopLevelContent && !IsRemoteFrame() &&
!(mOwnerContent->IsXULElement() &&
mOwnerContent->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::forcemessagemanager,
@@ -3096,7 +3016,7 @@ nsresult nsFrameLoader::EnsureMessageManager() {
NS_ENSURE_TRUE(mChildMessageManager, NS_ERROR_UNEXPECTED);
// Set up session store
- if (StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
+ if (SessionStorePlatformCollection()) {
if (XRE_IsParentProcess() && mIsTopLevelContent) {
mSessionStoreChild = SessionStoreChild::GetOrCreate(
GetExtantBrowsingContext(), mOwnerContent);
@@ -3538,36 +3458,6 @@ BrowsingContext* nsFrameLoader::GetExtantBrowsingContext() {
return mPendingBrowsingContext;
}
-void nsFrameLoader::InitializeBrowserAPI() {
- if (!OwnerIsMozBrowserFrame()) {
- return;
- }
-
- nsresult rv = EnsureMessageManager();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return;
- }
- mMessageManager->LoadFrameScript(
- u"chrome://global/content/BrowserElementChild.js"_ns,
- /* allowDelayedLoad = */ true,
- /* aRunInGlobalScope */ true, IgnoreErrors());
-
- nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
- if (browserFrame) {
- browserFrame->InitializeBrowserAPI();
- }
-}
-
-void nsFrameLoader::DestroyBrowserFrameScripts() {
- if (!OwnerIsMozBrowserFrame()) {
- return;
- }
- nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
- if (browserFrame) {
- browserFrame->DestroyBrowserFrameScripts();
- }
-}
-
void nsFrameLoader::StartPersistence(
BrowsingContext* aContext, nsIWebBrowserPersistDocumentReceiver* aRecv,
ErrorResult& aRv) {
@@ -3673,9 +3563,9 @@ nsresult nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
nsresult nsFrameLoader::PopulateOriginContextIdsFromAttributes(
OriginAttributes& aAttr) {
- // Only XUL or mozbrowser frames are allowed to set context IDs
+ // Only XUL are allowed to set context IDs
uint32_t namespaceID = mOwnerContent->GetNameSpaceID();
- if (namespaceID != kNameSpaceID_XUL && !OwnerIsMozBrowserFrame()) {
+ if (namespaceID != kNameSpaceID_XUL) {
return NS_OK;
}
@@ -3693,7 +3583,7 @@ nsresult nsFrameLoader::PopulateOriginContextIdsFromAttributes(
mOwnerContent->GetAttr(nsGkAtoms::geckoViewSessionContextId,
attributeValue) &&
!attributeValue.IsEmpty()) {
- // XXX: Should we check the format from `GeckoViewNavigation.jsm` here?
+ // XXX: Should we check the format from `GeckoViewNavigation.sys.mjs` here?
aAttr.mGeckoViewSessionContextId = attributeValue;
}
@@ -3899,8 +3789,7 @@ bool nsFrameLoader::EnsureBrowsingContextAttached() {
// Inherit the `mFirstPartyDomain` flag from our parent document's result
// principal, if it was set.
if (parentContext->IsContent() &&
- !parentDoc->NodePrincipal()->IsSystemPrincipal() &&
- !OwnerIsMozBrowserFrame()) {
+ !parentDoc->NodePrincipal()->IsSystemPrincipal()) {
OriginAttributes docAttrs =
parentDoc->NodePrincipal()->OriginAttributesRef();
// We only want to inherit firstPartyDomain here, other attributes should
@@ -3918,15 +3807,6 @@ bool nsFrameLoader::EnsureBrowsingContextAttached() {
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
-
- // <iframe mozbrowser> is allowed to set `mozprivatebrowsing` to
- // force-enable private browsing.
- if (OwnerIsMozBrowserFrame()) {
- if (mOwnerContent->HasAttr(nsGkAtoms::mozprivatebrowsing)) {
- attrs.SyncAttributesWithPrivateBrowsing(true);
- usePrivateBrowsing = true;
- }
- }
}
// If we've already been attached, return.
diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h
index 159e3865a6..33c8000868 100644
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -264,12 +264,6 @@ class nsFrameLoader final : public nsStubMutationObserver,
bool IsNetworkCreated() const { return mNetworkCreated; }
- /**
- * Is this a frame loader for a bona fide <iframe mozbrowser>?
- * <xul:browser> is not a mozbrowser, so this is false for that case.
- */
- bool OwnerIsMozBrowserFrame();
-
nsIContent* GetParentObject() const;
/**
@@ -481,9 +475,6 @@ class nsFrameLoader final : public nsStubMutationObserver,
void AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
nsIDocShellTreeOwner* aOwner);
- void InitializeBrowserAPI();
- void DestroyBrowserFrameScripts();
-
nsresult GetNewTabContext(mozilla::dom::MutableTabContext* aTabContext,
nsIURI* aURI = nullptr);
diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp
index 8b69389790..5337e1588f 100644
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -167,6 +167,7 @@
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/dom/ToJSValue.h"
+#include "mozilla/dom/TrustedTypePolicyFactory.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/dom/VRDisplayEvent.h"
#include "mozilla/dom/VRDisplayEventBinding.h"
@@ -224,6 +225,7 @@
#include "nsIBrowserChild.h"
#include "nsICancelableRunnable.h"
#include "nsIChannel.h"
+#include "nsIClipboard.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIControllers.h"
#include "nsICookieJarSettings.h"
@@ -1283,6 +1285,8 @@ void nsGlobalWindowInner::FreeInnerObjects() {
mWebTaskScheduler = nullptr;
}
+ mTrustedTypePolicyFactory = nullptr;
+
mSharedWorkers.Clear();
#ifdef MOZ_WEBSPEECH
@@ -1378,6 +1382,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrustedTypePolicyFactory)
+
#ifdef MOZ_WEBSPEECH
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
#endif
@@ -1446,6 +1452,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInstallTrigger)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVisualViewport)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPasteDataTransfer)
tmp->TraverseObjectsInGlobal(cb);
@@ -1481,6 +1488,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
}
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrustedTypePolicyFactory)
+
#ifdef MOZ_WEBSPEECH
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
#endif
@@ -1554,6 +1563,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstallTrigger)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVisualViewport)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mCurrentPasteDataTransfer)
tmp->UnlinkObjectsInGlobal();
@@ -5082,7 +5092,7 @@ nsGlobalWindowInner::ShowSlowScriptDialog(JSContext* aCx,
}
// Reached only on non-e10s - once per slow script dialog.
- // On e10s - we probe once at ProcessHangsMonitor.jsm
+ // On e10s - we probe once at ProcessHangsMonitor.sys.mjs
Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT, 1);
// Get the nsIPrompt interface from the docshell
@@ -7603,6 +7613,27 @@ JS::loader::ModuleLoaderBase* nsGlobalWindowInner::GetModuleLoader(
return loader->GetModuleLoader();
}
+void nsGlobalWindowInner::SetCurrentPasteDataTransfer(
+ DataTransfer* aDataTransfer) {
+ MOZ_ASSERT_IF(aDataTransfer, aDataTransfer->GetEventMessage() == ePaste);
+ MOZ_ASSERT_IF(aDataTransfer, aDataTransfer->ClipboardType() ==
+ nsIClipboard::kGlobalClipboard);
+ MOZ_ASSERT_IF(aDataTransfer, aDataTransfer->GetAsyncGetClipboardData());
+ mCurrentPasteDataTransfer = aDataTransfer;
+}
+
+DataTransfer* nsGlobalWindowInner::GetCurrentPasteDataTransfer() const {
+ return mCurrentPasteDataTransfer;
+}
+
+TrustedTypePolicyFactory* nsGlobalWindowInner::TrustedTypes() {
+ if (!mTrustedTypePolicyFactory) {
+ mTrustedTypePolicyFactory = MakeRefPtr<TrustedTypePolicyFactory>(this);
+ }
+
+ return mTrustedTypePolicyFactory;
+}
+
nsIURI* nsPIDOMWindowInner::GetDocumentURI() const {
return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
}
diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h
index 100dbb9699..15fbc4259f 100644
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -104,6 +104,7 @@ class ClientSource;
class Console;
class Crypto;
class CustomElementRegistry;
+class DataTransfer;
class DocGroup;
class External;
class Function;
@@ -127,6 +128,7 @@ class WebTaskScheduler;
class WebTaskSchedulerMainThread;
class SpeechSynthesis;
class Timeout;
+class TrustedTypePolicyFactory;
class VisualViewport;
class VRDisplay;
enum class VRDisplayEventReason : uint8_t;
@@ -1254,11 +1256,18 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
virtual JS::loader::ModuleLoaderBase* GetModuleLoader(
JSContext* aCx) override;
+ mozilla::dom::TrustedTypePolicyFactory* TrustedTypes();
+
+ void SetCurrentPasteDataTransfer(mozilla::dom::DataTransfer* aDataTransfer);
+ mozilla::dom::DataTransfer* GetCurrentPasteDataTransfer() const;
+
private:
RefPtr<mozilla::dom::ContentMediaController> mContentMediaController;
RefPtr<mozilla::dom::WebTaskSchedulerMainThread> mWebTaskScheduler;
+ RefPtr<mozilla::dom::TrustedTypePolicyFactory> mTrustedTypePolicyFactory;
+
protected:
// Whether we need to care about orientation changes.
bool mHasOrientationChangeListeners : 1;
@@ -1460,6 +1469,10 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
mGroupMessageManagers{1};
} mChromeFields;
+ // Cache the DataTransfer created for a paste event, this will be reset after
+ // the event is dispatched.
+ RefPtr<mozilla::dom::DataTransfer> mCurrentPasteDataTransfer;
+
// These fields are used by the inner and outer windows to prevent
// programatically moving the window while the mouse is down.
static bool sMouseDown;
diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp
index 87874d49be..e28dcdb092 100644
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -99,7 +99,6 @@
// Other Classes
#include "mozilla/dom/BarProps.h"
-#include "nsContentCID.h"
#include "nsLayoutStatics.h"
#include "nsCCUncollectableMarker.h"
#include "mozilla/dom/WorkerCommon.h"
diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h
index de00012a01..700855370f 100644
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -21,6 +21,7 @@ class HTMLEditor;
struct URLExtraData;
namespace dom {
struct BindContext;
+struct UnbindContext;
class ShadowRoot;
class HTMLSlotElement;
} // namespace dom
@@ -58,6 +59,7 @@ class nsIContent : public nsINode {
using IMEEnabled = mozilla::widget::IMEEnabled;
using IMEState = mozilla::widget::IMEState;
using BindContext = mozilla::dom::BindContext;
+ using UnbindContext = mozilla::dom::UnbindContext;
void ConstructUbiNode(void* storage) override;
@@ -111,15 +113,10 @@ class nsIContent : public nsINode {
* from a parent, this will be called after it has been removed from the
* parent's child list and after the nsIDocumentObserver notifications for
* the removal have been dispatched.
- * @param aDeep Whether to recursively unbind the entire subtree rooted at
- * this node. The only time false should be passed is when the
- * parent node of the content is being destroyed.
- * @param aNullParent Whether to null out the parent pointer as well. This
- * is usually desirable. This argument should only be false while
- * recursively calling UnbindFromTree when a subtree is detached.
* @note This method is safe to call on nodes that are not bound to a tree.
*/
- virtual void UnbindFromTree(bool aNullParent = true) = 0;
+ virtual void UnbindFromTree(UnbindContext&) = 0;
+ void UnbindFromTree();
enum {
/**
diff --git a/dom/base/nsIDOMRequestService.idl b/dom/base/nsIDOMRequestService.idl
deleted file mode 100644
index 4f6fcd5784..0000000000
--- a/dom/base/nsIDOMRequestService.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-interface mozIDOMWindow;
-webidl DOMRequest;
-
-[scriptable, builtinclass, uuid(9a57e5de-ce93-45fa-8145-755722834f7c)]
-interface nsIDOMRequestService : nsISupports
-{
- DOMRequest createRequest(in mozIDOMWindow window);
-
- void fireSuccess(in DOMRequest request, in jsval result);
- void fireError(in DOMRequest request, in AString error);
- void fireSuccessAsync(in DOMRequest request, in jsval result);
- void fireErrorAsync(in DOMRequest request, in AString error);
-};
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index 3a9fe23899..d5455e5596 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -16,6 +16,7 @@
#include "js/JSON.h" // JS_ParseJSON
#include "mozAutoDocUpdate.h"
#include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/CORSMode.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
@@ -304,7 +305,7 @@ class IsItemInRangeComparator {
// @param aStartOffset has to be less or equal to aEndOffset.
IsItemInRangeComparator(const nsINode& aNode, const uint32_t aStartOffset,
const uint32_t aEndOffset,
- nsContentUtils::ComparePointsCache* aCache)
+ nsContentUtils::NodeIndexCache* aCache)
: mNode(aNode),
mStartOffset(aStartOffset),
mEndOffset(aEndOffset),
@@ -332,7 +333,7 @@ class IsItemInRangeComparator {
const nsINode& mNode;
const uint32_t mStartOffset;
const uint32_t mEndOffset;
- nsContentUtils::ComparePointsCache* mCache;
+ nsContentUtils::NodeIndexCache* mCache;
};
bool nsINode::IsSelected(const uint32_t aStartOffset,
@@ -367,7 +368,7 @@ bool nsINode::IsSelected(const uint32_t aStartOffset,
}
}
- nsContentUtils::ComparePointsCache cache;
+ nsContentUtils::NodeIndexCache cache;
IsItemInRangeComparator comparator{*this, aStartOffset, aEndOffset, &cache};
for (Selection* selection : ancestorSelections) {
// Binary search the sorted ranges in this selection.
@@ -1810,6 +1811,10 @@ Maybe<uint32_t> nsINode::ComputeIndexOf(const nsINode* aPossibleChild) const {
return Nothing();
}
+ if (aPossibleChild == GetFirstChild()) {
+ return Some(0);
+ }
+
if (aPossibleChild == GetLastChild()) {
MOZ_ASSERT(GetChildCount());
return Some(GetChildCount() - 1);
@@ -3672,15 +3677,13 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
}
newShadowRoot->SetIsDeclarative(originalShadowRoot->IsDeclarative());
- if (aDeep) {
- for (nsIContent* origChild = originalShadowRoot->GetFirstChild();
- origChild; origChild = origChild->GetNextSibling()) {
- nsCOMPtr<nsINode> child =
- CloneAndAdopt(origChild, aClone, aDeep, nodeInfoManager,
- aReparentScope, newShadowRoot, aError);
- if (NS_WARN_IF(aError.Failed())) {
- return nullptr;
- }
+ for (nsIContent* origChild = originalShadowRoot->GetFirstChild();
+ origChild; origChild = origChild->GetNextSibling()) {
+ nsCOMPtr<nsINode> child =
+ CloneAndAdopt(origChild, aClone, true, nodeInfoManager,
+ aReparentScope, newShadowRoot, aError);
+ if (NS_WARN_IF(aError.Failed())) {
+ return nullptr;
}
}
}
diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h
index ce9fbd55be..3a47992cc8 100644
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -1895,13 +1895,9 @@ class nsINode : public mozilla::dom::EventTarget {
// flags, because we can't use those to distinguish
// <bdi dir="some-invalid-value"> and <bdi dir="auto">.
NodeHasValidDirAttribute,
- // Set if the node has dir=auto and has a property pointing to the text
- // node that determines its direction
- NodeHasDirAutoSet,
- // Set if the node is a text node descendant of a node with dir=auto
- // and has a TextNodeDirectionalityMap property listing the elements whose
- // direction it determines.
- NodeHasTextNodeDirectionalityMap,
+ // Set if this node, which must be a text node, might be responsible for
+ // setting the directionality of a dir="auto" ancestor.
+ NodeMaySetDirAuto,
// Set if a node in the node's parent chain has dir=auto.
NodeAncestorHasDirAuto,
// Set if the node is handling a click.
@@ -2028,31 +2024,19 @@ class nsINode : public mozilla::dom::EventTarget {
void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
- void SetHasDirAutoSet() {
- MOZ_ASSERT(NodeType() != TEXT_NODE, "SetHasDirAutoSet on text node");
- SetBoolFlag(NodeHasDirAutoSet);
+ void SetMaySetDirAuto() {
+ // FIXME(bug 1881225): dir=auto should probably work on CDATA too.
+ MOZ_ASSERT(NodeType() == TEXT_NODE);
+ SetBoolFlag(NodeMaySetDirAuto);
}
- void ClearHasDirAutoSet() {
- MOZ_ASSERT(NodeType() != TEXT_NODE, "ClearHasDirAutoSet on text node");
- ClearBoolFlag(NodeHasDirAutoSet);
+ bool MaySetDirAuto() const {
+ MOZ_ASSERT(NodeType() == TEXT_NODE);
+ return GetBoolFlag(NodeMaySetDirAuto);
}
- bool HasDirAutoSet() const { return GetBoolFlag(NodeHasDirAutoSet); }
- void SetHasTextNodeDirectionalityMap() {
- MOZ_ASSERT(NodeType() == TEXT_NODE,
- "SetHasTextNodeDirectionalityMap on non-text node");
- SetBoolFlag(NodeHasTextNodeDirectionalityMap);
+ void ClearMaySetDirAuto() {
+ MOZ_ASSERT(NodeType() == TEXT_NODE);
+ ClearBoolFlag(NodeMaySetDirAuto);
}
- void ClearHasTextNodeDirectionalityMap() {
- MOZ_ASSERT(NodeType() == TEXT_NODE,
- "ClearHasTextNodeDirectionalityMap on non-text node");
- ClearBoolFlag(NodeHasTextNodeDirectionalityMap);
- }
- bool HasTextNodeDirectionalityMap() const {
- MOZ_ASSERT(NodeType() == TEXT_NODE,
- "HasTextNodeDirectionalityMap on non-text node");
- return GetBoolFlag(NodeHasTextNodeDirectionalityMap);
- }
-
void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); }
void ClearAncestorHasDirAuto() { ClearBoolFlag(NodeAncestorHasDirAuto); }
bool AncestorHasDirAuto() const {
diff --git a/dom/base/nsIScriptableContentIterator.idl b/dom/base/nsIScriptableContentIterator.idl
index caf689f550..370cd8c8a7 100644
--- a/dom/base/nsIScriptableContentIterator.idl
+++ b/dom/base/nsIScriptableContentIterator.idl
@@ -64,11 +64,3 @@ interface nsIScriptableContentIterator : nsISupports
// See ContentIteratorBase::PositionAt(nsINode*)
void positionAt(in Node aNode);
};
-
-%{C++
-#define SCRIPTABLE_CONTENT_ITERATOR_CID \
- { 0xf68037ec, 0x2790, 0x44c5, \
- { 0x8e, 0x5f, 0xdf, 0x5d, 0xa5, 0x8b, 0x93, 0xa7 } }
-#define SCRIPTABLE_CONTENT_ITERATOR_CONTRACTID \
- "@mozilla.org/scriptable-content-iterator;1"
-%}
diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp
index c1320a3472..fa1798ce35 100644
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -47,6 +47,7 @@
#include "mozilla/dom/BindContext.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/FetchPriority.h"
#include "mozilla/dom/PContent.h" // For TextRecognitionResult
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/ImageTextBinding.h"
@@ -1143,7 +1144,8 @@ nsresult nsImageLoadingContent::LoadImage(nsIURI* aNewURI, bool aForce,
nsresult rv = nsContentUtils::LoadImage(
aNewURI, element, aDocument, triggeringPrincipal, 0, referrerInfo, this,
loadFlags, element->LocalName(), getter_AddRefs(req), policyType,
- mUseUrgentStartForChannel);
+ mUseUrgentStartForChannel, /* aLinkPreload */ false,
+ /* aEarlyHintPreloaderId */ 0, GetFetchPriorityForImage());
// Reset the flag to avoid loading from XPCOM or somewhere again else without
// initiated by user interaction.
@@ -1639,10 +1641,12 @@ void nsImageLoadingContent::BindToTree(BindContext& aContext,
}
}
-void nsImageLoadingContent::UnbindFromTree(bool aNullParent) {
+void nsImageLoadingContent::UnbindFromTree() {
// We may be leaving the document, so if our image is tracked, untrack it.
nsCOMPtr<Document> doc = GetOurCurrentDoc();
- if (!doc) return;
+ if (!doc) {
+ return;
+ }
UntrackImage(mCurrentRequest);
UntrackImage(mPendingRequest);
@@ -1860,3 +1864,7 @@ nsLoadFlags nsImageLoadingContent::LoadFlags() {
}
return nsIRequest::LOAD_NORMAL;
}
+
+FetchPriority nsImageLoadingContent::GetFetchPriorityForImage() const {
+ return FetchPriority::Auto;
+}
diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h
index 6929f20a23..2b6dac53fb 100644
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -40,6 +40,7 @@ namespace dom {
struct BindContext;
class Document;
class Element;
+enum class FetchPriority : uint8_t;
} // namespace dom
} // namespace mozilla
@@ -221,7 +222,7 @@ class nsImageLoadingContent : public nsIImageLoadingContent {
// Subclasses are *required* to call BindToTree/UnbindFromTree.
void BindToTree(mozilla::dom::BindContext&, nsINode& aParent);
- void UnbindFromTree(bool aNullParent);
+ void UnbindFromTree();
void OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
void OnUnlockedDraw();
@@ -236,6 +237,8 @@ class nsImageLoadingContent : public nsIImageLoadingContent {
// want a non-const nsIContent.
virtual nsIContent* AsContent() = 0;
+ virtual mozilla::dom::FetchPriority GetFetchPriorityForImage() const;
+
/**
* Get width and height of the current request, using given image request if
* attributes are unset.
diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp
index 1d2eb16885..1397bd25b5 100644
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2227,6 +2227,21 @@ void nsJSContext::EnsureStatics() {
"javascript.options.mem.gc_max_helper_threads",
(void*)JSGC_MAX_HELPER_THREADS);
+ Preferences::RegisterCallbackAndCall(
+ SetMemoryPrefChangedCallbackInt,
+ "javascript.options.mem.nursery_eager_collection_threshold_kb",
+ (void*)JSGC_NURSERY_EAGER_COLLECTION_THRESHOLD_KB);
+
+ Preferences::RegisterCallbackAndCall(
+ SetMemoryPrefChangedCallbackInt,
+ "javascript.options.mem.nursery_eager_collection_threshold_percent",
+ (void*)JSGC_NURSERY_EAGER_COLLECTION_THRESHOLD_PERCENT);
+
+ Preferences::RegisterCallbackAndCall(
+ SetMemoryPrefChangedCallbackInt,
+ "javascript.options.mem.nursery_eager_collection_timeout_ms",
+ (void*)JSGC_NURSERY_EAGER_COLLECTION_TIMEOUT_MS);
+
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (!obs) {
MOZ_CRASH();
diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp
index 0a2ea3e62d..ab87c58e87 100644
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -223,7 +223,7 @@ already_AddRefed<nsIDocShell> nsObjectLoadingContent::SetupDocShell(
return docShell.forget();
}
-void nsObjectLoadingContent::UnbindFromTree(bool aNullParent) {
+void nsObjectLoadingContent::UnbindFromTree() {
// Reset state and clear pending events
/// XXX(johns): The implementation for GenericFrame notes that ideally we
/// would keep the docshell around, but trash the frameloader
@@ -1249,7 +1249,11 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
break;
}
- rv = uriLoader->OpenChannel(mChannel, nsIURILoader::DONT_RETARGET, req,
+ uint32_t uriLoaderFlags = nsDocShell::ComputeURILoaderFlags(
+ docShell->GetBrowsingContext(), LOAD_NORMAL,
+ /* aIsDocumentLoad */ false);
+
+ rv = uriLoader->OpenChannel(mChannel, uriLoaderFlags, req,
getter_AddRefs(finalListener));
// finalListener will receive OnStartRequest either below, or if
// `mChannel` is a `DocumentChannel`, it will be received after
diff --git a/dom/base/nsObjectLoadingContent.h b/dom/base/nsObjectLoadingContent.h
index 563ad4df3f..c679a7cc5d 100644
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -183,7 +183,7 @@ class nsObjectLoadingContent : public nsIStreamListener,
void CreateStaticClone(nsObjectLoadingContent* aDest) const;
- void UnbindFromTree(bool aNullParent = true);
+ void UnbindFromTree();
/**
* Return the content policy type used for loading the element.
diff --git a/dom/base/nsTextNode.cpp b/dom/base/nsTextNode.cpp
index df08c547be..e34b581c40 100644
--- a/dom/base/nsTextNode.cpp
+++ b/dom/base/nsTextNode.cpp
@@ -43,13 +43,13 @@ class nsAttributeTextNode final : public nsTextNode,
NS_ASSERTION(mAttrName, "Must have attr name");
}
- virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
- virtual void UnbindFromTree(bool aNullParent = true) override;
+ nsresult BindToTree(BindContext&, nsINode& aParent) override;
+ void UnbindFromTree(UnbindContext&) override;
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
- virtual already_AddRefed<CharacterData> CloneDataNode(
+ already_AddRefed<CharacterData> CloneDataNode(
mozilla::dom::NodeInfo* aNodeInfo, bool aCloneText) const override {
RefPtr<nsAttributeTextNode> it =
new (aNodeInfo->NodeInfoManager()) nsAttributeTextNode(
@@ -123,10 +123,9 @@ nsresult nsTextNode::BindToTree(BindContext& aContext, nsINode& aParent) {
return NS_OK;
}
-void nsTextNode::UnbindFromTree(bool aNullParent) {
- ResetDirectionSetByTextNode(this);
-
- CharacterData::UnbindFromTree(aNullParent);
+void nsTextNode::UnbindFromTree(UnbindContext& aContext) {
+ CharacterData::UnbindFromTree(aContext);
+ ResetDirectionSetByTextNode(this, aContext);
}
#ifdef MOZ_DOM_LIST
@@ -209,16 +208,16 @@ nsresult nsAttributeTextNode::BindToTree(BindContext& aContext,
return NS_OK;
}
-void nsAttributeTextNode::UnbindFromTree(bool aNullParent) {
+void nsAttributeTextNode::UnbindFromTree(UnbindContext& aContext) {
// UnbindFromTree can be called anytime so we have to be safe.
if (mGrandparent) {
- // aNullParent might not be true here, but we want to remove the
+ // aContext might not be true here, but we want to remove the
// mutation observer anyway since we only need it while we're
// in the document.
mGrandparent->RemoveMutationObserver(this);
mGrandparent = nullptr;
}
- nsTextNode::UnbindFromTree(aNullParent);
+ nsTextNode::UnbindFromTree(aContext);
}
void nsAttributeTextNode::AttributeChanged(Element* aElement,
diff --git a/dom/base/nsTextNode.h b/dom/base/nsTextNode.h
index 23d7aff8a8..b39497a3b1 100644
--- a/dom/base/nsTextNode.h
+++ b/dom/base/nsTextNode.h
@@ -45,7 +45,7 @@ class nsTextNode : public mozilla::dom::Text {
mozilla::dom::NodeInfo* aNodeInfo, bool aCloneText) const override;
nsresult BindToTree(BindContext&, nsINode& aParent) override;
- void UnbindFromTree(bool aNullParent = true) override;
+ void UnbindFromTree(UnbindContext&) override;
nsresult AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength,
bool aNotify, nsIContent* aNextSibling);
diff --git a/dom/base/nsWindowRoot.cpp b/dom/base/nsWindowRoot.cpp
index 1ee2368f1e..1874898b68 100644
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -13,8 +13,6 @@
#include "nsWindowRoot.h"
#include "nsPIDOMWindow.h"
#include "nsPresContext.h"
-#include "nsLayoutCID.h"
-#include "nsContentCID.h"
#include "nsString.h"
#include "nsFrameLoaderOwner.h"
#include "nsFrameLoader.h"
diff --git a/dom/base/test/browser.toml b/dom/base/test/browser.toml
index 1deeb88d89..a68bd2e873 100644
--- a/dom/base/test/browser.toml
+++ b/dom/base/test/browser.toml
@@ -109,6 +109,16 @@ skip-if = [
]
support-files = ["browser_multiple_popups.html"]
+["browser_object_attachment.js"]
+support-files = [
+ "file_img_object_attachment.html",
+ "file_img_attachment.jpg",
+ "file_img_attachment.jpg^headers^",
+ "file_pdf_object_attachment.html",
+ "file_pdf_attachment.pdf",
+ "file_pdf_attachment.pdf^headers^",
+]
+
["browser_outline_refocus.js"]
["browser_page_load_event_telemetry.js"]
diff --git a/dom/base/test/browser_object_attachment.js b/dom/base/test/browser_object_attachment.js
new file mode 100644
index 0000000000..b4432862f0
--- /dev/null
+++ b/dom/base/test/browser_object_attachment.js
@@ -0,0 +1,168 @@
+ChromeUtils.defineESModuleGetters(this, {
+ Downloads: "resource://gre/modules/Downloads.sys.mjs",
+});
+
+const httpsTestRoot = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+
+add_task(async function test_pdf_object_attachment() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.navigation.object_embed.allow_retargeting", false]],
+ });
+
+ await BrowserTestUtils.withNewTab(
+ `${httpsTestRoot}/file_pdf_object_attachment.html`,
+ async browser => {
+ is(
+ browser.browsingContext.children.length,
+ 1,
+ "Should have a child frame"
+ );
+ await SpecialPowers.spawn(browser, [], async () => {
+ let obj = content.document.querySelector("object");
+ is(
+ obj.displayedType,
+ Ci.nsIObjectLoadingContent.TYPE_DOCUMENT,
+ "should be displaying TYPE_DOCUMENT"
+ );
+ });
+ }
+ );
+});
+
+add_task(async function test_img_object_attachment() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.navigation.object_embed.allow_retargeting", false]],
+ });
+
+ await BrowserTestUtils.withNewTab(
+ `${httpsTestRoot}/file_img_object_attachment.html`,
+ async browser => {
+ is(
+ browser.browsingContext.children.length,
+ 1,
+ "Should have a child frame"
+ );
+ await SpecialPowers.spawn(browser, [], async () => {
+ let obj = content.document.querySelector("object");
+ is(
+ obj.displayedType,
+ Ci.nsIObjectLoadingContent.TYPE_DOCUMENT,
+ "should be displaying TYPE_DOCUMENT"
+ );
+ });
+ }
+ );
+});
+
+async function waitForDownload() {
+ // Get the downloads list and add a view to listen for a download to be added.
+ let downloadList = await Downloads.getList(Downloads.ALL);
+
+ // Wait for a single download
+ let downloadView;
+ let finishedAllDownloads = new Promise(resolve => {
+ downloadView = {
+ onDownloadAdded(aDownload) {
+ info("download added");
+ resolve(aDownload);
+ },
+ };
+ });
+ await downloadList.addView(downloadView);
+ let download = await finishedAllDownloads;
+ await downloadList.removeView(downloadView);
+
+ // Clean up the download from the list.
+ await downloadList.remove(download);
+ await download.finalize(true);
+
+ // Return the download
+ return download;
+}
+
+add_task(async function test_pdf_object_attachment_download() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.navigation.object_embed.allow_retargeting", true]],
+ });
+
+ // Set the behaviour to save pdfs to disk and not handle internally, so we
+ // don't end up with extra tabs after the test.
+ var gMimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+ var gHandlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
+ Ci.nsIHandlerService
+ );
+ const mimeInfo = gMimeSvc.getFromTypeAndExtension("application/pdf", "pdf");
+ let previousAction = mimeInfo.preferredAction;
+ mimeInfo.preferredAction = Ci.nsIHandlerInfo.saveToDisk;
+ gHandlerSvc.store(mimeInfo);
+ registerCleanupFunction(() => {
+ mimeInfo.preferredAction = previousAction;
+ gHandlerSvc.store(mimeInfo);
+ });
+
+ // Start listening for the download before opening the new tab.
+ let downloadPromise = waitForDownload();
+ await BrowserTestUtils.withNewTab(
+ `${httpsTestRoot}/file_pdf_object_attachment.html`,
+ async browser => {
+ let download = await downloadPromise;
+ is(
+ download.source.url,
+ `${httpsTestRoot}/file_pdf_attachment.pdf`,
+ "download should be the pdf"
+ );
+
+ await SpecialPowers.spawn(browser, [], async () => {
+ let obj = content.document.querySelector("object");
+ is(
+ obj.displayedType,
+ Ci.nsIObjectLoadingContent.TYPE_FALLBACK,
+ "should be displaying TYPE_FALLBACK"
+ );
+ });
+ }
+ );
+});
+
+add_task(async function test_img_object_attachment_download() {
+ // NOTE: This is testing our current behaviour here as of bug 1868001 (which
+ // is to download an image with `Content-Disposition: attachment` embedded
+ // within an object or embed element).
+ //
+ // Other browsers ignore the `Content-Disposition: attachment` header when
+ // loading images within object or embed element as-of december 2023, as
+ // we did prior to the changes in bug 1595491.
+ //
+ // If this turns out to be a web-compat issue, we may want to introduce
+ // special handling to ignore content-disposition when loading images within
+ // an object or embed element.
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.navigation.object_embed.allow_retargeting", true]],
+ });
+
+ // Start listening for the download before opening the new tab.
+ let downloadPromise = waitForDownload();
+ await BrowserTestUtils.withNewTab(
+ `${httpsTestRoot}/file_img_object_attachment.html`,
+ async browser => {
+ let download = await downloadPromise;
+ is(
+ download.source.url,
+ `${httpsTestRoot}/file_img_attachment.jpg`,
+ "download should be the jpg"
+ );
+
+ await SpecialPowers.spawn(browser, [], async () => {
+ let obj = content.document.querySelector("object");
+ is(
+ obj.displayedType,
+ Ci.nsIObjectLoadingContent.TYPE_FALLBACK,
+ "should be displaying TYPE_FALLBACK"
+ );
+ });
+ }
+ );
+});
diff --git a/dom/base/test/chrome.toml b/dom/base/test/chrome.toml
index 687d778cac..ec736a086c 100644
--- a/dom/base/test/chrome.toml
+++ b/dom/base/test/chrome.toml
@@ -1,6 +1,5 @@
[DEFAULT]
skip-if = ["os == 'android'"]
-prefs = ["dom.domrequest.enabled=true"]
support-files = [
"file_empty.html",
"file_blocking_image.html",
@@ -38,8 +37,6 @@ support-files = [
["test_bug1120222.html"]
-["test_domrequesthelper.xhtml"]
-
["test_fragment_sanitization.xhtml"]
["test_getLastOverWindowPointerLocationInCSSPixels.html"]
diff --git a/dom/base/test/chrome/bug418986-1.js b/dom/base/test/chrome/bug418986-1.js
index 7c39df0c13..e7e3c63b5c 100644
--- a/dom/base/test/chrome/bug418986-1.js
+++ b/dom/base/test/chrome/bug418986-1.js
@@ -1,4 +1,7 @@
/* globals chromeWindow */
+
+/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */
+
// The main test function.
var test = function (isContent) {
SimpleTest.waitForExplicitFinish();
diff --git a/dom/base/test/chrome/chrome.toml b/dom/base/test/chrome/chrome.toml
index b8439a2d2e..08265bcb97 100644
--- a/dom/base/test/chrome/chrome.toml
+++ b/dom/base/test/chrome/chrome.toml
@@ -18,7 +18,6 @@ support-files = [
"custom_element_ep.js",
"window_nsITextInputProcessor.xhtml",
"title_window.xhtml",
- "window_swapFrameLoaders.xhtml",
]
prefs = ["gfx.font_rendering.fallback.async=false"]
@@ -126,9 +125,6 @@ support-files = ["../dummy.html"]
["test_range_getClientRectsAndTexts.html"]
-["test_swapFrameLoaders.xhtml"]
-skip-if = ["os == 'mac'"] # bug 1674413
-
["test_title.xhtml"]
support-files = ["file_title.xhtml"]
diff --git a/dom/base/test/chrome/file_bug549682.xhtml b/dom/base/test/chrome/file_bug549682.xhtml
index 8ae05d38d8..0bb3080507 100644
--- a/dom/base/test/chrome/file_bug549682.xhtml
+++ b/dom/base/test/chrome/file_bug549682.xhtml
@@ -28,11 +28,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549682
}
var asyncPPML = false;
- function ppmASL(m) {
+ function ppmASL() {
asyncPPML = true;
}
var syncPPML = false;
- function ppmSL(m) {
+ function ppmSL() {
syncPPML = true;
}
ppm.addMessageListener("processmessageAsync", ppmASL);
@@ -42,7 +42,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549682
cpm.sendSyncMessage("processmessageSync", "");
var asyncCPML = false;
- function cpmASL(m) {
+ function cpmASL() {
asyncCPML = true;
}
cpm.addMessageListener("childprocessmessage", cpmASL);
@@ -93,7 +93,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549682
var weakListener = {
QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
- receiveMessage(msg) {
+ receiveMessage() {
if (weakMessageReceived) {
ok(false, 'Weak listener fired twice.');
return;
@@ -109,7 +109,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549682
var weakListener2 = {
QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
- receiveMessage(msg) {
+ receiveMessage() {
ok(false, 'Should not have received a message.');
}
};
diff --git a/dom/base/test/chrome/file_bug616841.xhtml b/dom/base/test/chrome/file_bug616841.xhtml
index b0512d162c..3651a00226 100644
--- a/dom/base/test/chrome/file_bug616841.xhtml
+++ b/dom/base/test/chrome/file_bug616841.xhtml
@@ -27,7 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=616841
[ "D", "\u010C" ] ];
var nCmps = 0;
- function recvContentReady(m) {
+ function recvContentReady() {
for (var i = 0; i < toCompare.length; ++i) {
var pair = toCompare[i];
messageManager.broadcastAsyncMessage("cmp",
diff --git a/dom/base/test/chrome/test_bug1339722.html b/dom/base/test/chrome/test_bug1339722.html
index d8d95f1faa..7655ff95fa 100644
--- a/dom/base/test/chrome/test_bug1339722.html
+++ b/dom/base/test/chrome/test_bug1339722.html
@@ -29,7 +29,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1339722
// behave similarly.
const TOPIC = "document-on-modify-request";
let win;
- const observe = (subject, topic, data) => {
+ const observe = (subject, topic) => {
info("Got " + topic);
Services.obs.removeObserver(observe, TOPIC);
@@ -58,7 +58,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1339722
// Remove the iframe to cause frameloader destroy.
iframe.remove();
- setTimeout($ => {
+ setTimeout(() => {
ok(!document.getElementById("testFrame"), "verify iframe removed");
SimpleTest.finish();
}, 0);
diff --git a/dom/base/test/chrome/test_bug339494.xhtml b/dom/base/test/chrome/test_bug339494.xhtml
index 203f6e644d..afab41b65c 100644
--- a/dom/base/test/chrome/test_bug339494.xhtml
+++ b/dom/base/test/chrome/test_bug339494.xhtml
@@ -55,7 +55,7 @@ SimpleTest.waitForExplicitFinish();
s.setAttribute("ggg", "testvalue");
await promiseFlushingMutationObserver();
- const observer = new MutationObserver((aMutationList, aObserver) => {
+ const observer = new MutationObserver(() => {
ok(s.hasAttribute("ggg"), "Value check 3. There should be a value");
isnot(s.getAttribute("ggg"), "testvalue", "Value check 4");
is(s.getAttribute("ggg"), "othervalue", "Value check 5");
diff --git a/dom/base/test/chrome/test_bug429785.xhtml b/dom/base/test/chrome/test_bug429785.xhtml
index fb51634fab..10c9977ccb 100644
--- a/dom/base/test/chrome/test_bug429785.xhtml
+++ b/dom/base/test/chrome/test_bug429785.xhtml
@@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429785
var errorLogged = false;
var listener = {
QueryInterface: ChromeUtils.generateQI(["nsIConsoleListener"]),
- observe(msg) { errorLogged = true; }
+ observe() { errorLogged = true; }
};
function step2() {
diff --git a/dom/base/test/chrome/test_bug430050.xhtml b/dom/base/test/chrome/test_bug430050.xhtml
index d7d6cf656c..dfe1e3c8ee 100644
--- a/dom/base/test/chrome/test_bug430050.xhtml
+++ b/dom/base/test/chrome/test_bug430050.xhtml
@@ -27,7 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=430050
}
function startTest() {
- const observer = new MutationObserver((aMutationList, aObserver) => {
+ const observer = new MutationObserver(() => {
document.getElementById('b').setAttribute("src",
"data:text/plain,failed");
const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
diff --git a/dom/base/test/chrome/test_chromeOuterWindowID.xhtml b/dom/base/test/chrome/test_chromeOuterWindowID.xhtml
index 1feb7c7c74..3aa482b636 100644
--- a/dom/base/test/chrome/test_chromeOuterWindowID.xhtml
+++ b/dom/base/test/chrome/test_chromeOuterWindowID.xhtml
@@ -42,7 +42,7 @@ windows.
"Both browsers should belong to the same document.");
let winID = getOuterWindowID(browser1.ownerGlobal);
- let getChildRootOuterId = browser => {
+ let getChildRootOuterId = () => {
try {
return docShell.browserChild?.chromeOuterWindowID;
} catch(ex) { }
diff --git a/dom/base/test/chrome/test_swapFrameLoaders.xhtml b/dom/base/test/chrome/test_swapFrameLoaders.xhtml
deleted file mode 100644
index 4ea11a1a62..0000000000
--- a/dom/base/test/chrome/test_swapFrameLoaders.xhtml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1242644
-Test swapFrameLoaders with different frame types and remoteness
--->
-<window title="Mozilla Bug 1242644"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-
- <!-- test results are displayed in the html:body -->
- <body xmlns="http://www.w3.org/1999/xhtml">
- <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1242644"
- target="_blank">Mozilla Bug 1242644</a>
- </body>
-
- <!-- test code goes here -->
- <script type="application/javascript"><![CDATA[
- SimpleTest.waitForExplicitFinish();
-
- window.openDialog("window_swapFrameLoaders.xhtml", "bug1242644",
- "chrome,width=600,height=600,noopener", window);
- ]]></script>
-</window>
diff --git a/dom/base/test/chrome/title_window.xhtml b/dom/base/test/chrome/title_window.xhtml
index f48cdaaaf1..5f9840c36c 100644
--- a/dom/base/test/chrome/title_window.xhtml
+++ b/dom/base/test/chrome/title_window.xhtml
@@ -63,10 +63,10 @@
}
}
- function listener2(ev) {
+ function listener2() {
inProgressDoc[description] = false;
}
- function listener3(ev) {
+ function listener3() {
inProgressWin[description] = false;
}
frame.addEventListener("DOMTitleChanged", listener);
diff --git a/dom/base/test/chrome/window_nsITextInputProcessor.xhtml b/dom/base/test/chrome/window_nsITextInputProcessor.xhtml
index c8ce6ee5e7..c62ba2ce47 100644
--- a/dom/base/test/chrome/window_nsITextInputProcessor.xhtml
+++ b/dom/base/test/chrome/window_nsITextInputProcessor.xhtml
@@ -4120,7 +4120,7 @@ function runUnloadTests1()
let oldSrc = iframe.src;
let parentWindow = window;
- iframe.addEventListener("load", function (aEvent) {
+ iframe.addEventListener("load", function () {
ok(true, description + "dummy page is loaded");
childWindow = iframe.contentWindow;
textareaInFrame = null;
@@ -4181,7 +4181,7 @@ function runUnloadTests2()
let oldSrc = iframe.src;
- iframe.addEventListener("load", function (aEvent) {
+ iframe.addEventListener("load", function () {
ok(true, description + "dummy page is loaded");
childWindow = iframe.contentWindow;
textareaInFrame = null;
diff --git a/dom/base/test/chrome/window_swapFrameLoaders.xhtml b/dom/base/test/chrome/window_swapFrameLoaders.xhtml
deleted file mode 100644
index 4a38bcc1fc..0000000000
--- a/dom/base/test/chrome/window_swapFrameLoaders.xhtml
+++ /dev/null
@@ -1,223 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1242644
-Test swapFrameLoaders with different frame types and remoteness
--->
-<window title="Mozilla Bug 1242644"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
- <script type="application/javascript"><![CDATA[
- ["SimpleTest", "SpecialPowers", "info", "is", "ok", "add_task"].forEach(key => {
- window[key] = window.arguments[0][key];
- })
-
- const NS = {
- xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
- html: "http://www.w3.org/1999/xhtml",
- }
-
- const TAG = {
- xul: "browser",
- html: "iframe", // mozbrowser
- }
-
- const SCENARIOS = [
- ["xul", "xul"],
- ["xul", "html"],
- ["html", "xul"],
- ["html", "html"],
- ["xul", "xul", { remote: true }],
- ["xul", "html", { remote: true }],
- ["html", "xul", { remote: true }],
- ["html", "html", { remote: true }],
- ["xul", "html", { userContextId: 2 }],
- ["xul", "html", { userContextId: 2, remote: true }],
- ];
-
- const HEIGHTS = [
- 200,
- 400
- ];
-
- function frameScript() {
- /* eslint-env mozilla/frame-script */
- addEventListener("load", function onLoad() {
- sendAsyncMessage("test:load");
- }, true);
- }
-
- // Watch for loads in new frames
- window.messageManager.loadFrameScript(`data:,(${frameScript})();`, true);
-
- function once(target, eventName, useCapture = false) {
- info("Waiting for event: '" + eventName + "' on " + target + ".");
-
- return new Promise(resolve => {
- for (let [add, remove] of [
- ["addEventListener", "removeEventListener"],
- ["addMessageListener", "removeMessageListener"],
- ]) {
- if ((add in target) && (remove in target)) {
- target[add](eventName, function onEvent(...aArgs) {
- info("Got event: '" + eventName + "' on " + target + ".");
- target[remove](eventName, onEvent, useCapture);
- resolve(aArgs);
- }, useCapture);
- break;
- }
- }
- });
- }
-
- async function addFrame(type, options, height) {
- let remote = options && options.remote;
- let userContextId = options && options.userContextId;
- let frame = document.createElementNS(NS[type], TAG[type]);
- frame.setAttribute("remote", remote);
- if (remote && type == "xul") {
- frame.setAttribute("style", "-moz-binding: none;");
- }
- if (userContextId) {
- frame.setAttribute("usercontextid", userContextId);
- }
- if (type == "html") {
- frame.setAttribute("mozbrowser", "true");
- frame.setAttribute("noisolation", "true");
- frame.setAttribute("allowfullscreen", "true");
- } else if (type == "xul") {
- frame.setAttribute("type", "content");
- }
- let src = `data:text/html,<!doctype html>` +
- `<body style="height:${height}px"/>`;
- frame.setAttribute("src", src);
- document.documentElement.appendChild(frame);
- let mm = frame.frameLoader.messageManager;
- await once(mm, "test:load");
- return frame;
- }
-
- add_task(async function() {
- for (let scenario of SCENARIOS) {
- let [ typeA, typeB, options ] = scenario;
- let heightA = HEIGHTS[0];
- info(`Adding frame A, type ${typeA}, options ${JSON.stringify(options)}, height ${heightA}`);
- let frameA = await addFrame(typeA, options, heightA);
-
- let heightB = HEIGHTS[1];
- info(`Adding frame B, type ${typeB}, options ${JSON.stringify(options)}, height ${heightB}`);
- let frameB = await addFrame(typeB, options, heightB);
-
- let frameScriptFactory = function(name) {
- /* eslint-env mozilla/frame-script */
- return `function() {
- addMessageListener("ping", function() {
- sendAsyncMessage("pong", "${name}");
- });
- addMessageListener("check-browser-api", function() {
- let exists = "api" in this;
- sendAsyncMessage("check-browser-api", {
- exists,
- running: exists && !this.api._shuttingDown,
- });
- });
- addEventListener("pagehide", function({ inFrameSwap }) {
- sendAsyncMessage("pagehide", inFrameSwap);
- }, {mozSystemGroup: true});
- }`;
- }
-
- // Load frame script into each frame
- {
- let mmA = frameA.frameLoader.messageManager;
- let mmB = frameB.frameLoader.messageManager;
-
- mmA.loadFrameScript("data:,(" + frameScriptFactory("A") + ")()", false);
- mmB.loadFrameScript("data:,(" + frameScriptFactory("B") + ")()", false);
- }
-
- // Ping before swap
- {
- let mmA = frameA.frameLoader.messageManager;
- let mmB = frameB.frameLoader.messageManager;
-
- let inflightA = once(mmA, "pong");
- let inflightB = once(mmB, "pong");
-
- info("Ping message manager for frame A");
- mmA.sendAsyncMessage("ping");
- let [ { data: pongA } ] = await inflightA;
- is(pongA, "A", "Frame A message manager gets reply A before swap");
-
- info("Ping message manager for frame B");
- mmB.sendAsyncMessage("ping");
- let [ { data: pongB } ] = await inflightB;
- is(pongB, "B", "Frame B message manager gets reply B before swap");
- }
-
- // Ping after swap using message managers acquired before
- {
- let mmA = frameA.frameLoader.messageManager;
- let mmB = frameB.frameLoader.messageManager;
-
- let pagehideA = once(mmA, "pagehide");
- let pagehideB = once(mmB, "pagehide");
-
- info("swapFrameLoaders");
- frameA.swapFrameLoaders(frameB);
-
- let [ { data: inFrameSwapA } ] = await pagehideA;
- ok(inFrameSwapA, "Frame A got pagehide with inFrameSwap: true");
- let [ { data: inFrameSwapB } ] = await pagehideB;
- ok(inFrameSwapB, "Frame B got pagehide with inFrameSwap: true");
-
- let inflightA = once(mmA, "pong");
- let inflightB = once(mmB, "pong");
-
- info("Ping message manager for frame A");
- mmA.sendAsyncMessage("ping");
- let [ { data: pongA } ] = await inflightA;
- is(pongA, "B", "Frame A message manager acquired before swap gets reply B after swap");
-
- info("Ping message manager for frame B");
- mmB.sendAsyncMessage("ping");
- let [ { data: pongB } ] = await inflightB;
- is(pongB, "A", "Frame B message manager acquired before swap gets reply A after swap");
- }
-
- // Check height after swap
- if (frameA.getContentDimensions) {
- let { height } = await frameA.getContentDimensions();
- is(height, heightB, "Frame A's content height is 400px after swap");
- }
- if (frameB.getContentDimensions) {
- let { height } = await frameB.getContentDimensions();
- is(height, heightA, "Frame B's content height is 200px after swap");
- }
-
- // Ping after swap using message managers acquired after
- {
- let mmA = frameA.frameLoader.messageManager;
- let mmB = frameB.frameLoader.messageManager;
-
- let inflightA = once(mmA, "pong");
- let inflightB = once(mmB, "pong");
-
- info("Ping message manager for frame A");
- mmA.sendAsyncMessage("ping");
- let [ { data: pongA } ] = await inflightA;
- is(pongA, "B", "Frame A message manager acquired after swap gets reply B after swap");
-
- info("Ping message manager for frame B");
- mmB.sendAsyncMessage("ping");
- let [ { data: pongB } ] = await inflightB;
- is(pongB, "A", "Frame B message manager acquired after swap gets reply A after swap");
- }
-
- frameA.remove();
- frameB.remove();
- }
- });
- ]]></script>
-</window>
diff --git a/dom/base/test/common_postMessages.js b/dom/base/test/common_postMessages.js
index c4836fdd77..044f3e7f34 100644
--- a/dom/base/test/common_postMessages.js
+++ b/dom/base/test/common_postMessages.js
@@ -1,3 +1,5 @@
+/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */
+
function getType(a) {
if (a === null || a === undefined) {
return "null";
diff --git a/dom/base/test/file_bug1008126_worker.js b/dom/base/test/file_bug1008126_worker.js
index aaba278de5..4e418d777e 100644
--- a/dom/base/test/file_bug1008126_worker.js
+++ b/dom/base/test/file_bug1008126_worker.js
@@ -3,6 +3,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
+/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */
+
var gEntry1 = "data_1.txt";
var gEntry2 = "data_2.txt";
var gEntry3 = "data_big.txt";
diff --git a/dom/base/test/file_bug945152_worker.js b/dom/base/test/file_bug945152_worker.js
index 9664045b6d..c0feebf0d6 100644
--- a/dom/base/test/file_bug945152_worker.js
+++ b/dom/base/test/file_bug945152_worker.js
@@ -1,3 +1,4 @@
+/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */
var gData1 = "TEST_DATA_1:ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var gData2 = "TEST_DATA_2:1234567890";
var gPaddingChar = ".";
diff --git a/dom/base/test/file_focus_shadow_dom.html b/dom/base/test/file_focus_shadow_dom.html
index 6fa9d1b88e..7a0a0da729 100644
--- a/dom/base/test/file_focus_shadow_dom.html
+++ b/dom/base/test/file_focus_shadow_dom.html
@@ -79,10 +79,16 @@
opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (3)");
synthesizeKey("KEY_Tab");
opener.is(lastFocusTarget, shadowDate, "Should have focused date element with a calendar button in shadow DOM. (3)");
- synthesizeKey("KEY_Tab");
- opener.is(shadowIframe.contentDocument.activeElement,
- shadowIframe.contentDocument.documentElement,
- "Should have focused document element in shadow iframe. (3)");
+
+ let canTabMoveFocusToRootElement =
+ !SpecialPowers.getBoolPref("dom.disable_tab_focus_to_root_element");
+ if (canTabMoveFocusToRootElement) {
+ synthesizeKey("KEY_Tab");
+ opener.is(shadowIframe.contentDocument.activeElement,
+ shadowIframe.contentDocument.documentElement,
+ "Should have focused document element in shadow iframe. (3)");
+ }
+
synthesizeKey("KEY_Tab");
opener.is(shadowIframe.contentDocument.activeElement,
shadowIframe.contentDocument.body.firstChild,
@@ -99,10 +105,12 @@
opener.is(shadowIframe.contentDocument.activeElement,
shadowIframe.contentDocument.body.firstChild,
"Should have focused input element in shadow iframe. (4)");
- synthesizeKey("KEY_Tab", {shiftKey: true});
- opener.is(shadowIframe.contentDocument.activeElement,
- shadowIframe.contentDocument.documentElement,
- "Should have focused document element in shadow iframe. (4)");
+ if (canTabMoveFocusToRootElement) {
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(shadowIframe.contentDocument.activeElement,
+ shadowIframe.contentDocument.documentElement,
+ "Should have focused document element in shadow iframe. (4)");
+ }
synthesizeKey("KEY_Tab", {shiftKey: true});
opener.is(lastFocusTarget, shadowDate, "Should have focused date element with a calendar button in shadow DOM. (4)");
synthesizeKey("KEY_Tab", {shiftKey: true});
diff --git a/dom/base/test/file_img_attachment.jpg b/dom/base/test/file_img_attachment.jpg
new file mode 100644
index 0000000000..dcd99b9670
--- /dev/null
+++ b/dom/base/test/file_img_attachment.jpg
Binary files differ
diff --git a/dom/base/test/file_img_attachment.jpg^headers^ b/dom/base/test/file_img_attachment.jpg^headers^
new file mode 100644
index 0000000000..71ed8e7805
--- /dev/null
+++ b/dom/base/test/file_img_attachment.jpg^headers^
@@ -0,0 +1 @@
+Content-Disposition: attachment
diff --git a/dom/base/test/file_img_object_attachment.html b/dom/base/test/file_img_object_attachment.html
new file mode 100644
index 0000000000..502894041e
--- /dev/null
+++ b/dom/base/test/file_img_object_attachment.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <object data="file_img_attachment.jpg" type="image/jpeg" width="100%" height="600">fallback</object>
+ </body>
+</html>
diff --git a/dom/base/test/file_pdf_attachment.pdf b/dom/base/test/file_pdf_attachment.pdf
new file mode 100644
index 0000000000..89066463f1
--- /dev/null
+++ b/dom/base/test/file_pdf_attachment.pdf
Binary files differ
diff --git a/dom/base/test/file_pdf_attachment.pdf^headers^ b/dom/base/test/file_pdf_attachment.pdf^headers^
new file mode 100644
index 0000000000..562009a8de
--- /dev/null
+++ b/dom/base/test/file_pdf_attachment.pdf^headers^
@@ -0,0 +1,2 @@
+Content-Type: application/octet-stream
+Content-Disposition: attachment
diff --git a/dom/base/test/file_pdf_object_attachment.html b/dom/base/test/file_pdf_object_attachment.html
new file mode 100644
index 0000000000..d87eff9923
--- /dev/null
+++ b/dom/base/test/file_pdf_object_attachment.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <object data="file_pdf_attachment.pdf" type="application/pdf" width="100%" height="600">fallback</object>
+ </body>
+</html>
diff --git a/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml b/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml
index 93f00311e7..bc92abf3e0 100644
--- a/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml
+++ b/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml
@@ -79,7 +79,7 @@ function thirdEntry(event) {
gOuterDoc.exitFullscreen();
}
-function earlyExit(event) {
+function earlyExit() {
ok(false, "MozDOMFullscreen:Exited should only be triggered after cancel all fullscreen");
}
diff --git a/dom/base/test/fullscreen/browser_fullscreen-navigation-history-race.js b/dom/base/test/fullscreen/browser_fullscreen-navigation-history-race.js
index 2ea2b9ee40..49a48c3177 100644
--- a/dom/base/test/fullscreen/browser_fullscreen-navigation-history-race.js
+++ b/dom/base/test/fullscreen/browser_fullscreen-navigation-history-race.js
@@ -82,7 +82,7 @@ function preventBFCache(aBrowsingContext, aPrevent) {
let target = content.document.getElementById("div");
target.addEventListener(
"mousedown",
- function (e) {
+ function () {
content.window.history.back();
},
{ once: true }
diff --git a/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js b/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js
index 10d10a0b0f..1338c4a550 100644
--- a/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js
+++ b/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js
@@ -70,7 +70,7 @@ async function WaitRemoveDocumentAndCloseTab(aBrowser, aBrowsingContext) {
return new Promise(resolve => {
content.document.addEventListener(
"fullscreenchange",
- e => {
+ () => {
resolve();
},
{ once: true }
diff --git a/dom/base/test/fullscreen/file_fullscreen-api.html b/dom/base/test/fullscreen/file_fullscreen-api.html
index 645e6ece46..9661b10de9 100644
--- a/dom/base/test/fullscreen/file_fullscreen-api.html
+++ b/dom/base/test/fullscreen/file_fullscreen-api.html
@@ -112,7 +112,7 @@ function enter2(event) {
promise = document.exitFullscreen();
}
-function exit2(event) {
+function exit2() {
is(document.fullscreenElement, null,
"Full-screen element should have rolled back.");
is(iframe.contentDocument.fullscreenElement, null,
@@ -156,7 +156,7 @@ function exit3(event) {
promise = outOfDocElement.requestFullscreen();
}
-function error1(event) {
+function error1() {
ok(!document.fullscreenElement,
"Requests for full-screen from not-in-doc elements should fail.");
assertPromiseRejected(promise, "in error1");
@@ -181,7 +181,7 @@ function enter4(event) {
"Should not have a full-screen element again.");
}
-async function exit_to_arg_test_1(event) {
+async function exit_to_arg_test_1() {
ok(!document.fullscreenElement,
"Should have left full-screen mode (third time).");
addFullscreenChangeContinuation("enter", enter_from_arg_test_1);
@@ -196,14 +196,14 @@ async function exit_to_arg_test_1(event) {
ok(!threw, "requestFullscreen with bogus arg (123) shouldn't throw exception");
}
-function enter_from_arg_test_1(event) {
+function enter_from_arg_test_1() {
ok(document.fullscreenElement,
"Should have entered full-screen after calling with bogus (ignored) argument (fourth time)");
addFullscreenChangeContinuation("exit", exit_to_arg_test_2);
document.exitFullscreen();
}
-async function exit_to_arg_test_2(event) {
+async function exit_to_arg_test_2() {
ok(!document.fullscreenElement,
"Should have left full-screen mode (fourth time).");
addFullscreenChangeContinuation("enter", enter_from_arg_test_2);
@@ -218,14 +218,14 @@ async function exit_to_arg_test_2(event) {
ok(!threw, "requestFullscreen with { vrDisplay: null } shouldn't throw exception");
}
-function enter_from_arg_test_2(event) {
+function enter_from_arg_test_2() {
ok(document.fullscreenElement,
"Should have entered full-screen after calling with vrDisplay null argument (fifth time)");
addFullscreenChangeContinuation("exit", exit4);
document.exitFullscreen();
}
-function exit4(event) {
+function exit4() {
ok(!document.fullscreenElement,
"Should be back in non-full-screen mode (fifth time)");
SpecialPowers.pushPrefEnv({"set":[["full-screen-api.allow-trusted-requests-only", true]]}, function() {
@@ -234,7 +234,7 @@ function exit4(event) {
});
}
-function error2(event) {
+function error2() {
ok(!document.fullscreenElement,
"Should still be in normal mode, because calling context isn't trusted.");
button = document.createElement("button");
@@ -246,13 +246,13 @@ function error2(event) {
sendMouseClick(button);
}
-function enter5(event) {
+function enter5() {
ok(document.fullscreenElement, "Moved to full-screen after mouse click");
addFullscreenChangeContinuation("exit", exit5);
document.exitFullscreen();
}
-function exit5(event) {
+function exit5() {
ok(!document.fullscreenElement,
"Should have left full-screen mode (last time).");
SpecialPowers.pushPrefEnv({
@@ -264,7 +264,7 @@ function exit5(event) {
});
}
-function error3(event) {
+function error3() {
ok(!document.fullscreenElement,
"Should still be in normal mode, because pref is not enabled.");
diff --git a/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html b/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html
index 61db80c228..48f2dea09d 100644
--- a/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html
+++ b/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html
@@ -2,7 +2,7 @@
<button>Launch</button>
<script>
let button = document.querySelector("button");
-button.addEventListener("click", function(e) {
+button.addEventListener("click", function() {
let newWindow = window.open("", "", "newWindow");
newWindow.document.write(`<!DOCTYPE HTML>
<button>click me!</button>
diff --git a/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html b/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html
index 7490f12936..beafd79661 100644
--- a/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html
+++ b/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html
@@ -2,7 +2,7 @@
<button>click me!</button>
<script>
let button = document.querySelector("button");
-button.addEventListener("click", function(e) {
+button.addEventListener("click", function() {
document.documentElement.requestFullscreen();
setTimeout(() => {
while(true) {
diff --git a/dom/base/test/fullscreen/file_fullscreen-denied.html b/dom/base/test/fullscreen/file_fullscreen-denied.html
index db9a69e71a..fe4244ec7f 100644
--- a/dom/base/test/fullscreen/file_fullscreen-denied.html
+++ b/dom/base/test/fullscreen/file_fullscreen-denied.html
@@ -137,7 +137,7 @@ function requestFullscreenMouseBtn(event, button) {
synthesizeMouseAtCenter(clickEl, { button });
}
-async function testFullscreenMouseBtn(event, button, next) {
+async function testFullscreenMouseBtn() {
await SpecialPowers.pushPrefEnv({
"set": [["full-screen-api.mouse-event-allow-left-button-only", true]]
});
diff --git a/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html b/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html
index d7d8a90aaf..210b2af1b6 100644
--- a/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html
+++ b/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html
@@ -33,7 +33,7 @@ function is(a, b, msg) {
var escKeyReceived = false;
var escKeySent = false;
-function keyHandler(event) {
+function keyHandler() {
if (escKeyReceived == KeyboardEvent.DOM_VK_ESC) {
escKeyReceived = true;
}
diff --git a/dom/base/test/fullscreen/file_fullscreen-esc-exit.html b/dom/base/test/fullscreen/file_fullscreen-esc-exit.html
index f65f930b3f..1e2252f1ab 100644
--- a/dom/base/test/fullscreen/file_fullscreen-esc-exit.html
+++ b/dom/base/test/fullscreen/file_fullscreen-esc-exit.html
@@ -34,14 +34,14 @@ function finish() {
opener.nextTest();
}
-function fullscreenchange1(event) {
+function fullscreenchange1() {
is(document.fullscreenElement, document.body, "FSE should be doc");
addFullscreenChangeContinuation("exit", fullscreenchange2);
ok(!document.getElementById("subdoc").contentWindow.escKeySent, "Should not yet have sent ESC key press.");
document.getElementById("subdoc").contentWindow.startTest();
}
-function fullscreenchange2(event) {
+function fullscreenchange2() {
ok(document.getElementById("subdoc").contentWindow.escKeySent, "Should have sent ESC key press.");
ok(!document.getElementById("subdoc").contentWindow.escKeyReceived, "ESC key press to exit should not be delivered.");
ok(!document.fullscreenElement, "Should have left full-screen mode on ESC key press");
diff --git a/dom/base/test/fullscreen/file_fullscreen-shadowdom.html b/dom/base/test/fullscreen/file_fullscreen-shadowdom.html
index 348e08ae87..1972e1457e 100644
--- a/dom/base/test/fullscreen/file_fullscreen-shadowdom.html
+++ b/dom/base/test/fullscreen/file_fullscreen-shadowdom.html
@@ -29,7 +29,7 @@
var elem = shadowRoot.firstChild;
var gotFullscreenEvent = false;
- document.addEventListener("fullscreenchange", function (e) {
+ document.addEventListener("fullscreenchange", function () {
if (document.fullscreenElement === host) {
is(shadowRoot.fullscreenElement, elem,
"Expected element entered fullsceen");
diff --git a/dom/base/test/fullscreen/file_fullscreen-svg-element.html b/dom/base/test/fullscreen/file_fullscreen-svg-element.html
index 1dfc78aa1c..d03a13ee84 100644
--- a/dom/base/test/fullscreen/file_fullscreen-svg-element.html
+++ b/dom/base/test/fullscreen/file_fullscreen-svg-element.html
@@ -32,7 +32,7 @@
var elem = document.getElementById("svg-elem")
, elemWasLocked = false;
- document.addEventListener("fullscreenchange", function (e) {
+ document.addEventListener("fullscreenchange", function () {
if (document.fullscreenElement === elem) {
elemWasLocked = true;
document.exitFullscreen();
diff --git a/dom/base/test/fullscreen/fullscreen.xhtml b/dom/base/test/fullscreen/fullscreen.xhtml
index 2cc95642b6..76986db540 100644
--- a/dom/base/test/fullscreen/fullscreen.xhtml
+++ b/dom/base/test/fullscreen/fullscreen.xhtml
@@ -11,7 +11,7 @@
window.addEventListener("fullscreen", onFullScreen, true);
-function onFullScreen(event)
+function onFullScreen()
{
window.arguments[0].done(window.fullScreen);
}
diff --git a/dom/base/test/fullscreen/fullscreen_helpers.js b/dom/base/test/fullscreen/fullscreen_helpers.js
index 6e78015cd8..f097ae316e 100644
--- a/dom/base/test/fullscreen/fullscreen_helpers.js
+++ b/dom/base/test/fullscreen/fullscreen_helpers.js
@@ -83,7 +83,7 @@ function waitWidgetFullscreenEvent(
aIsInFullscreen,
aWaitUntil = false
) {
- return BrowserTestUtils.waitForEvent(aWindow, "fullscreen", false, aEvent => {
+ return BrowserTestUtils.waitForEvent(aWindow, "fullscreen", false, () => {
if (
aWaitUntil &&
aIsInFullscreen !=
@@ -106,7 +106,7 @@ function waitForFullScreenObserver(
aIsInFullscreen,
aWaitUntil = false
) {
- return TestUtils.topicObserved("fullscreen-painted", (subject, data) => {
+ return TestUtils.topicObserved("fullscreen-painted", () => {
if (
aWaitUntil &&
aIsInFullscreen !=
diff --git a/dom/base/test/fullscreen/test_fullscreen-api.html b/dom/base/test/fullscreen/test_fullscreen-api.html
index 2a59d6eeb0..ef07a5f97f 100644
--- a/dom/base/test/fullscreen/test_fullscreen-api.html
+++ b/dom/base/test/fullscreen/test_fullscreen-api.html
@@ -111,7 +111,7 @@ function runNextTest() {
// otherwise, the fullscreen request might be denied.
if (testWindow.document.hidden) {
info("Waiting for document to unhide");
- waitForEvent(testWindow.document, "visibilitychange", (event) => {
+ waitForEvent(testWindow.document, "visibilitychange", () => {
return !testWindow.document.hidden;
}, testWindow.begin);
return;
diff --git a/dom/base/test/fullscreen/test_fullscreen_modal.html b/dom/base/test/fullscreen/test_fullscreen_modal.html
index 78e70d9052..fef4e3867d 100644
--- a/dom/base/test/fullscreen/test_fullscreen_modal.html
+++ b/dom/base/test/fullscreen/test_fullscreen_modal.html
@@ -21,7 +21,7 @@ const button = document.querySelector("button");
let clickCount = 0;
let lastFullscreenPromise = null;
let shouldEnterFullscreen = false;
-button.addEventListener("click", function(e) {
+button.addEventListener("click", function() {
clickCount++;
if (shouldEnterFullscreen) {
const fullscreenElement = document.getElementById("fullscreen");
@@ -58,6 +58,15 @@ async function testFullscreenIsModal(modal) {
ok(document.fullscreenElement.matches(":fullscreen"), "Fullscreen element matches :fullscreen");
is(document.fullscreenElement.matches(":modal"), modal, "Fullscreen element matches :modal");
+ // Before exiting fullscreen, wait on the document becoming active,
+ // which signifies that the fullscreen request has been completely
+ // processed. It is important that the fullscreen request is all
+ // the way done, or the exit fullscreen request could be dropped.
+ let documentWrapper = SpecialPowers.wrap(document);
+ await SimpleTest.promiseWaitForCondition(() => documentWrapper.isActive(),
+ "Timed out waiting for document to become active.");
+ ok(documentWrapper.isActive(), "Document is active.");
+
await document.exitFullscreen();
clickButton(/* expectEvent = */ true);
}
diff --git a/dom/base/test/gtest/TestMimeType.cpp b/dom/base/test/gtest/TestMimeType.cpp
index fecb3f8678..40916130a8 100644
--- a/dom/base/test/gtest/TestMimeType.cpp
+++ b/dom/base/test/gtest/TestMimeType.cpp
@@ -9,12 +9,10 @@
#include "MimeType.h"
#include "nsString.h"
-using mozilla::UniquePtr;
-
TEST(MimeType, EmptyString)
{
const auto in = u""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Empty string";
}
@@ -22,7 +20,7 @@ TEST(MimeType, EmptyString)
TEST(MimeType, JustWhitespace)
{
const auto in = u" \t\r\n "_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Just whitespace";
}
@@ -30,7 +28,7 @@ TEST(MimeType, JustWhitespace)
TEST(MimeType, JustBackslash)
{
const auto in = u"\\"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Just backslash";
}
@@ -38,7 +36,7 @@ TEST(MimeType, JustBackslash)
TEST(MimeType, JustForwardslash)
{
const auto in = u"/"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Just forward slash";
}
@@ -46,7 +44,7 @@ TEST(MimeType, JustForwardslash)
TEST(MimeType, MissingType1)
{
const auto in = u"/bogus"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Missing type #1";
}
@@ -54,7 +52,7 @@ TEST(MimeType, MissingType1)
TEST(MimeType, MissingType2)
{
const auto in = u" \r\n\t/bogus"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Missing type #2";
}
@@ -62,7 +60,7 @@ TEST(MimeType, MissingType2)
TEST(MimeType, MissingSubtype1)
{
const auto in = u"bogus"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Missing subtype #1";
}
@@ -70,7 +68,7 @@ TEST(MimeType, MissingSubtype1)
TEST(MimeType, MissingSubType2)
{
const auto in = u"bogus/"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Missing subtype #2";
}
@@ -78,7 +76,7 @@ TEST(MimeType, MissingSubType2)
TEST(MimeType, MissingSubType3)
{
const auto in = u"bogus;"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Missing subtype #3";
}
@@ -86,7 +84,7 @@ TEST(MimeType, MissingSubType3)
TEST(MimeType, MissingSubType4)
{
const auto in = u"bogus; \r\n\t"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Missing subtype #3";
}
@@ -94,7 +92,7 @@ TEST(MimeType, MissingSubType4)
TEST(MimeType, ExtraForwardSlash)
{
const auto in = u"bogus/bogus/;"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Extra forward slash";
}
@@ -102,7 +100,7 @@ TEST(MimeType, ExtraForwardSlash)
TEST(MimeType, WhitespaceInType)
{
const auto in = u"t\re\nx\tt /html"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Type with whitespace";
}
@@ -110,7 +108,7 @@ TEST(MimeType, WhitespaceInType)
TEST(MimeType, WhitespaceInSubtype)
{
const auto in = u"text/ h\rt\nm\tl"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Subtype with whitespace";
}
@@ -118,7 +116,7 @@ TEST(MimeType, WhitespaceInSubtype)
TEST(MimeType, NonAlphanumericMediaType1)
{
const auto in = u"</>"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Non-alphanumeric media type #1";
}
@@ -126,7 +124,7 @@ TEST(MimeType, NonAlphanumericMediaType1)
TEST(MimeType, NonAlphanumericMediaType2)
{
const auto in = u"(/)"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Non-alphanumeric media type #2";
}
@@ -134,7 +132,7 @@ TEST(MimeType, NonAlphanumericMediaType2)
TEST(MimeType, NonAlphanumericMediaType3)
{
const auto in = u"{/}"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Non-alphanumeric media type #3";
}
@@ -142,7 +140,7 @@ TEST(MimeType, NonAlphanumericMediaType3)
TEST(MimeType, NonAlphanumericMediaType4)
{
const auto in = u"\"/\""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Non-alphanumeric media type #4";
}
@@ -150,7 +148,7 @@ TEST(MimeType, NonAlphanumericMediaType4)
TEST(MimeType, NonAlphanumericMediaType5)
{
const auto in = u"\0/\0"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Non-alphanumeric media type #5";
}
@@ -158,7 +156,7 @@ TEST(MimeType, NonAlphanumericMediaType5)
TEST(MimeType, NonAlphanumericMediaType6)
{
const auto in = u"text/html(;doesnot=matter"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Non-alphanumeric media type #6";
}
@@ -166,7 +164,7 @@ TEST(MimeType, NonAlphanumericMediaType6)
TEST(MimeType, NonLatin1MediaType1)
{
const auto in = u"ÿ/ÿ"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Non-latin1 media type #1";
}
@@ -174,7 +172,7 @@ TEST(MimeType, NonLatin1MediaType1)
TEST(MimeType, NonLatin1MediaType2)
{
const auto in = u"\x0100/\x0100"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_FALSE(parsed)
<< "Non-latin1 media type #2";
}
@@ -182,7 +180,7 @@ TEST(MimeType, NonLatin1MediaType2)
TEST(MimeType, MultipleParameters)
{
const auto in = u"text/html;charset=gbk;no=1;charset_=gbk_;yes=2"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsString out;
@@ -194,7 +192,7 @@ TEST(MimeType, MultipleParameters)
TEST(MimeType, DuplicateParameter1)
{
const auto in = u"text/html;charset=gbk;charset=windows-1255"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsString out;
@@ -206,7 +204,7 @@ TEST(MimeType, DuplicateParameter1)
TEST(MimeType, DuplicateParameter2)
{
const auto in = u"text/html;charset=();charset=GBK"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsString out;
@@ -218,7 +216,7 @@ TEST(MimeType, DuplicateParameter2)
TEST(MimeType, CString)
{
const auto in = "text/html;charset=();charset=GBK"_ns;
- UniquePtr<CMimeType> parsed = CMimeType::Parse(in);
+ RefPtr<CMimeType> parsed = CMimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsCString out;
@@ -234,7 +232,7 @@ TEST(MimeType, CString)
TEST(MimeType, NonAlphanumericParametersAreQuoted)
{
const auto in = u"text/html;test=\x00FF\\;charset=gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsString out;
@@ -249,7 +247,7 @@ TEST(MimeType, NonAlphanumericParametersAreQuoted)
TEST(MimeType, ParameterQuotedIfHasLeadingWhitespace1)
{
const auto in = u"text/html;charset= g\\\"bk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -261,7 +259,7 @@ TEST(MimeType, ParameterQuotedIfHasLeadingWhitespace1)
TEST(MimeType, ParameterQuotedIfHasLeadingWhitespace2)
{
const auto in = u"text/html;charset= \"g\\bk\""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -273,7 +271,7 @@ TEST(MimeType, ParameterQuotedIfHasLeadingWhitespace2)
TEST(MimeType, ParameterQuotedIfHasInternalWhitespace)
{
const auto in = u"text/html;charset=g \\b\"k"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -285,7 +283,7 @@ TEST(MimeType, ParameterQuotedIfHasInternalWhitespace)
TEST(MimeType, ImproperlyQuotedParameter1)
{
const auto in = u"x/x;test=\""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -297,7 +295,7 @@ TEST(MimeType, ImproperlyQuotedParameter1)
TEST(MimeType, ImproperlyQuotedParameter2)
{
const auto in = u"x/x;test=\"\\"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -309,7 +307,7 @@ TEST(MimeType, ImproperlyQuotedParameter2)
TEST(MimeType, NonLatin1ParameterIgnored)
{
const auto in = u"x/x;test=\xFFFD;x=x"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -321,7 +319,7 @@ TEST(MimeType, NonLatin1ParameterIgnored)
TEST(MimeType, ParameterIgnoredIfWhitespaceInName1)
{
const auto in = u"text/html;charset =gbk;charset=123"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -333,7 +331,7 @@ TEST(MimeType, ParameterIgnoredIfWhitespaceInName1)
TEST(MimeType, ParameterIgnoredIfWhitespaceInName2)
{
const auto in = u"text/html;cha rset =gbk;charset=123"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -345,7 +343,7 @@ TEST(MimeType, ParameterIgnoredIfWhitespaceInName2)
TEST(MimeType, WhitespaceTrimmed)
{
const auto in = u"\n\r\t text/plain\n\r\t ;\n\r\t charset=123\n\r\t "_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -357,7 +355,7 @@ TEST(MimeType, WhitespaceTrimmed)
TEST(MimeType, WhitespaceOnlyParameterIgnored)
{
const auto in = u"x/x;x= \r\n\t"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -369,7 +367,7 @@ TEST(MimeType, WhitespaceOnlyParameterIgnored)
TEST(MimeType, IncompleteParameterIgnored1)
{
const auto in = u"x/x;test"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -381,7 +379,7 @@ TEST(MimeType, IncompleteParameterIgnored1)
TEST(MimeType, IncompleteParameterIgnored2)
{
const auto in = u"x/x;test="_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -393,7 +391,7 @@ TEST(MimeType, IncompleteParameterIgnored2)
TEST(MimeType, IncompleteParameterIgnored3)
{
const auto in = u"x/x;test= \r\n\t"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -405,7 +403,7 @@ TEST(MimeType, IncompleteParameterIgnored3)
TEST(MimeType, IncompleteParameterIgnored4)
{
const auto in = u"text/html;test;charset=gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -417,7 +415,7 @@ TEST(MimeType, IncompleteParameterIgnored4)
TEST(MimeType, IncompleteParameterIgnored5)
{
const auto in = u"text/html;test=;charset=gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -429,7 +427,7 @@ TEST(MimeType, IncompleteParameterIgnored5)
TEST(MimeType, EmptyParameterIgnored1)
{
const auto in = u"text/html ; ; charset=gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -441,7 +439,7 @@ TEST(MimeType, EmptyParameterIgnored1)
TEST(MimeType, EmptyParameterIgnored2)
{
const auto in = u"text/html;;;;charset=gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -453,7 +451,7 @@ TEST(MimeType, EmptyParameterIgnored2)
TEST(MimeType, InvalidParameterIgnored1)
{
const auto in = u"text/html;';charset=gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -465,7 +463,7 @@ TEST(MimeType, InvalidParameterIgnored1)
TEST(MimeType, InvalidParameterIgnored2)
{
const auto in = u"text/html;\";charset=gbk;=123; =321"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -477,7 +475,7 @@ TEST(MimeType, InvalidParameterIgnored2)
TEST(MimeType, InvalidParameterIgnored3)
{
const auto in = u"text/html;charset= \"\u007F;charset=GBK"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -490,7 +488,7 @@ TEST(MimeType, InvalidParameterIgnored4)
{
const auto in = nsLiteralString(
u"text/html;charset=\"\u007F;charset=foo\";charset=GBK;charset=");
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -502,7 +500,7 @@ TEST(MimeType, InvalidParameterIgnored4)
TEST(MimeType, SingleQuotes1)
{
const auto in = u"text/html;charset='gbk'"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -514,7 +512,7 @@ TEST(MimeType, SingleQuotes1)
TEST(MimeType, SingleQuotes2)
{
const auto in = u"text/html;charset='gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -526,7 +524,7 @@ TEST(MimeType, SingleQuotes2)
TEST(MimeType, SingleQuotes3)
{
const auto in = u"text/html;charset=gbk'"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -538,7 +536,7 @@ TEST(MimeType, SingleQuotes3)
TEST(MimeType, SingleQuotes4)
{
const auto in = u"text/html;charset=';charset=GBK"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -550,7 +548,7 @@ TEST(MimeType, SingleQuotes4)
TEST(MimeType, SingleQuotes5)
{
const auto in = u"text/html;charset=''';charset=GBK"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -562,7 +560,7 @@ TEST(MimeType, SingleQuotes5)
TEST(MimeType, DoubleQuotes1)
{
const auto in = u"text/html;charset=\"gbk\""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -574,7 +572,7 @@ TEST(MimeType, DoubleQuotes1)
TEST(MimeType, DoubleQuotes2)
{
const auto in = u"text/html;charset=\"gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -586,7 +584,7 @@ TEST(MimeType, DoubleQuotes2)
TEST(MimeType, DoubleQuotes3)
{
const auto in = u"text/html;charset=gbk\""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -598,7 +596,7 @@ TEST(MimeType, DoubleQuotes3)
TEST(MimeType, DoubleQuotes4)
{
const auto in = u"text/html;charset=\" gbk\""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -610,7 +608,7 @@ TEST(MimeType, DoubleQuotes4)
TEST(MimeType, DoubleQuotes5)
{
const auto in = u"text/html;charset=\"gbk \""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -622,7 +620,7 @@ TEST(MimeType, DoubleQuotes5)
TEST(MimeType, DoubleQuotes6)
{
const auto in = u"text/html;charset=\"\\ gbk\""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -634,7 +632,7 @@ TEST(MimeType, DoubleQuotes6)
TEST(MimeType, DoubleQuotes7)
{
const auto in = u"text/html;charset=\"\\g\\b\\k\""_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -646,7 +644,7 @@ TEST(MimeType, DoubleQuotes7)
TEST(MimeType, DoubleQuotes8)
{
const auto in = u"text/html;charset=\"gbk\"x"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -658,7 +656,7 @@ TEST(MimeType, DoubleQuotes8)
TEST(MimeType, DoubleQuotes9)
{
const auto in = u"text/html;charset=\"\";charset=GBK"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -670,7 +668,7 @@ TEST(MimeType, DoubleQuotes9)
TEST(MimeType, DoubleQuotes10)
{
const auto in = u"text/html;charset=\";charset=GBK"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -682,7 +680,7 @@ TEST(MimeType, DoubleQuotes10)
TEST(MimeType, UnexpectedCodePoints)
{
const auto in = u"text/html;charset={gbk}"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -699,7 +697,7 @@ TEST(MimeType, LongTypesSubtypesAccepted)
"2345678901234567890123456789012345678901234567890123456789/"
"012345678901234567890123456789012345678901234567890123456789012345678901"
"2345678901234567890123456789012345678901234567890123456789");
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -716,7 +714,7 @@ TEST(MimeType, LongParametersAccepted)
"012345678901234567890123456789012345678901234567890123456789012345678901"
"2345678901234567890123456789012345678901234567890123456789=x;charset="
"gbk");
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -744,7 +742,7 @@ TEST(MimeType, AllValidCharactersAccepted1)
u"\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED"
u"\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8"
u"\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF\"");
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -756,7 +754,7 @@ TEST(MimeType, AllValidCharactersAccepted1)
TEST(MimeType, CaseNormalization1)
{
const auto in = u"TEXT/PLAIN;CHARSET=TEST"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -775,7 +773,7 @@ TEST(MimeType, CaseNormalization2)
".^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$"
"%&'*+-.^_`|~"
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -794,7 +792,7 @@ TEST(MimeType, CaseNormalization2)
TEST(MimeType, LegacyCommentSyntax1)
{
const auto in = u"text/html;charset=gbk("_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
@@ -806,7 +804,7 @@ TEST(MimeType, LegacyCommentSyntax1)
TEST(MimeType, LegacyCommentSyntax2)
{
const auto in = u"text/html;x=(;charset=gbk"_ns;
- UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ RefPtr<MimeType> parsed = MimeType::Parse(in);
ASSERT_TRUE(parsed)
<< "Parsing succeeded";
nsAutoString out;
diff --git a/dom/base/test/meta_viewport/viewport_helpers.js b/dom/base/test/meta_viewport/viewport_helpers.js
index d4d346b5d0..cad6613549 100644
--- a/dom/base/test/meta_viewport/viewport_helpers.js
+++ b/dom/base/test/meta_viewport/viewport_helpers.js
@@ -40,5 +40,6 @@ function getViewportInfo(aDisplayWidth, aDisplayHeight) {
}
function fuzzeq(a, b, msg) {
+ // eslint-disable-next-line mozilla/no-comparison-or-assignment-inside-ok
ok(Math.abs(a - b) < 1e-6, msg);
}
diff --git a/dom/base/test/mochitest.toml b/dom/base/test/mochitest.toml
index 6415c4b33b..fb6724e497 100644
--- a/dom/base/test/mochitest.toml
+++ b/dom/base/test/mochitest.toml
@@ -3,7 +3,6 @@ tags = "condprof"
prefs = [
"formhelper.autozoom.force-disable.test-only=true",
"plugins.rewrite_youtube_embeds=true",
- "dom.domrequest.enabled=true",
]
support-files = [
"audio.ogg",
@@ -1232,8 +1231,6 @@ skip-if = [
["test_domparsing.html"]
-["test_domrequest.html"]
-
["test_domwindowutils.html"]
skip-if = ["os == 'android'"] # Bug 1525959
@@ -1301,6 +1298,8 @@ skip-if = [
"http2",
]
+["test_focus_radio.html"]
+
["test_focus_scroll_padding_tab.html"]
["test_focus_scrollable_fieldset.html"]
diff --git a/dom/base/test/test_domrequest.html b/dom/base/test/test_domrequest.html
deleted file mode 100644
index 1aea26f657..0000000000
--- a/dom/base/test/test_domrequest.html
+++ /dev/null
@@ -1,233 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <title>Test for DOMRequest</title>
- <script src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script class="testbody" type="application/javascript">
-"use strict";
-
-var reqserv = SpecialPowers.getDOMRequestService();
-ok("createRequest" in reqserv, "appears to be a service");
-
-function testBasics() {
- // create a request
- var req = reqserv.createRequest(window);
- ok("result" in req, "request has result");
- ok("error" in req, "request has error");
- ok("onsuccess" in req, "request has onsuccess");
- ok("onerror" in req, "request has onerror");
- ok("readyState" in req, "request has readyState");
- ok("then" in req, "request has then");
-
- is(req.readyState, "pending", "readyState is pending");
- is(req.result, undefined, "result is undefined");
- is(req.onsuccess, null, "onsuccess is null");
- is(req.onerror, null, "onerror is null");
-
- runTest();
-}
-
-function testSuccess() {
- // fire success
- var req = reqserv.createRequest(window);
- var ev = null;
- req.onsuccess = function(e) {
- ev = e;
- }
- var result = null;
- var promise = req.then(function(r) {
- is(r, "my result", "correct result when resolving the promise");
- result = r;
- runTest();
- }, function(e) {
- ok(false, "promise should not be rejected");
- runTest();
- });
- ok(promise instanceof Promise, "then() should return a Promise");
- reqserv.fireSuccess(req, "my result");
- ok(ev, "got success event");
- is(ev.type, "success", "correct type during success");
- is(ev.target, req, "correct target during success");
- is(req.readyState, "done", "correct readyState after success");
- is(req.error, null, "correct error after success");
- is(req.result, "my result", "correct result after success");
- is(result, null, "Promise should not be resolved synchronously");
-}
-
-function testError() {
- // fire error
- var req = reqserv.createRequest(window);
- var ev = null;
- req.onerror = function(e) {
- ev = e;
- }
- var error = null;
- var promise = req.then(function(r) {
- ok(false, "promise should not be resolved");
- runTest();
- }, function(e) {
- ok(e instanceof DOMException, "got error rejection");
- ok(e === req.error, "got correct error when rejecting the promise");
- error = e;
- runTest();
- });
- ok(promise instanceof Promise, "then() should return a Promise");
- reqserv.fireError(req, "OhMyError");
- ok(ev, "got error event");
- is(ev.type, "error", "correct type during error");
- is(ev.target, req, "correct target during error");
- is(req.readyState, "done", "correct readyState after error");
- is(req.error.name, "UnknownError", "correct error type after error");
- is(req.error.message, "OhMyError", "correct error message after error");
- is(req.result, undefined, "correct result after error");
- is(error, null, "Promise should not be rejected synchronously");
-}
-
-function testDetailedError() {
- // fire detailed error
- var req = reqserv.createRequest(window);
- var ev = null;
- req.onerror = function(e) {
- ev = e;
- };
- var error = null;
- var promise = req.then(function(r) {
- ok(false, "promise should not be resolved");
- runTest();
- }, function(e) {
- ok(e instanceof DOMException, "got error rejection");
- ok(e === req.error, "got correct error when rejecting the promise");
- error = e;
- runTest();
- });
- ok(promise instanceof Promise, "then() should return a Promise");
- SpecialPowers.wrwp(req).fireDetailedError(new DOMException("detailedError"));
- ok(ev, "got error event");
- is(ev.type, "error", "correct type during error");
- is(ev.target, req, "correct target during error");
- is(req.readyState, "done", "correct readyState after error");
- is(req.error.name, "UnknownError", "correct error type after error");
- is(req.error.message, "detailedError", "correct error message after error");
- is(req.result, undefined, "correct result after error");
- is(error, null, "Promise should not be rejected synchronously");
-}
-
-function testThenAfterSuccess() {
- // fire success
- var req = reqserv.createRequest(window);
- var ev = null;
- req.onsuccess = function(e) {
- ev = e;
- }
- reqserv.fireSuccess(req, "my result");
- ok(ev, "got success event");
- is(ev.type, "success", "correct type during success");
- is(ev.target, req, "correct target during success");
- is(req.readyState, "done", "correct readyState after success");
- is(req.error, null, "correct error after success");
- is(req.result, "my result", "correct result after success");
- var result = null;
- var promise = req.then(function(r) {
- is(r, "my result", "correct result when resolving the promise");
- result = r;
- runTest();
- }, function(e) {
- ok(false, "promise should not be rejected");
- runTest();
- });
- ok(promise instanceof Promise, "then() should return a Promise");
- is(result, null, "Promise should not be resolved synchronously");
-}
-
-function testThenAfterError() {
- // fire error
- var req = reqserv.createRequest(window);
- var ev = null;
- req.onerror = function(e) {
- ev = e;
- }
- reqserv.fireError(req, "OhMyError");
- ok(ev, "got error event");
- is(ev.type, "error", "correct type during error");
- is(ev.target, req, "correct target during error");
- is(req.readyState, "done", "correct readyState after error");
- is(req.error.name, "UnknownError", "correct error type after error");
- is(req.error.message, "OhMyError", "correct error message after error");
- is(req.result, undefined, "correct result after error");
- var error = null;
- var promise = req.then(function(r) {
- ok(false, "promise should not be resolved");
- runTest();
- }, function(e) {
- ok(e instanceof DOMException, "got error rejection");
- ok(e === req.error, "got correct error when rejecting the promise");
- error = e;
- runTest();
- });
- ok(promise instanceof Promise, "then() should return a Promise");
- is(error, null, "Promise should not be rejected synchronously");
-}
-
-function testDetailedError() {
- // fire detailed error
- var req = reqserv.createRequest(window);
- var ev = null;
- req.onerror = function(e) {
- ev = e;
- };
- var error = null;
- var promise = req.then(function(r) {
- ok(false, "promise should not be resolved");
- runTest();
- }, function(e) {
- ok(e instanceof DOMException, "got error rejection");
- ok(e === req.error, "got correct error when rejecting the promise");
- error = e;
- runTest();
- });
- ok(promise instanceof Promise, "then() should return a Promise");
- SpecialPowers.wrap(req).fireDetailedError(new DOMException("detailedError"));
- ok(ev, "got error event");
- is(ev.type, "error", "correct type during error");
- is(ev.target, req, "correct target during error");
- is(req.readyState, "done", "correct readyState after error");
- is(req.error.name, "Error", "correct error type after error");
- is(req.error.message, "detailedError", "correct error message after error");
- is(req.result, undefined, "correct result after error");
- is(error, null, "Promise should not be rejected synchronously");
-}
-
-var tests = [
- testBasics,
- testSuccess,
- testError,
- testDetailedError,
- testThenAfterSuccess,
- testThenAfterError,
-];
-
-function runTest() {
- if (!tests.length) {
- SimpleTest.finish();
- return;
- }
-
- var test = tests.shift();
- test();
-}
-
-SimpleTest.waitForExplicitFinish();
-runTest();
-
-</script>
-</pre>
-</body>
-</html>
diff --git a/dom/base/test/test_domrequesthelper.xhtml b/dom/base/test/test_domrequesthelper.xhtml
deleted file mode 100644
index 6b9061b8a2..0000000000
--- a/dom/base/test/test_domrequesthelper.xhtml
+++ /dev/null
@@ -1,549 +0,0 @@
-<?xml version="1.0"?>
-<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
--->
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
-
-<window title="DOMRequestHelper Test"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- onload="start();">
-
- <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-
- <script type="application/javascript">
- <![CDATA[
- const {DOMRequestIpcHelper} = ChromeUtils.importESModule(
- "resource://gre/modules/DOMRequestHelper.sys.mjs"
- );
- let obs = Cc["@mozilla.org/observer-service;1"].
- getService(Ci.nsIObserverService);
- let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService();
-
- function DummyHelperSubclass() {
- this.onuninit = null;
- }
- DummyHelperSubclass.prototype = {
- __proto__: DOMRequestIpcHelper.prototype,
- uninit() {
- if (typeof this.onuninit === "function") {
- this.onuninit();
- }
- this.onuninit = null;
- }
- };
-
- var dummy = new DummyHelperSubclass();
- var isDOMRequestHelperDestroyed = false;
-
- /**
- * Init & destroy.
- */
- function initDOMRequestHelperTest(aMessages) {
- // If we haven't initialized the DOMRequestHelper object, its private
- // properties will be undefined, but once destroyDOMRequestHelper is
- // called, they're set to null.
- var expectedPrivatePropertyValues =
- isDOMRequestHelperDestroyed ? null : undefined;
-
- is(dummy._requests, expectedPrivatePropertyValues, "Request is expected");
- is(dummy._messages, undefined, "Messages is undefined");
- is(dummy._window, expectedPrivatePropertyValues, "Window is expected");
-
- dummy.initDOMRequestHelper(window, aMessages);
-
- ok(dummy._window, "Window exists");
- is(dummy._window, window, "Correct window");
- if (aMessages) {
- is(typeof dummy._listeners, "object", "Listeners is an object");
- }
- }
-
- function destroyDOMRequestHelperTest() {
- dummy.destroyDOMRequestHelper();
- isDOMRequestHelperDestroyed = true;
-
- is(dummy._requests, null, "Request is null");
- is(dummy._messages, undefined, "Messages is undefined");
- is(dummy._window, null, "Window is null");
- }
-
- /**
- * Message listeners.
- */
- function checkMessageListeners(aExpectedListeners, aCount) {
- info("Checking message listeners\n" + "Expected listeners " +
- JSON.stringify(aExpectedListeners) + " \nExpected count " + aCount);
- let count = 0;
- Object.keys(dummy._listeners).forEach(function(name) {
- count++;
- is(aExpectedListeners[name].weakRef, dummy._listeners[name].weakRef,
- "Message found " + name + " - Same weakRef");
- is(aExpectedListeners[name].count, dummy._listeners[name].count,
- "Message found " + name + " - Same count");
- });
- is(aCount, count, "Correct number of listeners");
- }
-
- function addMessageListenersTest(aMessages, aExpectedListeners, aCount) {
- dummy.addMessageListeners(aMessages);
- info(JSON.stringify(dummy._listeners));
- checkMessageListeners(aExpectedListeners, aCount);
- }
-
- function removeMessageListenersTest(aMessages, aExpectedListeners, aCount) {
- dummy.removeMessageListeners(aMessages);
- checkMessageListeners(aExpectedListeners, aCount);
- }
-
- /**
- * Utility function to test window destruction behavior. In general this
- * function does the following:
- *
- * 1) Create a new iframe
- * 2) Create a new DOMRequestHelper
- * 3) initDOMRequestHelper(), optionally with weak or strong listeners
- * 4) Optionally force a garbage collection to reap weak references
- * 5) Destroy the iframe triggering an inner-window-destroyed event
- * 6) Callback with a boolean indicating if DOMRequestHelper.uninit() was
- * called.
- *
- * Example usage:
- *
- * checkWindowDestruction({ messages: ["foo"], gc: true },
- * function(uninitCalled) {
- * // expect uninitCalled === false since GC with only weak refs
- * });
- */
- const TOPIC = "inner-window-destroyed";
- function checkWindowDestruction(aOptions, aCallback) {
- aOptions = aOptions || {};
- aOptions.messages = aOptions.messages || [];
- aOptions.gc = !!aOptions.gc;
-
- if (typeof aCallback !== "function") {
- aCallback = function() { };
- }
-
- let uninitCalled = false;
-
- // Use a secondary observer so we know when to expect the uninit(). We
- // can then reasonably expect uninitCalled to be set properly on the
- // next tick.
- let observer = {
- observe(aSubject, aTopic, aData) {
- if (aTopic !== TOPIC) {
- return;
- }
- obs.removeObserver(observer, TOPIC);
- setTimeout(function() {
- aCallback(uninitCalled);
- });
- }
- };
-
- let frame = document.createXULElement("iframe");
- frame.onload = function() {
- obs.addObserver(observer, TOPIC);
- // Create dummy DOMRequestHelper specific to checkWindowDestruction()
- let cwdDummy = new DummyHelperSubclass();
- cwdDummy.onuninit = function() {
- uninitCalled = true;
-
- if (!aOptions.messages || !aOptions.messages.length) {
- return;
- }
-
- // If all message listeners are removed, cwdDummy.receiveMessage
- // should never be called.
- ppmm.broadcastAsyncMessage(aOptions.messages[0].name);
- };
-
- // Test if we still receive messages from ppmm.
- cwdDummy.receiveMessage = function(aMessage) {
- ok(false, "cwdDummy.receiveMessage should NOT be called: " + aMessage.name);
- };
-
- cwdDummy.initDOMRequestHelper(frame.contentWindow, aOptions.messages);
- // Make sure to clear our strong ref here so that we can test our
- // weak reference listeners and observer.
- cwdDummy = null;
- if (aOptions.gc) {
- Cu.schedulePreciseGC(function() {
- SpecialPowers.DOMWindowUtils.cycleCollect();
- SpecialPowers.DOMWindowUtils.garbageCollect();
- SpecialPowers.DOMWindowUtils.garbageCollect();
- document.documentElement.removeChild(frame);
- });
- return;
- }
- document.documentElement.removeChild(frame);
- };
- document.documentElement.appendChild(frame);
- }
-
- /**
- * Test steps.
- */
- var tests = [
- function() {
- info("== InitDOMRequestHelper no messages");
- initDOMRequestHelperTest(null);
- next();
- },
- function() {
- info("== DestroyDOMRequestHelper");
- destroyDOMRequestHelperTest();
- next();
- },
- function() {
- info("== InitDOMRequestHelper empty array");
- initDOMRequestHelperTest([]);
- checkMessageListeners({}, 0);
- next();
- },
- function() {
- info("== DestroyDOMRequestHelper");
- destroyDOMRequestHelperTest();
- next();
- },
- function() {
- info("== InitDOMRequestHelper with strings array");
- initDOMRequestHelperTest(["name1", "nameN"]);
- checkMessageListeners({"name1": {weakRef: false, count: 1},
- "nameN": {weakRef: false, count: 1}}, 2);
- next();
- },
- function() {
- info("== DestroyDOMRequestHelper");
- destroyDOMRequestHelperTest();
- next();
- },
- function() {
- info("== InitDOMRequestHelper with objects array");
- initDOMRequestHelperTest([{
- name: "name1",
- weakRef: false
- }, {
- name: "nameN",
- weakRef: true
- }]);
- checkMessageListeners({
- "name1": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 2);
- next();
- },
- function() {
- info("== AddMessageListeners empty array");
- addMessageListenersTest([], {
- "name1": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 2);
- next();
- },
- function() {
- info("== AddMessageListeners null");
- addMessageListenersTest(null, {
- "name1": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 2);
- next();
- },
- function() {
- info("== AddMessageListeners new listener, string only");
- addMessageListenersTest("name2", {
- "name1": {weakRef: false, count: 1},
- "name2": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 3);
- next();
- },
- function() {
- info("== AddMessageListeners new listeners, strings array");
- addMessageListenersTest(["name3", "name4"], {
- "name1": {weakRef: false, count: 1},
- "name2": {weakRef: false, count: 1},
- "name3": {weakRef: false, count: 1},
- "name4": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 5);
- next();
- },
- function() {
- info("== AddMessageListeners new listeners, objects array");
- addMessageListenersTest([{
- name: "name5",
- weakRef: true
- }, {
- name: "name6",
- weakRef: false
- }], {
- "name1": {weakRef: false, count: 1},
- "name2": {weakRef: false, count: 1},
- "name3": {weakRef: false, count: 1},
- "name4": {weakRef: false, count: 1},
- "name5": {weakRef: true, count: 1},
- "name6": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 7);
- next();
- },
- function() {
- info("== RemoveMessageListeners, null");
- removeMessageListenersTest(null, {
- "name1": {weakRef: false, count: 1},
- "name2": {weakRef: false, count: 1},
- "name3": {weakRef: false, count: 1},
- "name4": {weakRef: false, count: 1},
- "name5": {weakRef: true, count: 1},
- "name6": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 7);
- next();
- },
- function() {
- info("== RemoveMessageListeners, one message");
- removeMessageListenersTest("name1", {
- "name2": {weakRef: false, count: 1},
- "name3": {weakRef: false, count: 1},
- "name4": {weakRef: false, count: 1},
- "name5": {weakRef: true, count: 1},
- "name6": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 6);
- next();
- },
- function() {
- info("== RemoveMessageListeners, array of messages");
- removeMessageListenersTest(["name2", "name3"], {
- "name4": {weakRef: false, count: 1},
- "name5": {weakRef: true, count: 1},
- "name6": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 4);
- next();
- },
- function() {
- info("== RemoveMessageListeners, unknown message");
- removeMessageListenersTest("unknown", {
- "name4": {weakRef: false, count: 1},
- "name5": {weakRef: true, count: 1},
- "name6": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 4);
- next();
- },
- function() {
- try {
- info("== AddMessageListeners, same message, same kind");
- addMessageListenersTest("name4", {
- "name4": {weakRef: false, count: 2},
- "name5": {weakRef: true, count: 1},
- "name6": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 4);
- next();
- } catch (ex) {
- ok(false, "Unexpected exception " + ex);
- }
- },
- function() {
- info("== AddMessageListeners, same message, different kind");
- try {
- addMessageListenersTest({name: "name4", weakRef: true}, {
- "name4": {weakRef: false, count: 2},
- "name5": {weakRef: true, count: 1},
- "name6": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 4);
- ok(false, "Should have thrown an exception");
- } catch (ex) {
- ok(true, "Expected exception");
- next();
- }
- },
- function() {
- info("== RemoveMessageListeners, message with two listeners");
- try {
- removeMessageListenersTest(["name4", "name5"], {
- "name4": {weakRef: false, count: 1},
- "name6": {weakRef: false, count: 1},
- "nameN": {weakRef: true, count: 1}
- }, 3);
- next();
- } catch (ex) {
- ok(false, "Unexpected exception " + ex);
- }
- },
- function() {
- info("== Test createRequest()");
- ok(DOMRequest, "DOMRequest object exists");
- var req = dummy.createRequest();
- ok(DOMRequest.isInstance(req), "Returned a DOMRequest");
- next();
- },
- function() {
- info("== Test getRequestId(), removeRequest() and getRequest()");
- var req = dummy.createRequest();
- var id = dummy.getRequestId(req);
- is(typeof id, "string", "id is a string");
- var req_ = dummy.getRequest(id);
- is(req, req_, "Got correct request");
- dummy.removeRequest(id);
- req = dummy.getRequest(id);
- is(req, undefined, "No request");
- next();
- },
- function() {
- info("== Test createPromise()");
- ok(Promise, "Promise object exists");
- var promise = dummy.createPromise(function(resolve, reject) {
- resolve(true);
- });
- ok(promise instanceof Promise, "Returned a Promise");
- promise.then(next);
- },
- function() {
- info("== Test createPromiseWithId()");
- var _resolverId;
- var promise = dummy.createPromiseWithId(function(resolverId) {
- _resolverId = resolverId;
- });
- var resolver = dummy.getPromiseResolver(_resolverId);
- ok(promise instanceof Promise, "Returned a Promise");
- ok(typeof _resolverId === "string", "resolverId is a string");
- ok(resolver != null, "resolverId is a valid id");
- next();
- },
- function() {
- info("== Test getResolver()");
- var id;
- var resolver;
- var promise = dummy.createPromise(function(resolve, reject) {
- var r = { resolve, reject };
- id = dummy.getPromiseResolverId(r);
- resolver = r;
- ok(typeof id === "string", "id is a string");
- r.resolve(true);
- }).then(function(unused) {
- var r = dummy.getPromiseResolver(id);
- ok(resolver === r, "Get succeeded");
- next();
- });
- },
- function() {
- info("== Test removeResolver");
- var id;
- var promise = dummy.createPromise(function(resolve, reject) {
- var r = { resolve, reject };
- id = dummy.getPromiseResolverId(r);
- ok(typeof id === "string", "id is a string");
-
- var resolver = dummy.getPromiseResolver(id);
- info("Got resolver " + JSON.stringify(resolver));
- ok(resolver === r, "Resolver get succeeded");
-
- r.resolve(true);
- }).then(function(unused) {
- dummy.removePromiseResolver(id);
- var resolver = dummy.getPromiseResolver(id);
- ok(resolver === undefined, "removeResolver: get failed");
- next();
- });
- },
- function() {
- info("== Test takeResolver");
- var id;
- var resolver;
- var promise = dummy.createPromise(function(resolve, reject) {
- var r = { resolve, reject };
- id = dummy.getPromiseResolverId(r);
- resolver = r;
- ok(typeof id === "string", "id is a string");
-
- var gotR = dummy.getPromiseResolver(id);
- ok(gotR === r, "resolver get succeeded");
-
- r.resolve(true);
- }).then(function(unused) {
- var r = dummy.takePromiseResolver(id);
- ok(resolver === r, "take should succeed");
-
- r = dummy.getPromiseResolver(id);
- ok(r === undefined, "takeResolver: get failed");
- next();
- });
- },
- function() {
- info("== Test window destroyed without messages and without GC");
- checkWindowDestruction({ gc: false }, function(uninitCalled) {
- ok(uninitCalled, "uninit() should have been called");
- next();
- });
- },
- function() {
- info("== Test window destroyed without messages and with GC");
- checkWindowDestruction({ gc: true }, function(uninitCalled) {
- ok(!uninitCalled, "uninit() should NOT have been called");
- next();
- });
- },
- function() {
- info("== Test window destroyed with weak messages and without GC");
- checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
- gc: false }, function(uninitCalled) {
- ok(uninitCalled, "uninit() should have been called");
- next();
- });
- },
- function() {
- info("== Test window destroyed with weak messages and with GC");
- checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
- gc: true }, function(uninitCalled) {
- ok(!uninitCalled, "uninit() should NOT have been called");
- next();
- });
- },
- function() {
- info("== Test window destroyed with strong messages and without GC");
- checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
- gc: false }, function(uninitCalled) {
- ok(uninitCalled, "uninit() should have been called");
- next();
- });
- },
- function() {
- info("== Test window destroyed with strong messages and with GC");
- checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
- gc: true }, function(uninitCalled) {
- ok(uninitCalled, "uninit() should have been called");
- next();
- });
- }
- ];
-
- function next() {
- if (!tests.length) {
- SimpleTest.finish();
- return;
- }
-
- var test = tests.shift();
- test();
- }
-
- function start() {
- SimpleTest.waitForExplicitFinish();
- next();
- }
- ]]>
- </script>
-
- <body xmlns="http://www.w3.org/1999/xhtml">
- <p id="display"></p>
- <div id="content" style="display: none"></div>
- <pre id="test"></pre>
- </body>
-</window>
diff --git a/dom/base/test/test_focus_radio.html b/dom/base/test/test_focus_radio.html
new file mode 100644
index 0000000000..8e97012745
--- /dev/null
+++ b/dom/base/test/test_focus_radio.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<title>Test for input radio focus</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+
+<button id="before">before</button>
+<fieldset>
+ <legend>a</legend>
+ <label><input id="a1" type="radio" name="a" checked>a1</label>
+ <label><input id="a2" type="radio" name="a">a2</label>
+</fieldset>
+<fieldset>
+ <legend>b</legend>
+ <label><input id="b1" type="radio" name="b">b1</label>
+ <label><input id="b2" type="radio" name="b" checked>b2</label>
+</fieldset>
+<fieldset>
+ <legend>c</legend>
+ <label><input id="c1" type="radio" name="c">c1</label>
+ <label><input id="c2" type="radio" name="c">c2</label>
+</fieldset>
+<fieldset>
+ <legend>d</legend>
+ <label><input id="d1" type="radio" name="d" disabled>d1</label>
+ <label><input id="d2" type="radio" name="d">d2</label>
+ <label><input id="d3" type="radio" name="d" disabled>d3</label>
+ <label><input id="d4" type="radio" name="d">d4</label>
+</fieldset>
+<button id="after">after</button>
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ function expectFocusAfterKey(key, id) {
+ const res = key.match(/(Shift\+)?(.*)/);
+ const shiftKey = Boolean(res[1]);
+ const rawKey = res[2];
+ synthesizeKey(`KEY_${rawKey}`, { shiftKey });
+ is(document.activeElement.id, id, `${id} is focused after ${key}`);
+ }
+
+ SimpleTest.waitForFocus(async function() {
+ await SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+
+ expectFocusAfterKey("Tab", "before");
+ // a1 is checked.
+ expectFocusAfterKey("Tab", "a1");
+ // b2 is checked.
+ expectFocusAfterKey("Tab", "b2");
+ // Nothing is checked in group c, so c1 should get focus.
+ expectFocusAfterKey("Tab", "c1");
+ // d1 is disabled, so d2 should get focus.
+ expectFocusAfterKey("Tab", "d2");
+ expectFocusAfterKey("Tab", "after");
+
+ expectFocusAfterKey("Shift+Tab", "d2");
+ expectFocusAfterKey("Shift+Tab", "c1");
+ expectFocusAfterKey("Shift+Tab", "b2");
+ expectFocusAfterKey("Shift+Tab", "a1");
+ expectFocusAfterKey("Shift+Tab", "before");
+
+ expectFocusAfterKey("Tab", "a1");
+ expectFocusAfterKey("ArrowDown", "a2");
+ expectFocusAfterKey("Tab", "b2");
+ // a2 is now checked, so shift+tab should focus it.
+ expectFocusAfterKey("Shift+Tab", "a2");
+
+ expectFocusAfterKey("Tab", "b2");
+ expectFocusAfterKey("ArrowUp", "b1");
+ expectFocusAfterKey("Shift+Tab", "a2");
+ expectFocusAfterKey("Tab", "b1");
+
+ expectFocusAfterKey("Tab", "c1");
+ expectFocusAfterKey("ArrowDown", "c2");
+ expectFocusAfterKey("Tab", "d2");
+ expectFocusAfterKey("Shift+Tab", "c2");
+
+ expectFocusAfterKey("Tab", "d2");
+ // d3 is disabled, so down arrow should focus d4.
+ expectFocusAfterKey("ArrowDown", "d4");
+ expectFocusAfterKey("ArrowUp", "d2");
+ expectFocusAfterKey("ArrowDown", "d4");
+ // Down arrow should wrap at the bottom, skipping disabled.
+ expectFocusAfterKey("ArrowDown", "d2");
+ // Up arrow should wrap at the top.
+ expectFocusAfterKey("ArrowUp", "d4");
+
+ SimpleTest.finish();
+ });
+</script>
diff --git a/dom/base/test/unit/test_error_codes.js b/dom/base/test/unit/test_error_codes.js
index 73c893c512..5c26331d11 100644
--- a/dom/base/test/unit/test_error_codes.js
+++ b/dom/base/test/unit/test_error_codes.js
@@ -10,7 +10,7 @@ function asyncXHR(expectedStatus, nextTestFunc) {
xhr.open("GET", "http://localhost:4444/test_error_code.xml", true);
var sawError = false;
- xhr.addEventListener("loadend", function doAsyncRequest_onLoad(event) {
+ xhr.addEventListener("loadend", function doAsyncRequest_onLoad() {
Assert.ok(sawError, "Should have received an error");
nextTestFunc();
});
diff --git a/dom/base/test/useractivation/file_clipboard_common.js b/dom/base/test/useractivation/file_clipboard_common.js
index fe172e52c8..3925404350 100644
--- a/dom/base/test/useractivation/file_clipboard_common.js
+++ b/dom/base/test/useractivation/file_clipboard_common.js
@@ -373,10 +373,10 @@ function allMechanisms(aCb, aClipOverride, aNegateAll) {
case 0:
// Keyboard issued
cutCopyAll(
- function docut(aSucc) {
+ function docut() {
synthesizeKey("x", { accelKey: true });
},
- function docopy(aSucc) {
+ function docopy() {
synthesizeKey("c", { accelKey: true });
},
function done() {
@@ -411,14 +411,14 @@ function allMechanisms(aCb, aClipOverride, aNegateAll) {
case 2:
// Not triggered by user gesture
cutCopyAll(
- function doCut(aSucc) {
+ function doCut() {
is(
false,
document.execCommand("cut"),
"Can't directly execCommand not in a user callback"
);
},
- function doCopy(aSucc) {
+ function doCopy() {
is(
false,
document.execCommand("copy"),
diff --git a/dom/base/test/useractivation/test_popup_blocker_async_callback.html b/dom/base/test/useractivation/test_popup_blocker_async_callback.html
index dc53596531..4667229116 100644
--- a/dom/base/test/useractivation/test_popup_blocker_async_callback.html
+++ b/dom/base/test/useractivation/test_popup_blocker_async_callback.html
@@ -16,7 +16,7 @@ SimpleTest.requestFlakyTimeout("Need to test setTimeout");
function startTest(aTestAsyncFun, aAllowPopup = true) {
return new Promise(aResolve => {
let target = document.getElementById("target");
- target.addEventListener("click", (e) => {
+ target.addEventListener("click", () => {
aTestAsyncFun(() => {
let w = window.open("about:blank");
is(!!w, aAllowPopup, `Should ${aAllowPopup ? "allow" : "block"} popup`);
diff --git a/dom/base/test/useractivation/test_useractivation_scrollbar.html b/dom/base/test/useractivation/test_useractivation_scrollbar.html
index 778d6d0898..197cdc49fb 100644
--- a/dom/base/test/useractivation/test_useractivation_scrollbar.html
+++ b/dom/base/test/useractivation/test_useractivation_scrollbar.html
@@ -78,7 +78,7 @@ if (!opener) {
SimpleTest.waitForFocus(async function() {
function waitForEvent(aTarget, aEvent) {
return new Promise((aResolve) => {
- aTarget.addEventListener(aEvent, function listener(event) {
+ aTarget.addEventListener(aEvent, function listener() {
aResolve();
}, { once: true });
});
diff --git a/dom/base/use_counter_metrics.yaml b/dom/base/use_counter_metrics.yaml
index f94029689c..211d3e1344 100644
--- a/dom/base/use_counter_metrics.yaml
+++ b/dom/base/use_counter_metrics.yaml
@@ -20150,6 +20150,23 @@ use.counter.css.page:
send_in_pings:
- use-counters
+ css_transition_behavior:
+ type: counter
+ description: >
+ Whether a page used the CSS property transition-behavior.
+ Compare against `use.counter.top_level_content_documents_destroyed`
+ to calculate the rate.
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
+ notification_emails:
+ - dom-core@mozilla.com
+ - emilio@mozilla.com
+ expires: never
+ send_in_pings:
+ - use-counters
+
css_transition_delay:
type: counter
description: >
@@ -31984,6 +32001,23 @@ use.counter.css.doc:
send_in_pings:
- use-counters
+ css_transition_behavior:
+ type: counter
+ description: >
+ Whether a document used the CSS property transition-behavior.
+ Compare against `use.counter.content_documents_destroyed`
+ to calculate the rate.
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
+ notification_emails:
+ - dom-core@mozilla.com
+ - emilio@mozilla.com
+ expires: never
+ send_in_pings:
+ - use-counters
+
css_transition_delay:
type: counter
description: >