mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-02 17:28:50 +02:00
Bug 1932150 - Allow using flat tree order for point comparing in selection r=jjaschke,smaug,dom-core
Differential Revision: https://phabricator.services.mozilla.com/D231588
This commit is contained in:
parent
4381c6ea7b
commit
a8fbcd54a1
11 changed files with 363 additions and 127 deletions
|
|
@ -26,25 +26,58 @@ template bool RangeUtils::IsValidPoints(const RawRangeBoundary& aStartBoundary,
|
|||
template bool RangeUtils::IsValidPoints(const RawRangeBoundary& aStartBoundary,
|
||||
const RawRangeBoundary& aEndBoundary);
|
||||
|
||||
template nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
||||
template nsresult
|
||||
RangeUtils::CompareNodeToRangeBoundaries<TreeKind::ShadowIncludingDOM>(
|
||||
nsINode* aNode, const RangeBoundary& aStartBoundary,
|
||||
const RangeBoundary& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
template nsresult RangeUtils::CompareNodeToRangeBoundaries<TreeKind::Flat>(
|
||||
nsINode* aNode, const RangeBoundary& aStartBoundary,
|
||||
const RangeBoundary& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
|
||||
template nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
||||
template nsresult
|
||||
RangeUtils::CompareNodeToRangeBoundaries<TreeKind::ShadowIncludingDOM>(
|
||||
nsINode* aNode, const RangeBoundary& aStartBoundary,
|
||||
const RawRangeBoundary& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
template nsresult RangeUtils::CompareNodeToRangeBoundaries<TreeKind::Flat>(
|
||||
nsINode* aNode, const RangeBoundary& aStartBoundary,
|
||||
const RawRangeBoundary& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
|
||||
template nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
||||
template nsresult
|
||||
RangeUtils::CompareNodeToRangeBoundaries<TreeKind::ShadowIncludingDOM>(
|
||||
nsINode* aNode, const RawRangeBoundary& aStartBoundary,
|
||||
const RangeBoundary& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
template nsresult RangeUtils::CompareNodeToRangeBoundaries<TreeKind::Flat>(
|
||||
nsINode* aNode, const RawRangeBoundary& aStartBoundary,
|
||||
const RangeBoundary& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
|
||||
template nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
||||
template nsresult
|
||||
RangeUtils::CompareNodeToRangeBoundaries<TreeKind::ShadowIncludingDOM>(
|
||||
nsINode* aNode, const RawRangeBoundary& aStartBoundary,
|
||||
const RawRangeBoundary& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
template nsresult RangeUtils::CompareNodeToRangeBoundaries<TreeKind::Flat>(
|
||||
nsINode* aNode, const RawRangeBoundary& aStartBoundary,
|
||||
const RawRangeBoundary& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
|
||||
template nsresult RangeUtils::CompareNodeToRange<TreeKind::ShadowIncludingDOM>(
|
||||
nsINode* aNode, AbstractRange* aAbstractRange, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
template nsresult RangeUtils::CompareNodeToRange<TreeKind::Flat>(
|
||||
nsINode* aNode, AbstractRange* aAbstractRange, bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
|
||||
template Maybe<bool>
|
||||
RangeUtils::IsNodeContainedInRange<TreeKind::ShadowIncludingDOM>(
|
||||
nsINode& aNode, AbstractRange* aAbstractRange);
|
||||
template Maybe<bool> RangeUtils::IsNodeContainedInRange<TreeKind::Flat>(
|
||||
nsINode& aNode, AbstractRange* aAbstractRange);
|
||||
|
||||
[[nodiscard]] static inline bool ParentNodeIsInSameSelection(
|
||||
const nsINode& aNode) {
|
||||
|
|
@ -67,17 +100,6 @@ template nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
|||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
nsINode* RangeUtils::GetParentNodeInSameSelection(const nsINode* aNode) {
|
||||
if (MOZ_UNLIKELY(!aNode)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!ParentNodeIsInSameSelection(*aNode)) {
|
||||
return nullptr;
|
||||
}
|
||||
return aNode->GetParentNode();
|
||||
}
|
||||
|
||||
// static
|
||||
nsINode* RangeUtils::ComputeRootNode(nsINode* aNode) {
|
||||
if (!aNode) {
|
||||
|
|
@ -150,13 +172,14 @@ bool RangeUtils::IsValidPoints(
|
|||
}
|
||||
|
||||
// static
|
||||
template <TreeKind aKind, typename Dummy>
|
||||
Maybe<bool> RangeUtils::IsNodeContainedInRange(nsINode& aNode,
|
||||
AbstractRange* aAbstractRange) {
|
||||
bool nodeIsBeforeRange{false};
|
||||
bool nodeIsAfterRange{false};
|
||||
|
||||
const nsresult rv = CompareNodeToRange(&aNode, aAbstractRange,
|
||||
&nodeIsBeforeRange, &nodeIsAfterRange);
|
||||
const nsresult rv = CompareNodeToRange<aKind>(
|
||||
&aNode, aAbstractRange, &nodeIsBeforeRange, &nodeIsAfterRange);
|
||||
if (NS_FAILED(rv)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
|
@ -172,6 +195,7 @@ Maybe<bool> RangeUtils::IsNodeContainedInRange(nsINode& aNode,
|
|||
// XXX - callers responsibility to ensure node in same doc as range!
|
||||
|
||||
// static
|
||||
template <TreeKind aKind, typename Dummy>
|
||||
nsresult RangeUtils::CompareNodeToRange(nsINode* aNode,
|
||||
AbstractRange* aAbstractRange,
|
||||
bool* aNodeIsBeforeRange,
|
||||
|
|
@ -180,12 +204,13 @@ nsresult RangeUtils::CompareNodeToRange(nsINode* aNode,
|
|||
NS_WARN_IF(!aAbstractRange->IsPositioned())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
return CompareNodeToRangeBoundaries(
|
||||
return CompareNodeToRangeBoundaries<aKind>(
|
||||
aNode, aAbstractRange->MayCrossShadowBoundaryStartRef(),
|
||||
aAbstractRange->MayCrossShadowBoundaryEndRef(), aNodeIsBeforeRange,
|
||||
aNodeIsAfterRange);
|
||||
}
|
||||
template <typename SPT, typename SRT, typename EPT, typename ERT>
|
||||
template <TreeKind aKind, typename SPT, typename SRT, typename EPT,
|
||||
typename ERT, typename Dummy>
|
||||
nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
||||
nsINode* aNode, const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
|
||||
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
|
|
@ -208,7 +233,17 @@ nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
|||
// gather up the dom point info
|
||||
int32_t nodeStart;
|
||||
uint32_t nodeEnd;
|
||||
const nsINode* parent = GetParentNodeInSameSelection(aNode);
|
||||
const nsINode* parent = nullptr;
|
||||
|
||||
MOZ_ASSERT_IF(aKind == TreeKind::Flat,
|
||||
StaticPrefs::dom_shadowdom_selection_across_boundary_enabled());
|
||||
// ShadowRoot has no parent, nor can be represented by parent/offset pair.
|
||||
if (!aNode->IsShadowRoot()) {
|
||||
parent = ShadowDOMSelectionHelpers::GetParentNodeInSameSelection(
|
||||
*aNode, aKind == TreeKind::Flat ? AllowRangeCrossShadowBoundary::Yes
|
||||
: AllowRangeCrossShadowBoundary::No);
|
||||
}
|
||||
|
||||
if (!parent) {
|
||||
// can't make a parent/offset pair to represent start or
|
||||
// end of the root node, because it has no parent.
|
||||
|
|
@ -216,6 +251,14 @@ nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
|||
parent = aNode;
|
||||
nodeStart = 0;
|
||||
nodeEnd = aNode->GetChildCount();
|
||||
} else if (const HTMLSlotElement* slotAsParent =
|
||||
HTMLSlotElement::FromNode(parent);
|
||||
slotAsParent && aKind == TreeKind::Flat) {
|
||||
// aNode is a slotted content, use the index in the assigned nodes
|
||||
// to represent this node.
|
||||
auto index = slotAsParent->AssignedNodes().IndexOf(aNode);
|
||||
nodeStart = index;
|
||||
nodeEnd = nodeStart + 1;
|
||||
} else {
|
||||
nodeStart = parent->ComputeIndexOf_Deprecated(aNode);
|
||||
NS_WARNING_ASSERTION(
|
||||
|
|
@ -240,17 +283,19 @@ nsresult RangeUtils::CompareNodeToRangeBoundaries(
|
|||
// silence the warning. (Bug 1438996)
|
||||
|
||||
// is RANGE(start) <= NODE(start) ?
|
||||
Maybe<int32_t> order = nsContentUtils::ComparePoints_AllowNegativeOffsets(
|
||||
aStartBoundary.GetContainer(),
|
||||
*aStartBoundary.Offset(
|
||||
RangeBoundaryBase<SPT, SRT>::OffsetFilter::kValidOrInvalidOffsets),
|
||||
parent, nodeStart);
|
||||
Maybe<int32_t> order =
|
||||
nsContentUtils::ComparePoints_AllowNegativeOffsets<aKind>(
|
||||
aStartBoundary.GetContainer(),
|
||||
*aStartBoundary.Offset(
|
||||
RangeBoundaryBase<SPT,
|
||||
SRT>::OffsetFilter::kValidOrInvalidOffsets),
|
||||
parent, nodeStart);
|
||||
if (NS_WARN_IF(!order)) {
|
||||
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
|
||||
}
|
||||
*aNodeIsBeforeRange = *order > 0;
|
||||
// is RANGE(end) >= NODE(end) ?
|
||||
order = nsContentUtils::ComparePointsWithIndices(
|
||||
order = nsContentUtils::ComparePointsWithIndices<aKind>(
|
||||
aEndBoundary.GetContainer(),
|
||||
*aEndBoundary.Offset(
|
||||
RangeBoundaryBase<EPT, ERT>::OffsetFilter::kValidOrInvalidOffsets),
|
||||
|
|
@ -315,10 +360,17 @@ nsINode* ShadowDOMSelectionHelpers::GetParentNodeInSameSelection(
|
|||
if (!ParentNodeIsInSameSelection(aNode)) {
|
||||
return nullptr;
|
||||
}
|
||||
return (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled() &&
|
||||
aAllowCrossShadowBoundary)
|
||||
? aNode.GetParentOrShadowHostNode()
|
||||
: aNode.GetParentNode();
|
||||
|
||||
if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled() &&
|
||||
aAllowCrossShadowBoundary == AllowRangeCrossShadowBoundary::Yes) {
|
||||
if (aNode.IsContent()) {
|
||||
if (HTMLSlotElement* slot = aNode.AsContent()->GetAssignedSlot()) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return aNode.GetParentOrShadowHostNode();
|
||||
}
|
||||
return aNode.GetParentNode();
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/RangeBoundary.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
@ -55,8 +56,6 @@ class RangeUtils final {
|
|||
using AbstractRange = dom::AbstractRange;
|
||||
|
||||
public:
|
||||
static nsINode* GetParentNodeInSameSelection(const nsINode* aNode);
|
||||
|
||||
/**
|
||||
* GetRawRangeBoundaryBefore() and GetRawRangeBoundaryAfter() retrieve
|
||||
* RawRangeBoundary which points before or after aNode.
|
||||
|
|
@ -137,6 +136,9 @@ class RangeUtils final {
|
|||
/**
|
||||
* The caller needs to ensure aNode is in the same doc like aAbstractRange.
|
||||
*/
|
||||
template <TreeKind aKind = TreeKind::ShadowIncludingDOM,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
static Maybe<bool> IsNodeContainedInRange(nsINode& aNode,
|
||||
AbstractRange* aAbstractRange);
|
||||
|
||||
|
|
@ -145,12 +147,18 @@ class RangeUtils final {
|
|||
* ends after a range. If neither it is contained inside the range.
|
||||
* Note that callers responsibility to ensure node in same doc as range.
|
||||
*/
|
||||
template <TreeKind aKind = TreeKind::ShadowIncludingDOM,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
static nsresult CompareNodeToRange(nsINode* aNode,
|
||||
AbstractRange* aAbstractRange,
|
||||
bool* aNodeIsBeforeRange,
|
||||
bool* aNodeIsAfterRange);
|
||||
|
||||
template <typename SPT, typename SRT, typename EPT, typename ERT>
|
||||
template <TreeKind aKind, typename SPT, typename SRT, typename EPT,
|
||||
typename ERT,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
static nsresult CompareNodeToRangeBoundaries(
|
||||
nsINode* aNode, const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
|
||||
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, bool* aNodeIsBeforeRange,
|
||||
|
|
|
|||
|
|
@ -928,9 +928,15 @@ static int32_t CompareToRangeStart(
|
|||
return 1;
|
||||
}
|
||||
|
||||
// The points are in the same subtree, hence there has to be an order.
|
||||
return *nsContentUtils::ComparePoints(
|
||||
aCompareBoundary, aRange.MayCrossShadowBoundaryStartRef(), aCache);
|
||||
nsINode* start = aRange.GetMayCrossShadowBoundaryStartContainer();
|
||||
uint32_t startOffset = aRange.MayCrossShadowBoundaryStartOffset();
|
||||
if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) {
|
||||
return *nsContentUtils::ComparePoints<TreeKind::Flat>(
|
||||
aCompareBoundary, ConstRawRangeBoundary{start, startOffset}, aCache);
|
||||
}
|
||||
|
||||
return *nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
aCompareBoundary, ConstRawRangeBoundary{start, startOffset}, aCache);
|
||||
}
|
||||
|
||||
template <typename PT, typename RT>
|
||||
|
|
@ -956,9 +962,14 @@ static int32_t CompareToRangeEnd(
|
|||
return 1;
|
||||
}
|
||||
|
||||
// The points are in the same subtree, hence there has to be an order.
|
||||
return *nsContentUtils::ComparePoints(aCompareBoundary,
|
||||
aRange.MayCrossShadowBoundaryEndRef());
|
||||
nsINode* end = aRange.GetMayCrossShadowBoundaryEndContainer();
|
||||
uint32_t endOffset = aRange.MayCrossShadowBoundaryEndOffset();
|
||||
if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) {
|
||||
return *nsContentUtils::ComparePoints<TreeKind::Flat>(
|
||||
aCompareBoundary, ConstRawRangeBoundary{end, endOffset});
|
||||
}
|
||||
return *nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
aCompareBoundary, ConstRawRangeBoundary{end, endOffset});
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -3123,17 +3134,24 @@ void Selection::Extend(nsINode& aContainer, uint32_t aOffset,
|
|||
const uint32_t endOffset = range->MayCrossShadowBoundaryEndOffset();
|
||||
|
||||
bool shouldClearRange = false;
|
||||
|
||||
auto ComparePoints = [](const nsINode* aNode1, const uint32_t aOffset1,
|
||||
const nsINode* aNode2, const uint32_t aOffset2) {
|
||||
if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) {
|
||||
return nsContentUtils::ComparePointsWithIndices<TreeKind::Flat>(
|
||||
aNode1, aOffset1, aNode2, aOffset2);
|
||||
}
|
||||
return nsContentUtils::ComparePointsWithIndices<
|
||||
TreeKind::ShadowIncludingDOM>(aNode1, aOffset1, aNode2, aOffset2);
|
||||
};
|
||||
const Maybe<int32_t> anchorOldFocusOrder =
|
||||
nsContentUtils::ComparePointsWithIndices(anchorNode, anchorOffset,
|
||||
focusNode, focusOffset);
|
||||
ComparePoints(anchorNode, anchorOffset, focusNode, focusOffset);
|
||||
shouldClearRange |= !anchorOldFocusOrder;
|
||||
const Maybe<int32_t> oldFocusNewFocusOrder =
|
||||
nsContentUtils::ComparePointsWithIndices(focusNode, focusOffset,
|
||||
&aContainer, aOffset);
|
||||
ComparePoints(focusNode, focusOffset, &aContainer, aOffset);
|
||||
shouldClearRange |= !oldFocusNewFocusOrder;
|
||||
const Maybe<int32_t> anchorNewFocusOrder =
|
||||
nsContentUtils::ComparePointsWithIndices(anchorNode, anchorOffset,
|
||||
&aContainer, aOffset);
|
||||
ComparePoints(anchorNode, anchorOffset, &aContainer, aOffset);
|
||||
shouldClearRange |= !anchorNewFocusOrder;
|
||||
|
||||
// If the points are disconnected, the range will be collapsed below,
|
||||
|
|
@ -4231,7 +4249,10 @@ void Selection::SetBaseAndExtentInternal(InLimiter aInLimiter,
|
|||
// new nsRange instance?
|
||||
SelectionBatcher batch(this, __FUNCTION__);
|
||||
const Maybe<int32_t> order =
|
||||
nsContentUtils::ComparePoints(aAnchorRef, aFocusRef);
|
||||
StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()
|
||||
? nsContentUtils::ComparePoints<TreeKind::Flat>(aAnchorRef, aFocusRef)
|
||||
: nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
aAnchorRef, aFocusRef);
|
||||
if (order && (*order <= 0)) {
|
||||
SetStartAndEndInternal(aInLimiter, aAnchorRef, aFocusRef, eDirNext, aRv);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -487,31 +487,61 @@ mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump");
|
|||
int32_t nsContentUtils::sInnerOrOuterWindowCount = 0;
|
||||
uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0;
|
||||
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
template Maybe<int32_t>
|
||||
nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary,
|
||||
NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints<TreeKind::Flat>(
|
||||
const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary,
|
||||
NodeIndexCache* aIndexCache);
|
||||
|
||||
template Maybe<int32_t>
|
||||
nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
const RangeBoundary& aFirstBoundary,
|
||||
const RawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints<TreeKind::Flat>(
|
||||
const RangeBoundary& aFirstBoundary,
|
||||
const RawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
|
||||
template Maybe<int32_t>
|
||||
nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
const RawRangeBoundary& aFirstBoundary,
|
||||
const RangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints<TreeKind::Flat>(
|
||||
const RawRangeBoundary& aFirstBoundary,
|
||||
const RangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
|
||||
template Maybe<int32_t>
|
||||
nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
const RawRangeBoundary& aFirstBoundary,
|
||||
const RawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints<TreeKind::Flat>(
|
||||
const RawRangeBoundary& aFirstBoundary,
|
||||
const RawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
|
||||
template Maybe<int32_t>
|
||||
nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
const RangeBoundary& aFirstBoundary,
|
||||
const ConstRawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints<TreeKind::Flat>(
|
||||
const RangeBoundary& aFirstBoundary,
|
||||
const ConstRawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
|
||||
template Maybe<int32_t>
|
||||
nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
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(
|
||||
|
||||
template Maybe<int32_t>
|
||||
nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
const ConstRawRangeBoundary& aFirstBoundary,
|
||||
const RawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
|
||||
template Maybe<int32_t>
|
||||
nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
const ConstRawRangeBoundary& aFirstBoundary,
|
||||
const ConstRawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
template Maybe<int32_t> nsContentUtils::ComparePoints<TreeKind::Flat>(
|
||||
const ConstRawRangeBoundary& aFirstBoundary,
|
||||
const ConstRawRangeBoundary& aSecondBoundary, NodeIndexCache* aIndexCache);
|
||||
|
||||
|
|
@ -757,9 +787,10 @@ static auto* GetFlattenedTreeParent(const nsIContent* aContent) {
|
|||
return aContent->GetFlattenedTreeParent();
|
||||
}
|
||||
|
||||
static auto* GetFlattenedTreeParentNodeForSelection(
|
||||
const nsIContent* aContent) {
|
||||
return aContent->GetFlattenedTreeParentNodeForSelection();
|
||||
static nsIContent* GetFlattenedTreeParentNodeForSelection(
|
||||
const nsIContent* aNode) {
|
||||
nsINode* parent = aNode->GetFlattenedTreeParentNodeForSelection();
|
||||
return parent && parent->IsContent() ? parent->AsContent() : nullptr;
|
||||
}
|
||||
|
||||
static auto* GetFlattenedTreeParentElementForStyle(const Element* aElement) {
|
||||
|
|
@ -772,6 +803,17 @@ static auto* GetParentBrowserParent(const BrowserParent* aBrowserParent) {
|
|||
: nullptr;
|
||||
}
|
||||
|
||||
static bool AreNodesInSameSlot(const nsINode* aNode1, const nsINode* aNode2) {
|
||||
if (auto* content1 = nsIContent::FromNodeOrNull(aNode1)) {
|
||||
if (auto* slot = content1->GetAssignedSlot()) {
|
||||
if (auto* content2 = nsIContent::FromNodeOrNull(aNode2)) {
|
||||
return slot == content2->GetAssignedSlot();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Node1, typename Node2, typename GetParentFunc>
|
||||
class MOZ_STACK_CLASS CommonAncestors final {
|
||||
public:
|
||||
|
|
@ -826,9 +868,12 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
|||
return GetClosestCommonAncestorChild(mInclusiveAncestors2);
|
||||
}
|
||||
|
||||
template <TreeKind aKind>
|
||||
void WarnIfClosestCommonAncestorChildrenAreNotInChildList() const {
|
||||
WarnIfClosestCommonAncestorChildIsNotInChildList(mInclusiveAncestors1);
|
||||
WarnIfClosestCommonAncestorChildIsNotInChildList(mInclusiveAncestors2);
|
||||
WarnIfClosestCommonAncestorChildIsNotInChildList<aKind>(
|
||||
mInclusiveAncestors1);
|
||||
WarnIfClosestCommonAncestorChildIsNotInChildList<aKind>(
|
||||
mInclusiveAncestors2);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -870,7 +915,9 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
|||
return child;
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
template <TreeKind aKind, typename Node,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
void WarnIfClosestCommonAncestorChildIsNotInChildList(
|
||||
const nsTArray<Node*>& aInclusiveAncestors) const {
|
||||
#ifdef DEBUG
|
||||
|
|
@ -879,8 +926,24 @@ class MOZ_STACK_CLASS CommonAncestors final {
|
|||
if (!child) {
|
||||
return;
|
||||
}
|
||||
const Maybe<uint32_t> childIndex =
|
||||
mClosestCommonAncestor->ComputeIndexOf(child);
|
||||
|
||||
if (mClosestCommonAncestor->GetShadowRoot() == child) {
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<uint32_t> childIndex;
|
||||
if constexpr (aKind == TreeKind::Flat) {
|
||||
if (auto* slot = HTMLSlotElement::FromNode(mClosestCommonAncestor)) {
|
||||
auto index = slot->AssignedNodes().IndexOf(child);
|
||||
if (index != nsTArray<RefPtr<nsINode>>::NoIndex) {
|
||||
childIndex = Some(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (childIndex.isNothing()) {
|
||||
childIndex = mClosestCommonAncestor->ComputeIndexOf(child);
|
||||
}
|
||||
if (MOZ_LIKELY(childIndex.isSome())) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -3164,6 +3227,7 @@ Element* nsContentUtils::GetCommonFlattenedTreeAncestorForStyle(
|
|||
}
|
||||
|
||||
/* static */
|
||||
template <TreeKind aKind, typename Dummy>
|
||||
Maybe<int32_t> nsContentUtils::CompareChildNodes(
|
||||
const nsINode* aChild1, const nsINode* aChild2,
|
||||
NodeIndexCache* aIndexCache /* = nullptr */) {
|
||||
|
|
@ -3186,6 +3250,23 @@ Maybe<int32_t> nsContentUtils::CompareChildNodes(
|
|||
MOZ_ASSERT(aChild1->GetParentOrShadowHostNode());
|
||||
return Some(-1);
|
||||
}
|
||||
|
||||
if constexpr (aKind == TreeKind::Flat) {
|
||||
if (AreNodesInSameSlot(aChild1, aChild2)) {
|
||||
// They differ at slot, so use their position in slot
|
||||
const auto* slot = aChild1->AsContent()->GetAssignedSlot();
|
||||
MOZ_ASSERT(slot);
|
||||
|
||||
auto child1Index = slot->AssignedNodes().IndexOf(aChild1);
|
||||
auto child2Index = slot->AssignedNodes().IndexOf(aChild2);
|
||||
|
||||
MOZ_ASSERT(child1Index != nsTArray<RefPtr<nsINode>>::NoIndex);
|
||||
MOZ_ASSERT(child2Index != nsTArray<RefPtr<nsINode>>::NoIndex);
|
||||
|
||||
return Some(child1Index < child2Index ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aChild1->GetParentOrShadowHostNode());
|
||||
const nsINode& commonParentNode = *aChild1->GetParentOrShadowHostNode();
|
||||
MOZ_ASSERT(aChild2->GetParentOrShadowHostNode() == &commonParentNode);
|
||||
|
|
@ -3254,9 +3335,10 @@ Maybe<int32_t> nsContentUtils::CompareChildNodes(
|
|||
}
|
||||
|
||||
/* static */
|
||||
template <TreeKind aKind, typename Dummy>
|
||||
Maybe<int32_t> nsContentUtils::CompareClosestCommonAncestorChildren(
|
||||
const nsINode& aParent, const nsINode* aChild1, const nsINode* aChild2,
|
||||
nsContentUtils::NodeIndexCache* aIndexCache = nullptr) {
|
||||
nsContentUtils::NodeIndexCache* aIndexCache) {
|
||||
MOZ_ASSERT_IF(aChild1, GetParentOrShadowHostNode(aChild1));
|
||||
MOZ_ASSERT_IF(aChild2, GetParentOrShadowHostNode(aChild2));
|
||||
|
||||
|
|
@ -3281,7 +3363,7 @@ Maybe<int32_t> nsContentUtils::CompareClosestCommonAncestorChildren(
|
|||
return Some(1);
|
||||
}
|
||||
const Maybe<int32_t> comp =
|
||||
nsContentUtils::CompareChildNodes(aChild1, aChild2, aIndexCache);
|
||||
nsContentUtils::CompareChildNodes<aKind>(aChild1, aChild2, aIndexCache);
|
||||
if (MOZ_UNLIKELY(comp.isNothing())) {
|
||||
NS_ASSERTION(comp.isSome(),
|
||||
"nsContentUtils::CompareChildNodes() must return Some here. "
|
||||
|
|
@ -3291,14 +3373,16 @@ Maybe<int32_t> nsContentUtils::CompareClosestCommonAncestorChildren(
|
|||
return Some(1);
|
||||
}
|
||||
MOZ_ASSERT_IF(!*comp, aChild1 == aChild2);
|
||||
MOZ_ASSERT_IF(*comp < 0, (aChild1 ? *aChild1->ComputeIndexInParentNode()
|
||||
: aParent.GetChildCount()) <
|
||||
(aChild2 ? *aChild2->ComputeIndexInParentNode()
|
||||
: aParent.GetChildCount()));
|
||||
MOZ_ASSERT_IF(*comp > 0, (aChild2 ? *aChild2->ComputeIndexInParentNode()
|
||||
: aParent.GetChildCount()) <
|
||||
(aChild1 ? *aChild1->ComputeIndexInParentNode()
|
||||
: aParent.GetChildCount()));
|
||||
MOZ_ASSERT_IF(*comp < 0 && !AreNodesInSameSlot(aChild1, aChild2),
|
||||
(aChild1 ? *aChild1->ComputeIndexInParentNode()
|
||||
: aParent.GetChildCount()) <
|
||||
(aChild2 ? *aChild2->ComputeIndexInParentNode()
|
||||
: aParent.GetChildCount()));
|
||||
MOZ_ASSERT_IF(*comp > 0 && !AreNodesInSameSlot(aChild1, aChild2),
|
||||
(aChild2 ? *aChild2->ComputeIndexInParentNode()
|
||||
: aParent.GetChildCount()) <
|
||||
(aChild1 ? *aChild1->ComputeIndexInParentNode()
|
||||
: aParent.GetChildCount()));
|
||||
return comp;
|
||||
}
|
||||
|
||||
|
|
@ -3350,6 +3434,7 @@ Maybe<int32_t> nsContentUtils::CompareChildNodeAndChildOffset(
|
|||
}
|
||||
|
||||
/* static */
|
||||
template <TreeKind aKind, typename Dummy>
|
||||
Maybe<int32_t> nsContentUtils::ComparePointsWithIndices(
|
||||
const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2,
|
||||
uint32_t aOffset2, NodeIndexCache* aIndexCache) {
|
||||
|
|
@ -3360,8 +3445,17 @@ Maybe<int32_t> nsContentUtils::ComparePointsWithIndices(
|
|||
return Some(aOffset1 < aOffset2 ? -1 : (aOffset1 > aOffset2 ? 1 : 0));
|
||||
}
|
||||
|
||||
const CommonAncestors commonAncestors(*aParent1, *aParent2,
|
||||
GetParentOrShadowHostNode);
|
||||
auto GetParentFunc = [](const nsINode* aNode) -> nsINode* {
|
||||
MOZ_ASSERT(aNode);
|
||||
if constexpr (aKind == TreeKind::Flat) {
|
||||
if (aNode->IsContent() && aNode->AsContent()->GetAssignedSlot()) {
|
||||
return aNode->GetFlattenedTreeParentNodeForSelection();
|
||||
}
|
||||
}
|
||||
return aNode->GetParentOrShadowHostNode();
|
||||
};
|
||||
|
||||
const CommonAncestors commonAncestors(*aParent1, *aParent2, GetParentFunc);
|
||||
|
||||
if (MOZ_UNLIKELY(!commonAncestors.GetClosestCommonAncestor())) {
|
||||
return Nothing();
|
||||
|
|
@ -3372,16 +3466,22 @@ Maybe<int32_t> nsContentUtils::ComparePointsWithIndices(
|
|||
const nsINode* closestCommonAncestorChild2 =
|
||||
commonAncestors.GetClosestCommonAncestorChild2();
|
||||
MOZ_ASSERT(closestCommonAncestorChild1 != closestCommonAncestorChild2);
|
||||
commonAncestors.WarnIfClosestCommonAncestorChildrenAreNotInChildList();
|
||||
commonAncestors
|
||||
.template WarnIfClosestCommonAncestorChildrenAreNotInChildList<aKind>();
|
||||
if (closestCommonAncestorChild1 && closestCommonAncestorChild2) {
|
||||
return CompareClosestCommonAncestorChildren(
|
||||
return CompareClosestCommonAncestorChildren<aKind>(
|
||||
*commonAncestors.GetClosestCommonAncestor(),
|
||||
closestCommonAncestorChild1, closestCommonAncestorChild2, aIndexCache);
|
||||
}
|
||||
|
||||
if (closestCommonAncestorChild2) {
|
||||
MOZ_ASSERT(closestCommonAncestorChild2->GetParentOrShadowHostNode() ==
|
||||
aParent1);
|
||||
MOZ_ASSERT(GetParentFunc(closestCommonAncestorChild2) == aParent1);
|
||||
if (aParent1->GetShadowRoot() == closestCommonAncestorChild2) {
|
||||
// Comparing a shadow host with its shadow root.
|
||||
// We consider: [host, 0] < anything in shadow root < [host, 1]
|
||||
return aOffset1 > 0 ? Some(-1) : Some(1);
|
||||
}
|
||||
|
||||
// FIXME: bug 1946001, bug 1946003 and bug 1946008.
|
||||
if (MOZ_UNLIKELY(
|
||||
closestCommonAncestorChild2->IsRootOfNativeAnonymousSubtree() ||
|
||||
|
|
@ -3408,9 +3508,14 @@ Maybe<int32_t> nsContentUtils::ComparePointsWithIndices(
|
|||
return comp;
|
||||
}
|
||||
|
||||
if (aParent2->GetShadowRoot() == closestCommonAncestorChild1) {
|
||||
// Comparing a shadow host with its shadow root.
|
||||
// We consider: [host, 0] < anything in shadow root < [host, 1]
|
||||
return aOffset2 > 0 ? Some(-1) : Some(1);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(closestCommonAncestorChild1);
|
||||
MOZ_ASSERT(closestCommonAncestorChild1->GetParentOrShadowHostNode() ==
|
||||
aParent2);
|
||||
MOZ_ASSERT(GetParentFunc(closestCommonAncestorChild1) == aParent2);
|
||||
// FIXME: bug 1946001, bug 1946003 and bug 1946008.
|
||||
if (MOZ_UNLIKELY(
|
||||
closestCommonAncestorChild1->IsRootOfNativeAnonymousSubtree() ||
|
||||
|
|
@ -3500,7 +3605,8 @@ Element* nsContentUtils::GetTargetElement(Document* aDocument,
|
|||
}
|
||||
|
||||
/* static */
|
||||
template <typename PT1, typename RT1, typename PT2, typename RT2>
|
||||
template <TreeKind aKind, typename PT1, typename RT1, typename PT2,
|
||||
typename RT2, typename Dummy>
|
||||
Maybe<int32_t> nsContentUtils::ComparePoints(
|
||||
const RangeBoundaryBase<PT1, RT1>& aBoundary1,
|
||||
const RangeBoundaryBase<PT2, RT2>& aBoundary2,
|
||||
|
|
@ -3517,7 +3623,7 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
|||
// offset in the container. If both instances have computed offset, we can
|
||||
// use ComparePointsWithIndices() which works with offsets.
|
||||
if (aBoundary1.HasOffset() && aBoundary2.HasOffset()) {
|
||||
return ComparePointsWithIndices(
|
||||
return ComparePointsWithIndices<aKind>(
|
||||
aBoundary1.GetContainer(), *aBoundary1.Offset(kValidOrInvalidOffsets1),
|
||||
aBoundary2.GetContainer(), *aBoundary2.Offset(kValidOrInvalidOffsets2),
|
||||
aIndexCache);
|
||||
|
|
@ -3535,18 +3641,27 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
|||
if (aBoundary1.GetContainer() == aBoundary2.GetContainer()) {
|
||||
const nsIContent* const child1 = aBoundary1.GetChildAtOffset();
|
||||
const nsIContent* const child2 = aBoundary2.GetChildAtOffset();
|
||||
return CompareClosestCommonAncestorChildren(*aBoundary1.GetContainer(),
|
||||
child1, child2, aIndexCache);
|
||||
return CompareClosestCommonAncestorChildren<aKind>(
|
||||
*aBoundary1.GetContainer(), child1, child2, aIndexCache);
|
||||
}
|
||||
|
||||
auto GetParentFunc = [](const nsINode* aNode) -> nsINode* {
|
||||
MOZ_ASSERT(aNode);
|
||||
if constexpr (aKind == TreeKind::Flat) {
|
||||
if (aNode->IsContent() && aNode->AsContent()->GetAssignedSlot()) {
|
||||
return aNode->GetFlattenedTreeParentNodeForSelection();
|
||||
}
|
||||
}
|
||||
return aNode->GetParentOrShadowHostNode();
|
||||
};
|
||||
|
||||
// Otherwise, we need to compare the common ancestor children which is the
|
||||
// most distant different inclusive ancestors of the containers. So, the
|
||||
// following implementation is similar to ComparePointsWithIndices(), but we
|
||||
// don't have offset, so, we cannot use offset when we compare the boundaries
|
||||
// whose one is a descendant of the other.
|
||||
const CommonAncestors commonAncestors(*aBoundary1.GetContainer(),
|
||||
*aBoundary2.GetContainer(),
|
||||
GetParentOrShadowHostNode);
|
||||
const CommonAncestors commonAncestors(
|
||||
*aBoundary1.GetContainer(), *aBoundary2.GetContainer(), GetParentFunc);
|
||||
|
||||
if (MOZ_UNLIKELY(!commonAncestors.GetClosestCommonAncestor())) {
|
||||
return Nothing();
|
||||
|
|
@ -3557,10 +3672,11 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
|||
commonAncestors.GetClosestCommonAncestorChild1();
|
||||
const nsINode* closestCommonAncestorChild2 =
|
||||
commonAncestors.GetClosestCommonAncestorChild2();
|
||||
commonAncestors.WarnIfClosestCommonAncestorChildrenAreNotInChildList();
|
||||
commonAncestors
|
||||
.template WarnIfClosestCommonAncestorChildrenAreNotInChildList<aKind>();
|
||||
MOZ_ASSERT(closestCommonAncestorChild1 != closestCommonAncestorChild2);
|
||||
if (closestCommonAncestorChild1 && closestCommonAncestorChild2) {
|
||||
return CompareClosestCommonAncestorChildren(
|
||||
return CompareClosestCommonAncestorChildren<aKind>(
|
||||
*commonAncestors.GetClosestCommonAncestor(),
|
||||
closestCommonAncestorChild1, closestCommonAncestorChild2, aIndexCache);
|
||||
}
|
||||
|
|
@ -3575,7 +3691,7 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
|||
// XXX Keep the odd traditional behavior for now.
|
||||
return Some(1);
|
||||
}
|
||||
const Maybe<int32_t> comp = nsContentUtils::CompareChildNodes(
|
||||
const Maybe<int32_t> comp = nsContentUtils::CompareChildNodes<aKind>(
|
||||
aBoundary1.GetChildAtOffset(), closestCommonAncestorChild2,
|
||||
aIndexCache);
|
||||
if (NS_WARN_IF(comp.isNothing())) {
|
||||
|
|
@ -3613,7 +3729,7 @@ Maybe<int32_t> nsContentUtils::ComparePoints(
|
|||
// XXX Keep the odd traditional behavior for now.
|
||||
return Some(-1);
|
||||
}
|
||||
const Maybe<int32_t> comp = nsContentUtils::CompareChildNodes(
|
||||
const Maybe<int32_t> comp = nsContentUtils::CompareChildNodes<aKind>(
|
||||
closestCommonAncestorChild1, aBoundary2.GetChildAtOffset(), aIndexCache);
|
||||
if (NS_WARN_IF(comp.isNothing())) {
|
||||
NS_ASSERTION(comp.isSome(),
|
||||
|
|
|
|||
|
|
@ -716,6 +716,9 @@ class nsContentUtils {
|
|||
* 0 if point1 == point2.
|
||||
* `Nothing` if the two nodes aren't in the same connected subtree.
|
||||
*/
|
||||
template <TreeKind aKind = TreeKind::ShadowIncludingDOM,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
static mozilla::Maybe<int32_t> ComparePointsWithIndices(
|
||||
const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2,
|
||||
uint32_t aOffset2, NodeIndexCache* aIndexCache = nullptr);
|
||||
|
|
@ -730,7 +733,10 @@ class nsContentUtils {
|
|||
* 0 if point1 == point2.
|
||||
* `Nothing` if the two nodes aren't in the same connected subtree.
|
||||
*/
|
||||
template <typename PT1, typename RT1, typename PT2, typename RT2>
|
||||
template <TreeKind aKind = TreeKind::ShadowIncludingDOM, typename PT1,
|
||||
typename RT1, typename PT2, typename RT2,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
static mozilla::Maybe<int32_t> ComparePoints(
|
||||
const mozilla::RangeBoundaryBase<PT1, RT1>& aBoundary1,
|
||||
const mozilla::RangeBoundaryBase<PT2, RT2>& aBoundary2,
|
||||
|
|
@ -746,6 +752,9 @@ class nsContentUtils {
|
|||
* traditional behavior. If you want to use this in new code, it means that
|
||||
* you **should** check the offset values and call `ComparePoints` instead.
|
||||
*/
|
||||
template <TreeKind aKind = TreeKind::ShadowIncludingDOM,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
static mozilla::Maybe<int32_t> ComparePoints_AllowNegativeOffsets(
|
||||
const nsINode* aParent1, int64_t aOffset1, const nsINode* aParent2,
|
||||
int64_t aOffset2) {
|
||||
|
|
@ -768,7 +777,7 @@ class nsContentUtils {
|
|||
}
|
||||
// Otherwise, aOffset1 nor aOffset2 is referred so that any value is fine
|
||||
// if negative.
|
||||
return ComparePointsWithIndices(
|
||||
return ComparePointsWithIndices<aKind>(
|
||||
aParent1,
|
||||
// Avoid warnings.
|
||||
aOffset1 < 0 ? aParent1->GetChildCount()
|
||||
|
|
@ -780,7 +789,8 @@ class nsContentUtils {
|
|||
: std::min(static_cast<uint32_t>(aOffset2),
|
||||
aParent2->GetChildCount()));
|
||||
}
|
||||
return ComparePointsWithIndices(aParent1, aOffset1, aParent2, aOffset2);
|
||||
return ComparePointsWithIndices<aKind>(aParent1, aOffset1, aParent2,
|
||||
aOffset2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3642,6 +3652,9 @@ class nsContentUtils {
|
|||
* node.
|
||||
* Return Nothing if aChild1 is a root of the native anonymous subtree.
|
||||
*/
|
||||
template <TreeKind aKind,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
static mozilla::Maybe<int32_t> CompareChildNodes(
|
||||
const nsINode* aChild1, const nsINode* aChild2,
|
||||
NodeIndexCache* aIndexCache = nullptr);
|
||||
|
|
@ -3671,8 +3684,12 @@ class nsContentUtils {
|
|||
* includes odd traditional behavior. Therefore, do not use this method as a
|
||||
* utility method.
|
||||
*/
|
||||
template <TreeKind aKind = TreeKind::ShadowIncludingDOM,
|
||||
typename = std::enable_if_t<aKind == TreeKind::ShadowIncludingDOM ||
|
||||
aKind == TreeKind::Flat>>
|
||||
static mozilla::Maybe<int32_t> CompareClosestCommonAncestorChildren(
|
||||
const nsINode&, const nsINode*, const nsINode*, NodeIndexCache*);
|
||||
const nsINode&, const nsINode*, const nsINode*,
|
||||
NodeIndexCache* = nullptr);
|
||||
|
||||
static nsIXPConnect* sXPConnect;
|
||||
|
||||
|
|
|
|||
|
|
@ -144,9 +144,8 @@ inline nsINode* nsINode::GetFlattenedTreeParentNodeForStyle() const {
|
|||
return ::GetFlattenedTreeParentNode<nsINode::eForStyle>(this);
|
||||
}
|
||||
|
||||
inline nsIContent* nsINode::GetFlattenedTreeParentNodeForSelection() const {
|
||||
nsINode* parent = ::GetFlattenedTreeParentNode<nsINode::eForSelection>(this);
|
||||
return (parent && parent->IsContent()) ? parent->AsContent() : nullptr;
|
||||
inline nsINode* nsINode::GetFlattenedTreeParentNodeForSelection() const {
|
||||
return ::GetFlattenedTreeParentNode<nsINode::eForSelection>(this);
|
||||
}
|
||||
|
||||
inline bool nsINode::NodeOrAncestorHasDirAuto() const {
|
||||
|
|
|
|||
|
|
@ -343,16 +343,28 @@ class IsItemInRangeComparator {
|
|||
}
|
||||
|
||||
int operator()(const AbstractRange* const aRange) const {
|
||||
Maybe<int32_t> cmp = nsContentUtils::ComparePoints(
|
||||
ConstRawRangeBoundary(&mNode, mEndOffset,
|
||||
RangeBoundaryIsMutationObserved::No),
|
||||
aRange->MayCrossShadowBoundaryStartRef(), mCache);
|
||||
if (cmp.valueOr(1) == 1) {
|
||||
cmp = nsContentUtils::ComparePoints(
|
||||
ConstRawRangeBoundary(&mNode, mStartOffset,
|
||||
RangeBoundaryIsMutationObserved::No),
|
||||
aRange->MayCrossShadowBoundaryEndRef(), mCache);
|
||||
if (cmp.valueOr(1) == -1) {
|
||||
auto ComparePoints = [](const nsINode* aNode1, const uint32_t aOffset1,
|
||||
const nsINode* aNode2, const uint32_t aOffset2,
|
||||
nsContentUtils::NodeIndexCache* aCache) {
|
||||
if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) {
|
||||
return nsContentUtils::ComparePointsWithIndices<TreeKind::Flat>(
|
||||
aNode1, aOffset1, aNode2, aOffset2, aCache);
|
||||
}
|
||||
return nsContentUtils::ComparePointsWithIndices<
|
||||
TreeKind::ShadowIncludingDOM>(aNode1, aOffset1, aNode2, aOffset2,
|
||||
aCache);
|
||||
};
|
||||
|
||||
Maybe<int32_t> cmp = ComparePoints(
|
||||
&mNode, mEndOffset, aRange->GetMayCrossShadowBoundaryStartContainer(),
|
||||
aRange->MayCrossShadowBoundaryStartOffset(), mCache);
|
||||
MOZ_ASSERT(cmp.isSome()); // Should always be connected at this point.
|
||||
if (cmp.value() == 1) {
|
||||
cmp = ComparePoints(&mNode, mStartOffset,
|
||||
aRange->GetMayCrossShadowBoundaryEndContainer(),
|
||||
aRange->MayCrossShadowBoundaryEndOffset(), mCache);
|
||||
MOZ_ASSERT(cmp.isSome());
|
||||
if (cmp.value() == -1) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -1190,7 +1190,7 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||
* 2. For contents that are slotted into a UA shadow tree, use its
|
||||
* parent rather than the slot element.
|
||||
*/
|
||||
inline nsIContent* GetFlattenedTreeParentNodeForSelection() const;
|
||||
inline nsINode* GetFlattenedTreeParentNodeForSelection() const;
|
||||
|
||||
inline mozilla::dom::Element* GetFlattenedTreeParentElement() const;
|
||||
inline mozilla::dom::Element* GetFlattenedTreeParentElementForStyle() const;
|
||||
|
|
|
|||
|
|
@ -285,12 +285,21 @@ static RangeBehaviour GetRangeBehaviour(
|
|||
const RangeBoundary& otherSideExistingBoundary =
|
||||
aIsSetStart ? aRange->EndRef() : aRange->StartRef();
|
||||
|
||||
auto ComparePoints = [aAllowCrossShadowBoundary](
|
||||
const RawRangeBoundary& aBoundary1,
|
||||
const RawRangeBoundary& aBoundary2) {
|
||||
if (aAllowCrossShadowBoundary == AllowRangeCrossShadowBoundary::Yes) {
|
||||
return nsContentUtils::ComparePoints<TreeKind::Flat>(aBoundary1,
|
||||
aBoundary2);
|
||||
}
|
||||
return nsContentUtils::ComparePoints<TreeKind::ShadowIncludingDOM>(
|
||||
aBoundary1, aBoundary2);
|
||||
};
|
||||
// Both bondaries are in the same root, now check for their position
|
||||
const Maybe<int32_t> order =
|
||||
aIsSetStart ? nsContentUtils::ComparePoints(aNewBoundary,
|
||||
otherSideExistingBoundary)
|
||||
: nsContentUtils::ComparePoints(otherSideExistingBoundary,
|
||||
aNewBoundary);
|
||||
aIsSetStart
|
||||
? ComparePoints(aNewBoundary, otherSideExistingBoundary.AsRaw())
|
||||
: ComparePoints(otherSideExistingBoundary.AsRaw(), aNewBoundary);
|
||||
|
||||
if (order) {
|
||||
if (*order != 1) {
|
||||
|
|
@ -324,11 +333,12 @@ static RangeBehaviour GetRangeBehaviour(
|
|||
// otherSideExistingBoundary. However, it's possible that aNewBoundary
|
||||
// is valid with the otherSideExistingCrossShadowBoundaryBoundary.
|
||||
const Maybe<int32_t> withCrossShadowBoundaryOrder =
|
||||
aIsSetStart
|
||||
? nsContentUtils::ComparePoints(
|
||||
aNewBoundary, otherSideExistingCrossShadowBoundaryBoundary)
|
||||
: nsContentUtils::ComparePoints(
|
||||
otherSideExistingCrossShadowBoundaryBoundary, aNewBoundary);
|
||||
aIsSetStart ? ComparePoints(
|
||||
aNewBoundary,
|
||||
otherSideExistingCrossShadowBoundaryBoundary.AsRaw())
|
||||
: ComparePoints(
|
||||
otherSideExistingCrossShadowBoundaryBoundary.AsRaw(),
|
||||
aNewBoundary);
|
||||
|
||||
// Valid to the cross boundary boundary.
|
||||
if (withCrossShadowBoundaryOrder && *withCrossShadowBoundaryOrder != 1) {
|
||||
|
|
@ -3246,8 +3256,7 @@ void nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges) {
|
|||
nsINode* node = preOrderIter.GetCurrentNode();
|
||||
preOrderIter.Next();
|
||||
bool selectable = true;
|
||||
nsIContent* content =
|
||||
node && node->IsContent() ? node->AsContent() : nullptr;
|
||||
nsIContent* content = nsIContent::FromNodeOrNull(node);
|
||||
if (content) {
|
||||
if (firstNonSelectableContent &&
|
||||
ExcludeIfNextToNonSelectable(content)) {
|
||||
|
|
|
|||
|
|
@ -2829,9 +2829,10 @@ HTMLEditUtils::ComputePointToPutCaretInElementIfOutside(
|
|||
// Use range boundaries and RangeUtils::CompareNodeToRange() to compare
|
||||
// selection start to new block.
|
||||
bool nodeBefore, nodeAfter;
|
||||
nsresult rv = RangeUtils::CompareNodeToRangeBoundaries(
|
||||
const_cast<Element*>(&aElement), aCurrentPoint.ToRawRangeBoundary(),
|
||||
aCurrentPoint.ToRawRangeBoundary(), &nodeBefore, &nodeAfter);
|
||||
nsresult rv =
|
||||
RangeUtils::CompareNodeToRangeBoundaries<TreeKind::ShadowIncludingDOM>(
|
||||
const_cast<Element*>(&aElement), aCurrentPoint.ToRawRangeBoundary(),
|
||||
aCurrentPoint.ToRawRangeBoundary(), &nodeBefore, &nodeAfter);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("RangeUtils::CompareNodeToRange() failed");
|
||||
return Err(rv);
|
||||
|
|
|
|||
|
|
@ -5063,7 +5063,8 @@ nsRect PresShell::ClipListToRange(nsDisplayListBuilder* aBuilder,
|
|||
// if the node is within the range, append it to the temporary list
|
||||
bool before, after;
|
||||
nsresult rv =
|
||||
RangeUtils::CompareNodeToRange(content, aRange, &before, &after);
|
||||
RangeUtils::CompareNodeToRange<TreeKind::ShadowIncludingDOM>(
|
||||
content, aRange, &before, &after);
|
||||
if (NS_SUCCEEDED(rv) && !before && !after) {
|
||||
itemToInsert = i;
|
||||
bool snap;
|
||||
|
|
|
|||
Loading…
Reference in a new issue