diff options
Diffstat (limited to 'dom/base')
57 files changed, 833 insertions, 350 deletions
diff --git a/dom/base/AbstractRange.cpp b/dom/base/AbstractRange.cpp index c9138a19d2..f5d584599b 100644 --- a/dom/base/AbstractRange.cpp +++ b/dom/base/AbstractRange.cpp @@ -49,6 +49,8 @@ template nsresult AbstractRange::SetStartAndEndInternal( const RawRangeBoundary& aEndBoundary, StaticRange* aRange); template bool AbstractRange::MaybeCacheToReuse(nsRange& aInstance); template bool AbstractRange::MaybeCacheToReuse(StaticRange& aInstance); +template bool AbstractRange::MaybeCacheToReuse( + CrossShadowBoundaryRange& aInstance); bool AbstractRange::sHasShutDown = false; @@ -209,6 +211,12 @@ void AbstractRange::Shutdown() { cachedRanges->Clear(); delete cachedRanges; } + if (nsTArray<RefPtr<CrossShadowBoundaryRange>>* cachedRanges = + CrossShadowBoundaryRange::sCachedRanges) { + CrossShadowBoundaryRange::sCachedRanges = nullptr; + cachedRanges->Clear(); + delete cachedRanges; + } } // static diff --git a/dom/base/BodyConsumer.cpp b/dom/base/BodyConsumer.cpp index 754586a08b..81c9bb113d 100644 --- a/dom/base/BodyConsumer.cpp +++ b/dom/base/BodyConsumer.cpp @@ -74,7 +74,7 @@ class ContinueConsumeBodyRunnable final : public MainThreadWorkerRunnable { ContinueConsumeBodyRunnable(BodyConsumer* aBodyConsumer, WorkerPrivate* aWorkerPrivate, nsresult aStatus, uint32_t aLength, uint8_t* aResult) - : MainThreadWorkerRunnable(aWorkerPrivate, "ContinueConsumeBodyRunnable"), + : MainThreadWorkerRunnable("ContinueConsumeBodyRunnable"), mBodyConsumer(aBodyConsumer), mStatus(aStatus), mLength(aLength), @@ -97,7 +97,7 @@ class AbortConsumeBodyControlRunnable final public: AbortConsumeBodyControlRunnable(BodyConsumer* aBodyConsumer, WorkerPrivate* aWorkerPrivate) - : MainThreadWorkerControlRunnable(aWorkerPrivate), + : MainThreadWorkerControlRunnable("AbortConsumeBodyControlRunnable"), mBodyConsumer(aBodyConsumer) { MOZ_ASSERT(NS_IsMainThread()); } @@ -131,7 +131,7 @@ class MOZ_STACK_CLASS AutoFailConsumeBody final { RefPtr<AbortConsumeBodyControlRunnable> r = new AbortConsumeBodyControlRunnable(mBodyConsumer, mWorkerRef->Private()); - if (!r->Dispatch()) { + if (!r->Dispatch(mWorkerRef->Private())) { MOZ_CRASH("We are going to leak"); } return; @@ -159,8 +159,7 @@ class ContinueConsumeBlobBodyRunnable final : public MainThreadWorkerRunnable { ContinueConsumeBlobBodyRunnable(BodyConsumer* aBodyConsumer, WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl) - : MainThreadWorkerRunnable(aWorkerPrivate, - "ContinueConsumeBlobBodyRunnable"), + : MainThreadWorkerRunnable("ContinueConsumeBlobBodyRunnable"), mBodyConsumer(aBodyConsumer), mBlobImpl(aBlobImpl) { MOZ_ASSERT(NS_IsMainThread()); @@ -182,7 +181,7 @@ class AbortConsumeBlobBodyControlRunnable final public: AbortConsumeBlobBodyControlRunnable(BodyConsumer* aBodyConsumer, WorkerPrivate* aWorkerPrivate) - : MainThreadWorkerControlRunnable(aWorkerPrivate), + : MainThreadWorkerControlRunnable("AbortConsumeBlobBodyControlRunnable"), mBodyConsumer(aBodyConsumer) { MOZ_ASSERT(NS_IsMainThread()); } @@ -227,7 +226,7 @@ class ConsumeBodyDoneObserver final : public nsIStreamLoaderObserver, RefPtr<ContinueConsumeBodyRunnable> r = new ContinueConsumeBodyRunnable( mBodyConsumer, mWorkerRef->Private(), aStatus, aResultLength, nonconstResult); - if (r->Dispatch()) { + if (r->Dispatch(mWorkerRef->Private())) { // The caller is responsible for data. return NS_SUCCESS_ADOPTED_DATA; } @@ -239,7 +238,7 @@ class ConsumeBodyDoneObserver final : public nsIStreamLoaderObserver, RefPtr<AbortConsumeBodyControlRunnable> r = new AbortConsumeBodyControlRunnable(mBodyConsumer, mWorkerRef->Private()); - if (NS_WARN_IF(!r->Dispatch())) { + if (NS_WARN_IF(!r->Dispatch(mWorkerRef->Private()))) { return NS_ERROR_FAILURE; } @@ -620,14 +619,14 @@ void BodyConsumer::DispatchContinueConsumeBlobBody( new ContinueConsumeBlobBodyRunnable(this, aWorkerRef->Private(), aBlobImpl); - if (r->Dispatch()) { + if (r->Dispatch(aWorkerRef->Private())) { return; } } else { RefPtr<ContinueConsumeBodyRunnable> r = new ContinueConsumeBodyRunnable( this, aWorkerRef->Private(), NS_ERROR_DOM_ABORT_ERR, 0, nullptr); - if (r->Dispatch()) { + if (r->Dispatch(aWorkerRef->Private())) { return; } } @@ -638,7 +637,7 @@ void BodyConsumer::DispatchContinueConsumeBlobBody( RefPtr<AbortConsumeBlobBodyControlRunnable> r = new AbortConsumeBlobBodyControlRunnable(this, aWorkerRef->Private()); - Unused << NS_WARN_IF(!r->Dispatch()); + Unused << NS_WARN_IF(!r->Dispatch(aWorkerRef->Private())); } /* @@ -673,12 +672,14 @@ void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength, if (NS_WARN_IF(NS_FAILED(aStatus))) { // Per - // https://fetch.spec.whatwg.org/#concept-read-all-bytes-from-readablestream + // https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes // Decoding errors should reject with a TypeError if (aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) { localPromise->MaybeRejectWithTypeError<MSG_DOM_DECODING_FAILED>(); } else if (aStatus == NS_ERROR_DOM_WRONG_TYPE_ERR) { localPromise->MaybeRejectWithTypeError<MSG_FETCH_BODY_WRONG_TYPE>(); + } else if (aStatus == NS_ERROR_NET_PARTIAL_TRANSFER) { + localPromise->MaybeRejectWithTypeError<MSG_FETCH_PARTIAL>(); } else { localPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); } diff --git a/dom/base/ContentIterator.cpp b/dom/base/ContentIterator.cpp index 0b405f0348..80c795d137 100644 --- a/dom/base/ContentIterator.cpp +++ b/dom/base/ContentIterator.cpp @@ -715,7 +715,7 @@ nsIContent* ContentIteratorBase<NodeType>::GetNextSibling( // For shadow root, instead of getting to the sibling of the parent // directly, we need to get into the light tree of the parent to handle // slotted contents. - if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(aNode)) { + if (aNode->IsShadowRoot()) { if (nsIContent* child = parent->GetFirstChild()) { return child; } diff --git a/dom/base/CrossShadowBoundaryRange.cpp b/dom/base/CrossShadowBoundaryRange.cpp new file mode 100644 index 0000000000..33fa9760e6 --- /dev/null +++ b/dom/base/CrossShadowBoundaryRange.cpp @@ -0,0 +1,115 @@ +/* -*- 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 "mozilla/dom/CrossShadowBoundaryRange.h" +#include "nsContentUtils.h" +#include "nsINode.h" + +namespace mozilla::dom { +template already_AddRefed<CrossShadowBoundaryRange> +CrossShadowBoundaryRange::Create(const RangeBoundary& aStartBoundary, + const RangeBoundary& aEndBoundary); +template already_AddRefed<CrossShadowBoundaryRange> +CrossShadowBoundaryRange::Create(const RangeBoundary& aStartBoundary, + const RawRangeBoundary& aEndBoundary); +template already_AddRefed<CrossShadowBoundaryRange> +CrossShadowBoundaryRange::Create(const RawRangeBoundary& aStartBoundary, + const RangeBoundary& aEndBoundary); +template already_AddRefed<CrossShadowBoundaryRange> +CrossShadowBoundaryRange::Create(const RawRangeBoundary& aStartBoundary, + const RawRangeBoundary& aEndBoundary); + +template void CrossShadowBoundaryRange::DoSetRange( + const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, + nsINode* aRootNode); +template void CrossShadowBoundaryRange::DoSetRange( + const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary, + nsINode* aRootNode); +template void CrossShadowBoundaryRange::DoSetRange( + const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, + nsINode* aRootNode); +template void CrossShadowBoundaryRange::DoSetRange( + const RawRangeBoundary& aStartBoundary, + const RawRangeBoundary& aEndBoundary, nsINode* aRootNode); + +template nsresult CrossShadowBoundaryRange::SetStartAndEnd( + const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary); +template nsresult CrossShadowBoundaryRange::SetStartAndEnd( + const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary); +template nsresult CrossShadowBoundaryRange::SetStartAndEnd( + const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary); +template nsresult CrossShadowBoundaryRange::SetStartAndEnd( + const RawRangeBoundary& aStartBoundary, + const RawRangeBoundary& aEndBoundary); + +nsTArray<RefPtr<CrossShadowBoundaryRange>>* + CrossShadowBoundaryRange::sCachedRanges = nullptr; + +NS_IMPL_CYCLE_COLLECTING_ADDREF(CrossShadowBoundaryRange) + +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_INTERRUPTABLE_LAST_RELEASE( + CrossShadowBoundaryRange, + DoSetRange(RawRangeBoundary(), RawRangeBoundary(), nullptr), + AbstractRange::MaybeCacheToReuse(*this)) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CrossShadowBoundaryRange) +NS_INTERFACE_MAP_END_INHERITING(CrossShadowBoundaryRange) + +NS_IMPL_CYCLE_COLLECTION_CLASS(CrossShadowBoundaryRange) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CrossShadowBoundaryRange, + StaticRange) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommonAncestor) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CrossShadowBoundaryRange, + StaticRange) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommonAncestor) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(CrossShadowBoundaryRange, + StaticRange) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +/* static */ +template <typename SPT, typename SRT, typename EPT, typename ERT> +already_AddRefed<CrossShadowBoundaryRange> CrossShadowBoundaryRange::Create( + const RangeBoundaryBase<SPT, SRT>& aStartBoundary, + const RangeBoundaryBase<EPT, ERT>& aEndBoundary) { + RefPtr<CrossShadowBoundaryRange> range; + if (!sCachedRanges || sCachedRanges->IsEmpty()) { + range = new CrossShadowBoundaryRange(aStartBoundary.Container()); + } else { + range = sCachedRanges->PopLastElement().forget(); + } + + range->Init(aStartBoundary.Container()); + range->DoSetRange(aStartBoundary, aEndBoundary, nullptr); + return range.forget(); +} + +template <typename SPT, typename SRT, typename EPT, typename ERT> +void CrossShadowBoundaryRange::DoSetRange( + const RangeBoundaryBase<SPT, SRT>& aStartBoundary, + const RangeBoundaryBase<EPT, ERT>& aEndBoundary, nsINode* aRootNode) { + // aRootNode is useless to CrossShadowBoundaryRange because aStartBoundary + // and aEndBoundary could have different roots. + StaticRange::DoSetRange(aStartBoundary, aEndBoundary, nullptr); + + nsINode* startRoot = RangeUtils::ComputeRootNode(mStart.Container()); + nsINode* endRoot = RangeUtils::ComputeRootNode(mEnd.Container()); + + if (startRoot == endRoot) { + // This should be the case when Release() is called. + MOZ_ASSERT(!startRoot && !endRoot); + mCommonAncestor = startRoot; + } else { + mCommonAncestor = + nsContentUtils::GetClosestCommonShadowIncludingInclusiveAncestor( + mStart.Container(), mEnd.Container()); + } +} +} // namespace mozilla::dom diff --git a/dom/base/CrossShadowBoundaryRange.h b/dom/base/CrossShadowBoundaryRange.h new file mode 100644 index 0000000000..3ad4fa1793 --- /dev/null +++ b/dom/base/CrossShadowBoundaryRange.h @@ -0,0 +1,89 @@ +/* -*- 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_CrossShadowBoundaryRange_h +#define mozilla_dom_CrossShadowBoundaryRange_h + +#include "mozilla/RangeBoundary.h" +#include "mozilla/RangeUtils.h" +#include "mozilla/dom/AbstractRange.h" +#include "mozilla/dom/StaticRange.h" +#include "nsTArray.h" + +namespace mozilla { +class ErrorResult; + +namespace dom { + +class CrossShadowBoundaryRange final : public StaticRange { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_IMETHODIMP_(void) DeleteCycleCollectable(void) override; + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED( + CrossShadowBoundaryRange, StaticRange) + + CrossShadowBoundaryRange() = delete; + explicit CrossShadowBoundaryRange(const StaticRange& aOther) = delete; + + template <typename SPT, typename SRT, typename EPT, typename ERT> + static already_AddRefed<CrossShadowBoundaryRange> Create( + const RangeBoundaryBase<SPT, SRT>& aStartBoundary, + const RangeBoundaryBase<EPT, ERT>& aEndBoundary); + + void NotifyNodeBecomesShadowHost(nsINode* aNode) { + if (aNode == mStart.Container()) { + mStart.NotifyParentBecomesShadowHost(); + } + + if (aNode == mEnd.Container()) { + mEnd.NotifyParentBecomesShadowHost(); + } + } + + nsINode* GetCommonAncestor() const { return mCommonAncestor; } + + // CrossShadowBoundaryRange should have a very limited usage. + nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset, + nsINode* aEndContainer, uint32_t aEndOffset) = delete; + + template <typename SPT, typename SRT, typename EPT, typename ERT> + nsresult SetStartAndEnd(const RangeBoundaryBase<SPT, SRT>& aStartBoundary, + const RangeBoundaryBase<EPT, ERT>& aEndBoundary) { + return StaticRange::SetStartAndEnd(aStartBoundary, aEndBoundary); + } + + private: + explicit CrossShadowBoundaryRange(nsINode* aNode) : StaticRange(aNode) {} + virtual ~CrossShadowBoundaryRange() = default; + + /** + * DoSetRange() is called when `AbstractRange::SetStartAndEndInternal()` sets + * mStart and mEnd. + * + * @param aStartBoundary Computed start point. This must equals or be before + * aEndBoundary in the DOM tree order. + * @param aEndBoundary Computed end point. + * @param aRootNode The root node of aStartBoundary or aEndBoundary. + * It's useless to CrossShadowBoundaryRange. + */ + template <typename SPT, typename SRT, typename EPT, typename ERT> + void DoSetRange(const RangeBoundaryBase<SPT, SRT>& aStartBoundary, + const RangeBoundaryBase<EPT, ERT>& aEndBoundary, + nsINode* aRootNode); + + // This is either NULL if this CrossShadowBoundaryRange has been + // reset by Release() or the closest common shadow-including ancestor + // of mStart and mEnd. + nsCOMPtr<nsINode> mCommonAncestor; + + static nsTArray<RefPtr<CrossShadowBoundaryRange>>* sCachedRanges; + + friend class AbstractRange; +}; +} // namespace dom +} // namespace mozilla + +#endif // #ifndef mozilla_dom_CrossShadowBoundaryRange_h diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index 12f7ee3029..37d17ddcd3 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -323,7 +323,8 @@ static Maybe<nsRect> ComputeTheIntersection( // // `intersectionRect` is kept relative to `target` during the loop. auto inflowRect = nsLayoutUtils::GetAllInFlowRectsUnion( - target, target, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + target, target, + nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms); // For content-visibility, we need to observe the overflow clip edge, // https://drafts.csswg.org/css-contain-2/#close-to-the-viewport if (aIsForProximityToViewport == diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 8cbf8b8075..68e4100540 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -16423,47 +16423,33 @@ WindowContext* Document::GetWindowContextForPageUseCounters() const { return wc; } -void Document::UpdateIntersectionObservations(TimeStamp aNowTime) { - if (mIntersectionObservers.IsEmpty()) { - return; - } - - DOMHighResTimeStamp time = 0; - if (nsPIDOMWindowInner* win = GetInnerWindow()) { - if (Performance* perf = win->GetPerformance()) { - time = perf->TimeStampToDOMHighResForRendering(aNowTime); +void Document::UpdateIntersections(TimeStamp aNowTime) { + if (!mIntersectionObservers.IsEmpty()) { + DOMHighResTimeStamp time = 0; + if (nsPIDOMWindowInner* win = GetInnerWindow()) { + if (Performance* perf = win->GetPerformance()) { + time = perf->TimeStampToDOMHighResForRendering(aNowTime); + } } - } - - const auto observers = ToTArray<nsTArray<RefPtr<DOMIntersectionObserver>>>( - mIntersectionObservers); - for (const auto& observer : observers) { - if (observer) { + for (DOMIntersectionObserver* observer : mIntersectionObservers) { observer->Update(*this, time); } + Dispatch(NewRunnableMethod("Document::NotifyIntersectionObservers", this, + &Document::NotifyIntersectionObservers)); } -} - -void Document::ScheduleIntersectionObserverNotification() { - if (mIntersectionObservers.IsEmpty()) { - return; - } - MOZ_RELEASE_ASSERT(NS_IsMainThread()); - nsCOMPtr<nsIRunnable> notification = - NewRunnableMethod("Document::NotifyIntersectionObservers", this, - &Document::NotifyIntersectionObservers); - Dispatch(notification.forget()); + EnumerateSubDocuments([aNowTime](Document& aDoc) { + aDoc.UpdateIntersections(aNowTime); + return CallState::Continue; + }); } void Document::NotifyIntersectionObservers() { const auto observers = ToTArray<nsTArray<RefPtr<DOMIntersectionObserver>>>( mIntersectionObservers); for (const auto& observer : observers) { - if (observer) { - // MOZ_KnownLive because the 'observers' array guarantees to keep it - // alive. - MOZ_KnownLive(observer)->Notify(); - } + // MOZ_KnownLive because the 'observers' array guarantees to keep it + // alive. + MOZ_KnownLive(observer)->Notify(); } } @@ -18647,6 +18633,13 @@ nsICookieJarSettings* Document::CookieJarSettings() { if (!mCookieJarSettings) { Document* inProcessParent = GetInProcessParentDocument(); + auto shouldInheritFrom = [this](Document* aDoc) { + return aDoc && (this->NodePrincipal()->Equals(aDoc->NodePrincipal()) || + this->NodePrincipal()->GetIsNullPrincipal()); + }; + RefPtr<BrowsingContext> opener = + GetBrowsingContext() ? GetBrowsingContext()->GetOpener() : nullptr; + if (inProcessParent) { mCookieJarSettings = net::CookieJarSettings::Create( inProcessParent->CookieJarSettings()->GetCookieBehavior(), @@ -18674,6 +18667,18 @@ nsICookieJarSettings* Document::CookieJarSettings() { ->SetTopLevelWindowContextId( net::CookieJarSettings::Cast(inProcessParent->CookieJarSettings()) ->GetTopLevelWindowContextId()); + } else if (opener && shouldInheritFrom(opener->GetDocument())) { + mCookieJarSettings = net::CookieJarSettings::Create(NodePrincipal()); + + nsTArray<uint8_t> randomKey; + nsresult rv = opener->GetDocument() + ->CookieJarSettings() + ->GetFingerprintingRandomizationKey(randomKey); + + if (NS_SUCCEEDED(rv)) { + net::CookieJarSettings::Cast(mCookieJarSettings) + ->SetFingerprintingRandomizationKey(randomKey); + } } else { mCookieJarSettings = net::CookieJarSettings::Create(NodePrincipal()); @@ -18933,8 +18938,7 @@ void Document::AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement, } bool Document::ShouldAvoidNativeTheme() const { - return StaticPrefs::widget_non_native_theme_enabled() && - (!IsInChromeDocShell() || XRE_IsContentProcess()); + return !IsInChromeDocShell() || XRE_IsContentProcess(); } bool Document::UseRegularPrincipal() const { diff --git a/dom/base/Document.h b/dom/base/Document.h index 0b0d0ca3d0..e919f19be0 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -3709,8 +3709,9 @@ class Document : public nsINode, return !mIntersectionObservers.IsEmpty(); } - void UpdateIntersectionObservations(TimeStamp aNowTime); - void ScheduleIntersectionObserverNotification(); + // Update intersection observers in this document and all + // same-process subdocuments. + void UpdateIntersections(TimeStamp aNowTime); MOZ_CAN_RUN_SCRIPT void NotifyIntersectionObservers(); DOMIntersectionObserver* GetLazyLoadObserver() { return mLazyLoadObserver; } diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index b6f5d5c3be..758134990b 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1088,7 +1088,7 @@ already_AddRefed<DOMRectList> Element::GetClientRects() { nsLayoutUtils::RectListBuilder builder(rectList); nsLayoutUtils::GetAllInFlowRects( frame, nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder, - nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms); return rectList.forget(); } @@ -1353,7 +1353,7 @@ already_AddRefed<ShadowRoot> Element::AttachShadowWithoutNameChecks( for (const AbstractRange* range : *ranges) { if (range->MayCrossShadowBoundary()) { MOZ_ASSERT(range->IsDynamicRange()); - StaticRange* crossBoundaryRange = + CrossShadowBoundaryRange* crossBoundaryRange = range->AsDynamicRange()->GetCrossShadowBoundaryRange(); MOZ_ASSERT(crossBoundaryRange); // We may have previously selected this node before it diff --git a/dom/base/EventSource.cpp b/dom/base/EventSource.cpp index def3c90ec0..9e73f31fc6 100644 --- a/dom/base/EventSource.cpp +++ b/dom/base/EventSource.cpp @@ -1827,14 +1827,14 @@ nsresult EventSourceImpl::ParseCharacter(char16_t aChr) { namespace { -class WorkerRunnableDispatcher final : public WorkerRunnable { +class WorkerRunnableDispatcher final : public WorkerThreadRunnable { RefPtr<EventSourceImpl> mEventSourceImpl; public: WorkerRunnableDispatcher(RefPtr<EventSourceImpl>&& aImpl, WorkerPrivate* aWorkerPrivate, already_AddRefed<nsIRunnable> aEvent) - : WorkerRunnable(aWorkerPrivate, "WorkerRunnableDispatcher"), + : WorkerThreadRunnable("WorkerRunnableDispatcher"), mEventSourceImpl(std::move(aImpl)), mEvent(std::move(aEvent)) {} @@ -1928,7 +1928,7 @@ EventSourceImpl::Dispatch(already_AddRefed<nsIRunnable> aEvent, RefPtr<WorkerRunnableDispatcher> event = new WorkerRunnableDispatcher( this, mWorkerRef->Private(), event_ref.forget()); - if (!event->Dispatch()) { + if (!event->Dispatch(mWorkerRef->Private())) { return NS_ERROR_FAILURE; } return NS_OK; diff --git a/dom/base/FocusModel.h b/dom/base/FocusModel.h new file mode 100644 index 0000000000..588c0503a2 --- /dev/null +++ b/dom/base/FocusModel.h @@ -0,0 +1,41 @@ +/* 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_FocusModel_h +#define mozilla_FocusModel_h + +#include "mozilla/StaticPrefs_accessibility.h" +#include "mozilla/TypedEnumBits.h" + +namespace mozilla { + +enum class IsFocusableFlags : uint8_t { + WithMouse = 1 << 0, + // Whether to treat an invisible frame as not focusable + IgnoreVisibility = 1 << 1, +}; + +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(IsFocusableFlags); + +enum class TabFocusableType : uint8_t { + TextControls = 1, // Textboxes and lists always tabbable + FormElements = 1 << 1, // Non-text form elements + Links = 1 << 2, // Links + Any = TextControls | FormElements | Links, +}; + +class FocusModel final { + public: + static bool AppliesToXUL() { + return StaticPrefs::accessibility_tabfocus_applies_to_xul(); + } + + static bool IsTabFocusable(TabFocusableType aType) { + return StaticPrefs::accessibility_tabfocus() & int32_t(aType); + } +}; + +} // namespace mozilla + +#endif diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 87fd81bfa3..8338fc6b9e 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -105,8 +105,6 @@ using namespace mozilla; using namespace mozilla::dom; -int32_t nsIContent::sTabFocusModel = eTabFocus_any; -bool nsIContent::sTabFocusModelAppliesToXUL = false; uint64_t nsMutationGuard::sGeneration = 0; NS_IMPL_CYCLE_COLLECTION_CLASS(nsIContent) @@ -1022,7 +1020,7 @@ void nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor) { } } -Element* nsIContent::GetAutofocusDelegate(bool aWithMouse) const { +Element* nsIContent::GetAutofocusDelegate(IsFocusableFlags aFlags) const { for (nsINode* node = GetFirstChild(); node; node = node->GetNextNode(this)) { auto* descendant = Element::FromNode(*node); if (!descendant || !descendant->GetBoolAttr(nsGkAtoms::autofocus)) { @@ -1030,14 +1028,14 @@ Element* nsIContent::GetAutofocusDelegate(bool aWithMouse) const { } nsIFrame* frame = descendant->GetPrimaryFrame(); - if (frame && frame->IsFocusable(aWithMouse)) { + if (frame && frame->IsFocusable(aFlags)) { return descendant; } } return nullptr; } -Element* nsIContent::GetFocusDelegate(bool aWithMouse) const { +Element* nsIContent::GetFocusDelegate(IsFocusableFlags aFlags) const { const nsIContent* whereToLook = this; if (ShadowRoot* root = GetShadowRoot()) { if (!root->DelegatesFocus()) { @@ -1055,7 +1053,7 @@ Element* nsIContent::GetFocusDelegate(bool aWithMouse) const { return {}; } - return frame->IsFocusable(aWithMouse); + return frame->IsFocusable(aFlags); }; Element* potentialFocus = nullptr; @@ -1097,7 +1095,7 @@ Element* nsIContent::GetFocusDelegate(bool aWithMouse) const { if (auto* shadow = el->GetShadowRoot()) { if (shadow->DelegatesFocus()) { - if (Element* delegatedFocus = shadow->GetFocusDelegate(aWithMouse)) { + if (Element* delegatedFocus = shadow->GetFocusDelegate(aFlags)) { if (autofocus) { // This element has autofocus and we found an focus delegates // in its descendants, so use the focus delegates @@ -1114,7 +1112,7 @@ Element* nsIContent::GetFocusDelegate(bool aWithMouse) const { return potentialFocus; } -Focusable nsIContent::IsFocusableWithoutStyle(bool aWithMouse) { +Focusable nsIContent::IsFocusableWithoutStyle(IsFocusableFlags) { // Default, not tabbable return {}; } diff --git a/dom/base/Highlight.cpp b/dom/base/Highlight.cpp index cd0efccce5..0bac8193d7 100644 --- a/dom/base/Highlight.cpp +++ b/dom/base/Highlight.cpp @@ -101,24 +101,36 @@ already_AddRefed<Selection> Highlight::CreateHighlightSelection( } void Highlight::Add(AbstractRange& aRange, ErrorResult& aRv) { + // Manually check if the range `aKey` is already present in this highlight, + // because `SetlikeHelpers::Add()` doesn't indicate this. + // To keep the setlike and the mirrored array in sync, the range must not + // be added to `mRanges` if it was already present. + // `SetlikeHelpers::Has()` is much faster in checking this than + // `nsTArray<>::Contains()`. + if (Highlight_Binding::SetlikeHelpers::Has(this, aRange, aRv) || + aRv.Failed()) { + return; + } Highlight_Binding::SetlikeHelpers::Add(this, aRange, aRv); if (aRv.Failed()) { return; } - if (!mRanges.Contains(&aRange)) { - mRanges.AppendElement(&aRange); - AutoFrameSelectionBatcher selectionBatcher(__FUNCTION__, - mHighlightRegistries.Count()); - for (const RefPtr<HighlightRegistry>& registry : - mHighlightRegistries.Keys()) { - auto frameSelection = registry->GetFrameSelection(); - selectionBatcher.AddFrameSelection(frameSelection); - // since this is run in a context guarded by a selection batcher, - // no strong reference is needed to keep `registry` alive. - MOZ_KnownLive(registry)->MaybeAddRangeToHighlightSelection(aRange, *this); - if (aRv.Failed()) { - return; - } + + MOZ_ASSERT(!mRanges.Contains(&aRange), + "setlike and DOM mirror are not in sync"); + + mRanges.AppendElement(&aRange); + AutoFrameSelectionBatcher selectionBatcher(__FUNCTION__, + mHighlightRegistries.Count()); + for (const RefPtr<HighlightRegistry>& registry : + mHighlightRegistries.Keys()) { + auto frameSelection = registry->GetFrameSelection(); + selectionBatcher.AddFrameSelection(frameSelection); + // since this is run in a context guarded by a selection batcher, + // no strong reference is needed to keep `registry` alive. + MOZ_KnownLive(registry)->MaybeAddRangeToHighlightSelection(aRange, *this); + if (aRv.Failed()) { + return; } } } diff --git a/dom/base/HighlightRegistry.cpp b/dom/base/HighlightRegistry.cpp index 035aadb78a..755977286f 100644 --- a/dom/base/HighlightRegistry.cpp +++ b/dom/base/HighlightRegistry.cpp @@ -133,18 +133,28 @@ void HighlightRegistry::AddHighlightSelectionsToFrameSelection() { void HighlightRegistry::Set(const nsAString& aKey, Highlight& aValue, ErrorResult& aRv) { + // manually check if the highlight `aKey` is already registered to be able to + // provide a fast path later that avoids calling `std::find_if()`. + const bool highlightAlreadyPresent = + HighlightRegistry_Binding::MaplikeHelpers::Has(this, aKey, aRv); + if (aRv.Failed()) { + return; + } HighlightRegistry_Binding::MaplikeHelpers::Set(this, aKey, aValue, aRv); if (aRv.Failed()) { return; } RefPtr<nsFrameSelection> frameSelection = GetFrameSelection(); RefPtr<nsAtom> highlightNameAtom = NS_AtomizeMainThread(aKey); - auto foundIter = - std::find_if(mHighlightsOrdered.begin(), mHighlightsOrdered.end(), - [&highlightNameAtom](auto const& aElm) { - return aElm.first() == highlightNameAtom; - }); - if (foundIter != mHighlightsOrdered.end()) { + if (highlightAlreadyPresent) { + // If the highlight named `aKey` was present before, replace its value. + auto foundIter = + std::find_if(mHighlightsOrdered.begin(), mHighlightsOrdered.end(), + [&highlightNameAtom](auto const& aElm) { + return aElm.first() == highlightNameAtom; + }); + MOZ_ASSERT(foundIter != mHighlightsOrdered.end(), + "webIDL maplike and DOM mirror are not in sync"); foundIter->second()->RemoveFromHighlightRegistry(*this, *highlightNameAtom); if (frameSelection) { frameSelection->RemoveHighlightSelection(highlightNameAtom); diff --git a/dom/base/MimeType.cpp b/dom/base/MimeType.cpp index da61489c1f..1e6d6a7cd4 100644 --- a/dom/base/MimeType.cpp +++ b/dom/base/MimeType.cpp @@ -328,13 +328,13 @@ template <typename char_type> template <typename char_type> void TMimeType<char_type>::Serialize(nsTSubstring<char_type>& aOutput) const { aOutput.Assign(mType); - aOutput.AppendLiteral("/"); + aOutput.Append('/'); aOutput.Append(mSubtype); for (uint32_t i = 0; i < mParameterNames.Length(); i++) { auto name = mParameterNames[i]; - aOutput.AppendLiteral(";"); + aOutput.Append(';'); aOutput.Append(name); - aOutput.AppendLiteral("="); + aOutput.Append('='); GetParameterValue(name, aOutput, true); } } @@ -342,7 +342,7 @@ void TMimeType<char_type>::Serialize(nsTSubstring<char_type>& aOutput) const { template <typename char_type> void TMimeType<char_type>::GetEssence(nsTSubstring<char_type>& aOutput) const { aOutput.Assign(mType); - aOutput.AppendLiteral("/"); + aOutput.Append('/'); aOutput.Append(mSubtype); } @@ -366,17 +366,17 @@ bool TMimeType<char_type>::GetParameterValue( } if (aWithQuotes && (value.mRequiresQuoting || value.IsEmpty())) { - aOutput.AppendLiteral("\""); + aOutput.Append('"'); const char_type* vcur = value.BeginReading(); const char_type* vend = value.EndReading(); while (vcur < vend) { if (*vcur == '"' || *vcur == '\\') { - aOutput.AppendLiteral("\\"); + aOutput.Append('\\'); } aOutput.Append(*vcur); vcur++; } - aOutput.AppendLiteral("\""); + aOutput.Append('"'); } else { aOutput.Append(value); } diff --git a/dom/base/RadioGroupContainer.cpp b/dom/base/RadioGroupContainer.cpp index 3bb4d7da20..988c8186f9 100644 --- a/dom/base/RadioGroupContainer.cpp +++ b/dom/base/RadioGroupContainer.cpp @@ -8,6 +8,7 @@ #include "mozilla/dom/RadioGroupContainer.h" #include "mozilla/dom/TreeOrderedArrayInlines.h" #include "mozilla/Assertions.h" +#include "nsIFrame.h" #include "nsIRadioVisitor.h" #include "nsRadioVisitor.h" @@ -125,7 +126,9 @@ nsresult RadioGroupContainer::GetNextRadioButton( index = 0; } radio = radioGroup->mRadioButtons->ElementAt(index); - } while (radio->Disabled() && radio != currentRadio); + } while ((radio->Disabled() || !radio->GetPrimaryFrame() || + !radio->GetPrimaryFrame()->IsVisibleConsideringAncestors()) && + radio != currentRadio); radio.forget(aRadioOut); return NS_OK; @@ -135,7 +138,8 @@ HTMLInputElement* RadioGroupContainer::GetFirstRadioButton( const nsAString& aName) { nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); for (HTMLInputElement* radio : radioGroup->mRadioButtons.AsList()) { - if (!radio->Disabled()) { + if (!radio->Disabled() && radio->GetPrimaryFrame() && + radio->GetPrimaryFrame()->IsVisibleConsideringAncestors()) { return radio; } } diff --git a/dom/base/ResizeObserver.h b/dom/base/ResizeObserver.h index eaa0e1726d..2fd630c66c 100644 --- a/dom/base/ResizeObserver.h +++ b/dom/base/ResizeObserver.h @@ -121,7 +121,6 @@ class ResizeObservation final : public LinkedListElement<ResizeObservation> { * https://drafts.csswg.org/resize-observer/#api */ class ResizeObserver final : public nsISupports, public nsWrapperCache { - public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ResizeObserver) diff --git a/dom/base/Selection.h b/dom/base/Selection.h index 08563993ac..101bada49f 100644 --- a/dom/base/Selection.h +++ b/dom/base/Selection.h @@ -386,6 +386,30 @@ class Selection final : public nsSupportsWeakReference, return mStyledRanges.mRanges[0].mRange->Collapsed(); } + // Returns whether both normal range and cross-shadow-boundary + // range are collapsed. + // + // If StaticPrefs::dom_shadowdom_selection_across_boundary_enabled is + // disabled, this method always returns result as nsRange::IsCollapsed. + bool AreNormalAndCrossShadowBoundaryRangesCollapsed() const { + if (!IsCollapsed()) { + return false; + } + + size_t cnt = mStyledRanges.Length(); + if (cnt == 0) { + return true; + } + + AbstractRange* range = mStyledRanges.mRanges[0].mRange; + MOZ_ASSERT_IF( + range->MayCrossShadowBoundary(), + !range->AsDynamicRange()->CrossShadowBoundaryRangeCollapsed()); + // Returns false if nsRange::mCrossBoundaryRange exists, + // true otherwise. + return !range->MayCrossShadowBoundary(); + } + // *JS() methods are mapped to Selection.*(). // They may move focus only when the range represents normal selection. // These methods shouldn't be used by non-JS callers. diff --git a/dom/base/StaticRange.h b/dom/base/StaticRange.h index af7054f843..249c938b2f 100644 --- a/dom/base/StaticRange.h +++ b/dom/base/StaticRange.h @@ -19,7 +19,7 @@ class ErrorResult; namespace dom { -class StaticRange final : public AbstractRange { +class StaticRange : public AbstractRange { public: StaticRange() = delete; explicit StaticRange(const StaticRange& aOther) = delete; @@ -71,16 +71,6 @@ class StaticRange final : public AbstractRange { */ bool IsValid() const; - void NotifyNodeBecomesShadowHost(nsINode* aNode) { - if (aNode == mStart.Container()) { - mStart.NotifyParentBecomesShadowHost(); - } - - if (aNode == mEnd.Container()) { - mEnd.NotifyParentBecomesShadowHost(); - } - } - private: // Whether the start and end points are in the same tree. // They could be in different trees, i.e, cross shadow boundaries. diff --git a/dom/base/crashtests/1419902.html b/dom/base/crashtests/1419902.html index b0742b5be0..a0aa1b0698 100644 --- a/dom/base/crashtests/1419902.html +++ b/dom/base/crashtests/1419902.html @@ -1,23 +1 @@ -<html> - <head> - <script> - var winsToClose = [] - onbeforeunload = function() { - for (let win of winsToClose) { - if (win) { - win.close(); - } - } - }; - for (let i = 0; i < 38; i++) { - customElements.define("custom-element_0", class extends HTMLElement { - constructor() { - try { o1 = document.createElement("custom-element_0") } catch (e) {} - try { winsToClose.push(window.open("javascript:'<html><body>dummy</body></html>';")); } catch (e) {} - } - }) - try { o3 = document.createElement("custom-element_0") } catch (e) {} - } - </script> - </head> -</html> +<!-- file is now located at testing/crashtest/final/dom/base/crashtests/1419902.html --> diff --git a/dom/base/crashtests/1741957.html b/dom/base/crashtests/1741957.html new file mode 100644 index 0000000000..56b695052e --- /dev/null +++ b/dom/base/crashtests/1741957.html @@ -0,0 +1,22 @@ +<html><head><style> +:root { + column-width: 0px; +} +* { + height: 0; +} +</style> +<script> +function go() { + document.execCommand("selectAll", false) + a.appendChild(b) +} +</script> +<link href="moz-extension://1abf2dce-edd2-4c86-b0c5-2eeeaa9386d5/css/content.css" rel="stylesheet" type="text/css"></head><body onload="go()"> + +<button> +<font dir="rtl">x</font> +<animatetransform id="a"> +<textarea id="b">x</textarea></animatetransform></button> +<!-- x --> +</body><div></div></html> diff --git a/dom/base/crashtests/crashtests.list b/dom/base/crashtests/crashtests.list index 22aaf50e6b..7aa5e6a92a 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(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 1419902.html # this test is run at the very end in testing/crashtest/final/crashtests.list load 1422883.html load 1428053.html load 1441029.html @@ -265,6 +265,7 @@ load 1757923.html load 1766472.html pref(dom.enable_web_task_scheduling,true) load 1780790.html load 1700237.html +load 1741957.html load 1811939.html load 1822717.html load 1835886.html diff --git a/dom/base/fragmentdirectives/lib.rs b/dom/base/fragmentdirectives/lib.rs index 0003849eb7..5f9d5ebdd8 100644 --- a/dom/base/fragmentdirectives/lib.rs +++ b/dom/base/fragmentdirectives/lib.rs @@ -96,9 +96,7 @@ pub extern "C" fn parse_fragment_directive( &url_as_rust_string, ) { - result - .url_without_fragment_directive - .assign(&stripped_url); + result.url_without_fragment_directive.assign(&stripped_url); result.fragment_directive.assign(&fragment_directive); result.text_directives.extend( text_directives diff --git a/dom/base/fragmentdirectives/test.rs b/dom/base/fragmentdirectives/test.rs index d4509cb033..e5479d8022 100644 --- a/dom/base/fragmentdirectives/test.rs +++ b/dom/base/fragmentdirectives/test.rs @@ -145,13 +145,16 @@ mod test { ), ( "http://example.com/page.html?query=irrelevant:~:#bar:~:text=foo", - "http://example.com/page.html?query=irrelevant:~:#bar" - ) + "http://example.com/page.html?query=irrelevant:~:#bar", + ), ] { let (stripped_url, fragment_directive, _) = parse_fragment_directive_and_remove_it_from_hash(&url) .expect("The parser must find a result"); - assert_eq!(stripped_url, stripped_url_ref, "The stripped url is not correct."); + assert_eq!( + stripped_url, stripped_url_ref, + "The stripped url is not correct." + ); assert_eq!(fragment_directive, "text=foo"); } } @@ -195,9 +198,8 @@ mod test { #[test] fn test_parse_multiple_text_fragments() { let url = "#:~:text=prefix-,start,-suffix&text=foo&text=bar,-suffix"; - let (_, _, text_directives) = - parse_fragment_directive_and_remove_it_from_hash(&url) - .expect("The parser must find a result."); + let (_, _, text_directives) = parse_fragment_directive_and_remove_it_from_hash(&url) + .expect("The parser must find a result."); assert_eq!( text_directives.len(), 3, @@ -339,8 +341,7 @@ mod test { "text=prefix-,start", "#:~:text=foo-,bar,-baz:~:text=foo", ] { - let text_directives = - parse_fragment_directive_and_remove_it_from_hash(&url); + let text_directives = parse_fragment_directive_and_remove_it_from_hash(&url); assert!( text_directives.is_none(), "The fragment `{}` does not contain a valid or known fragment directive.", @@ -369,8 +370,7 @@ mod test { "#:~:text=,prefix,start", "#:~:text=", ] { - let text_directives = - parse_fragment_directive_and_remove_it_from_hash(&url); + let text_directives = parse_fragment_directive_and_remove_it_from_hash(&url); assert!( text_directives.is_none(), "The fragment directive `{}` does not contain a valid text directive.", diff --git a/dom/base/moz.build b/dom/base/moz.build index ffcfb0aaf6..e2cf2dfb78 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -126,6 +126,7 @@ EXPORTS.mozilla += [ "ContentIterator.h", "CORSMode.h", "FlushType.h", + "FocusModel.h", "FullscreenChange.h", "GlobalTeardownObserver.h", "IdentifierMapEntry.h", @@ -166,6 +167,7 @@ EXPORTS.mozilla.dom += [ "CompressionStream.h", "ContentFrameMessageManager.h", "ContentProcessMessageManager.h", + "CrossShadowBoundaryRange.h", "CustomElementRegistry.h", "DecompressionStream.h", "DirectionalityUtils.h", @@ -336,6 +338,7 @@ UNIFIED_SOURCES += [ "ContentFrameMessageManager.cpp", "ContentIterator.cpp", "ContentProcessMessageManager.cpp", + "CrossShadowBoundaryRange.cpp", "Crypto.cpp", "CustomElementRegistry.cpp", "DirectionalityUtils.cpp", diff --git a/dom/base/nsAttrValue.cpp b/dom/base/nsAttrValue.cpp index 01efef2eb9..e4bf977f56 100644 --- a/dom/base/nsAttrValue.cpp +++ b/dom/base/nsAttrValue.cpp @@ -141,7 +141,7 @@ bool MiscContainer::GetString(nsAString& aString) const { } if (isString) { auto* buffer = static_cast<nsStringBuffer*>(ptr); - buffer->ToString(buffer->StorageSize() / sizeof(char16_t) - 1, aString); + aString.Assign(buffer, buffer->StorageSize() / sizeof(char16_t) - 1); } else { static_cast<nsAtom*>(ptr)->ToString(aString); } @@ -280,11 +280,9 @@ void nsAttrValue::Shutdown() { void nsAttrValue::Reset() { switch (BaseType()) { case eStringBase: { - nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); - if (str) { + if (auto* str = static_cast<nsStringBuffer*>(GetPtr())) { str->Release(); } - break; } case eOtherBase: { @@ -320,8 +318,7 @@ void nsAttrValue::SetTo(const nsAttrValue& aOther) { switch (aOther.BaseType()) { case eStringBase: { ResetIfSet(); - nsStringBuffer* str = static_cast<nsStringBuffer*>(aOther.GetPtr()); - if (str) { + if (auto* str = static_cast<nsStringBuffer*>(aOther.GetPtr())) { str->AddRef(); SetPtrValueAndType(str, eStringBase); } @@ -623,18 +620,16 @@ void nsAttrValue::ToString(nsAString& aResult) const { switch (Type()) { case eString: { - nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); - if (str) { - str->ToString(str->StorageSize() / sizeof(char16_t) - 1, aResult); + if (auto* str = static_cast<nsStringBuffer*>(GetPtr())) { + aResult.Assign(str, str->StorageSize() / sizeof(char16_t) - 1); } else { aResult.Truncate(); } break; } case eAtom: { - nsAtom* atom = static_cast<nsAtom*>(GetPtr()); + auto* atom = static_cast<nsAtom*>(GetPtr()); atom->ToString(aResult); - break; } case eInteger: { @@ -895,8 +890,7 @@ nsAtom* nsAttrValue::AtomAt(int32_t aIndex) const { uint32_t nsAttrValue::HashValue() const { switch (BaseType()) { case eStringBase: { - nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); - if (str) { + if (auto* str = static_cast<nsStringBuffer*>(GetPtr())) { uint32_t len = str->StorageSize() / sizeof(char16_t) - 1; return HashString(static_cast<char16_t*>(str->Data()), len); } @@ -1208,8 +1202,7 @@ bool nsAttrValue::SubstringCheck(const nsAString& aValue, nsCaseTreatment aCaseSensitive) const { switch (BaseType()) { case eStringBase: { - auto str = static_cast<nsStringBuffer*>(GetPtr()); - if (str) { + if (auto* str = static_cast<nsStringBuffer*>(GetPtr())) { return F::Check(static_cast<char16_t*>(str->Data()), str->StorageSize() / sizeof(char16_t) - 1, aValue, aCaseSensitive); @@ -1217,7 +1210,7 @@ bool nsAttrValue::SubstringCheck(const nsAString& aValue, return aValue.IsEmpty(); } case eAtomBase: { - auto atom = static_cast<nsAtom*>(GetPtr()); + auto* atom = static_cast<nsAtom*>(GetPtr()); return F::Check(atom->GetUTF16String(), atom->GetLength(), aValue, aCaseSensitive); } @@ -2107,12 +2100,11 @@ already_AddRefed<nsStringBuffer> nsAttrValue::GetStringBuffer( if (!len) { return nullptr; } - - RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aValue); - if (buf && (buf->StorageSize() / sizeof(char16_t) - 1) == len) { + if (nsStringBuffer* buf = aValue.GetStringBuffer(); + buf && (buf->StorageSize() / sizeof(char16_t) - 1) == len) { // We can only reuse the buffer if it's exactly sized, since we rely on // StorageSize() to get the string length in ToString(). - return buf.forget(); + return do_AddRef(buf); } return nsStringBuffer::Create(aValue.Data(), aValue.Length()); } diff --git a/dom/base/nsAttrValue.h b/dom/base/nsAttrValue.h index 4ef63c287f..b32dfc98fb 100644 --- a/dom/base/nsAttrValue.h +++ b/dom/base/nsAttrValue.h @@ -108,7 +108,9 @@ const uintptr_t NS_ATTRVALUE_BASETYPE_MASK = 3; class nsCheapString : public nsString { public: explicit nsCheapString(nsStringBuffer* aBuf) { - if (aBuf) aBuf->ToString(aBuf->StorageSize() / sizeof(char16_t) - 1, *this); + if (aBuf) { + Assign(aBuf, aBuf->StorageSize() / sizeof(char16_t) - 1); + } } }; diff --git a/dom/base/nsContentAreaDragDrop.cpp b/dom/base/nsContentAreaDragDrop.cpp index 3ca21e725a..b2ccc8cb1c 100644 --- a/dom/base/nsContentAreaDragDrop.cpp +++ b/dom/base/nsContentAreaDragDrop.cpp @@ -295,7 +295,7 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable* aTransferable, bool isPrivate = aTransferable->GetIsPrivateData(); - nsCOMPtr<nsIPrincipal> principal = aTransferable->GetRequestingPrincipal(); + nsCOMPtr<nsIPrincipal> principal = aTransferable->GetDataPrincipal(); nsContentPolicyType contentPolicyType = aTransferable->GetContentPolicyType(); nsCOMPtr<nsICookieJarSettings> cookieJarSettings = diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index d2c863bd65..e4f4fadf9c 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -3011,6 +3011,18 @@ nsINode* nsContentUtils::GetCommonAncestorHelper(nsINode* aNode1, } /* static */ +nsINode* nsContentUtils::GetClosestCommonShadowIncludingInclusiveAncestor( + nsINode* aNode1, nsINode* aNode2) { + if (aNode1 == aNode2) { + return aNode1; + } + + return GetCommonAncestorInternal(aNode1, aNode2, [](nsINode* aNode) { + return aNode->GetParentOrShadowHostNode(); + }); +} + +/* static */ nsIContent* nsContentUtils::GetCommonFlattenedTreeAncestorHelper( nsIContent* aContent1, nsIContent* aContent2) { return GetCommonAncestorInternal( @@ -6998,25 +7010,6 @@ bool nsContentUtils::PlatformToDOMLineBreaks(nsString& aString, return true; } -void nsContentUtils::PopulateStringFromStringBuffer(nsStringBuffer* aBuf, - nsAString& aResultString) { - MOZ_ASSERT(aBuf, "Expecting a non-null string buffer"); - - uint32_t stringLen = NS_strlen(static_cast<char16_t*>(aBuf->Data())); - - // SANITY CHECK: In case the nsStringBuffer isn't correctly - // null-terminated, let's clamp its length using the allocated size, to be - // sure the resulting string doesn't sample past the end of the the buffer. - // (Note that StorageSize() is in units of bytes, so we have to convert that - // to units of PRUnichars, and subtract 1 for the null-terminator.) - uint32_t allocStringLen = (aBuf->StorageSize() / sizeof(char16_t)) - 1; - MOZ_ASSERT(stringLen <= allocStringLen, - "string buffer lacks null terminator!"); - stringLen = std::min(stringLen, allocStringLen); - - aBuf->ToString(stringLen, aResultString); -} - already_AddRefed<nsContentList> nsContentUtils::GetElementsByClassName( nsINode* aRootNode, const nsAString& aClasses) { MOZ_ASSERT(aRootNode, "Must have root node"); @@ -7442,8 +7435,12 @@ int32_t nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame, // static bool nsContentUtils::IsPointInSelection( const mozilla::dom::Selection& aSelection, const nsINode& aNode, - const uint32_t aOffset) { - if (aSelection.IsCollapsed()) { + const uint32_t aOffset, const bool aAllowCrossShadowBoundary) { + const bool selectionIsCollapsed = + !aAllowCrossShadowBoundary + ? aSelection.IsCollapsed() + : aSelection.AreNormalAndCrossShadowBoundaryRangesCollapsed(); + if (selectionIsCollapsed) { return false; } @@ -7457,7 +7454,8 @@ bool nsContentUtils::IsPointInSelection( } // Done when we find a range that we are in - if (range->IsPointInRange(aNode, aOffset, IgnoreErrors())) { + if (range->IsPointInRange(aNode, aOffset, IgnoreErrors(), + aAllowCrossShadowBoundary)) { return true; } } @@ -8211,7 +8209,7 @@ nsresult nsContentUtils::IPCTransferableToTransferable( aTransferable->SetCookieJarSettings(cookieJarSettings); } aTransferable->SetReferrerInfo(aIPCTransferable.referrerInfo()); - aTransferable->SetRequestingPrincipal(aIPCTransferable.requestingPrincipal()); + aTransferable->SetDataPrincipal(aIPCTransferable.dataPrincipal()); aTransferable->SetContentPolicyType(aIPCTransferable.contentPolicyType()); return NS_OK; @@ -8302,7 +8300,7 @@ nsresult nsContentUtils::CalculateBufferSizeForImage( } static already_AddRefed<DataSourceSurface> BigBufferToDataSurface( - BigBuffer& aData, uint32_t aStride, const IntSize& aImageSize, + const BigBuffer& aData, uint32_t aStride, const IntSize& aImageSize, SurfaceFormat aFormat) { if (!aData.Size() || !aImageSize.width || !aImageSize.height) { return nullptr; @@ -8325,22 +8323,13 @@ static already_AddRefed<DataSourceSurface> BigBufferToDataSurface( nsresult nsContentUtils::DeserializeTransferableDataImageContainer( const IPCTransferableDataImageContainer& aData, imgIContainer** aContainer) { - const IntSize size(aData.width(), aData.height()); - size_t maxBufferSize = 0; - size_t usedBufferSize = 0; - nsresult rv = CalculateBufferSizeForImage( - aData.stride(), size, aData.format(), &maxBufferSize, &usedBufferSize); - NS_ENSURE_SUCCESS(rv, rv); - if (usedBufferSize > aData.data().Size()) { - return NS_ERROR_FAILURE; - } - RefPtr<DataSourceSurface> surface = - CreateDataSourceSurfaceFromData(size, aData.format(), aData.data().Data(), - static_cast<int32_t>(aData.stride())); + RefPtr<DataSourceSurface> surface = IPCImageToSurface(aData.image()); if (!surface) { return NS_ERROR_FAILURE; } - RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(surface, size); + + RefPtr<gfxDrawable> drawable = + new gfxSurfaceDrawable(surface, surface->GetSize()); nsCOMPtr<imgIContainer> imageContainer = image::ImageOps::CreateFromDrawable(drawable); imageContainer.forget(aContainer); @@ -8472,23 +8461,16 @@ void nsContentUtils::TransferableToIPCTransferableData( if (!dataSurface) { continue; } - size_t length; - int32_t stride; - Maybe<BigBuffer> surfaceData = - GetSurfaceData(*dataSurface, &length, &stride); - if (surfaceData.isNothing()) { + auto imageData = nsContentUtils::SurfaceToIPCImage(*dataSurface); + if (!imageData) { continue; } IPCTransferableDataItem* item = aTransferableData->items().AppendElement(); item->flavor() = flavorStr; - - mozilla::gfx::IntSize size = dataSurface->GetSize(); - item->data() = IPCTransferableDataImageContainer( - std::move(*surfaceData), size.width, size.height, stride, - dataSurface->GetFormat()); + item->data() = IPCTransferableDataImageContainer(std::move(*imageData)); continue; } @@ -8569,8 +8551,7 @@ void nsContentUtils::TransferableToIPCTransferable( aIPCTransferable->data() = std::move(ipcTransferableData); aIPCTransferable->isPrivateData() = aTransferable->GetIsPrivateData(); - aIPCTransferable->requestingPrincipal() = - aTransferable->GetRequestingPrincipal(); + aIPCTransferable->dataPrincipal() = aTransferable->GetDataPrincipal(); aIPCTransferable->cookieJarSettings() = std::move(cookieJarSettingsArgs); aIPCTransferable->contentPolicyType() = aTransferable->GetContentPolicyType(); aIPCTransferable->referrerInfo() = aTransferable->GetReferrerInfo(); @@ -8617,7 +8598,7 @@ Maybe<IPCImage> nsContentUtils::SurfaceToIPCImage(DataSourceSurface& aSurface) { } already_AddRefed<DataSourceSurface> nsContentUtils::IPCImageToSurface( - IPCImage&& aImage) { + const IPCImage& aImage) { return BigBufferToDataSurface(aImage.data(), aImage.stride(), aImage.size().ToUnknownSize(), aImage.format()); } diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 4291d2c5d1..a1f466fa8d 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -115,7 +115,6 @@ class nsNodeInfoManager; class nsParser; class nsPIWindowRoot; class nsPresContext; -class nsStringBuffer; class nsTextFragment; class nsView; class nsWrapperCache; @@ -501,6 +500,9 @@ class nsContentUtils { return GetCommonAncestorHelper(aNode1, aNode2); } + static nsINode* GetClosestCommonShadowIncludingInclusiveAncestor( + nsINode* aNode1, nsINode* aNode2); + /** * Returns the common flattened tree ancestor, if any, for two given content * nodes. @@ -2443,14 +2445,6 @@ class nsContentUtils { [[nodiscard]] static bool PlatformToDOMLineBreaks(nsString& aString, const mozilla::fallible_t&); - /** - * Populates aResultString with the contents of the string-buffer aBuf, up - * to aBuf's null-terminator. aBuf must not be null. Ownership of the string - * is not transferred. - */ - static void PopulateStringFromStringBuffer(nsStringBuffer* aBuf, - nsAString& aResultString); - static bool IsHandlingKeyBoardEvent() { return sIsHandlingKeyBoardEvent; } static void SetIsHandlingKeyBoardEvent(bool aHandling) { @@ -2778,9 +2772,13 @@ class nsContentUtils { * check. aNode and aOffset can be computed with * UIEvent::GetRangeParentContentAndOffset() if you want to * check the click point. + * @param aAllowCrossShadowBoundary If true, this method allows the selection + * to have boundaries that cross shadow + * boundaries. */ static bool IsPointInSelection(const mozilla::dom::Selection& aSelection, - const nsINode& aNode, const uint32_t aOffset); + const nsINode& aNode, const uint32_t aOffset, + const bool aAllowCrossShadowBoundary = false); /** * Takes a selection, and a text control element (<input> or <textarea>), and @@ -3041,7 +3039,7 @@ class nsContentUtils { static mozilla::Maybe<mozilla::dom::IPCImage> SurfaceToIPCImage( mozilla::gfx::DataSourceSurface&); static already_AddRefed<mozilla::gfx::DataSourceSurface> IPCImageToSurface( - mozilla::dom::IPCImage&&); + const mozilla::dom::IPCImage&); // Helpers shared by the implementations of nsContentUtils methods and // nsIDOMWindowUtils methods. @@ -3597,6 +3595,8 @@ class nsContentUtils { aCallback); static nsINode* GetCommonAncestorHelper(nsINode* aNode1, nsINode* aNode2); + static nsINode* GetCommonShadowIncludingAncestorHelper(nsINode* aNode1, + nsINode* aNode2); static nsIContent* GetCommonFlattenedTreeAncestorHelper( nsIContent* aContent1, nsIContent* aContent2); diff --git a/dom/base/nsCopySupport.cpp b/dom/base/nsCopySupport.cpp index 15c0cf4cf0..2e24d963c8 100644 --- a/dom/base/nsCopySupport.cpp +++ b/dom/base/nsCopySupport.cpp @@ -245,7 +245,7 @@ static nsresult CreateTransferable( NS_ENSURE_TRUE(aTransferable, NS_ERROR_NULL_POINTER); aTransferable->Init(aDocument.GetLoadContext()); - aTransferable->SetRequestingPrincipal(aDocument.NodePrincipal()); + aTransferable->SetDataPrincipal(aDocument.NodePrincipal()); if (aEncodedDocumentWithContext.mUnicodeEncodingIsTextHTML) { // Set up a format converter so that clipboard flavor queries work. // This converter isn't really used for conversions. @@ -332,7 +332,8 @@ static nsresult PutToClipboard( rv = CreateTransferable(aEncodedDocumentWithContext, aDocument, transferable); NS_ENSURE_SUCCESS(rv, rv); - rv = clipboard->SetData(transferable, nullptr, aClipboardID); + rv = clipboard->SetData(transferable, nullptr, aClipboardID, + aDocument.GetWindowContext()); NS_ENSURE_SUCCESS(rv, rv); return rv; @@ -455,9 +456,9 @@ nsresult nsCopySupport::GetContents(const nsACString& aMimeType, return docEncoder->EncodeToString(outdata); } -nsresult nsCopySupport::ImageCopy(nsIImageLoadingContent* aImageElement, - nsILoadContext* aLoadContext, - int32_t aCopyFlags) { +nsresult nsCopySupport::ImageCopy( + nsIImageLoadingContent* aImageElement, nsILoadContext* aLoadContext, + int32_t aCopyFlags, mozilla::dom::WindowContext* aSettingWindowContext) { nsresult rv; nsCOMPtr<nsINode> imageNode = do_QueryInterface(aImageElement, &rv); @@ -467,7 +468,7 @@ nsresult nsCopySupport::ImageCopy(nsIImageLoadingContent* aImageElement, nsCOMPtr<nsITransferable> trans(do_CreateInstance(kCTransferableCID, &rv)); NS_ENSURE_SUCCESS(rv, rv); trans->Init(aLoadContext); - trans->SetRequestingPrincipal(imageNode->NodePrincipal()); + trans->SetDataPrincipal(imageNode->NodePrincipal()); if (aCopyFlags & nsIDocumentViewerEdit::COPY_IMAGE_TEXT) { // get the location from the element @@ -527,11 +528,13 @@ nsresult nsCopySupport::ImageCopy(nsIImageLoadingContent* aImageElement, // check whether the system supports the selection clipboard or not. if (clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionClipboard)) { // put the transferable on the clipboard - rv = clipboard->SetData(trans, nullptr, nsIClipboard::kSelectionClipboard); + rv = clipboard->SetData(trans, nullptr, nsIClipboard::kSelectionClipboard, + aSettingWindowContext); NS_ENSURE_SUCCESS(rv, rv); } - return clipboard->SetData(trans, nullptr, nsIClipboard::kGlobalClipboard); + return clipboard->SetData(trans, nullptr, nsIClipboard::kGlobalClipboard, + aSettingWindowContext); } static nsresult AppendString(nsITransferable* aTransferable, @@ -928,7 +931,12 @@ bool nsCopySupport::FireClipboardEvent(EventMessage aEventMessage, NS_ENSURE_TRUE(transferable, false); // put the transferable on the clipboard - nsresult rv = clipboard->SetData(transferable, nullptr, aClipboardType); + WindowContext* settingWindowContext = nullptr; + if (aPresShell && aPresShell->GetDocument()) { + settingWindowContext = aPresShell->GetDocument()->GetWindowContext(); + } + nsresult rv = clipboard->SetData(transferable, nullptr, aClipboardType, + settingWindowContext); if (NS_FAILED(rv)) { return false; } diff --git a/dom/base/nsCopySupport.h b/dom/base/nsCopySupport.h index a6b4b5e783..5552e1a607 100644 --- a/dom/base/nsCopySupport.h +++ b/dom/base/nsCopySupport.h @@ -23,6 +23,7 @@ class PresShell; namespace dom { class Document; class Selection; +class WindowContext; } // namespace dom } // namespace mozilla @@ -46,7 +47,8 @@ class nsCopySupport { mozilla::dom::Document* aDoc, nsAString& outdata); static nsresult ImageCopy(nsIImageLoadingContent* aImageElement, - nsILoadContext* aLoadContext, int32_t aCopyFlags); + nsILoadContext* aLoadContext, int32_t aCopyFlags, + mozilla::dom::WindowContext* aSettingWindowContext); // Get the selection as a transferable. // @param aSelection Can be nullptr. diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 9bc8340b90..16bf19534a 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -2039,7 +2039,7 @@ nsDOMWindowUtils::GetBoundsWithoutFlushing(Element* aElement, if (frame) { nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion( frame, nsLayoutUtils::GetContainingBlockForClientRect(frame), - nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms); rect->SetLayoutRect(r); } @@ -3333,12 +3333,6 @@ nsDOMWindowUtils::IsPartOfOpaqueLayer(Element* aElement, bool* aResult) { } NS_IMETHODIMP -nsDOMWindowUtils::NumberOfAssignedPaintedLayers( - const nsTArray<RefPtr<Element>>& aElements, uint32_t* aResult) { - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP nsDOMWindowUtils::EnableDialogs() { nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index 4e2d604693..56827a457f 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -45,6 +45,7 @@ #include "mozilla/AccessibleCaretEventHub.h" #include "mozilla/ContentEvents.h" +#include "mozilla/FocusModel.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/DocumentInlines.h" @@ -173,7 +174,6 @@ bool nsFocusManager::sTestMode = false; uint64_t nsFocusManager::sFocusActionCounter = 0; static const char* kObservedPrefs[] = {"accessibility.browsewithcaret", - "accessibility.tabfocus_applies_to_xul", "focusmanager.testmode", nullptr}; nsFocusManager::nsFocusManager() @@ -198,10 +198,6 @@ nsFocusManager::~nsFocusManager() { nsresult nsFocusManager::Init() { sInstance = new nsFocusManager(); - nsIContent::sTabFocusModelAppliesToXUL = - Preferences::GetBool("accessibility.tabfocus_applies_to_xul", - nsIContent::sTabFocusModelAppliesToXUL); - sTestMode = Preferences::GetBool("focusmanager.testmode", false); Preferences::RegisterCallbacks(nsFocusManager::PrefChanged, kObservedPrefs, @@ -229,10 +225,6 @@ void nsFocusManager::PrefChanged(const char* aPref) { nsDependentCString pref(aPref); if (pref.EqualsLiteral("accessibility.browsewithcaret")) { UpdateCaretForCaretBrowsingMode(); - } else if (pref.EqualsLiteral("accessibility.tabfocus_applies_to_xul")) { - nsIContent::sTabFocusModelAppliesToXUL = - Preferences::GetBool("accessibility.tabfocus_applies_to_xul", - nsIContent::sTabFocusModelAppliesToXUL); } else if (pref.EqualsLiteral("focusmanager.testmode")) { sTestMode = Preferences::GetBool("focusmanager.testmode", false); } @@ -3362,9 +3354,6 @@ nsresult nsFocusManager::DetermineElementToMoveFocus( doc = aWindow->GetExtantDoc(); if (!doc) return NS_OK; - LookAndFeel::GetInt(LookAndFeel::IntID::TabFocusModel, - &nsIContent::sTabFocusModel); - // True if we are navigating by document (F6/Shift+F6) or false if we are // navigating by element (Tab/Shift+Tab). const bool forDocumentNavigation = @@ -3674,12 +3663,10 @@ nsresult nsFocusManager::DetermineElementToMoveFocus( } } else { if (aNavigateByKey) { - // There is no parent, so call the tree owner. This will tell the - // embedder or parent process that it should take the focus. - bool tookFocus; - docShell->TabToTreeOwner(forward, forDocumentNavigation, &tookFocus); - // If the tree owner took the focus, blur the current element. - if (tookFocus) { + // There is no parent, so move the focus to the parent process. + if (auto* child = BrowserChild::GetFrom(docShell)) { + child->SendMoveFocus(forward, forDocumentNavigation); + // Blur the current element. RefPtr<BrowsingContext> focusedBC = GetFocusedBrowsingContext(); if (focusedBC && focusedBC->IsInProcess()) { Blur(focusedBC, nullptr, true, true, false, @@ -4303,20 +4290,22 @@ nsresult nsFocusManager::GetNextTabbableContent( // Stepping out popover scope. // For forward, search for the next tabbable content after invoker. - // For backward, we should get back to the invoker. + // For backward, we should get back to the invoker if the invoker is + // focusable. Otherwise search for the next tabbable content after + // invoker. if (oldTopLevelScopeOwner && IsOpenPopoverWithInvoker(oldTopLevelScopeOwner) && currentTopLevelScopeOwner != oldTopLevelScopeOwner) { if (auto* popover = Element::FromNode(oldTopLevelScopeOwner)) { RefPtr<nsIContent> invokerContent = popover->GetPopoverData()->GetInvoker()->AsContent(); + RefPtr<nsIContent> rootElement = invokerContent; + if (auto* doc = invokerContent->GetComposedDoc()) { + rootElement = doc->GetRootElement(); + } if (aForward) { nsIFrame* frame = invokerContent->GetPrimaryFrame(); int32_t tabIndex = frame->IsFocusable().mTabIndex; - RefPtr<nsIContent> rootElement = invokerContent; - if (auto* doc = invokerContent->GetComposedDoc()) { - rootElement = doc->GetRootElement(); - } if (tabIndex >= 0 && (aIgnoreTabIndex || aCurrentTabIndex == tabIndex)) { nsresult rv = GetNextTabbableContent( @@ -4327,12 +4316,19 @@ nsresult nsFocusManager::GetNextTabbableContent( return rv; } } - } else if (invokerContent && - invokerContent->IsFocusableWithoutStyle()) { - // FIXME(emilio): The check above should probably use - // nsIFrame::IsFocusable, not IsFocusableWithoutStyle. - invokerContent.forget(aResultContent); - return NS_OK; + } else if (invokerContent) { + nsIFrame* frame = invokerContent->GetPrimaryFrame(); + if (frame && frame->IsFocusable()) { + invokerContent.forget(aResultContent); + return NS_OK; + } + nsresult rv = GetNextTabbableContent( + aPresShell, rootElement, aOriginalStartContent, invokerContent, + false, 0, true, false, aNavigateByKey, true, + aReachedToEndForDocumentNavigation, aResultContent); + if (NS_SUCCEEDED(rv) && *aResultContent) { + return rv; + } } } } @@ -5518,6 +5514,14 @@ bool nsFocusManager::CanSkipFocus(nsIContent* aContent) { return false; } +static IsFocusableFlags FocusManagerFlagsToIsFocusableFlags(uint32_t aFlags) { + auto flags = IsFocusableFlags(0); + if (aFlags & nsIFocusManager::FLAG_BYMOUSE) { + flags |= IsFocusableFlags::WithMouse; + } + return flags; +} + /* static */ Element* nsFocusManager::GetTheFocusableArea(Element* aTarget, uint32_t aFlags) { @@ -5547,7 +5551,8 @@ Element* nsFocusManager::GetTheFocusableArea(Element* aTarget, // 3. If focus target is a navigable container with a non-null content // navigable // nsIFrame::IsFocusable will effectively perform the checks for them. - if (frame->IsFocusable(aFlags & FLAG_BYMOUSE)) { + IsFocusableFlags flags = FocusManagerFlagsToIsFocusableFlags(aFlags); + if (frame->IsFocusable(flags)) { return aTarget; } @@ -5567,8 +5572,7 @@ Element* nsFocusManager::GetTheFocusableArea(Element* aTarget, } } - if (Element* firstFocusable = - root->GetFocusDelegate(aFlags & FLAG_BYMOUSE)) { + if (Element* firstFocusable = root->GetFocusDelegate(flags)) { return firstFocusable; } } @@ -5586,7 +5590,7 @@ bool nsFocusManager::IsAreaElementFocusable(HTMLAreaElement& aArea) { // GetPrimaryFrame() is not relevant as to whether it is focusable or // not, so we have to do all the relevant checks manually for them. return frame->IsVisibleConsideringAncestors() && - aArea.IsFocusableWithoutStyle(false /* aWithMouse */); + aArea.IsFocusableWithoutStyle(); } nsresult NS_NewFocusManager(nsIFocusManager** aResult) { diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp index 7dcd265ca4..f263c8efcc 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -48,6 +48,7 @@ #include "mozilla/Attributes.h" #include "mozilla/BaseProfilerMarkersPrerequisites.h" #include "mozilla/BasicEvents.h" +#include "mozilla/BounceTrackingStorageObserver.h" #include "mozilla/CallState.h" #include "mozilla/CycleCollectedJSContext.h" #include "mozilla/DOMEventTargetHelper.h" @@ -3502,18 +3503,7 @@ double nsGlobalWindowInner::GetDevicePixelRatio(CallerType aCallerType, if (nsIGlobalObject::ShouldResistFingerprinting( aCallerType, RFPTarget::WindowDevicePixelRatio)) { - // Spoofing the DevicePixelRatio causes blurriness in some situations - // on HiDPI displays. pdf.js is a non-system caller; but it can't - // expose the fingerprintable information, so we can safely disable - // spoofing in this situation. It doesn't address the issue for - // web-rendered content (including pdf.js instances on the web.) - // In the future we hope to have a better solution to fix all HiDPI - // blurriness... - nsAutoCString origin; - nsresult rv = this->GetPrincipal()->GetOrigin(origin); - if (NS_FAILED(rv) || origin != "resource://pdf.js"_ns) { - return 1.0; - } + return 2.0; } if (aCallerType == CallerType::NonSystem) { @@ -4648,6 +4638,19 @@ already_AddRefed<nsICSSDeclaration> nsGlobalWindowInner::GetComputedStyleHelper( aError, nullptr); } +void nsGlobalWindowInner::MaybeNotifyStorageKeyUsed() { + // Only notify once per window lifetime. + if (hasNotifiedStorageKeyUsed) { + return; + } + nsresult rv = + BounceTrackingStorageObserver::OnInitialStorageAccess(GetWindowContext()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + hasNotifiedStorageKeyUsed = true; +} + Storage* nsGlobalWindowInner::GetSessionStorage(ErrorResult& aError) { nsIPrincipal* principal = GetPrincipal(); nsIPrincipal* storagePrincipal; @@ -4770,6 +4773,8 @@ Storage* nsGlobalWindowInner::GetSessionStorage(ErrorResult& aError) { } } + MaybeNotifyStorageKeyUsed(); + MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug, ("nsGlobalWindowInner %p returns %p sessionStorage", this, mSessionStorage.get())); @@ -4938,6 +4943,8 @@ Storage* nsGlobalWindowInner::GetLocalStorage(ErrorResult& aError) { new PartitionedLocalStorage(this, principal, storagePrincipal, cache); } + MaybeNotifyStorageKeyUsed(); + MOZ_ASSERT(mLocalStorage); MOZ_ASSERT( mLocalStorage->Type() == @@ -4957,6 +4964,8 @@ IDBFactory* nsGlobalWindowInner::GetIndexedDB(JSContext* aCx, } } + MaybeNotifyStorageKeyUsed(); + return mIndexedDB; } diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h index 215e362dad..33e1264571 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h @@ -728,6 +728,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, mozilla::ErrorResult& aError); void Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String, mozilla::ErrorResult& aError); + + void MaybeNotifyStorageKeyUsed(); + mozilla::dom::Storage* GetSessionStorage(mozilla::ErrorResult& aError); mozilla::dom::Storage* GetLocalStorage(mozilla::ErrorResult& aError); mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError); @@ -1389,6 +1392,11 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, mozilla::Maybe<mozilla::StorageAccess> mStorageAllowedCache; uint32_t mStorageAllowedReasonCache; + // When window associated storage is accessed we need to notify the parent + // process. This flag is used to ensure we only do it once per window + // lifetime. + bool hasNotifiedStorageKeyUsed{false}; + RefPtr<mozilla::dom::DebuggerNotificationManager> mDebuggerNotificationManager; diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h index 700855370f..e6fc8fc430 100644 --- a/dom/base/nsIContent.h +++ b/dom/base/nsIContent.h @@ -16,6 +16,7 @@ class nsTextFragment; class nsIFrame; namespace mozilla { +enum class IsFocusableFlags : uint8_t; class EventChainPreVisitor; class HTMLEditor; struct URLExtraData; @@ -274,13 +275,14 @@ class nsIContent : public nsINode { * some widgets may be focusable but removed from the tab order. * @return whether the content is focusable via mouse, kbd or script. */ - virtual Focusable IsFocusableWithoutStyle(bool aWithMouse = false); + virtual Focusable IsFocusableWithoutStyle( + mozilla::IsFocusableFlags = mozilla::IsFocusableFlags(0)); // https://html.spec.whatwg.org/multipage/interaction.html#focus-delegate - mozilla::dom::Element* GetFocusDelegate(bool aWithMouse) const; + mozilla::dom::Element* GetFocusDelegate(mozilla::IsFocusableFlags) const; // https://html.spec.whatwg.org/multipage/interaction.html#autofocus-delegate - mozilla::dom::Element* GetAutofocusDelegate(bool aWithMouse) const; + mozilla::dom::Element* GetAutofocusDelegate(mozilla::IsFocusableFlags) const; /* * Get desired IME state for the content. @@ -753,21 +755,6 @@ class nsIContent : public nsINode { virtual void DumpContent(FILE* out = stdout, int32_t aIndent = 0, bool aDumpAll = true) const = 0; #endif - - enum ETabFocusType { - eTabFocus_textControlsMask = - (1 << 0), // textboxes and lists always tabbable - eTabFocus_formElementsMask = (1 << 1), // non-text form elements - eTabFocus_linksMask = (1 << 2), // links - eTabFocus_any = 1 + (1 << 1) + (1 << 2) // everything that can be focused - }; - - // Tab focus model bit field: - static int32_t sTabFocusModel; - - // accessibility.tabfocus_applies_to_xul pref - if it is set to true, - // the tabfocus bit field applies to xul elements. - static bool sTabFocusModelAppliesToXUL; }; NON_VIRTUAL_ADDREF_RELEASE(nsIContent) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index a14a22bcf0..035faa1ee1 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2139,6 +2139,11 @@ void nsJSContext::EnsureStatics() { (void*)JSGC_PARALLEL_MARKING_THRESHOLD_MB); Preferences::RegisterCallbackAndCall( + SetMemoryPrefChangedCallbackInt, + "javascript.options.mem.gc_max_parallel_marking_threads", + (void*)JSGC_MAX_MARKING_THREADS); + + Preferences::RegisterCallbackAndCall( SetMemoryGCSliceTimePrefChangedCallback, "javascript.options.mem.gc_incremental_slice_ms"); diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index cf15f239c5..e879bb5806 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -792,8 +792,17 @@ void nsRange::ParentChainChanged(nsIContent* aContent) { DoSetRange(mStart, mEnd, newRoot); } +bool nsRange::IsShadowIncludingInclusiveDescendantOfCrossBoundaryRangeAncestor( + const nsINode& aContainer) const { + MOZ_ASSERT(mCrossShadowBoundaryRange && + mCrossShadowBoundaryRange->GetCommonAncestor()); + return aContainer.IsShadowIncludingInclusiveDescendantOf( + mCrossShadowBoundaryRange->GetCommonAncestor()); +} + bool nsRange::IsPointComparableToRange(const nsINode& aContainer, uint32_t aOffset, + bool aAllowCrossShadowBoundary, ErrorResult& aRv) const { // our range is in a good state? if (!mIsPositioned) { @@ -801,7 +810,13 @@ bool nsRange::IsPointComparableToRange(const nsINode& aContainer, return false; } - if (!aContainer.IsInclusiveDescendantOf(mRoot)) { + const bool isContainerInRange = + aContainer.IsInclusiveDescendantOf(mRoot) || + (aAllowCrossShadowBoundary && mCrossShadowBoundaryRange && + IsShadowIncludingInclusiveDescendantOfCrossBoundaryRangeAncestor( + aContainer)); + + if (!isContainerInRange) { // TODO(emilio): Switch to ThrowWrongDocumentError, but IsPointInRange // relies on the error code right now in order to suppress the exception. aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR); @@ -832,8 +847,10 @@ bool nsRange::IsPointComparableToRange(const nsINode& aContainer, } bool nsRange::IsPointInRange(const nsINode& aContainer, uint32_t aOffset, - ErrorResult& aRv) const { - uint16_t compareResult = ComparePoint(aContainer, aOffset, aRv); + ErrorResult& aRv, + bool aAllowCrossShadowBoundary) const { + int16_t compareResult = + ComparePoint(aContainer, aOffset, aRv, aAllowCrossShadowBoundary); // If the node isn't in the range's document, it clearly isn't in the range. if (aRv.ErrorCodeIs(NS_ERROR_DOM_WRONG_DOCUMENT_ERR)) { aRv.SuppressException(); @@ -844,8 +861,10 @@ bool nsRange::IsPointInRange(const nsINode& aContainer, uint32_t aOffset, } int16_t nsRange::ComparePoint(const nsINode& aContainer, uint32_t aOffset, - ErrorResult& aRv) const { - if (!IsPointComparableToRange(aContainer, aOffset, aRv)) { + ErrorResult& aRv, + bool aAllowCrossShadowBoundary) const { + if (!IsPointComparableToRange(aContainer, aOffset, aAllowCrossShadowBoundary, + aRv)) { return 0; } @@ -853,11 +872,15 @@ int16_t nsRange::ComparePoint(const nsINode& aContainer, uint32_t aOffset, MOZ_ASSERT(point.IsSetAndValid()); - if (Maybe<int32_t> order = nsContentUtils::ComparePoints(point, mStart); + if (Maybe<int32_t> order = nsContentUtils::ComparePoints( + point, aAllowCrossShadowBoundary ? MayCrossShadowBoundaryStartRef() + : StartRef()); order && *order <= 0) { return int16_t(*order); } - if (Maybe<int32_t> order = nsContentUtils::ComparePoints(mEnd, point); + if (Maybe<int32_t> order = nsContentUtils::ComparePoints( + aAllowCrossShadowBoundary ? MayCrossShadowBoundaryEndRef() : EndRef(), + point); order && *order == -1) { return 1; } @@ -881,7 +904,9 @@ bool nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv) { return false; } - if (!IsPointComparableToRange(*parent, *nodeIndex, IgnoreErrors())) { + if (!IsPointComparableToRange(*parent, *nodeIndex, + false /* aAllowCrossShadowBoundary */, + IgnoreErrors())) { return false; } @@ -2866,7 +2891,8 @@ static void CollectClientRectsForSubtree( if (!aTextOnly || isText) { nsLayoutUtils::GetAllInFlowRectsAndTexts( frame, nsLayoutUtils::GetContainingBlockForClientRect(frame), - aCollector, aTextList, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + aCollector, aTextList, + nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms); if (isText) { return; } @@ -3504,7 +3530,7 @@ void nsRange::CreateOrUpdateCrossShadowBoundaryRangeIfNeeded( if (!mCrossShadowBoundaryRange) { mCrossShadowBoundaryRange = - StaticRange::Create(aStartBoundary, aEndBoundary, IgnoreErrors()); + CrossShadowBoundaryRange::Create(aStartBoundary, aEndBoundary); return; } diff --git a/dom/base/nsRange.h b/dom/base/nsRange.h index 94459087cb..3c8f43a7dc 100644 --- a/dom/base/nsRange.h +++ b/dom/base/nsRange.h @@ -14,6 +14,7 @@ #include "nsCOMPtr.h" #include "mozilla/dom/AbstractRange.h" #include "mozilla/dom/StaticRange.h" +#include "mozilla/dom/CrossShadowBoundaryRange.h" #include "prmon.h" #include "nsStubMutationObserver.h" #include "nsWrapperCache.h" @@ -209,7 +210,8 @@ class nsRange final : public mozilla::dom::AbstractRange, int16_t CompareBoundaryPoints(uint16_t aHow, const nsRange& aOtherRange, ErrorResult& aRv); int16_t ComparePoint(const nsINode& aContainer, uint32_t aOffset, - ErrorResult& aRv) const; + ErrorResult& aRv, + bool aAllowCrossShadowBoundary = false) const; void DeleteContents(ErrorResult& aRv); already_AddRefed<mozilla::dom::DocumentFragment> ExtractContents( ErrorResult& aErr); @@ -223,7 +225,8 @@ class nsRange final : public mozilla::dom::AbstractRange, void InsertNode(nsINode& aNode, ErrorResult& aErr); bool IntersectsNode(nsINode& aNode, ErrorResult& aRv); bool IsPointInRange(const nsINode& aContainer, uint32_t aOffset, - ErrorResult& aRv) const; + ErrorResult& aRv, + bool aAllowCrossShadowBoundary = false) const; void ToString(nsAString& aReturn, ErrorResult& aErr); void Detach(); @@ -336,8 +339,14 @@ class nsRange final : public mozilla::dom::AbstractRange, // document as the range, aContainer is a DOCUMENT_TYPE_NODE and // aOffset doesn't exceed aContainer's length. bool IsPointComparableToRange(const nsINode& aContainer, uint32_t aOffset, + bool aAllowCrossShadowBoundary, ErrorResult& aErrorResult) const; + // @return true iff aContainer is a shadow including inclusive descendant of + // the common ancestor of the mCrossBoundaryRange. + bool IsShadowIncludingInclusiveDescendantOfCrossBoundaryRangeAncestor( + const nsINode& aContainer) const; + /** * @brief Returns true if the range is part of exactly one |Selection|. */ @@ -424,7 +433,7 @@ class nsRange final : public mozilla::dom::AbstractRange, : mEnd.GetChildAtOffset(); } - mozilla::dom::StaticRange* GetCrossShadowBoundaryRange() const { + mozilla::dom::CrossShadowBoundaryRange* GetCrossShadowBoundaryRange() const { return mCrossShadowBoundaryRange; } @@ -549,7 +558,7 @@ class nsRange final : public mozilla::dom::AbstractRange, // just return one point when a collapse is needed. // Bug https://bugzilla.mozilla.org/show_bug.cgi?id=1886028 is going // to be used to improve mCrossShadowBoundaryRange. - RefPtr<mozilla::dom::StaticRange> mCrossShadowBoundaryRange; + RefPtr<mozilla::dom::CrossShadowBoundaryRange> mCrossShadowBoundaryRange; friend class mozilla::dom::AbstractRange; }; diff --git a/dom/base/nsTextFragment.cpp b/dom/base/nsTextFragment.cpp index 5cba2577b8..c3f3d388be 100644 --- a/dom/base/nsTextFragment.cpp +++ b/dom/base/nsTextFragment.cpp @@ -198,23 +198,22 @@ bool nsTextFragment::SetTo(const char16_t* aBuffer, uint32_t aLength, } if (aForce2b && mState.mIs2b && !m2b->IsReadonly()) { + // Try to re-use our existing StringBuffer. uint32_t storageSize = m2b->StorageSize(); uint32_t neededSize = aLength * sizeof(char16_t); if (!neededSize) { if (storageSize < AutoStringDefaultStorageSize) { // If we're storing small enough nsStringBuffer, let's preserve it. - static_cast<char16_t*>(m2b->Data())[0] = char16_t(0); mState.mLength = 0; mState.mIsBidi = false; return true; } - } else if ((neededSize < storageSize) && - ((storageSize / 2) < - (neededSize + AutoStringDefaultStorageSize))) { - // Don't try to reuse the existing nsStringBuffer, if it would have - // lots of unused space. - + } else if (neededSize < storageSize && + (storageSize / 2) < + (neededSize + AutoStringDefaultStorageSize)) { + // Don't try to reuse the existing nsStringBuffer, if it would have lots + // of unused space. memcpy(m2b->Data(), aBuffer, neededSize); static_cast<char16_t*>(m2b->Data())[aLength] = char16_t(0); mState.mLength = aLength; @@ -226,19 +225,18 @@ bool nsTextFragment::SetTo(const char16_t* aBuffer, uint32_t aLength, } } - ReleaseText(); - if (aLength == 0) { + ReleaseText(); return true; } char16_t firstChar = *aBuffer; if (!aForce2b && aLength == 1 && firstChar < 256) { + ReleaseText(); m1b = sSingleCharSharedString + firstChar; mState.mInHeap = false; mState.mIs2b = false; mState.mLength = 1; - return true; } @@ -266,6 +264,7 @@ bool nsTextFragment::SetTo(const char16_t* aBuffer, uint32_t aLength, if (ucp == uend && endNewLine - start <= TEXTFRAG_MAX_NEWLINES && ucp - endNewLine <= TEXTFRAG_WHITE_AFTER_NEWLINE) { + ReleaseText(); char** strings = space == ' ' ? sSpaceSharedString : sTabSharedString; m1b = strings[endNewLine - start]; @@ -287,27 +286,29 @@ bool nsTextFragment::SetTo(const char16_t* aBuffer, uint32_t aLength, if (first16bit != -1) { // aBuffer contains no non-8bit character // Use ucs2 storage because we have to - CheckedUint32 m2bSize = CheckedUint32(aLength) + 1; - if (!m2bSize.isValid()) { + CheckedUint32 size = CheckedUint32(aLength) + 1; + if (!size.isValid()) { return false; } - m2bSize *= sizeof(char16_t); - if (!m2bSize.isValid()) { + size *= sizeof(char16_t); + if (!size.isValid()) { return false; } - m2b = nsStringBuffer::Alloc(m2bSize.value()).take(); - if (!m2b) { + RefPtr<nsStringBuffer> newBuffer = nsStringBuffer::Alloc(size.value()); + if (!newBuffer) { return false; } - memcpy(m2b->Data(), aBuffer, aLength * sizeof(char16_t)); - static_cast<char16_t*>(m2b->Data())[aLength] = char16_t(0); + ReleaseText(); + memcpy(newBuffer->Data(), aBuffer, aLength * sizeof(char16_t)); + static_cast<char16_t*>(newBuffer->Data())[aLength] = char16_t(0); + + m2b = newBuffer.forget().take(); mState.mIs2b = true; if (aUpdateBidi) { UpdateBidiFlag(aBuffer + first16bit, aLength - first16bit); } - } else { // Use 1 byte storage because we can char* buff = static_cast<char*>(malloc(aLength)); @@ -315,6 +316,7 @@ bool nsTextFragment::SetTo(const char16_t* aBuffer, uint32_t aLength, return false; } + ReleaseText(); // Copy data LossyConvertUtf16toLatin1(Span(aBuffer, aLength), Span(buff, aLength)); m1b = buff; diff --git a/dom/base/nsTextFragment.h b/dom/base/nsTextFragment.h index 5330815683..91efa49254 100644 --- a/dom/base/nsTextFragment.h +++ b/dom/base/nsTextFragment.h @@ -113,8 +113,7 @@ class nsTextFragment final { } ReleaseText(); if (aForce2b && !aUpdateBidi) { - nsStringBuffer* buffer = nsStringBuffer::FromString(aString); - if (buffer) { + if (nsStringBuffer* buffer = aString.GetStringBuffer()) { NS_ADDREF(m2b = buffer); mState.mInHeap = true; mState.mIs2b = true; @@ -154,19 +153,13 @@ class nsTextFragment final { const mozilla::fallible_t& aFallible) const { if (mState.mIs2b) { if (aString.IsEmpty()) { - m2b->ToString(mState.mLength, aString); + aString.Assign(m2b, mState.mLength); return true; } - bool ok = aString.Append(Get2b(), mState.mLength, aFallible); - if (!ok) { - return false; - } - - return true; - } else { - return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString, - aFallible); + return aString.Append(Get2b(), mState.mLength, aFallible); } + return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString, + aFallible); } /** diff --git a/dom/base/test/browser_page_load_event_telemetry.js b/dom/base/test/browser_page_load_event_telemetry.js index 871e06026a..530d45db9a 100644 --- a/dom/base/test/browser_page_load_event_telemetry.js +++ b/dom/base/test/browser_page_load_event_telemetry.js @@ -34,6 +34,16 @@ add_task(async function () { 30, "Should have at least 30 page load events" ); + + // Ensure the events in the pageload ping are reasonable. + record.forEach(entry => { + Assert.equal(entry.name, "page_load"); + Assert.greater(parseInt(entry.extra.load_time), 0); + Assert.ok( + entry.extra.using_webdriver, + "Webdriver field should be set to true." + ); + }); }); // Perform page load 30 times to trigger the ping being sent diff --git a/dom/base/test/chrome/bug418986-1.js b/dom/base/test/chrome/bug418986-1.js index e7e3c63b5c..565ae418dd 100644 --- a/dom/base/test/chrome/bug418986-1.js +++ b/dom/base/test/chrome/bug418986-1.js @@ -35,7 +35,7 @@ var test = function (isContent) { ["screen.orientation.type", "'landscape-primary'"], ["screen.orientation.angle", 0], ["screen.mozOrientation", "'landscape-primary'"], - ["devicePixelRatio", 1], + ["devicePixelRatio", 2], ]; // checkPair: tests if members of pair [a, b] are equal when evaluated. diff --git a/dom/base/test/fullscreen/browser.toml b/dom/base/test/fullscreen/browser.toml index dc883a4ac2..7c989bafcb 100644 --- a/dom/base/test/fullscreen/browser.toml +++ b/dom/base/test/fullscreen/browser.toml @@ -45,6 +45,9 @@ skip-if = [ ["browser_fullscreen-sizemode.js"] ["browser_fullscreen-tab-close-race.js"] +skip-if = [ + "apple_silicon && !debug", # Bug 1877642 +] ["browser_fullscreen-tab-close.js"] diff --git a/dom/base/test/jsmodules/importmaps/bug_1893164_module_1.mjs b/dom/base/test/jsmodules/importmaps/bug_1893164_module_1.mjs new file mode 100644 index 0000000000..45894ce609 --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/bug_1893164_module_1.mjs @@ -0,0 +1,3 @@ +/* eslint-disable import/no-named-default, import/no-unresolved */ +import { default as default_non } from "./non_existing.mjs"; +import { default as default_3 } from "./bug_1893164_module_3.mjs"; diff --git a/dom/base/test/jsmodules/importmaps/bug_1893164_module_2.mjs b/dom/base/test/jsmodules/importmaps/bug_1893164_module_2.mjs new file mode 100644 index 0000000000..e6f5e9f9f0 --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/bug_1893164_module_2.mjs @@ -0,0 +1,5 @@ +/* eslint-disable import/no-named-default */ +import { default as default_3 } from "./bug_1893164_module_3.mjs"; + +module2_loaded = true; +result = default_3; diff --git a/dom/base/test/jsmodules/importmaps/bug_1893164_module_3.mjs b/dom/base/test/jsmodules/importmaps/bug_1893164_module_3.mjs new file mode 100644 index 0000000000..dbb41f0e1f --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/bug_1893164_module_3.mjs @@ -0,0 +1 @@ +export default 3; diff --git a/dom/base/test/jsmodules/importmaps/bug_1894631_module_1.mjs b/dom/base/test/jsmodules/importmaps/bug_1894631_module_1.mjs new file mode 100644 index 0000000000..b0c91fe0cf --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/bug_1894631_module_1.mjs @@ -0,0 +1,5 @@ +/* eslint-disable import/no-named-default, import/no-unresolved, import/named */ +import { default as default_2 } from "./bug_1894631_module_2.mjs"; +import { default as default_non } from "./non_existing.mjs"; + +module1_loaded = true; diff --git a/dom/base/test/jsmodules/importmaps/bug_1894631_module_2.mjs b/dom/base/test/jsmodules/importmaps/bug_1894631_module_2.mjs new file mode 100644 index 0000000000..dd17da2abc --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/bug_1894631_module_2.mjs @@ -0,0 +1,3 @@ +/* eslint-disable import/no-named-default */ +import { default as default_3 } from "./bug_1894631_module_3.mjs"; +import { default as default_4 } from "./bug_1894631_module_4.mjs"; diff --git a/dom/base/test/jsmodules/importmaps/bug_1894631_module_3.mjs b/dom/base/test/jsmodules/importmaps/bug_1894631_module_3.mjs new file mode 100644 index 0000000000..dbb41f0e1f --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/bug_1894631_module_3.mjs @@ -0,0 +1 @@ +export default 3; diff --git a/dom/base/test/jsmodules/importmaps/bug_1894631_module_4.mjs b/dom/base/test/jsmodules/importmaps/bug_1894631_module_4.mjs new file mode 100644 index 0000000000..456ffaafac --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/bug_1894631_module_4.mjs @@ -0,0 +1 @@ +export default 4; diff --git a/dom/base/test/jsmodules/importmaps/mochitest.toml b/dom/base/test/jsmodules/importmaps/mochitest.toml index 1f95b155ac..b71bf21def 100644 --- a/dom/base/test/jsmodules/importmaps/mochitest.toml +++ b/dom/base/test/jsmodules/importmaps/mochitest.toml @@ -3,6 +3,13 @@ support-files = [ "bug_1865410_module_a.mjs", "bug_1865410_module_b.mjs", "bug_1873417.mjs", + "bug_1893164_module_1.mjs", + "bug_1893164_module_2.mjs", + "bug_1893164_module_3.mjs", + "bug_1894631_module_1.mjs", + "bug_1894631_module_2.mjs", + "bug_1894631_module_3.mjs", + "bug_1894631_module_4.mjs", "classic_script.js", "module_chain_1.mjs", "module_chain_2.mjs", @@ -34,7 +41,10 @@ support-files = [ ["test_bug_1873417.html"] +["test_bug_1893164.html"] + ["test_importMap_with_external_script.html"] ["test_importMap_with_nonexisting_module.html"] ["test_dynamic_importMap_with_external_script.html"] ["test_dynamic_importMap_load_completes.html"] +["test_shared_submodules_with_modulepreload.html"] diff --git a/dom/base/test/jsmodules/importmaps/test_bug_1893164.html b/dom/base/test/jsmodules/importmaps/test_bug_1893164.html new file mode 100644 index 0000000000..6c5306b815 --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/test_bug_1893164.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Test module cancel</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script> + var module2_loaded = false, result; + + SimpleTest.waitForExplicitFinish(); + + function testLoaded() { + ok(module2_loaded, 'module_2.mjs should be loaded'); + ok(result == 3, "result should be 3 from module_3.mjs"); + SimpleTest.finish(); + } +</script> + +<script src="./bug_1893164_module_1.mjs" type="module"></script> +<script src="./bug_1893164_module_2.mjs" type="module"></script> + +<body onload='testLoaded()'></body> diff --git a/dom/base/test/jsmodules/importmaps/test_shared_submodules_with_modulepreload.html b/dom/base/test/jsmodules/importmaps/test_shared_submodules_with_modulepreload.html new file mode 100644 index 0000000000..a99582f8d3 --- /dev/null +++ b/dom/base/test/jsmodules/importmaps/test_shared_submodules_with_modulepreload.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Test module cancel won't trigger an assert</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="modulepreload" href="./bug_1894631_module_2.mjs" /> +<link rel="modulepreload" href="./bug_1894631_module_3.mjs" /> +<link rel="modulepreload" href="./non_existing.mjs" /> + +<script src="./bug_1894631_module_1.mjs" type="module" id="module_1"></script> +<script> + var module1_loaded = false; + var module1_error = false; + + SimpleTest.waitForExplicitFinish(); + + const module1 = document.getElementById("module_1"); + module1.addEventListener("error", (event) => { + info("error event"); + module1_error = true; + }); + + function testLoaded() { + ok(module1_error, "module_1.mjs should fire an error event"); + ok(!module1_loaded, "module_1.mjs should not be loaded"); + SimpleTest.finish(); + } +</script> + +<body onload='testLoaded()'> +</body> diff --git a/dom/base/test/test_anchor_target_blank_referrer.html b/dom/base/test/test_anchor_target_blank_referrer.html index b494c28017..643cfd6c03 100644 --- a/dom/base/test/test_anchor_target_blank_referrer.html +++ b/dom/base/test/test_anchor_target_blank_referrer.html @@ -35,6 +35,9 @@ const testCases = [ {ACTION: ["generate-anchor-target-blank-policy-test"], + PREFS: [ + ["dom.security.https_first", false], // need to test http and https + ], TESTS: [ // Referrer policy is set in meta {NAME: 'origin-in-meta-rel-noopener', diff --git a/dom/base/test/test_focus_radio.html b/dom/base/test/test_focus_radio.html index 8e97012745..9e14143143 100644 --- a/dom/base/test/test_focus_radio.html +++ b/dom/base/test/test_focus_radio.html @@ -2,7 +2,14 @@ <title>Test for input radio focus</title> <script src="/tests/SimpleTest/SimpleTest.js"></script> <script src="/tests/SimpleTest/EventUtils.js"></script> - +<style> +.visHidden { + visibility: hidden; +} +.dispNone { + display: none; +} +</style> <button id="before">before</button> <fieldset> <legend>a</legend> @@ -26,6 +33,27 @@ <label><input id="d3" type="radio" name="d" disabled>d3</label> <label><input id="d4" type="radio" name="d">d4</label> </fieldset> +<fieldset> + <legend>e</legend> + <label><input id="e1" type="radio" name="e" hidden>e1</label> + <label><input id="e2" type="radio" name="e">e2</label> + <label><input id="e3" type="radio" name="e" hidden>e3</label> + <label><input id="e4" type="radio" name="e">e4</label> +</fieldset> +<fieldset> + <legend>f</legend> + <label><input id="f1" type="radio" name="f" class="visHidden">f1</label> + <label><input id="f2" type="radio" name="f">f2</label> + <label><input id="f3" type="radio" name="f" class="visHidden">f3</label> + <label><input id="f4" type="radio" name="f">f4</label> +</fieldset> +<fieldset> + <legend>g</legend> + <label><input id="g1" type="radio" name="g" class="dispNone">g1</label> + <label><input id="g2" type="radio" name="g">g2</label> + <label><input id="g3" type="radio" name="g" class="dispNone">g3</label> + <label><input id="g4" type="radio" name="g">g4</label> +</fieldset> <button id="after">after</button> <script> @@ -51,8 +79,17 @@ expectFocusAfterKey("Tab", "c1"); // d1 is disabled, so d2 should get focus. expectFocusAfterKey("Tab", "d2"); + // e1 is hidden, so e2 should get focus. + expectFocusAfterKey("Tab", "e2"); + // f1 is hidden, so f2 should get focus. + expectFocusAfterKey("Tab", "f2"); + // g1 is hidden, so g2 should get focus. + expectFocusAfterKey("Tab", "g2"); expectFocusAfterKey("Tab", "after"); + expectFocusAfterKey("Shift+Tab", "g2"); + expectFocusAfterKey("Shift+Tab", "f2"); + expectFocusAfterKey("Shift+Tab", "e2"); expectFocusAfterKey("Shift+Tab", "d2"); expectFocusAfterKey("Shift+Tab", "c1"); expectFocusAfterKey("Shift+Tab", "b2"); @@ -85,6 +122,36 @@ // Up arrow should wrap at the top. expectFocusAfterKey("ArrowUp", "d4"); + expectFocusAfterKey("Tab", "e2"); + // e3 is hidden, so down arrow should focus e4. + expectFocusAfterKey("ArrowDown", "e4"); + expectFocusAfterKey("ArrowUp", "e2"); + expectFocusAfterKey("ArrowDown", "e4"); + // Down arrow should wrap at the bottom, skipping hidden. + expectFocusAfterKey("ArrowDown", "e2"); + // Up arrow should wrap at the top. + expectFocusAfterKey("ArrowUp", "e4"); + + expectFocusAfterKey("Tab", "f2"); + // f3 is hidden, so down arrow should focus f4. + expectFocusAfterKey("ArrowDown", "f4"); + expectFocusAfterKey("ArrowUp", "f2"); + expectFocusAfterKey("ArrowDown", "f4"); + // Down arrow should wrap at the bottom, skipping hidden. + expectFocusAfterKey("ArrowDown", "f2"); + // Up arrow should wrap at the top. + expectFocusAfterKey("ArrowUp", "f4"); + + expectFocusAfterKey("Tab", "g2"); + // g3 is hidden, so down arrow should focus g4. + expectFocusAfterKey("ArrowDown", "g4"); + expectFocusAfterKey("ArrowUp", "g2"); + expectFocusAfterKey("ArrowDown", "g4"); + // Down arrow should wrap at the bottom, skipping hidden. + expectFocusAfterKey("ArrowDown", "g2"); + // Up arrow should wrap at the top. + expectFocusAfterKey("ArrowUp", "g4"); + SimpleTest.finish(); }); </script> |