diff --git a/dom/base/AbstractRange.cpp b/dom/base/AbstractRange.cpp index ca527a93d7f7..bc557b863d0a 100644 --- a/dom/base/AbstractRange.cpp +++ b/dom/base/AbstractRange.cpp @@ -13,8 +13,10 @@ #include "mozilla/RangeUtils.h" #include "mozilla/dom/ChildIterator.h" #include "mozilla/dom/Document.h" +#include "mozilla/dom/DocumentInlines.h" #include "mozilla/dom/StaticRange.h" #include "mozilla/dom/Selection.h" +#include "mozilla/dom/TreeIterator.h" #include "mozilla/dom/CrossShadowBoundaryRange.h" #include "nsContentUtils.h" #include "nsCycleCollectionParticipant.h" @@ -27,28 +29,33 @@ namespace mozilla::dom { template nsresult AbstractRange::SetStartAndEndInternal( const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, - nsRange* aRange); + nsRange* aRange, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template nsresult AbstractRange::SetStartAndEndInternal( const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary, - nsRange* aRange); + nsRange* aRange, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template nsresult AbstractRange::SetStartAndEndInternal( const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, - nsRange* aRange); + nsRange* aRange, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template nsresult AbstractRange::SetStartAndEndInternal( const RawRangeBoundary& aStartBoundary, - const RawRangeBoundary& aEndBoundary, nsRange* aRange); + const RawRangeBoundary& aEndBoundary, nsRange* aRange, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template nsresult AbstractRange::SetStartAndEndInternal( const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, - StaticRange* aRange); + StaticRange* aRange, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template nsresult AbstractRange::SetStartAndEndInternal( const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary, - StaticRange* aRange); + StaticRange* aRange, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template nsresult AbstractRange::SetStartAndEndInternal( const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, - StaticRange* aRange); + StaticRange* aRange, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template nsresult AbstractRange::SetStartAndEndInternal( const RawRangeBoundary& aStartBoundary, - const RawRangeBoundary& aEndBoundary, StaticRange* aRange); + const RawRangeBoundary& aEndBoundary, StaticRange* aRange, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template bool AbstractRange::MaybeCacheToReuse(nsRange& aInstance); template bool AbstractRange::MaybeCacheToReuse(StaticRange& aInstance); template bool AbstractRange::MaybeCacheToReuse( @@ -91,32 +98,65 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AbstractRange) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRegisteredClosestCommonInclusiveAncestor) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -// When aMarkDesendants is true, Set -// DescendantOfClosestCommonInclusiveAncestorForRangeInSelection flag for the -// shadow including children of aNode. When aMarkDesendants is false, unset that -// flag for the shadow including children of aNode. -void UpdateDescendantsByShadowIncludingOrder(const nsIContent& aNode, - bool aMarkDesendants) { - ShadowIncludingTreeIterator iter(*const_cast(&aNode)); - ++iter; // We don't want to mark the root node - - while (iter) { - nsINode* node = *iter; +static void UpdateDescendantsInSameTree(const nsINode& aNode, + bool aMarkDesendants) { + MOZ_ASSERT(!StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()); + // don't set the Descendant bit on |aNode| itself + nsINode* node = aNode.GetNextNode(&aNode); + while (node) { if (aMarkDesendants) { node->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection(); } else { node->ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection(); } - if (node->IsClosestCommonInclusiveAncestorForRangeInSelection()) { - iter.SkipChildren(); - continue; + if (!node->IsClosestCommonInclusiveAncestorForRangeInSelection()) { + node = node->GetNextNode(&aNode); + } else { + // We found an ancestor of an overlapping range, skip its descendants. + node = node->GetNextNonChildNode(&aNode); } - ++iter; } } -void AbstractRange::MarkDescendants(const nsINode& aNode) { +void AbstractRange::UpdateDescendantsInFlattenedTree(nsINode& aNode, + bool aMarkDescendants) { + MOZ_ASSERT(StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()); + + auto UpdateDescendant = [aMarkDescendants](nsINode* node) { + if (aMarkDescendants) { + node->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection(); + } else { + node->ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection(); + } + }; + + nsINode* target = &aNode; + + if (target->IsDocument()) { + if (auto* rootElement = aNode.AsDocument()->GetRootElement()) { + target = rootElement; + UpdateDescendant(target); + } + } + + if (!target || !target->IsContent()) { + return; + } + + TreeIterator iter(*target->AsContent()); + iter.GetNext(); // Skip aNode itself. + while (nsIContent* curNode = iter.GetCurrent()) { + UpdateDescendant(curNode); + if (curNode->IsClosestCommonInclusiveAncestorForRangeInSelection()) { + iter.GetNextSkippingChildren(); + } else { + iter.GetNext(); + } + } +} + +void AbstractRange::MarkDescendants(nsINode& aNode) { // Set NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection on // aNode's descendants unless aNode is already marked as a range common // ancestor or a descendant of one, in which case all of our descendants have @@ -124,59 +164,26 @@ void AbstractRange::MarkDescendants(const nsINode& aNode) { if (!aNode.IsMaybeSelected()) { // If aNode has a web-exposed shadow root, use this shadow tree and ignore // the children of aNode. - if (aNode.GetShadowRootForSelection()) { - UpdateDescendantsByShadowIncludingOrder(*aNode.AsContent(), true); - return; - } - // don't set the Descendant bit on |aNode| itself - nsINode* node = aNode.GetNextNode(&aNode); - while (node) { - node->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection(); - if (!node->IsClosestCommonInclusiveAncestorForRangeInSelection()) { - if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) { - UpdateDescendantsByShadowIncludingOrder(*node->AsContent(), true); - // sub-tree of node has been marked already - node = node->GetNextNonChildNode(&aNode); - } else { - node = node->GetNextNode(&aNode); - } - } else { - // optimize: skip this sub-tree since it's marked already. - node = node->GetNextNonChildNode(&aNode); - } + + if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) { + UpdateDescendantsInFlattenedTree(aNode, true /* aMarkDescendants */); + } else { + UpdateDescendantsInSameTree(aNode, true /* aMarkDescendants */); } } } -void AbstractRange::UnmarkDescendants(const nsINode& aNode) { +void AbstractRange::UnmarkDescendants(nsINode& aNode) { // Unset NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection // on aNode's descendants unless aNode is a descendant of another range common // ancestor. Also, exclude descendants of range common ancestors (but not the // common ancestor itself). if (!aNode .IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) { - // If aNode has a web-exposed shadow root, use this shadow tree and ignore - // the children of aNode. - if (aNode.GetShadowRootForSelection()) { - UpdateDescendantsByShadowIncludingOrder(*aNode.AsContent(), false); - return; - } - // we know |aNode| doesn't have any bit set - nsINode* node = aNode.GetNextNode(&aNode); - while (node) { - node->ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection(); - if (!node->IsClosestCommonInclusiveAncestorForRangeInSelection()) { - if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) { - UpdateDescendantsByShadowIncludingOrder(*node->AsContent(), false); - // sub-tree has been marked already - node = node->GetNextNonChildNode(&aNode); - } else { - node = node->GetNextNode(&aNode); - } - } else { - // We found an ancestor of an overlapping range, skip its descendants. - node = node->GetNextNonChildNode(&aNode); - } + if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) { + UpdateDescendantsInFlattenedTree(aNode, false /* aMarkDescendants */); + } else { + UpdateDescendantsInSameTree(aNode, false /* aMarkDescendants */); } } } @@ -303,7 +310,8 @@ template nsresult AbstractRange::SetStartAndEndInternal( const RangeBoundaryBase& aStartBoundary, - const RangeBoundaryBase& aEndBoundary, RangeType* aRange) { + const RangeBoundaryBase& aEndBoundary, RangeType* aRange, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary) { if (NS_WARN_IF(!aStartBoundary.IsSet()) || NS_WARN_IF(!aEndBoundary.IsSet())) { return NS_ERROR_INVALID_ARG; @@ -371,7 +379,11 @@ nsresult AbstractRange::SetStartAndEndInternal( } const Maybe pointOrder = - nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary); + aAllowCrossShadowBoundary == AllowRangeCrossShadowBoundary::Yes && + StaticPrefs::dom_shadowdom_selection_across_boundary_enabled() + ? nsContentUtils::ComparePoints(aStartBoundary, + aEndBoundary) + : nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary); if (!pointOrder) { // Safely return a value but also detected this in debug builds. MOZ_ASSERT_UNREACHABLE(); diff --git a/dom/base/AbstractRange.h b/dom/base/AbstractRange.h index 399fe5a994db..4828523d5337 100644 --- a/dom/base/AbstractRange.h +++ b/dom/base/AbstractRange.h @@ -30,6 +30,7 @@ namespace mozilla::dom { class Document; class Selection; class StaticRange; +class HTMLSlotElement; enum class AllowRangeCrossShadowBoundary : bool { No, Yes }; @@ -193,7 +194,9 @@ class AbstractRange : public nsISupports, typename RangeType> static nsresult SetStartAndEndInternal( const RangeBoundaryBase& aStartBoundary, - const RangeBoundaryBase& aEndBoundary, RangeType* aRange); + const RangeBoundaryBase& aEndBoundary, RangeType* aRange, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary = + AllowRangeCrossShadowBoundary::No); template static bool MaybeCacheToReuse(RangeType& aInstance); @@ -227,8 +230,15 @@ class AbstractRange : public nsISupports, void UpdateCommonAncestorIfNecessary(); - static void MarkDescendants(const nsINode& aNode); - static void UnmarkDescendants(const nsINode& aNode); + static void MarkDescendants(nsINode& aNode); + static void UnmarkDescendants(nsINode& aNode); + + static void UpdateDescendantsInFlattenedTree(nsINode& aNode, + bool aMarkDescendants); + friend void mozilla::SlotAssignedNodeAdded(dom::HTMLSlotElement* aSlot, + nsIContent& aAssignedNode); + friend void mozilla::SlotAssignedNodeRemoved(dom::HTMLSlotElement* aSlot, + nsIContent& aUnassignedNode); private: void ClearForReuse(); diff --git a/dom/base/DirectionalityUtils.cpp b/dom/base/DirectionalityUtils.cpp index 3318268bff10..798f8e941477 100644 --- a/dom/base/DirectionalityUtils.cpp +++ b/dom/base/DirectionalityUtils.cpp @@ -559,6 +559,19 @@ static void MaybeClearAffectsDirAutoSlot(nsIContent* aContent) { } void SlotAssignedNodeAdded(HTMLSlotElement* aSlot, nsIContent& aAssignedNode) { + MOZ_ASSERT(aSlot); + if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) { + if (aSlot->IsMaybeSelected()) { + // Normally it's nsRange::ContentAppended's responsibility to + // mark new descendants, however this doesn't work for slotted + // content because nsRange observes the common ancestor of + // start/end, whereas slotted element may not have the same + // ancestor as them. + dom::AbstractRange::UpdateDescendantsInFlattenedTree( + aAssignedNode, true /* aMarkDesendants*/); + } + } + if (aSlot->HasDirAuto()) { aAssignedNode.SetAffectsDirAutoSlot(); DownwardPropagateDirAutoFlags(&aAssignedNode); @@ -568,6 +581,19 @@ void SlotAssignedNodeAdded(HTMLSlotElement* aSlot, nsIContent& aAssignedNode) { void SlotAssignedNodeRemoved(HTMLSlotElement* aSlot, nsIContent& aUnassignedNode) { + if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled() && + aUnassignedNode.IsMaybeSelected()) { + // Normally, this shouldn't happen because nsRange::ContentRemoved + // should be called for content removal, and then + // AbstractRange::UnmarkDescendants will be used to clear the flags. + // Though this doesn't work for slotted element because nsRange + // observers the common ancestor of start/end, whereas slotted element + // may not have the same ancestor as them, so we have to clear + // the flags manually here. + dom::AbstractRange::UpdateDescendantsInFlattenedTree( + aUnassignedNode, false /* aMarkDesendants*/); + } + if (aSlot->HasDirAuto()) { MaybeClearAffectsDirAutoSlot(&aUnassignedNode); } diff --git a/dom/base/RangeUtils.cpp b/dom/base/RangeUtils.cpp index 898f1e5d90e3..d1d7702ede2c 100644 --- a/dom/base/RangeUtils.cpp +++ b/dom/base/RangeUtils.cpp @@ -10,6 +10,7 @@ #include "mozilla/dom/AbstractRange.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/ShadowRoot.h" +#include "mozilla/dom/HTMLSlotElement.h" #include "nsContentUtils.h" #include "nsFrameSelection.h" diff --git a/dom/base/Selection.cpp b/dom/base/Selection.cpp index 2f5c94164835..31ae959063b4 100644 --- a/dom/base/Selection.cpp +++ b/dom/base/Selection.cpp @@ -3185,7 +3185,10 @@ void Selection::Extend(nsINode& aContainer, uint32_t aOffset, } SetDirection(eDirNext); res = difRange->SetStartAndEnd( - focusNode, focusOffset, range->GetEndContainer(), range->EndOffset()); + focusNode, focusOffset, + range->GetMayCrossShadowBoundaryEndContainer(), + range->MayCrossShadowBoundaryEndOffset(), + AllowRangeCrossShadowBoundary::Yes); if (NS_FAILED(res)) { aRv.Throw(res); return; @@ -3214,8 +3217,9 @@ void Selection::Extend(nsINode& aContainer, uint32_t aOffset, } else if (*anchorNewFocusOrder <= 0 && *oldFocusNewFocusOrder >= 0) { // a,2,1 or a2,1 or a,21 or a21 // deselect from 2 to 1 - res = difRange->SetStartAndEnd(&aContainer, aOffset, focusNode, - focusOffset); + res = + difRange->SetStartAndEnd(&aContainer, aOffset, focusNode, focusOffset, + AllowRangeCrossShadowBoundary::Yes); if (NS_FAILED(res)) { aRv.Throw(res); return; @@ -3285,12 +3289,14 @@ void Selection::Extend(nsINode& aContainer, uint32_t aOffset, } else if (*oldFocusNewFocusOrder <= 0 && *anchorNewFocusOrder >= 0) { // 1,2,a or 12,a or 1,2a or 12a // deselect from 1 to 2 - res = difRange->SetStartAndEnd(focusNode, focusOffset, &aContainer, - aOffset); + res = + difRange->SetStartAndEnd(focusNode, focusOffset, &aContainer, aOffset, + AllowRangeCrossShadowBoundary::Yes); if (NS_FAILED(res)) { aRv.Throw(res); return; } + SetDirection(eDirPrevious); range->SetStart(aContainer, aOffset, aRv, AllowRangeCrossShadowBoundary::Yes); @@ -3324,7 +3330,8 @@ void Selection::Extend(nsINode& aContainer, uint32_t aOffset, if (focusNode != anchorNode || focusOffset != anchorOffset) { // if collapsed diff dont do anything res = difRange->SetStartAndEnd(anchorNode, anchorOffset, focusNode, - focusOffset); + focusOffset, + AllowRangeCrossShadowBoundary::Yes); nsresult tmp = SetAnchorFocusToRange(range); if (NS_FAILED(tmp)) { res = tmp; @@ -3352,9 +3359,9 @@ void Selection::Extend(nsINode& aContainer, uint32_t aOffset, return; } SetDirection(eDirPrevious); - res = difRange->SetStartAndEnd(range->GetStartContainer(), - range->StartOffset(), focusNode, - focusOffset); + res = difRange->SetStartAndEnd( + range->GetStartContainer(), range->StartOffset(), focusNode, + focusOffset, AllowRangeCrossShadowBoundary::Yes); if (NS_FAILED(res)) { aRv.Throw(res); return; @@ -4337,7 +4344,11 @@ void Selection::SetStartAndEndInternal(InLimiter aInLimiter, } } - RefPtr newRange = nsRange::Create(aStartRef, aEndRef, aRv); + RefPtr newRange = nsRange::Create( + aStartRef, aEndRef, aRv, + StaticPrefs::dom_shadowdom_selection_across_boundary_enabled() + ? AllowRangeCrossShadowBoundary::Yes + : AllowRangeCrossShadowBoundary::No); if (aRv.Failed()) { return; } diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 2d4d95806bd6..79453a8dbbed 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -310,17 +310,26 @@ static const nsINode* GetClosestCommonInclusiveAncestorForRangeInSelection( const nsINode* aNode) { while (aNode && !aNode->IsClosestCommonInclusiveAncestorForRangeInSelection()) { - const bool isNodeInShadowTree = + const bool isNodeInFlattenedShadowTree = StaticPrefs::dom_shadowdom_selection_across_boundary_enabled() && - aNode->IsInShadowTree(); + (aNode->IsInShadowTree() || + (aNode->IsContent() && aNode->AsContent()->GetAssignedSlot())); + if (!aNode ->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() && - !isNodeInShadowTree) { + !isNodeInFlattenedShadowTree) { return nullptr; } - aNode = StaticPrefs::dom_shadowdom_selection_across_boundary_enabled() - ? aNode->GetParentOrShadowHostNode() - : aNode->GetParentNode(); + + if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) { + if (aNode->IsContent() && aNode->AsContent()->GetAssignedSlot()) { + aNode = aNode->AsContent()->GetAssignedSlot(); + } else { + aNode = aNode->GetParentOrShadowHostNode(); + } + continue; + } + aNode = aNode->GetParentNode(); } return aNode; } diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index 65c0518f9d60..cbba9dde91c7 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -87,26 +87,31 @@ using namespace mozilla::dom; template already_AddRefed nsRange::Create( const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, - ErrorResult& aRv); + ErrorResult& aRv, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template already_AddRefed nsRange::Create( const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary, - ErrorResult& aRv); + ErrorResult& aRv, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template already_AddRefed nsRange::Create( const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, - ErrorResult& aRv); + ErrorResult& aRv, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template already_AddRefed nsRange::Create( const RawRangeBoundary& aStartBoundary, - const RawRangeBoundary& aEndBoundary, ErrorResult& aRv); + const RawRangeBoundary& aEndBoundary, ErrorResult& aRv, + AllowRangeCrossShadowBoundary aAlloCrossShadowBoundary); -template nsresult nsRange::SetStartAndEnd(const RangeBoundary& aStartBoundary, - const RangeBoundary& aEndBoundary); -template nsresult nsRange::SetStartAndEnd(const RangeBoundary& aStartBoundary, - const RawRangeBoundary& aEndBoundary); template nsresult nsRange::SetStartAndEnd( - const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary); + const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); +template nsresult nsRange::SetStartAndEnd( + const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); +template nsresult nsRange::SetStartAndEnd( + const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template nsresult nsRange::SetStartAndEnd( const RawRangeBoundary& aStartBoundary, - const RawRangeBoundary& aEndBoundary); + const RawRangeBoundary& aEndBoundary, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary); template void nsRange::DoSetRange(const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary, @@ -209,11 +214,13 @@ already_AddRefed nsRange::Create(nsINode* aNode) { template already_AddRefed nsRange::Create( const RangeBoundaryBase& aStartBoundary, - const RangeBoundaryBase& aEndBoundary, ErrorResult& aRv) { + const RangeBoundaryBase& aEndBoundary, ErrorResult& aRv, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary) { // If we fail to initialize the range a lot, nsRange should have a static // initializer since the allocation cost is not cheap in hot path. RefPtr range = nsRange::Create(aStartBoundary.GetContainer()); - aRv = range->SetStartAndEnd(aStartBoundary, aEndBoundary); + aRv = range->SetStartAndEnd(aStartBoundary, aEndBoundary, + aAllowCrossShadowBoundary); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } diff --git a/dom/base/nsRange.h b/dom/base/nsRange.h index d5e841e61e89..9d9479b91e14 100644 --- a/dom/base/nsRange.h +++ b/dom/base/nsRange.h @@ -100,7 +100,8 @@ class nsRange final : public mozilla::dom::AbstractRange, static already_AddRefed Create( const mozilla::RangeBoundaryBase& aStartBoundary, const mozilla::RangeBoundaryBase& aEndBoundary, - ErrorResult& aRv); + ErrorResult& aRv, + AllowRangeCrossShadowBoundary = AllowRangeCrossShadowBoundary::No); NS_DECL_ISUPPORTS_INHERITED NS_IMETHODIMP_(void) DeleteCycleCollectable(void) override; @@ -160,17 +161,23 @@ class nsRange final : public mozilla::dom::AbstractRange, * collapsed at the end point. Similarly, if they are in different root, * the range will be collapsed at the end point. */ - nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset, - nsINode* aEndContainer, uint32_t aEndOffset) { + nsresult SetStartAndEnd( + nsINode* aStartContainer, uint32_t aStartOffset, nsINode* aEndContainer, + uint32_t aEndOffset, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary = + AllowRangeCrossShadowBoundary::No) { return SetStartAndEnd(RawRangeBoundary(aStartContainer, aStartOffset), - RawRangeBoundary(aEndContainer, aEndOffset)); + RawRangeBoundary(aEndContainer, aEndOffset), + aAllowCrossShadowBoundary); } template nsresult SetStartAndEnd( const mozilla::RangeBoundaryBase& aStartBoundary, - const mozilla::RangeBoundaryBase& aEndBoundary) { - return AbstractRange::SetStartAndEndInternal(aStartBoundary, aEndBoundary, - this); + const mozilla::RangeBoundaryBase& aEndBoundary, + AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary = + AllowRangeCrossShadowBoundary::No) { + return AbstractRange::SetStartAndEndInternal( + aStartBoundary, aEndBoundary, this, aAllowCrossShadowBoundary); } /**