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:
committed by
sefeng@mozilla.com
parent
59893c42dc
commit
d3f6c9a968
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user