Bug 1945711 - part 3: Make some callers of nsContentUtils::ComparePoints use the RangeBoundaryBase version r=jjaschke,dom-core
There are some callers of parent/offset version which computes offset before. However, the offset may not be used. Therefore, the callers should use `RangeBoundaryBase` version. Additionally, if only one of the pairs is computed from `RangeBoundaryBase`, such callers should use the `RangeBoundaryBase` version too because the offset computation may be skipped. In this case, temporary `RangeBoundaryBase` should be a `RawRangeBoundary` and whose `aRangeIsMutationObserver` should be set to `RangeBoundaryIsMutationObserved::No` to avoid immediately to compute the child node from `aOffset`. I think that this should be default to `RangeBoundaryIsMutationObserved::No` in the future, but for now, we should just make the users explicitly set it to `RangeBoundaryIsMutationObserved::No` for avoiding regressions. Differential Revision: https://phabricator.services.mozilla.com/D236793
This commit is contained in:
@@ -816,39 +816,38 @@ bool HyperTextAccessible::SelectionBoundsAt(int32_t aSelectionNum,
|
||||
|
||||
nsRange* range = ranges[aSelectionNum];
|
||||
|
||||
// Get start and end points.
|
||||
nsINode* startNode = range->GetStartContainer();
|
||||
nsINode* endNode = range->GetEndContainer();
|
||||
uint32_t startOffset = range->StartOffset();
|
||||
uint32_t endOffset = range->EndOffset();
|
||||
|
||||
// Make sure start is before end, by swapping DOM points. This occurs when
|
||||
// the user selects backwards in the text.
|
||||
const Maybe<int32_t> order =
|
||||
nsContentUtils::ComparePoints(endNode, endOffset, startNode, startOffset);
|
||||
nsContentUtils::ComparePoints(range->EndRef(), range->StartRef());
|
||||
|
||||
if (!order) {
|
||||
MOZ_ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*order < 0) {
|
||||
std::swap(startNode, endNode);
|
||||
std::swap(startOffset, endOffset);
|
||||
}
|
||||
const RangeBoundary& precedingBoundary =
|
||||
*order < 0 ? range->EndRef() : range->StartRef();
|
||||
const RangeBoundary& followingBoundary =
|
||||
*order < 0 ? range->StartRef() : range->EndRef();
|
||||
|
||||
if (!startNode->IsInclusiveDescendantOf(mContent)) {
|
||||
if (!precedingBoundary.Container()->IsInclusiveDescendantOf(mContent)) {
|
||||
*aStartOffset = 0;
|
||||
} else {
|
||||
*aStartOffset =
|
||||
DOMPointToOffset(startNode, AssertedCast<int32_t>(startOffset));
|
||||
*aStartOffset = DOMPointToOffset(
|
||||
precedingBoundary.Container(),
|
||||
AssertedCast<int32_t>(*precedingBoundary.Offset(
|
||||
RangeBoundary::OffsetFilter::kValidOrInvalidOffsets)));
|
||||
}
|
||||
|
||||
if (!endNode->IsInclusiveDescendantOf(mContent)) {
|
||||
if (!followingBoundary.Container()->IsInclusiveDescendantOf(mContent)) {
|
||||
*aEndOffset = CharacterCount();
|
||||
} else {
|
||||
*aEndOffset =
|
||||
DOMPointToOffset(endNode, AssertedCast<int32_t>(endOffset), true);
|
||||
*aEndOffset = DOMPointToOffset(
|
||||
followingBoundary.Container(),
|
||||
AssertedCast<int32_t>(*followingBoundary.Offset(
|
||||
RangeBoundary::OffsetFilter::kValidOrInvalidOffsets)),
|
||||
true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,9 +41,11 @@ class EditorDOMPointBase;
|
||||
template <typename ParentType, typename RefType>
|
||||
class RangeBoundaryBase;
|
||||
|
||||
typedef RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent>>
|
||||
RangeBoundary;
|
||||
typedef RangeBoundaryBase<nsINode*, nsIContent*> RawRangeBoundary;
|
||||
using RangeBoundary =
|
||||
RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent>>;
|
||||
using RawRangeBoundary = RangeBoundaryBase<nsINode*, nsIContent*>;
|
||||
using ConstRawRangeBoundary =
|
||||
RangeBoundaryBase<const nsINode*, const nsIContent*>;
|
||||
|
||||
/**
|
||||
* There are two ways of ensuring that `mRef` points to the correct node.
|
||||
@@ -69,9 +71,9 @@ typedef RangeBoundaryBase<nsINode*, nsIContent*> RawRangeBoundary;
|
||||
*/
|
||||
enum class RangeBoundaryIsMutationObserved { No = 0, Yes = 1 };
|
||||
|
||||
// This class has two specializations, one using reference counting
|
||||
// pointers and one using raw pointers. This helps us avoid unnecessary
|
||||
// AddRef/Release calls.
|
||||
// This class has two types of specializations, one using reference counting
|
||||
// pointers and one using raw pointers (both non-const and const versions). The
|
||||
// latter help us avoid unnecessary AddRef/Release calls.
|
||||
template <typename ParentType, typename RefType>
|
||||
class RangeBoundaryBase {
|
||||
template <typename T, typename U>
|
||||
@@ -90,8 +92,26 @@ class RangeBoundaryBase {
|
||||
|
||||
static const uint32_t kFallbackOffset = 0;
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct GetNodeType;
|
||||
template <typename T>
|
||||
struct GetNodeType<T, std::enable_if_t<std::is_pointer_v<T>>> {
|
||||
using type = std::remove_pointer_t<T>;
|
||||
};
|
||||
template <typename T>
|
||||
struct GetNodeType<T, std::enable_if_t<!std::is_pointer_v<T>>> {
|
||||
using type = typename T::element_type;
|
||||
};
|
||||
|
||||
public:
|
||||
RangeBoundaryBase(nsINode* aContainer, nsIContent* aRef)
|
||||
using RawParentType = typename GetNodeType<ParentType>::type;
|
||||
static_assert(std::is_same_v<RawParentType, nsINode> ||
|
||||
std::is_same_v<RawParentType, const nsINode>);
|
||||
using RawRefType = typename GetNodeType<RefType>::type;
|
||||
static_assert(std::is_same_v<RawRefType, nsIContent> ||
|
||||
std::is_same_v<RawRefType, const nsIContent>);
|
||||
|
||||
RangeBoundaryBase(RawParentType* aContainer, RawRefType* aRef)
|
||||
: mParent(aContainer), mRef(aRef), mIsMutationObserved(true) {
|
||||
if (mRef) {
|
||||
NS_WARNING_ASSERTION(mRef->GetParentNode() == mParent,
|
||||
@@ -101,7 +121,7 @@ class RangeBoundaryBase {
|
||||
}
|
||||
}
|
||||
|
||||
RangeBoundaryBase(nsINode* aContainer, uint32_t aOffset,
|
||||
RangeBoundaryBase(RawParentType* aContainer, uint32_t aOffset,
|
||||
RangeBoundaryIsMutationObserved aRangeIsMutationObserver =
|
||||
RangeBoundaryIsMutationObserved::Yes)
|
||||
: mParent(aContainer),
|
||||
@@ -122,11 +142,30 @@ class RangeBoundaryBase {
|
||||
"Constructing RangeBoundary with invalid value");
|
||||
}
|
||||
|
||||
/**
|
||||
* Special constructor to create RangeBoundaryBase which stores both mRef and
|
||||
* mOffset. This can make the instance provide both mRef and mOffset without
|
||||
* computation, but the creator needs to guarantee that this is valid at least
|
||||
* at construction.
|
||||
*/
|
||||
RangeBoundaryBase(RawParentType* aContainer, RawRefType* aRef,
|
||||
uint32_t aOffset,
|
||||
RangeBoundaryIsMutationObserved aRangeIsMutationObserver =
|
||||
RangeBoundaryIsMutationObserved::Yes)
|
||||
: mParent(const_cast<nsINode*>(aContainer)),
|
||||
mRef(const_cast<nsIContent*>(aRef)),
|
||||
mOffset(mozilla::Some(aOffset)),
|
||||
mIsMutationObserved(bool(aRangeIsMutationObserver)) {
|
||||
MOZ_ASSERT(IsSetAndValid());
|
||||
}
|
||||
|
||||
RangeBoundaryBase()
|
||||
: mParent(nullptr), mRef(nullptr), mIsMutationObserved(true) {}
|
||||
|
||||
// Needed for initializing RawRangeBoundary from an existing RangeBoundary.
|
||||
template <typename PT, typename RT>
|
||||
// Convert from RawRangeBoundary or RangeBoundary.
|
||||
template <typename PT, typename RT,
|
||||
typename = std::enable_if_t<!std::is_const_v<RawParentType> ||
|
||||
std::is_const_v<PT>>>
|
||||
RangeBoundaryBase(const RangeBoundaryBase<PT, RT>& aOther,
|
||||
RangeBoundaryIsMutationObserved aIsMutationObserved)
|
||||
: mParent(aOther.mParent),
|
||||
@@ -145,7 +184,7 @@ class RangeBoundaryBase {
|
||||
* Code inside of this class should call this method exactly one time and
|
||||
* afterwards refer to `mRef` directly.
|
||||
*/
|
||||
nsIContent* Ref() const {
|
||||
RawRefType* Ref() const {
|
||||
if (mIsMutationObserved) {
|
||||
return mRef;
|
||||
}
|
||||
@@ -177,17 +216,21 @@ class RangeBoundaryBase {
|
||||
return mRef;
|
||||
}
|
||||
|
||||
nsINode* Container() const { return mParent; }
|
||||
RawParentType* Container() const { return mParent; }
|
||||
|
||||
dom::Document* GetComposedDoc() const {
|
||||
return mParent ? mParent->GetComposedDoc() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method may return `nullptr` if `mIsMutationObserved` is false and
|
||||
* `mOffset` is out of bounds.
|
||||
*/
|
||||
nsIContent* GetChildAtOffset() const {
|
||||
RawRefType* GetChildAtOffset() const {
|
||||
if (!mParent || !mParent->IsContainerNode()) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIContent* const ref = Ref();
|
||||
RawRefType* const ref = Ref();
|
||||
if (!ref) {
|
||||
if (!mIsMutationObserved && *mOffset != 0) {
|
||||
// This means that this boundary is invalid.
|
||||
@@ -209,11 +252,11 @@ class RangeBoundaryBase {
|
||||
* If this refers after the last child or the container cannot have children,
|
||||
* this returns nullptr with warning.
|
||||
*/
|
||||
nsIContent* GetNextSiblingOfChildAtOffset() const {
|
||||
RawRefType* GetNextSiblingOfChildAtOffset() const {
|
||||
if (NS_WARN_IF(!mParent) || NS_WARN_IF(!mParent->IsContainerNode())) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIContent* const ref = Ref();
|
||||
RawRefType* const ref = Ref();
|
||||
if (!ref) {
|
||||
if (!mIsMutationObserved && *mOffset != 0) {
|
||||
// This means that this boundary is invalid.
|
||||
@@ -241,11 +284,11 @@ class RangeBoundaryBase {
|
||||
* at offset. If this refers the first child or the container cannot have
|
||||
* children, this returns nullptr with warning.
|
||||
*/
|
||||
nsIContent* GetPreviousSiblingOfChildAtOffset() const {
|
||||
RawRefType* GetPreviousSiblingOfChildAtOffset() const {
|
||||
if (NS_WARN_IF(!mParent) || NS_WARN_IF(!mParent->IsContainerNode())) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIContent* const ref = Ref();
|
||||
RawRefType* const ref = Ref();
|
||||
if (NS_WARN_IF(!ref)) {
|
||||
// Already referring the start of the container.
|
||||
return nullptr;
|
||||
@@ -392,6 +435,10 @@ class RangeBoundaryBase {
|
||||
|
||||
bool IsSet() const { return mParent && (mRef || mOffset.isSome()); }
|
||||
|
||||
[[nodiscard]] bool IsSetAndInComposedDoc() const {
|
||||
return IsSet() && mParent->IsInComposedDoc();
|
||||
}
|
||||
|
||||
bool IsSetAndValid() const {
|
||||
if (!IsSet()) {
|
||||
return false;
|
||||
@@ -428,17 +475,25 @@ class RangeBoundaryBase {
|
||||
|
||||
// Convenience methods for switching between the two types
|
||||
// of RangeBoundary.
|
||||
RangeBoundaryBase<nsINode*, nsIContent*> AsRaw() const {
|
||||
return RangeBoundaryBase<nsINode*, nsIContent*>(
|
||||
template <typename PT = RawParentType,
|
||||
typename = std::enable_if_t<!std::is_const_v<PT>>>
|
||||
RawRangeBoundary AsRaw() const {
|
||||
return RawRangeBoundary(
|
||||
*this, RangeBoundaryIsMutationObserved(mIsMutationObserved));
|
||||
}
|
||||
ConstRawRangeBoundary AsConstRaw() const {
|
||||
return ConstRawRangeBoundary(
|
||||
*this, RangeBoundaryIsMutationObserved(mIsMutationObserved));
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
RangeBoundaryBase& operator=(const RangeBoundaryBase<A, B>& aOther) = delete;
|
||||
|
||||
template <typename A, typename B>
|
||||
template <
|
||||
typename PT, typename RT, typename RPT = RawParentType,
|
||||
typename = std::enable_if_t<!std::is_const_v<PT> || std::is_const_v<RPT>>>
|
||||
RangeBoundaryBase& CopyFrom(
|
||||
const RangeBoundaryBase<A, B>& aOther,
|
||||
const RangeBoundaryBase<PT, RT>& aOther,
|
||||
RangeBoundaryIsMutationObserved aIsMutationObserved) {
|
||||
// mParent and mRef can be strong pointers, so better to try to avoid any
|
||||
// extra AddRef/Release calls.
|
||||
@@ -455,7 +510,7 @@ class RangeBoundaryBase {
|
||||
// XXX What should we do if aOther is not updated for mutations and
|
||||
// mOffset has already been invalid?
|
||||
mOffset = aOther.Offset(
|
||||
RangeBoundaryBase<A, B>::OffsetFilter::kValidOrInvalidOffsets);
|
||||
RangeBoundaryBase<PT, RT>::OffsetFilter::kValidOrInvalidOffsets);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mOffset.isSome());
|
||||
} else {
|
||||
mOffset = aOther.mOffset;
|
||||
@@ -463,7 +518,7 @@ class RangeBoundaryBase {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Equals(const nsINode* aNode, uint32_t aOffset) const {
|
||||
bool Equals(const RawParentType* aNode, uint32_t aOffset) const {
|
||||
if (mParent != aNode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -890,16 +890,17 @@ void Selection::SetAnchorFocusRange(size_t aIndex) {
|
||||
mAnchorFocusRange = anchorFocusRange->AsDynamicRange();
|
||||
}
|
||||
|
||||
static int32_t CompareToRangeStart(const nsINode& aCompareNode,
|
||||
uint32_t aCompareOffset,
|
||||
const AbstractRange& aRange,
|
||||
nsContentUtils::NodeIndexCache* aCache) {
|
||||
template <typename PT, typename RT>
|
||||
static int32_t CompareToRangeStart(
|
||||
const RangeBoundaryBase<PT, RT>& aCompareBoundary,
|
||||
const AbstractRange& aRange, nsContentUtils::NodeIndexCache* aCache) {
|
||||
MOZ_ASSERT(aCompareBoundary.IsSet());
|
||||
MOZ_ASSERT(aRange.GetMayCrossShadowBoundaryStartContainer());
|
||||
nsINode* start = aRange.GetMayCrossShadowBoundaryStartContainer();
|
||||
// If the nodes that we're comparing are not in the same document, assume that
|
||||
// aCompareNode will fall at the end of the ranges.
|
||||
if (aCompareNode.GetComposedDoc() != start->GetComposedDoc() ||
|
||||
!start->GetComposedDoc()) {
|
||||
if (aCompareBoundary.GetComposedDoc() !=
|
||||
aRange.MayCrossShadowBoundaryStartRef().GetComposedDoc() ||
|
||||
!aRange.MayCrossShadowBoundaryStartRef().IsSetAndInComposedDoc()) {
|
||||
NS_WARNING(
|
||||
"`CompareToRangeStart` couldn't compare nodes, pretending some order.");
|
||||
return 1;
|
||||
@@ -907,41 +908,44 @@ static int32_t CompareToRangeStart(const nsINode& aCompareNode,
|
||||
|
||||
// The points are in the same subtree, hence there has to be an order.
|
||||
return *nsContentUtils::ComparePoints(
|
||||
&aCompareNode, aCompareOffset, start,
|
||||
aRange.MayCrossShadowBoundaryStartOffset(), aCache);
|
||||
aCompareBoundary, aRange.MayCrossShadowBoundaryStartRef(), aCache);
|
||||
}
|
||||
|
||||
static int32_t CompareToRangeStart(const nsINode& aCompareNode,
|
||||
uint32_t aCompareOffset,
|
||||
const AbstractRange& aRange) {
|
||||
return CompareToRangeStart(aCompareNode, aCompareOffset, aRange, nullptr);
|
||||
template <typename PT, typename RT>
|
||||
static int32_t CompareToRangeStart(
|
||||
const RangeBoundaryBase<PT, RT>& aCompareBoundary,
|
||||
const AbstractRange& aRange) {
|
||||
return CompareToRangeStart(aCompareBoundary, aRange, nullptr);
|
||||
}
|
||||
|
||||
static int32_t CompareToRangeEnd(const nsINode& aCompareNode,
|
||||
uint32_t aCompareOffset,
|
||||
const AbstractRange& aRange) {
|
||||
template <typename PT, typename RT>
|
||||
static int32_t CompareToRangeEnd(
|
||||
const RangeBoundaryBase<PT, RT>& aCompareBoundary,
|
||||
const AbstractRange& aRange) {
|
||||
MOZ_ASSERT(aCompareBoundary.IsSet());
|
||||
MOZ_ASSERT(aRange.IsPositioned());
|
||||
nsINode* end = aRange.GetMayCrossShadowBoundaryEndContainer();
|
||||
// If the nodes that we're comparing are not in the same document or in the
|
||||
// same subtree, assume that aCompareNode will fall at the end of the ranges.
|
||||
if (aCompareNode.GetComposedDoc() != end->GetComposedDoc() ||
|
||||
!end->GetComposedDoc()) {
|
||||
if (aCompareBoundary.GetComposedDoc() !=
|
||||
aRange.MayCrossShadowBoundaryEndRef().GetComposedDoc() ||
|
||||
!aRange.MayCrossShadowBoundaryEndRef().IsSetAndInComposedDoc()) {
|
||||
NS_WARNING(
|
||||
"`CompareToRangeEnd` couldn't compare nodes, pretending some order.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// The points are in the same subtree, hence there has to be an order.
|
||||
return *nsContentUtils::ComparePoints(
|
||||
&aCompareNode, aCompareOffset, end,
|
||||
aRange.MayCrossShadowBoundaryEndOffset());
|
||||
return *nsContentUtils::ComparePoints(aCompareBoundary,
|
||||
aRange.MayCrossShadowBoundaryEndRef());
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename PT, typename RT>
|
||||
size_t Selection::StyledRanges::FindInsertionPoint(
|
||||
const nsTArray<StyledRange>* aElementArray, const nsINode& aPointNode,
|
||||
uint32_t aPointOffset,
|
||||
int32_t (*aComparator)(const nsINode&, uint32_t, const AbstractRange&)) {
|
||||
const nsTArray<StyledRange>* aElementArray,
|
||||
const RangeBoundaryBase<PT, RT>& aBoundary,
|
||||
int32_t (*aComparator)(const RangeBoundaryBase<PT, RT>&,
|
||||
const AbstractRange&)) {
|
||||
int32_t beginSearch = 0;
|
||||
int32_t endSearch = aElementArray->Length(); // one beyond what to check
|
||||
|
||||
@@ -950,7 +954,7 @@ size_t Selection::StyledRanges::FindInsertionPoint(
|
||||
do {
|
||||
const AbstractRange* range = (*aElementArray)[center].mRange;
|
||||
|
||||
int32_t cmp{aComparator(aPointNode, aPointOffset, *range)};
|
||||
int32_t cmp{aComparator(aBoundary, *range)};
|
||||
|
||||
if (cmp < 0) { // point < cur
|
||||
endSearch = center;
|
||||
@@ -991,12 +995,10 @@ nsresult Selection::StyledRanges::SubtractRange(
|
||||
}
|
||||
|
||||
// First we want to compare to the range start
|
||||
int32_t cmp{CompareToRangeStart(*range->GetStartContainer(),
|
||||
range->StartOffset(), aSubtract)};
|
||||
int32_t cmp{CompareToRangeStart(range->StartRef(), aSubtract)};
|
||||
|
||||
// Also, make a comparison to the range end
|
||||
int32_t cmp2{CompareToRangeEnd(*range->GetEndContainer(), range->EndOffset(),
|
||||
aSubtract)};
|
||||
int32_t cmp2{CompareToRangeEnd(range->EndRef(), aSubtract)};
|
||||
|
||||
// If the existing range left overlaps the new range (aSubtract) then
|
||||
// cmp < 0, and cmp2 < 0
|
||||
@@ -1365,9 +1367,8 @@ nsresult Selection::StyledRanges::MaybeAddRangeAndTruncateOverlaps(
|
||||
|
||||
// Insert the new element into our "leftovers" array
|
||||
// `aRange` is positioned, so it has to have a start container.
|
||||
size_t insertionPoint{FindInsertionPoint(&temp, *aRange->GetStartContainer(),
|
||||
aRange->StartOffset(),
|
||||
CompareToRangeStart)};
|
||||
size_t insertionPoint{
|
||||
FindInsertionPoint(&temp, aRange->StartRef(), CompareToRangeStart)};
|
||||
|
||||
temp.InsertElementAt(insertionPoint, StyledRange(aRange));
|
||||
|
||||
@@ -1591,22 +1592,17 @@ void Selection::StyledRanges::ReorderRangesIfNecessary() {
|
||||
// the cache, which is reused by the sort call).
|
||||
nsContentUtils::NodeIndexCache cache;
|
||||
bool rangeOrderHasChanged = false;
|
||||
const nsINode* prevStartContainer = nullptr;
|
||||
uint32_t prevStartOffset = 0;
|
||||
RawRangeBoundary previousStartRef;
|
||||
for (const StyledRange& range : mRanges) {
|
||||
const nsINode* startContainer = range.mRange->GetStartContainer();
|
||||
uint32_t startOffset = range.mRange->StartOffset();
|
||||
if (!prevStartContainer) {
|
||||
prevStartContainer = startContainer;
|
||||
prevStartOffset = startOffset;
|
||||
if (!previousStartRef.IsSet()) {
|
||||
previousStartRef = range.mRange->StartRef().AsRaw();
|
||||
continue;
|
||||
}
|
||||
// Calling ComparePoints here saves one call of
|
||||
// AbstractRange::StartOffset() per iteration (which is surprisingly
|
||||
// expensive).
|
||||
const Maybe<int32_t> compareResult = nsContentUtils::ComparePoints(
|
||||
startContainer, startOffset, prevStartContainer, prevStartOffset,
|
||||
&cache);
|
||||
range.mRange->StartRef(), previousStartRef, &cache);
|
||||
// If the nodes are in different subtrees, the Maybe is empty.
|
||||
// Since CompareToRangeStart pretends ranges to be ordered, this aligns
|
||||
// to that behavior.
|
||||
@@ -1614,13 +1610,11 @@ void Selection::StyledRanges::ReorderRangesIfNecessary() {
|
||||
rangeOrderHasChanged = true;
|
||||
break;
|
||||
}
|
||||
prevStartContainer = startContainer;
|
||||
prevStartOffset = startOffset;
|
||||
previousStartRef = range.mRange->StartRef().AsRaw();
|
||||
}
|
||||
if (rangeOrderHasChanged) {
|
||||
mRanges.Sort([&cache](const StyledRange& a, const StyledRange& b) -> int {
|
||||
return CompareToRangeStart(*a.mRange->GetStartContainer(),
|
||||
a.mRange->StartOffset(), *b.mRange, &cache);
|
||||
return CompareToRangeStart(a.mRange->StartRef(), *b.mRange, &cache);
|
||||
});
|
||||
}
|
||||
mDocumentGeneration = currentDocumentGeneration;
|
||||
@@ -1654,8 +1648,11 @@ nsresult Selection::StyledRanges::GetIndicesForInterval(
|
||||
|
||||
// Ranges that end before the given interval and begin after the given
|
||||
// interval can be discarded
|
||||
size_t endsBeforeIndex{FindInsertionPoint(&mRanges, *aEndNode, aEndOffset,
|
||||
&CompareToRangeStart)};
|
||||
size_t endsBeforeIndex{FindInsertionPoint(
|
||||
&mRanges,
|
||||
ConstRawRangeBoundary(aEndNode, aEndOffset,
|
||||
RangeBoundaryIsMutationObserved::No),
|
||||
&CompareToRangeStart)};
|
||||
|
||||
if (endsBeforeIndex == 0) {
|
||||
const AbstractRange* endRange = mRanges[endsBeforeIndex].mRange;
|
||||
@@ -1676,8 +1673,11 @@ nsresult Selection::StyledRanges::GetIndicesForInterval(
|
||||
}
|
||||
aEndIndex.emplace(endsBeforeIndex);
|
||||
|
||||
size_t beginsAfterIndex{FindInsertionPoint(&mRanges, *aBeginNode,
|
||||
aBeginOffset, &CompareToRangeEnd)};
|
||||
size_t beginsAfterIndex{FindInsertionPoint(
|
||||
&mRanges,
|
||||
ConstRawRangeBoundary(aBeginNode, aBeginOffset,
|
||||
RangeBoundaryIsMutationObserved::No),
|
||||
&CompareToRangeEnd)};
|
||||
|
||||
if (beginsAfterIndex == mRanges.Length()) {
|
||||
return NS_OK; // optimization: all ranges are strictly before us
|
||||
|
||||
@@ -981,19 +981,21 @@ class Selection final : public nsSupportsWeakReference,
|
||||
|
||||
/**
|
||||
* Binary searches the given sorted array of ranges for the insertion point
|
||||
* for the given node/offset. The given comparator is used, and the index
|
||||
* for the given aBoundary. The given comparator is used, and the index
|
||||
* where the point should appear in the array is returned.
|
||||
|
||||
* If there is an item in the array equal to the input point (aPointNode,
|
||||
* aPointOffset), we will return the index of this item.
|
||||
* If there is an item in the array equal to aBoundary, we will return the
|
||||
index of this item.
|
||||
*
|
||||
* @return the index where the point should appear in the array. In
|
||||
* [0, `aElementArray->Length()`].
|
||||
*/
|
||||
template <typename PT, typename RT>
|
||||
static size_t FindInsertionPoint(
|
||||
const nsTArray<StyledRange>* aElementArray, const nsINode& aPointNode,
|
||||
uint32_t aPointOffset,
|
||||
int32_t (*aComparator)(const nsINode&, uint32_t, const AbstractRange&));
|
||||
const nsTArray<StyledRange>* aElementArray,
|
||||
const RangeBoundaryBase<PT, RT>& aBoundary,
|
||||
int32_t (*aComparator)(const RangeBoundaryBase<PT, RT>&,
|
||||
const AbstractRange&));
|
||||
|
||||
/**
|
||||
* Works on the same principle as GetRangesForIntervalArray, however
|
||||
|
||||
@@ -486,16 +486,32 @@ int32_t nsContentUtils::sInnerOrOuterWindowCount = 0;
|
||||
uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0;
|
||||
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary);
|
||||
const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary,
|
||||
NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const RangeBoundary& aFirstBoundary,
|
||||
const RawRangeBoundary& aSecondBoundary);
|
||||
const RawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const RawRangeBoundary& aFirstBoundary,
|
||||
const RangeBoundary& aSecondBoundary);
|
||||
const RangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const RawRangeBoundary& aFirstBoundary,
|
||||
const RawRangeBoundary& aSecondBoundary);
|
||||
const RawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const RangeBoundary& aFirstBoundary,
|
||||
const ConstRawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const ConstRawRangeBoundary& aFirstBoundary,
|
||||
const RangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const RawRangeBoundary& aFirstBoundary,
|
||||
const ConstRawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const ConstRawRangeBoundary& aFirstBoundary,
|
||||
const RawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const ConstRawRangeBoundary& aFirstBoundary,
|
||||
const ConstRawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
|
||||
// Subset of
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name
|
||||
@@ -750,10 +766,10 @@ static auto* GetParentBrowserParent(const BrowserParent* aBrowserParent) {
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
template <typename Node, typename GetParentFunc>
|
||||
template <typename Node1, typename Node2, typename GetParentFunc>
|
||||
class MOZ_STACK_CLASS CommonAncestors final {
|
||||
public:
|
||||
CommonAncestors(Node& aNode1, Node& aNode2, GetParentFunc aGetParentFunc)
|
||||
CommonAncestors(Node1& aNode1, Node2& aNode2, GetParentFunc aGetParentFunc)
|
||||
: GetParent(aGetParentFunc) {
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
mAssertNoGC.emplace();
|
||||
@@ -766,11 +782,11 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
||||
size_t depth1 = mInclusiveAncestors1.Length();
|
||||
size_t depth2 = mInclusiveAncestors2.Length();
|
||||
const size_t shorterLength = std::min(depth1, depth2);
|
||||
Node** const inclusiveAncestors1 = mInclusiveAncestors1.Elements();
|
||||
Node** const inclusiveAncestors2 = mInclusiveAncestors2.Elements();
|
||||
Node1** const inclusiveAncestors1 = mInclusiveAncestors1.Elements();
|
||||
Node2** const inclusiveAncestors2 = mInclusiveAncestors2.Elements();
|
||||
for ([[maybe_unused]] const size_t unused : IntegerRange(shorterLength)) {
|
||||
Node* const inclusiveAncestor1 = inclusiveAncestors1[--depth1];
|
||||
Node* const inclusiveAncestor2 = inclusiveAncestors2[--depth2];
|
||||
Node1* const inclusiveAncestor1 = inclusiveAncestors1[--depth1];
|
||||
Node2* const inclusiveAncestor2 = inclusiveAncestors2[--depth2];
|
||||
if (inclusiveAncestor1 != inclusiveAncestor2) {
|
||||
MOZ_ASSERT_IF(mClosestCommonAncestor,
|
||||
inclusiveAncestor1 == GetClosestCommonAncestorChild1());
|
||||
@@ -794,13 +810,13 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
||||
~CommonAncestors() { MOZ_DIAGNOSTIC_ASSERT(!mMutationGuard.Mutated(0)); }
|
||||
#endif // #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
|
||||
[[nodiscard]] Node* GetClosestCommonAncestor() const {
|
||||
[[nodiscard]] Node1* GetClosestCommonAncestor() const {
|
||||
return mClosestCommonAncestor;
|
||||
}
|
||||
[[nodiscard]] Node* GetClosestCommonAncestorChild1() const {
|
||||
[[nodiscard]] Node1* GetClosestCommonAncestorChild1() const {
|
||||
return GetClosestCommonAncestorChild(mInclusiveAncestors1);
|
||||
}
|
||||
[[nodiscard]] Node* GetClosestCommonAncestorChild2() const {
|
||||
[[nodiscard]] Node2* GetClosestCommonAncestorChild2() const {
|
||||
return GetClosestCommonAncestorChild(mInclusiveAncestors2);
|
||||
}
|
||||
|
||||
@@ -810,6 +826,7 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Node>
|
||||
static void AppendInclusiveAncestors(Node* aNode,
|
||||
GetParentFunc aGetParentFunc,
|
||||
nsTArray<Node*>& aArrayOfParents) {
|
||||
@@ -820,6 +837,7 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
Maybe<size_t> GetClosestCommonAncestorChildIndex(
|
||||
const nsTArray<Node*>& aInclusiveAncestors) const {
|
||||
if (!mClosestCommonAncestor ||
|
||||
@@ -830,6 +848,7 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
||||
- mNumberOfCommonAncestors); // before closest common ancestor
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
[[nodiscard]] Node* GetClosestCommonAncestorChild(
|
||||
const nsTArray<Node*>& aInclusiveAncestors) const {
|
||||
const Maybe<size_t> index =
|
||||
@@ -845,6 +864,7 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
||||
return child;
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
void WarnIfClosestCommonAncestorChildIsNotInChildList(
|
||||
const nsTArray<Node*>& aInclusiveAncestors) const {
|
||||
#ifdef DEBUG
|
||||
@@ -877,8 +897,9 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
||||
#endif
|
||||
}
|
||||
|
||||
AutoTArray<Node*, 30> mInclusiveAncestors1, mInclusiveAncestors2;
|
||||
Node* mClosestCommonAncestor = nullptr;
|
||||
AutoTArray<Node1*, 30> mInclusiveAncestors1;
|
||||
AutoTArray<Node2*, 30> mInclusiveAncestors2;
|
||||
Node1* mClosestCommonAncestor = nullptr;
|
||||
const GetParentFunc GetParent;
|
||||
uint32_t mNumberOfCommonAncestors = 0;
|
||||
|
||||
@@ -3522,7 +3543,8 @@ Element* nsContentUtils::GetTargetElement(Document* aDocument,
|
||||
template <typename PT1, typename RT1, typename PT2, typename RT2>
|
||||
Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const RangeBoundaryBase<PT1, RT1>& aBoundary1,
|
||||
const RangeBoundaryBase<PT2, RT2>& aBoundary2) {
|
||||
const RangeBoundaryBase<PT2, RT2>& aBoundary2,
|
||||
NodeIndexCache* aIndexCache /* = nullptr */) {
|
||||
if (!aBoundary1.IsSet() || !aBoundary2.IsSet()) {
|
||||
return Nothing{};
|
||||
}
|
||||
@@ -3537,7 +3559,8 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
if (aBoundary1.HasOffset() && aBoundary2.HasOffset()) {
|
||||
return ComparePoints(
|
||||
aBoundary1.Container(), *aBoundary1.Offset(kValidOrInvalidOffsets1),
|
||||
aBoundary2.Container(), *aBoundary2.Offset(kValidOrInvalidOffsets2));
|
||||
aBoundary2.Container(), *aBoundary2.Offset(kValidOrInvalidOffsets2),
|
||||
aIndexCache);
|
||||
}
|
||||
|
||||
// Otherwise, i.e., at least one RangeBoundaryBase stores the child node.
|
||||
@@ -3553,7 +3576,7 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const nsIContent* const child1 = aBoundary1.GetChildAtOffset();
|
||||
const nsIContent* const child2 = aBoundary2.GetChildAtOffset();
|
||||
return CompareClosestCommonAncestorChildren(*aBoundary1.Container(), child1,
|
||||
child2);
|
||||
child2, aIndexCache);
|
||||
}
|
||||
|
||||
// Otherwise, we need to compare the common ancestor children which is the
|
||||
@@ -3579,7 +3602,7 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
if (closestCommonAncestorChild1 && closestCommonAncestorChild2) {
|
||||
return CompareClosestCommonAncestorChildren(
|
||||
*commonAncestors.GetClosestCommonAncestor(),
|
||||
closestCommonAncestorChild1, closestCommonAncestorChild2);
|
||||
closestCommonAncestorChild1, closestCommonAncestorChild2, aIndexCache);
|
||||
}
|
||||
|
||||
if (closestCommonAncestorChild2) {
|
||||
@@ -3593,7 +3616,8 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
return Some(1);
|
||||
}
|
||||
const Maybe<int32_t> comp = nsContentUtils::CompareChildNodes(
|
||||
aBoundary1.GetChildAtOffset(), closestCommonAncestorChild2);
|
||||
aBoundary1.GetChildAtOffset(), closestCommonAncestorChild2,
|
||||
aIndexCache);
|
||||
if (NS_WARN_IF(comp.isNothing())) {
|
||||
NS_ASSERTION(
|
||||
comp.isSome(),
|
||||
@@ -3630,7 +3654,7 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
return Some(-1);
|
||||
}
|
||||
const Maybe<int32_t> comp = nsContentUtils::CompareChildNodes(
|
||||
closestCommonAncestorChild1, aBoundary2.GetChildAtOffset());
|
||||
closestCommonAncestorChild1, aBoundary2.GetChildAtOffset(), aIndexCache);
|
||||
if (NS_WARN_IF(comp.isNothing())) {
|
||||
NS_ASSERTION(comp.isSome(),
|
||||
"nsContentUtils::CompareChildOffsetAndChildNode() must return "
|
||||
|
||||
@@ -702,7 +702,8 @@ class nsContentUtils {
|
||||
template <typename PT1, typename RT1, typename PT2, typename RT2>
|
||||
static mozilla::Maybe<int32_t> ComparePoints(
|
||||
const mozilla::RangeBoundaryBase<PT1, RT1>& aBoundary1,
|
||||
const mozilla::RangeBoundaryBase<PT2, RT2>& aBoundary2);
|
||||
const mozilla::RangeBoundaryBase<PT2, RT2>& aBoundary2,
|
||||
NodeIndexCache* aIndexCache = nullptr);
|
||||
|
||||
/**
|
||||
* DO NOT USE this method for comparing the points in new code. this method
|
||||
|
||||
@@ -342,12 +342,14 @@ class IsItemInRangeComparator {
|
||||
|
||||
int operator()(const AbstractRange* const aRange) const {
|
||||
Maybe<int32_t> cmp = nsContentUtils::ComparePoints(
|
||||
&mNode, mEndOffset, aRange->GetMayCrossShadowBoundaryStartContainer(),
|
||||
aRange->MayCrossShadowBoundaryStartOffset(), mCache);
|
||||
ConstRawRangeBoundary(&mNode, mEndOffset,
|
||||
RangeBoundaryIsMutationObserved::No),
|
||||
aRange->MayCrossShadowBoundaryStartRef(), mCache);
|
||||
if (cmp.valueOr(1) == 1) {
|
||||
cmp = nsContentUtils::ComparePoints(
|
||||
&mNode, mStartOffset, aRange->GetMayCrossShadowBoundaryEndContainer(),
|
||||
aRange->MayCrossShadowBoundaryEndOffset(), mCache);
|
||||
ConstRawRangeBoundary(&mNode, mStartOffset,
|
||||
RangeBoundaryIsMutationObserved::No),
|
||||
aRange->MayCrossShadowBoundaryEndRef(), mCache);
|
||||
if (cmp.valueOr(1) == -1) {
|
||||
return 0;
|
||||
}
|
||||
@@ -433,17 +435,20 @@ bool nsINode::IsSelected(const uint32_t aStartOffset, const uint32_t aEndOffset,
|
||||
// if node end > start of middle+1, result = 1
|
||||
if (middle + 1 < high &&
|
||||
(middlePlus1 = selection->GetAbstractRangeAt(middle + 1)) &&
|
||||
nsContentUtils::ComparePoints(this, aEndOffset,
|
||||
middlePlus1->GetStartContainer(),
|
||||
middlePlus1->StartOffset(), &cache)
|
||||
nsContentUtils::ComparePoints(
|
||||
ConstRawRangeBoundary(this, aEndOffset,
|
||||
RangeBoundaryIsMutationObserved::No),
|
||||
middlePlus1->StartRef(), &cache)
|
||||
.valueOr(1) > 0) {
|
||||
result = 1;
|
||||
// if node start < end of middle - 1, result = -1
|
||||
} else if (middle >= 1 &&
|
||||
(middleMinus1 = selection->GetAbstractRangeAt(middle - 1)) &&
|
||||
nsContentUtils::ComparePoints(
|
||||
this, aStartOffset, middleMinus1->GetEndContainer(),
|
||||
middleMinus1->EndOffset(), &cache)
|
||||
ConstRawRangeBoundary(
|
||||
this, aStartOffset,
|
||||
RangeBoundaryIsMutationObserved::No),
|
||||
middleMinus1->EndRef(), &cache)
|
||||
.valueOr(1) < 0) {
|
||||
result = -1;
|
||||
} else {
|
||||
|
||||
@@ -904,13 +904,10 @@ bool nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv) {
|
||||
}
|
||||
|
||||
const Maybe<int32_t> startOrder = nsContentUtils::ComparePoints(
|
||||
mStart.Container(),
|
||||
*mStart.Offset(RangeBoundary::OffsetFilter::kValidOffsets), parent,
|
||||
*nodeIndex + 1u);
|
||||
mStart, RawRangeBoundary(parent, aNode.AsContent(), *nodeIndex + 1u));
|
||||
if (startOrder && (*startOrder < 0)) {
|
||||
const Maybe<int32_t> endOrder = nsContentUtils::ComparePoints(
|
||||
parent, *nodeIndex, mEnd.Container(),
|
||||
*mEnd.Offset(RangeBoundary::OffsetFilter::kValidOffsets));
|
||||
RawRangeBoundary(parent, aNode.GetPreviousSibling(), *nodeIndex), mEnd);
|
||||
return endOrder && (*endOrder < 0);
|
||||
}
|
||||
|
||||
@@ -2144,33 +2141,23 @@ int16_t nsRange::CompareBoundaryPoints(uint16_t aHow,
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsINode *ourNode, *otherNode;
|
||||
uint32_t ourOffset, otherOffset;
|
||||
|
||||
RawRangeBoundary ourBoundary, otherBoundary;
|
||||
switch (aHow) {
|
||||
case Range_Binding::START_TO_START:
|
||||
ourNode = mStart.Container();
|
||||
ourOffset = *mStart.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
|
||||
otherNode = aOtherRange.GetStartContainer();
|
||||
otherOffset = aOtherRange.StartOffset();
|
||||
ourBoundary = mStart.AsRaw();
|
||||
otherBoundary = aOtherRange.StartRef().AsRaw();
|
||||
break;
|
||||
case Range_Binding::START_TO_END:
|
||||
ourNode = mEnd.Container();
|
||||
ourOffset = *mEnd.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
|
||||
otherNode = aOtherRange.GetStartContainer();
|
||||
otherOffset = aOtherRange.StartOffset();
|
||||
ourBoundary = mEnd.AsRaw();
|
||||
otherBoundary = aOtherRange.StartRef().AsRaw();
|
||||
break;
|
||||
case Range_Binding::END_TO_START:
|
||||
ourNode = mStart.Container();
|
||||
ourOffset = *mStart.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
|
||||
otherNode = aOtherRange.GetEndContainer();
|
||||
otherOffset = aOtherRange.EndOffset();
|
||||
ourBoundary = mStart.AsRaw();
|
||||
otherBoundary = aOtherRange.EndRef().AsRaw();
|
||||
break;
|
||||
case Range_Binding::END_TO_END:
|
||||
ourNode = mEnd.Container();
|
||||
ourOffset = *mEnd.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
|
||||
otherNode = aOtherRange.GetEndContainer();
|
||||
otherOffset = aOtherRange.EndOffset();
|
||||
ourBoundary = mEnd.AsRaw();
|
||||
otherBoundary = aOtherRange.EndRef().AsRaw();
|
||||
break;
|
||||
default:
|
||||
// We were passed an illegal value
|
||||
@@ -2184,11 +2171,11 @@ int16_t nsRange::CompareBoundaryPoints(uint16_t aHow,
|
||||
}
|
||||
|
||||
const Maybe<int32_t> order =
|
||||
nsContentUtils::ComparePoints(ourNode, ourOffset, otherNode, otherOffset);
|
||||
nsContentUtils::ComparePoints(ourBoundary, otherBoundary);
|
||||
|
||||
// `this` and `aOtherRange` share the same root and (ourNode, ourOffset),
|
||||
// (otherNode, otherOffset) correspond to some of their boundaries. Hence,
|
||||
// (ourNode, ourOffset) and (otherNode, otherOffset) have to be comparable.
|
||||
// `this` and `aOtherRange` share the same root and ourBoundary, otherBoundary
|
||||
// correspond to some of their boundaries. Hence, ourBoundary and
|
||||
// otherBoundary have to be comparable.
|
||||
return *order;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,14 +136,7 @@ ContentEventHandler::SimpleRangeBase<nsINode*,
|
||||
template <typename NodeType, typename RangeBoundaryType>
|
||||
void ContentEventHandler::SimpleRangeBase<
|
||||
NodeType, RangeBoundaryType>::AssertStartIsBeforeOrEqualToEnd() {
|
||||
MOZ_ASSERT(
|
||||
*nsContentUtils::ComparePoints(
|
||||
mStart.Container(),
|
||||
*mStart.Offset(
|
||||
RangeBoundaryType::OffsetFilter::kValidOrInvalidOffsets),
|
||||
mEnd.Container(),
|
||||
*mEnd.Offset(
|
||||
RangeBoundaryType::OffsetFilter::kValidOrInvalidOffsets)) <= 0);
|
||||
MOZ_ASSERT(*nsContentUtils::ComparePoints(mStart, mEnd) <= 0);
|
||||
}
|
||||
|
||||
template <typename NodeType, typename RangeBoundaryType>
|
||||
|
||||
@@ -189,37 +189,27 @@ void FilteredContentIterator::Last() {
|
||||
// the traversal of the range in the specified mode.
|
||||
//
|
||||
static bool ContentIsInTraversalRange(nsIContent* aContent, bool aIsPreMode,
|
||||
nsINode* aStartContainer,
|
||||
int32_t aStartOffset,
|
||||
nsINode* aEndContainer,
|
||||
int32_t aEndOffset) {
|
||||
NS_ENSURE_TRUE(aStartContainer && aEndContainer && aContent, false);
|
||||
const RangeBoundary& aStartBoundary,
|
||||
const RangeBoundary& aEndBoundary) {
|
||||
NS_ENSURE_TRUE(aStartBoundary.IsSet() && aEndBoundary.IsSet() && aContent,
|
||||
false);
|
||||
|
||||
nsIContent* parentContent = aContent->GetParent();
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!parentContent))) {
|
||||
return false;
|
||||
}
|
||||
Maybe<uint32_t> offsetInParent = parentContent->ComputeIndexOf(aContent);
|
||||
NS_WARNING_ASSERTION(
|
||||
offsetInParent.isSome(),
|
||||
"Content is not in the parent, is this called during a DOM mutation?");
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(offsetInParent.isNothing()))) {
|
||||
if (NS_WARN_IF(!parentContent) ||
|
||||
NS_WARN_IF(parentContent->IsRootOfNativeAnonymousSubtree())) {
|
||||
return false;
|
||||
}
|
||||
const RawRangeBoundary compPoint(
|
||||
parentContent, aIsPreMode ? aContent->GetPreviousSibling() : aContent);
|
||||
|
||||
if (!aIsPreMode) {
|
||||
MOZ_ASSERT(*offsetInParent != UINT32_MAX);
|
||||
++(*offsetInParent);
|
||||
}
|
||||
|
||||
const Maybe<int32_t> startRes = nsContentUtils::ComparePoints(
|
||||
aStartContainer, aStartOffset, parentContent, *offsetInParent);
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!startRes))) {
|
||||
const Maybe<int32_t> startRes =
|
||||
nsContentUtils::ComparePoints(aStartBoundary, compPoint);
|
||||
if (NS_WARN_IF(!startRes)) {
|
||||
return false;
|
||||
}
|
||||
const Maybe<int32_t> endRes = nsContentUtils::ComparePoints(
|
||||
aEndContainer, aEndOffset, parentContent, *offsetInParent);
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!endRes))) {
|
||||
const Maybe<int32_t> endRes =
|
||||
nsContentUtils::ComparePoints(aEndBoundary, compPoint);
|
||||
if (NS_WARN_IF(!endRes)) {
|
||||
return false;
|
||||
}
|
||||
return *startRes <= 0 && *endRes >= 0;
|
||||
@@ -231,10 +221,8 @@ static bool ContentIsInTraversalRange(nsRange* aRange, nsIContent* aNextContent,
|
||||
// aNextContent!
|
||||
NS_ENSURE_TRUE(aNextContent && aRange, false);
|
||||
|
||||
return ContentIsInTraversalRange(
|
||||
aNextContent, aIsPreMode, aRange->GetStartContainer(),
|
||||
static_cast<int32_t>(aRange->StartOffset()), aRange->GetEndContainer(),
|
||||
static_cast<int32_t>(aRange->EndOffset()));
|
||||
return ContentIsInTraversalRange(aNextContent, aIsPreMode, aRange->StartRef(),
|
||||
aRange->EndRef());
|
||||
}
|
||||
|
||||
// Helper function to advance to the next or previous node
|
||||
|
||||
@@ -1161,10 +1161,10 @@ void nsFrameSelection::MaintainedRange::AdjustContentOffsets(
|
||||
nsIFrame::ContentOffsets& aOffsets, StopAtScroller aStopAtScroller) const {
|
||||
// Adjust offsets according to maintained amount
|
||||
if (mRange && mAmount != eSelectNoAmount) {
|
||||
nsINode* rangenode = mRange->GetStartContainer();
|
||||
int32_t rangeOffset = mRange->StartOffset();
|
||||
const Maybe<int32_t> relativePosition = nsContentUtils::ComparePoints(
|
||||
rangenode, rangeOffset, aOffsets.content, aOffsets.offset);
|
||||
mRange->StartRef(),
|
||||
RawRangeBoundary(aOffsets.content, aOffsets.offset,
|
||||
RangeBoundaryIsMutationObserved::No));
|
||||
if (NS_WARN_IF(!relativePosition)) {
|
||||
// Potentially handle this properly when Selection across Shadow DOM
|
||||
// boundary is implemented
|
||||
|
||||
Reference in New Issue
Block a user