Bug 1932150 - Update ranges to correctly set and update nodes for flattened selection r=jjaschke,smaug,dom-core

Differential Revision: https://phabricator.services.mozilla.com/D231589
This commit is contained in:
Sean Feng
2025-05-09 17:16:37 +00:00
committed by sefeng@mozilla.com
parent 59893c42dc
commit d3f6c9a968
8 changed files with 190 additions and 107 deletions

View File

@@ -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<nsIContent*>(&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<FlattenedChildIterator> 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 <typename SPT, typename SRT, typename EPT, typename ERT,
typename RangeType>
nsresult AbstractRange::SetStartAndEndInternal(
const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, RangeType* aRange) {
const RangeBoundaryBase<EPT, ERT>& 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<int32_t> pointOrder =
nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary);
aAllowCrossShadowBoundary == AllowRangeCrossShadowBoundary::Yes &&
StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()
? nsContentUtils::ComparePoints<TreeKind::Flat>(aStartBoundary,
aEndBoundary)
: nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary);
if (!pointOrder) {
// Safely return a value but also detected this in debug builds.
MOZ_ASSERT_UNREACHABLE();

View File

@@ -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<SPT, SRT>& aStartBoundary,
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, RangeType* aRange);
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, RangeType* aRange,
AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
AllowRangeCrossShadowBoundary::No);
template <class RangeType>
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();

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -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<nsRange> newRange = nsRange::Create(aStartRef, aEndRef, aRv);
RefPtr<nsRange> newRange = nsRange::Create(
aStartRef, aEndRef, aRv,
StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()
? AllowRangeCrossShadowBoundary::Yes
: AllowRangeCrossShadowBoundary::No);
if (aRv.Failed()) {
return;
}

View File

@@ -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;
}

View File

@@ -87,26 +87,31 @@ using namespace mozilla::dom;
template already_AddRefed<nsRange> nsRange::Create(
const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary,
ErrorResult& aRv);
ErrorResult& aRv, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary);
template already_AddRefed<nsRange> nsRange::Create(
const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary,
ErrorResult& aRv);
ErrorResult& aRv, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary);
template already_AddRefed<nsRange> nsRange::Create(
const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary,
ErrorResult& aRv);
ErrorResult& aRv, AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary);
template already_AddRefed<nsRange> 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> nsRange::Create(nsINode* aNode) {
template <typename SPT, typename SRT, typename EPT, typename ERT>
already_AddRefed<nsRange> nsRange::Create(
const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, ErrorResult& aRv) {
const RangeBoundaryBase<EPT, ERT>& 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<nsRange> range = nsRange::Create(aStartBoundary.GetContainer());
aRv = range->SetStartAndEnd(aStartBoundary, aEndBoundary);
aRv = range->SetStartAndEnd(aStartBoundary, aEndBoundary,
aAllowCrossShadowBoundary);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}

View File

@@ -100,7 +100,8 @@ class nsRange final : public mozilla::dom::AbstractRange,
static already_AddRefed<nsRange> Create(
const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
const mozilla::RangeBoundaryBase<EPT, ERT>& 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 <typename SPT, typename SRT, typename EPT, typename ERT>
nsresult SetStartAndEnd(
const mozilla::RangeBoundaryBase<SPT, SRT>& aStartBoundary,
const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary) {
return AbstractRange::SetStartAndEndInternal(aStartBoundary, aEndBoundary,
this);
const mozilla::RangeBoundaryBase<EPT, ERT>& aEndBoundary,
AllowRangeCrossShadowBoundary aAllowCrossShadowBoundary =
AllowRangeCrossShadowBoundary::No) {
return AbstractRange::SetStartAndEndInternal(
aStartBoundary, aEndBoundary, this, aAllowCrossShadowBoundary);
}
/**