Bug 1608071: part 1) Rename common ancestor to closest common inclusive ancestor around nsRange. r=smaug
It's more precise and enables one to reason more clearly about related code. Differential Revision: https://phabricator.services.mozilla.com/D59318
This commit is contained in:
@@ -2695,7 +2695,7 @@ void Element::List(FILE* out, int32_t aIndent, const nsCString& aPrefix) const {
|
|||||||
fprintf(out, " state=[%llx]",
|
fprintf(out, " state=[%llx]",
|
||||||
static_cast<unsigned long long>(State().GetInternalValue()));
|
static_cast<unsigned long long>(State().GetInternalValue()));
|
||||||
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
||||||
if (IsCommonAncestorForRangeInSelection()) {
|
if (IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
const LinkedList<nsRange>* ranges = GetExistingCommonAncestorRanges();
|
const LinkedList<nsRange>* ranges = GetExistingCommonAncestorRanges();
|
||||||
int32_t count = 0;
|
int32_t count = 0;
|
||||||
if (ranges) {
|
if (ranges) {
|
||||||
|
|||||||
@@ -1350,14 +1350,15 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||||||
inline bool IsRootOfChromeAccessOnlySubtree() const;
|
inline bool IsRootOfChromeAccessOnlySubtree() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if |this| node is the common ancestor of the start/end
|
* Returns true if |this| node is the closest common inclusive ancestor
|
||||||
* nodes of a Range in a Selection or a descendant of such a common ancestor.
|
* (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of the
|
||||||
* This node is definitely not selected when |false| is returned, but it may
|
* start/end nodes of a Range in a Selection or a descendant of such a common
|
||||||
* or may not be selected when |true| is returned.
|
* ancestor. This node is definitely not selected when |false| is returned,
|
||||||
|
* but it may or may not be selected when |true| is returned.
|
||||||
*/
|
*/
|
||||||
bool IsSelectionDescendant() const {
|
bool IsSelectionDescendant() const {
|
||||||
return IsDescendantOfCommonAncestorForRangeInSelection() ||
|
return IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() ||
|
||||||
IsCommonAncestorForRangeInSelection();
|
IsClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1595,11 +1596,11 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||||||
ElementHasPart,
|
ElementHasPart,
|
||||||
// Set if the element might have a contenteditable attribute set.
|
// Set if the element might have a contenteditable attribute set.
|
||||||
ElementMayHaveContentEditableAttr,
|
ElementMayHaveContentEditableAttr,
|
||||||
// Set if the node is the common ancestor of the start/end nodes of a Range
|
// Set if the node is the closest common inclusive ancestor of the start/end
|
||||||
// that is in a Selection.
|
// nodes of a Range that is in a Selection.
|
||||||
NodeIsCommonAncestorForRangeInSelection,
|
NodeIsClosestCommonInclusiveAncestorForRangeInSelection,
|
||||||
// Set if the node is a descendant of a node with the above bit set.
|
// Set if the node is a descendant of a node with the above bit set.
|
||||||
NodeIsDescendantOfCommonAncestorForRangeInSelection,
|
NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection,
|
||||||
// Set if CanSkipInCC check has been done for this subtree root.
|
// Set if CanSkipInCC check has been done for this subtree root.
|
||||||
NodeIsCCMarkedRoot,
|
NodeIsCCMarkedRoot,
|
||||||
// Maybe set if this node is in black subtree.
|
// Maybe set if this node is in black subtree.
|
||||||
@@ -1693,23 +1694,44 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||||||
bool MayHaveContentEditableAttr() const {
|
bool MayHaveContentEditableAttr() const {
|
||||||
return GetBoolFlag(ElementMayHaveContentEditableAttr);
|
return GetBoolFlag(ElementMayHaveContentEditableAttr);
|
||||||
}
|
}
|
||||||
bool IsCommonAncestorForRangeInSelection() const {
|
/**
|
||||||
return GetBoolFlag(NodeIsCommonAncestorForRangeInSelection);
|
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
|
||||||
|
*/
|
||||||
|
bool IsClosestCommonInclusiveAncestorForRangeInSelection() const {
|
||||||
|
return GetBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
|
||||||
}
|
}
|
||||||
void SetCommonAncestorForRangeInSelection() {
|
/**
|
||||||
SetBoolFlag(NodeIsCommonAncestorForRangeInSelection);
|
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
|
||||||
|
*/
|
||||||
|
void SetClosestCommonInclusiveAncestorForRangeInSelection() {
|
||||||
|
SetBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
|
||||||
}
|
}
|
||||||
void ClearCommonAncestorForRangeInSelection() {
|
/**
|
||||||
ClearBoolFlag(NodeIsCommonAncestorForRangeInSelection);
|
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
|
||||||
|
*/
|
||||||
|
void ClearClosestCommonInclusiveAncestorForRangeInSelection() {
|
||||||
|
ClearBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
|
||||||
}
|
}
|
||||||
bool IsDescendantOfCommonAncestorForRangeInSelection() const {
|
/**
|
||||||
return GetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection);
|
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
|
||||||
|
*/
|
||||||
|
bool IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() const {
|
||||||
|
return GetBoolFlag(
|
||||||
|
NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
|
||||||
}
|
}
|
||||||
void SetDescendantOfCommonAncestorForRangeInSelection() {
|
/**
|
||||||
SetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection);
|
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
|
||||||
|
*/
|
||||||
|
void SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() {
|
||||||
|
SetBoolFlag(
|
||||||
|
NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
|
||||||
}
|
}
|
||||||
void ClearDescendantOfCommonAncestorForRangeInSelection() {
|
/**
|
||||||
ClearBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection);
|
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
|
||||||
|
*/
|
||||||
|
void ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() {
|
||||||
|
ClearBoolFlag(
|
||||||
|
NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCCMarkedRoot(bool aValue) { SetBoolFlag(NodeIsCCMarkedRoot, aValue); }
|
void SetCCMarkedRoot(bool aValue) { SetBoolFlag(NodeIsCCMarkedRoot, aValue); }
|
||||||
|
|||||||
@@ -119,8 +119,10 @@ static void InvalidateAllFrames(nsINode* aNode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static nsINode* GetNextRangeCommonAncestor(nsINode* aNode) {
|
static nsINode* GetNextRangeCommonAncestor(nsINode* aNode) {
|
||||||
while (aNode && !aNode->IsCommonAncestorForRangeInSelection()) {
|
while (aNode &&
|
||||||
if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
!aNode->IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
|
if (!aNode
|
||||||
|
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
aNode = aNode->GetParentNode();
|
aNode = aNode->GetParentNode();
|
||||||
@@ -270,7 +272,7 @@ nsRange::~nsRange() {
|
|||||||
|
|
||||||
nsRange::nsRange(nsINode* aNode)
|
nsRange::nsRange(nsINode* aNode)
|
||||||
: AbstractRange(aNode),
|
: AbstractRange(aNode),
|
||||||
mRegisteredCommonAncestor(nullptr),
|
mRegisteredClosestCommonInclusiveAncestor(nullptr),
|
||||||
mNextStartRef(nullptr),
|
mNextStartRef(nullptr),
|
||||||
mNextEndRef(nullptr) {
|
mNextEndRef(nullptr) {
|
||||||
// printf("Size of nsRange: %zu\n", sizeof(nsRange));
|
// printf("Size of nsRange: %zu\n", sizeof(nsRange));
|
||||||
@@ -309,11 +311,12 @@ NS_INTERFACE_MAP_END_INHERITING(AbstractRange)
|
|||||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsRange)
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsRange)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsRange, AbstractRange)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsRange, AbstractRange)
|
||||||
// We _could_ just rely on Reset() to UnregisterCommonAncestor(),
|
// We _could_ just rely on Reset() to
|
||||||
// but it wouldn't know we're calling it from Unlink and so would do
|
// UnregisterClosestCommonInclusiveAncestor(), but it wouldn't know we're
|
||||||
// more work than it really needs to.
|
// calling it from Unlink and so would do more work than it really needs to.
|
||||||
if (tmp->mRegisteredCommonAncestor) {
|
if (tmp->mRegisteredClosestCommonInclusiveAncestor) {
|
||||||
tmp->UnregisterCommonAncestor(tmp->mRegisteredCommonAncestor, true);
|
tmp->UnregisterClosestCommonInclusiveAncestor(
|
||||||
|
tmp->mRegisteredClosestCommonInclusiveAncestor, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp->Reset();
|
tmp->Reset();
|
||||||
@@ -330,16 +333,16 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsRange, AbstractRange)
|
|||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||||
|
|
||||||
static void MarkDescendants(nsINode* aNode) {
|
static void MarkDescendants(nsINode* aNode) {
|
||||||
// Set NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
|
// Set NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection on
|
||||||
// descendants unless aNode is already marked as a range common ancestor
|
// aNode's descendants unless aNode is already marked as a range common
|
||||||
// or a descendant of one, in which case all of our descendants have the
|
// ancestor or a descendant of one, in which case all of our descendants have
|
||||||
// bit set already.
|
// the bit set already.
|
||||||
if (!aNode->IsSelectionDescendant()) {
|
if (!aNode->IsSelectionDescendant()) {
|
||||||
// don't set the Descendant bit on |aNode| itself
|
// don't set the Descendant bit on |aNode| itself
|
||||||
nsINode* node = aNode->GetNextNode(aNode);
|
nsINode* node = aNode->GetNextNode(aNode);
|
||||||
while (node) {
|
while (node) {
|
||||||
node->SetDescendantOfCommonAncestorForRangeInSelection();
|
node->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
if (!node->IsCommonAncestorForRangeInSelection()) {
|
if (!node->IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
node = node->GetNextNode(aNode);
|
node = node->GetNextNode(aNode);
|
||||||
} else {
|
} else {
|
||||||
// optimize: skip this sub-tree since it's marked already.
|
// optimize: skip this sub-tree since it's marked already.
|
||||||
@@ -350,16 +353,17 @@ static void MarkDescendants(nsINode* aNode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void UnmarkDescendants(nsINode* aNode) {
|
static void UnmarkDescendants(nsINode* aNode) {
|
||||||
// Unset NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
|
// Unset NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection
|
||||||
// descendants unless aNode is a descendant of another range common ancestor.
|
// on aNode's descendants unless aNode is a descendant of another range common
|
||||||
// Also, exclude descendants of range common ancestors (but not the common
|
// ancestor. Also, exclude descendants of range common ancestors (but not the
|
||||||
// ancestor itself).
|
// common ancestor itself).
|
||||||
if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
if (!aNode
|
||||||
|
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
// we know |aNode| doesn't have any bit set
|
// we know |aNode| doesn't have any bit set
|
||||||
nsINode* node = aNode->GetNextNode(aNode);
|
nsINode* node = aNode->GetNextNode(aNode);
|
||||||
while (node) {
|
while (node) {
|
||||||
node->ClearDescendantOfCommonAncestorForRangeInSelection();
|
node->ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
if (!node->IsCommonAncestorForRangeInSelection()) {
|
if (!node->IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
node = node->GetNextNode(aNode);
|
node = node->GetNextNode(aNode);
|
||||||
} else {
|
} else {
|
||||||
// We found an ancestor of an overlapping range, skip its descendants.
|
// We found an ancestor of an overlapping range, skip its descendants.
|
||||||
@@ -369,12 +373,12 @@ static void UnmarkDescendants(nsINode* aNode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsRange::RegisterCommonAncestor(nsINode* aNode) {
|
void nsRange::RegisterClosestCommonInclusiveAncestor(nsINode* aNode) {
|
||||||
MOZ_ASSERT(aNode, "bad arg");
|
MOZ_ASSERT(aNode, "bad arg");
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(IsInSelection(), "registering range not in selection");
|
MOZ_DIAGNOSTIC_ASSERT(IsInSelection(), "registering range not in selection");
|
||||||
|
|
||||||
mRegisteredCommonAncestor = aNode;
|
mRegisteredClosestCommonInclusiveAncestor = aNode;
|
||||||
|
|
||||||
MarkDescendants(aNode);
|
MarkDescendants(aNode);
|
||||||
|
|
||||||
@@ -385,17 +389,20 @@ void nsRange::RegisterCommonAncestor(nsINode* aNode) {
|
|||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!isInList());
|
MOZ_DIAGNOSTIC_ASSERT(!isInList());
|
||||||
ranges->insertBack(this);
|
ranges->insertBack(this);
|
||||||
aNode->SetCommonAncestorForRangeInSelection();
|
aNode->SetClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsRange::UnregisterCommonAncestor(nsINode* aNode, bool aIsUnlinking) {
|
void nsRange::UnregisterClosestCommonInclusiveAncestor(nsINode* aNode,
|
||||||
|
bool aIsUnlinking) {
|
||||||
MOZ_ASSERT(aNode, "bad arg");
|
MOZ_ASSERT(aNode, "bad arg");
|
||||||
NS_ASSERTION(aNode->IsCommonAncestorForRangeInSelection(), "wrong node");
|
NS_ASSERTION(aNode->IsClosestCommonInclusiveAncestorForRangeInSelection(),
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aNode == mRegisteredCommonAncestor, "wrong node");
|
"wrong node");
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(aNode == mRegisteredClosestCommonInclusiveAncestor,
|
||||||
|
"wrong node");
|
||||||
LinkedList<nsRange>* ranges = aNode->GetExistingCommonAncestorRanges();
|
LinkedList<nsRange>* ranges = aNode->GetExistingCommonAncestorRanges();
|
||||||
MOZ_ASSERT(ranges);
|
MOZ_ASSERT(ranges);
|
||||||
|
|
||||||
mRegisteredCommonAncestor = nullptr;
|
mRegisteredClosestCommonInclusiveAncestor = nullptr;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@@ -414,7 +421,7 @@ void nsRange::UnregisterCommonAncestor(nsINode* aNode, bool aIsUnlinking) {
|
|||||||
// We don't want to waste time unmarking flags on nodes that are
|
// We don't want to waste time unmarking flags on nodes that are
|
||||||
// being unlinked anyway.
|
// being unlinked anyway.
|
||||||
if (!aIsUnlinking && ranges->isEmpty()) {
|
if (!aIsUnlinking && ranges->isEmpty()) {
|
||||||
aNode->ClearCommonAncestorForRangeInSelection();
|
aNode->ClearClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
UnmarkDescendants(aNode);
|
UnmarkDescendants(aNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -554,13 +561,13 @@ void nsRange::CharacterDataChanged(nsIContent* aContent,
|
|||||||
bool isCommonAncestor =
|
bool isCommonAncestor =
|
||||||
IsInSelection() && mStart.Container() == mEnd.Container();
|
IsInSelection() && mStart.Container() == mEnd.Container();
|
||||||
if (isCommonAncestor) {
|
if (isCommonAncestor) {
|
||||||
UnregisterCommonAncestor(mStart.Container(), false);
|
UnregisterClosestCommonInclusiveAncestor(mStart.Container(), false);
|
||||||
RegisterCommonAncestor(newStart.Container());
|
RegisterClosestCommonInclusiveAncestor(newStart.Container());
|
||||||
}
|
}
|
||||||
if (mStart.Container()
|
if (mStart.Container()
|
||||||
->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
newStart.Container()
|
newStart.Container()
|
||||||
->SetDescendantOfCommonAncestorForRangeInSelection();
|
->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If boundary is inside changed text, position it before change
|
// If boundary is inside changed text, position it before change
|
||||||
@@ -607,12 +614,16 @@ void nsRange::CharacterDataChanged(nsIContent* aContent,
|
|||||||
IsInSelection() && mStart.Container() == mEnd.Container();
|
IsInSelection() && mStart.Container() == mEnd.Container();
|
||||||
if (isCommonAncestor && !newStart.Container()) {
|
if (isCommonAncestor && !newStart.Container()) {
|
||||||
// The split occurs inside the range.
|
// The split occurs inside the range.
|
||||||
UnregisterCommonAncestor(mStart.Container(), false);
|
UnregisterClosestCommonInclusiveAncestor(mStart.Container(), false);
|
||||||
RegisterCommonAncestor(mStart.Container()->GetParentNode());
|
RegisterClosestCommonInclusiveAncestor(
|
||||||
newEnd.Container()->SetDescendantOfCommonAncestorForRangeInSelection();
|
mStart.Container()->GetParentNode());
|
||||||
} else if (mEnd.Container()
|
newEnd.Container()
|
||||||
->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
newEnd.Container()->SetDescendantOfCommonAncestorForRangeInSelection();
|
} else if (
|
||||||
|
mEnd.Container()
|
||||||
|
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
|
newEnd.Container()
|
||||||
|
->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CheckedUint32 newEndOffset{0};
|
CheckedUint32 newEndOffset{0};
|
||||||
@@ -671,9 +682,11 @@ void nsRange::ContentAppended(nsIContent* aFirstNewContent) {
|
|||||||
if (container->IsSelectionDescendant() && IsInSelection()) {
|
if (container->IsSelectionDescendant() && IsInSelection()) {
|
||||||
nsINode* child = aFirstNewContent;
|
nsINode* child = aFirstNewContent;
|
||||||
while (child) {
|
while (child) {
|
||||||
if (!child->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
if (!child
|
||||||
|
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
MarkDescendants(child);
|
MarkDescendants(child);
|
||||||
child->SetDescendantOfCommonAncestorForRangeInSelection();
|
child
|
||||||
|
->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
}
|
}
|
||||||
child = child->GetNextSibling();
|
child = child->GetNextSibling();
|
||||||
}
|
}
|
||||||
@@ -724,9 +737,10 @@ void nsRange::ContentInserted(nsIContent* aChild) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (container->IsSelectionDescendant() &&
|
if (container->IsSelectionDescendant() &&
|
||||||
!aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
!aChild
|
||||||
|
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
MarkDescendants(aChild);
|
MarkDescendants(aChild);
|
||||||
aChild->SetDescendantOfCommonAncestorForRangeInSelection();
|
aChild->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNextStartRef || mNextEndRef) {
|
if (mNextStartRef || mNextEndRef) {
|
||||||
@@ -810,8 +824,10 @@ void nsRange::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling) {
|
|||||||
MOZ_ASSERT(mEnd.Ref() != aChild);
|
MOZ_ASSERT(mEnd.Ref() != aChild);
|
||||||
|
|
||||||
if (container->IsSelectionDescendant() &&
|
if (container->IsSelectionDescendant() &&
|
||||||
aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
aChild
|
||||||
aChild->ClearDescendantOfCommonAncestorForRangeInSelection();
|
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
|
aChild
|
||||||
|
->ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||||
UnmarkDescendants(aChild);
|
UnmarkDescendants(aChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1012,24 +1028,24 @@ void nsRange::DoSetRange(const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
|
|||||||
mEnd = aEndBoundary;
|
mEnd = aEndBoundary;
|
||||||
|
|
||||||
if (checkCommonAncestor) {
|
if (checkCommonAncestor) {
|
||||||
nsINode* oldCommonAncestor = mRegisteredCommonAncestor;
|
nsINode* oldCommonAncestor = mRegisteredClosestCommonInclusiveAncestor;
|
||||||
nsINode* newCommonAncestor = GetCommonAncestor();
|
nsINode* newCommonAncestor = GetCommonAncestor();
|
||||||
if (newCommonAncestor != oldCommonAncestor) {
|
if (newCommonAncestor != oldCommonAncestor) {
|
||||||
if (oldCommonAncestor) {
|
if (oldCommonAncestor) {
|
||||||
UnregisterCommonAncestor(oldCommonAncestor, false);
|
UnregisterClosestCommonInclusiveAncestor(oldCommonAncestor, false);
|
||||||
}
|
}
|
||||||
if (newCommonAncestor) {
|
if (newCommonAncestor) {
|
||||||
RegisterCommonAncestor(newCommonAncestor);
|
RegisterClosestCommonInclusiveAncestor(newCommonAncestor);
|
||||||
} else {
|
} else {
|
||||||
NS_ASSERTION(!mIsPositioned, "unexpected disconnected nodes");
|
NS_ASSERTION(!mIsPositioned, "unexpected disconnected nodes");
|
||||||
mSelection = nullptr;
|
mSelection = nullptr;
|
||||||
MOZ_DIAGNOSTIC_ASSERT(
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
!mRegisteredCommonAncestor,
|
!mRegisteredClosestCommonInclusiveAncestor,
|
||||||
"How can we have a registered common ancestor when we "
|
"How can we have a registered common ancestor when we "
|
||||||
"didn't register ourselves?");
|
"didn't register ourselves?");
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!isInList(),
|
MOZ_DIAGNOSTIC_ASSERT(!isInList(),
|
||||||
"Shouldn't be registered if we have no "
|
"Shouldn't be registered if we have no "
|
||||||
"mRegisteredCommonAncestor");
|
"mRegisteredClosestCommonInclusiveAncestor");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1077,16 +1093,18 @@ void nsRange::SetSelection(mozilla::dom::Selection* aSelection) {
|
|||||||
if (mSelection) {
|
if (mSelection) {
|
||||||
nsINode* commonAncestor = GetCommonAncestor();
|
nsINode* commonAncestor = GetCommonAncestor();
|
||||||
NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
|
NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
|
||||||
RegisterCommonAncestor(commonAncestor);
|
RegisterClosestCommonInclusiveAncestor(commonAncestor);
|
||||||
} else if (mRegisteredCommonAncestor) {
|
} else if (mRegisteredClosestCommonInclusiveAncestor) {
|
||||||
UnregisterCommonAncestor(mRegisteredCommonAncestor, false);
|
UnregisterClosestCommonInclusiveAncestor(
|
||||||
|
mRegisteredClosestCommonInclusiveAncestor, false);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
!mRegisteredCommonAncestor,
|
!mRegisteredClosestCommonInclusiveAncestor,
|
||||||
"How can we have a registered common ancestor when we "
|
"How can we have a registered common ancestor when we "
|
||||||
"just unregistered?");
|
"just unregistered?");
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!isInList(),
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
|
!isInList(),
|
||||||
"Shouldn't be registered if we have no "
|
"Shouldn't be registered if we have no "
|
||||||
"mRegisteredCommonAncestor after unregistering");
|
"mRegisteredClosestCommonInclusiveAncestor after unregistering");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2965,11 +2983,12 @@ nsresult nsRange::GetUsedFontFaces(nsLayoutUtils::UsedFontFaceList& aResult,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsINode* nsRange::GetRegisteredCommonAncestor() {
|
nsINode* nsRange::GetRegisteredClosestCommonInclusiveAncestor() {
|
||||||
MOZ_ASSERT(IsInSelection(),
|
MOZ_ASSERT(IsInSelection(),
|
||||||
"GetRegisteredCommonAncestor only valid for range in selection");
|
"GetRegisteredClosestCommonInclusiveAncestor only valid for range "
|
||||||
MOZ_ASSERT(mRegisteredCommonAncestor);
|
"in selection");
|
||||||
return mRegisteredCommonAncestor;
|
MOZ_ASSERT(mRegisteredClosestCommonInclusiveAncestor);
|
||||||
|
return mRegisteredClosestCommonInclusiveAncestor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
@@ -2988,10 +3007,12 @@ nsRange::AutoInvalidateSelection::~AutoInvalidateSelection() {
|
|||||||
// we have a different common ancestor now, and if so invalidate its subtree
|
// we have a different common ancestor now, and if so invalidate its subtree
|
||||||
// so it paints the selection it's in now.
|
// so it paints the selection it's in now.
|
||||||
if (mRange->IsInSelection()) {
|
if (mRange->IsInSelection()) {
|
||||||
nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor();
|
nsINode* commonAncestor =
|
||||||
|
mRange->GetRegisteredClosestCommonInclusiveAncestor();
|
||||||
// XXXbz can commonAncestor really be null here? I wouldn't think so! If
|
// XXXbz can commonAncestor really be null here? I wouldn't think so! If
|
||||||
// it _were_, then in a debug build GetRegisteredCommonAncestor() would have
|
// it _were_, then in a debug build
|
||||||
// fatally asserted.
|
// GetRegisteredClosestCommonInclusiveAncestor() would have fatally
|
||||||
|
// asserted.
|
||||||
if (commonAncestor && commonAncestor != mCommonAncestor) {
|
if (commonAncestor && commonAncestor != mCommonAncestor) {
|
||||||
::InvalidateAllFrames(commonAncestor);
|
::InvalidateAllFrames(commonAncestor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,8 +366,15 @@ class nsRange final : public mozilla::dom::AbstractRange,
|
|||||||
typedef nsTHashtable<nsPtrHashKey<nsRange>> RangeHashTable;
|
typedef nsTHashtable<nsPtrHashKey<nsRange>> RangeHashTable;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void RegisterCommonAncestor(nsINode* aNode);
|
/**
|
||||||
void UnregisterCommonAncestor(nsINode* aNode, bool aIsUnlinking);
|
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
|
||||||
|
*/
|
||||||
|
void RegisterClosestCommonInclusiveAncestor(nsINode* aNode);
|
||||||
|
/**
|
||||||
|
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
|
||||||
|
*/
|
||||||
|
void UnregisterClosestCommonInclusiveAncestor(nsINode* aNode,
|
||||||
|
bool aIsUnlinking);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DoSetRange() is called when `AbstractRange::SetStartAndEndInternal()` sets
|
* DoSetRange() is called when `AbstractRange::SetStartAndEndInternal()` sets
|
||||||
@@ -392,14 +399,16 @@ class nsRange final : public mozilla::dom::AbstractRange,
|
|||||||
nsINode* aRootNode, bool aNotInsertedYet = false);
|
nsINode* aRootNode, bool aNotInsertedYet = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For a range for which IsInSelection() is true, return the common ancestor
|
* For a range for which IsInSelection() is true, return the closest common
|
||||||
|
* inclusive ancestor
|
||||||
|
* (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor)
|
||||||
* for the range, which we had to compute when the common ancestor changed or
|
* for the range, which we had to compute when the common ancestor changed or
|
||||||
* IsInSelection became true, so we could register with it. That is, it's a
|
* IsInSelection became true, so we could register with it. That is, it's a
|
||||||
* faster version of GetCommonAncestor that only works for ranges in a
|
* faster version of GetCommonAncestor that only works for ranges in a
|
||||||
* Selection. The method will assert and the behavior is undefined if called
|
* Selection. The method will assert and the behavior is undefined if called
|
||||||
* on a range where IsInSelection() is false.
|
* on a range where IsInSelection() is false.
|
||||||
*/
|
*/
|
||||||
nsINode* GetRegisteredCommonAncestor();
|
nsINode* GetRegisteredClosestCommonInclusiveAncestor();
|
||||||
|
|
||||||
// Helper to IsNodeSelected.
|
// Helper to IsNodeSelected.
|
||||||
static bool IsNodeInSortedRanges(nsINode* aNode, uint32_t aStartOffset,
|
static bool IsNodeInSortedRanges(nsINode* aNode, uint32_t aStartOffset,
|
||||||
@@ -432,7 +441,7 @@ class nsRange final : public mozilla::dom::AbstractRange,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sIsNested = true;
|
sIsNested = true;
|
||||||
mCommonAncestor = mRange->GetRegisteredCommonAncestor();
|
mCommonAncestor = mRange->GetRegisteredClosestCommonInclusiveAncestor();
|
||||||
}
|
}
|
||||||
~AutoInvalidateSelection();
|
~AutoInvalidateSelection();
|
||||||
nsRange* mRange;
|
nsRange* mRange;
|
||||||
@@ -441,10 +450,10 @@ class nsRange final : public mozilla::dom::AbstractRange,
|
|||||||
};
|
};
|
||||||
|
|
||||||
nsCOMPtr<nsINode> mRoot;
|
nsCOMPtr<nsINode> mRoot;
|
||||||
// mRegisteredCommonAncestor is only non-null when the range
|
// mRegisteredClosestCommonInclusiveAncestor is only non-null when the range
|
||||||
// IsInSelection(). It's kept alive via mStart/mEnd,
|
// IsInSelection(). It's kept alive via mStart/mEnd,
|
||||||
// because we update it any time those could become disconnected from it.
|
// because we update it any time those could become disconnected from it.
|
||||||
nsINode* MOZ_NON_OWNING_REF mRegisteredCommonAncestor;
|
nsINode* MOZ_NON_OWNING_REF mRegisteredClosestCommonInclusiveAncestor;
|
||||||
mozilla::WeakPtr<mozilla::dom::Selection> mSelection;
|
mozilla::WeakPtr<mozilla::dom::Selection> mSelection;
|
||||||
|
|
||||||
// These raw pointers are used to remember a child that is about
|
// These raw pointers are used to remember a child that is about
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ void nsTextNode::List(FILE* out, int32_t aIndent) const {
|
|||||||
|
|
||||||
fprintf(out, "Text@%p", static_cast<const void*>(this));
|
fprintf(out, "Text@%p", static_cast<const void*>(this));
|
||||||
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
||||||
if (IsCommonAncestorForRangeInSelection()) {
|
if (IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||||
const LinkedList<nsRange>* ranges = GetExistingCommonAncestorRanges();
|
const LinkedList<nsRange>* ranges = GetExistingCommonAncestorRanges();
|
||||||
int32_t count = 0;
|
int32_t count = 0;
|
||||||
if (ranges) {
|
if (ranges) {
|
||||||
|
|||||||
Reference in New Issue
Block a user