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]",
|
||||
static_cast<unsigned long long>(State().GetInternalValue()));
|
||||
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
||||
if (IsCommonAncestorForRangeInSelection()) {
|
||||
if (IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
const LinkedList<nsRange>* ranges = GetExistingCommonAncestorRanges();
|
||||
int32_t count = 0;
|
||||
if (ranges) {
|
||||
|
||||
@@ -1350,14 +1350,15 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||
inline bool IsRootOfChromeAccessOnlySubtree() const;
|
||||
|
||||
/**
|
||||
* Returns true if |this| node is the common ancestor of the start/end
|
||||
* nodes of a Range in a Selection or a descendant of such a common ancestor.
|
||||
* This node is definitely not selected when |false| is returned, but it may
|
||||
* or may not be selected when |true| is returned.
|
||||
* Returns true if |this| node is the closest common inclusive ancestor
|
||||
* (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of the
|
||||
* start/end nodes of a Range in a Selection or a descendant of such a common
|
||||
* 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 {
|
||||
return IsDescendantOfCommonAncestorForRangeInSelection() ||
|
||||
IsCommonAncestorForRangeInSelection();
|
||||
return IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() ||
|
||||
IsClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1595,11 +1596,11 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||
ElementHasPart,
|
||||
// Set if the element might have a contenteditable attribute set.
|
||||
ElementMayHaveContentEditableAttr,
|
||||
// Set if the node is the common ancestor of the start/end nodes of a Range
|
||||
// that is in a Selection.
|
||||
NodeIsCommonAncestorForRangeInSelection,
|
||||
// Set if the node is the closest common inclusive ancestor of the start/end
|
||||
// nodes of a Range that is in a Selection.
|
||||
NodeIsClosestCommonInclusiveAncestorForRangeInSelection,
|
||||
// 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.
|
||||
NodeIsCCMarkedRoot,
|
||||
// Maybe set if this node is in black subtree.
|
||||
@@ -1693,23 +1694,44 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||
bool MayHaveContentEditableAttr() const {
|
||||
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); }
|
||||
|
||||
@@ -119,8 +119,10 @@ static void InvalidateAllFrames(nsINode* aNode) {
|
||||
}
|
||||
|
||||
static nsINode* GetNextRangeCommonAncestor(nsINode* aNode) {
|
||||
while (aNode && !aNode->IsCommonAncestorForRangeInSelection()) {
|
||||
if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
||||
while (aNode &&
|
||||
!aNode->IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
if (!aNode
|
||||
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
return nullptr;
|
||||
}
|
||||
aNode = aNode->GetParentNode();
|
||||
@@ -270,7 +272,7 @@ nsRange::~nsRange() {
|
||||
|
||||
nsRange::nsRange(nsINode* aNode)
|
||||
: AbstractRange(aNode),
|
||||
mRegisteredCommonAncestor(nullptr),
|
||||
mRegisteredClosestCommonInclusiveAncestor(nullptr),
|
||||
mNextStartRef(nullptr),
|
||||
mNextEndRef(nullptr) {
|
||||
// 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_UNLINK_BEGIN_INHERITED(nsRange, AbstractRange)
|
||||
// We _could_ just rely on Reset() to UnregisterCommonAncestor(),
|
||||
// but it wouldn't know we're calling it from Unlink and so would do
|
||||
// more work than it really needs to.
|
||||
if (tmp->mRegisteredCommonAncestor) {
|
||||
tmp->UnregisterCommonAncestor(tmp->mRegisteredCommonAncestor, true);
|
||||
// We _could_ just rely on Reset() to
|
||||
// UnregisterClosestCommonInclusiveAncestor(), but it wouldn't know we're
|
||||
// calling it from Unlink and so would do more work than it really needs to.
|
||||
if (tmp->mRegisteredClosestCommonInclusiveAncestor) {
|
||||
tmp->UnregisterClosestCommonInclusiveAncestor(
|
||||
tmp->mRegisteredClosestCommonInclusiveAncestor, true);
|
||||
}
|
||||
|
||||
tmp->Reset();
|
||||
@@ -330,16 +333,16 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsRange, AbstractRange)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
static void MarkDescendants(nsINode* aNode) {
|
||||
// Set NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
|
||||
// descendants unless aNode is already marked as a range common ancestor
|
||||
// or a descendant of one, in which case all of our descendants have the
|
||||
// bit set already.
|
||||
// Set NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection on
|
||||
// aNode's descendants unless aNode is already marked as a range common
|
||||
// ancestor or a descendant of one, in which case all of our descendants have
|
||||
// the bit set already.
|
||||
if (!aNode->IsSelectionDescendant()) {
|
||||
// don't set the Descendant bit on |aNode| itself
|
||||
nsINode* node = aNode->GetNextNode(aNode);
|
||||
while (node) {
|
||||
node->SetDescendantOfCommonAncestorForRangeInSelection();
|
||||
if (!node->IsCommonAncestorForRangeInSelection()) {
|
||||
node->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
if (!node->IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
node = node->GetNextNode(aNode);
|
||||
} else {
|
||||
// optimize: skip this sub-tree since it's marked already.
|
||||
@@ -350,16 +353,17 @@ static void MarkDescendants(nsINode* aNode) {
|
||||
}
|
||||
|
||||
static void UnmarkDescendants(nsINode* aNode) {
|
||||
// Unset NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
|
||||
// descendants unless aNode is a descendant of another range common ancestor.
|
||||
// Also, exclude descendants of range common ancestors (but not the common
|
||||
// ancestor itself).
|
||||
if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
||||
// Unset NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection
|
||||
// on aNode's descendants unless aNode is a descendant of another range common
|
||||
// ancestor. Also, exclude descendants of range common ancestors (but not the
|
||||
// common ancestor itself).
|
||||
if (!aNode
|
||||
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
// we know |aNode| doesn't have any bit set
|
||||
nsINode* node = aNode->GetNextNode(aNode);
|
||||
while (node) {
|
||||
node->ClearDescendantOfCommonAncestorForRangeInSelection();
|
||||
if (!node->IsCommonAncestorForRangeInSelection()) {
|
||||
node->ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
if (!node->IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
node = node->GetNextNode(aNode);
|
||||
} else {
|
||||
// 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_DIAGNOSTIC_ASSERT(IsInSelection(), "registering range not in selection");
|
||||
|
||||
mRegisteredCommonAncestor = aNode;
|
||||
mRegisteredClosestCommonInclusiveAncestor = aNode;
|
||||
|
||||
MarkDescendants(aNode);
|
||||
|
||||
@@ -385,17 +389,20 @@ void nsRange::RegisterCommonAncestor(nsINode* aNode) {
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(!isInList());
|
||||
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");
|
||||
NS_ASSERTION(aNode->IsCommonAncestorForRangeInSelection(), "wrong node");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aNode == mRegisteredCommonAncestor, "wrong node");
|
||||
NS_ASSERTION(aNode->IsClosestCommonInclusiveAncestorForRangeInSelection(),
|
||||
"wrong node");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aNode == mRegisteredClosestCommonInclusiveAncestor,
|
||||
"wrong node");
|
||||
LinkedList<nsRange>* ranges = aNode->GetExistingCommonAncestorRanges();
|
||||
MOZ_ASSERT(ranges);
|
||||
|
||||
mRegisteredCommonAncestor = nullptr;
|
||||
mRegisteredClosestCommonInclusiveAncestor = nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
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
|
||||
// being unlinked anyway.
|
||||
if (!aIsUnlinking && ranges->isEmpty()) {
|
||||
aNode->ClearCommonAncestorForRangeInSelection();
|
||||
aNode->ClearClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
UnmarkDescendants(aNode);
|
||||
}
|
||||
}
|
||||
@@ -554,13 +561,13 @@ void nsRange::CharacterDataChanged(nsIContent* aContent,
|
||||
bool isCommonAncestor =
|
||||
IsInSelection() && mStart.Container() == mEnd.Container();
|
||||
if (isCommonAncestor) {
|
||||
UnregisterCommonAncestor(mStart.Container(), false);
|
||||
RegisterCommonAncestor(newStart.Container());
|
||||
UnregisterClosestCommonInclusiveAncestor(mStart.Container(), false);
|
||||
RegisterClosestCommonInclusiveAncestor(newStart.Container());
|
||||
}
|
||||
if (mStart.Container()
|
||||
->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
||||
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
newStart.Container()
|
||||
->SetDescendantOfCommonAncestorForRangeInSelection();
|
||||
->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
}
|
||||
} else {
|
||||
// If boundary is inside changed text, position it before change
|
||||
@@ -607,12 +614,16 @@ void nsRange::CharacterDataChanged(nsIContent* aContent,
|
||||
IsInSelection() && mStart.Container() == mEnd.Container();
|
||||
if (isCommonAncestor && !newStart.Container()) {
|
||||
// The split occurs inside the range.
|
||||
UnregisterCommonAncestor(mStart.Container(), false);
|
||||
RegisterCommonAncestor(mStart.Container()->GetParentNode());
|
||||
newEnd.Container()->SetDescendantOfCommonAncestorForRangeInSelection();
|
||||
} else if (mEnd.Container()
|
||||
->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
||||
newEnd.Container()->SetDescendantOfCommonAncestorForRangeInSelection();
|
||||
UnregisterClosestCommonInclusiveAncestor(mStart.Container(), false);
|
||||
RegisterClosestCommonInclusiveAncestor(
|
||||
mStart.Container()->GetParentNode());
|
||||
newEnd.Container()
|
||||
->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
} else if (
|
||||
mEnd.Container()
|
||||
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
newEnd.Container()
|
||||
->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
}
|
||||
} else {
|
||||
CheckedUint32 newEndOffset{0};
|
||||
@@ -671,9 +682,11 @@ void nsRange::ContentAppended(nsIContent* aFirstNewContent) {
|
||||
if (container->IsSelectionDescendant() && IsInSelection()) {
|
||||
nsINode* child = aFirstNewContent;
|
||||
while (child) {
|
||||
if (!child->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
||||
if (!child
|
||||
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
MarkDescendants(child);
|
||||
child->SetDescendantOfCommonAncestorForRangeInSelection();
|
||||
child
|
||||
->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
}
|
||||
child = child->GetNextSibling();
|
||||
}
|
||||
@@ -724,9 +737,10 @@ void nsRange::ContentInserted(nsIContent* aChild) {
|
||||
}
|
||||
|
||||
if (container->IsSelectionDescendant() &&
|
||||
!aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
||||
!aChild
|
||||
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
MarkDescendants(aChild);
|
||||
aChild->SetDescendantOfCommonAncestorForRangeInSelection();
|
||||
aChild->SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
}
|
||||
|
||||
if (mNextStartRef || mNextEndRef) {
|
||||
@@ -810,8 +824,10 @@ void nsRange::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling) {
|
||||
MOZ_ASSERT(mEnd.Ref() != aChild);
|
||||
|
||||
if (container->IsSelectionDescendant() &&
|
||||
aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
||||
aChild->ClearDescendantOfCommonAncestorForRangeInSelection();
|
||||
aChild
|
||||
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
aChild
|
||||
->ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection();
|
||||
UnmarkDescendants(aChild);
|
||||
}
|
||||
}
|
||||
@@ -1012,24 +1028,24 @@ void nsRange::DoSetRange(const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
|
||||
mEnd = aEndBoundary;
|
||||
|
||||
if (checkCommonAncestor) {
|
||||
nsINode* oldCommonAncestor = mRegisteredCommonAncestor;
|
||||
nsINode* oldCommonAncestor = mRegisteredClosestCommonInclusiveAncestor;
|
||||
nsINode* newCommonAncestor = GetCommonAncestor();
|
||||
if (newCommonAncestor != oldCommonAncestor) {
|
||||
if (oldCommonAncestor) {
|
||||
UnregisterCommonAncestor(oldCommonAncestor, false);
|
||||
UnregisterClosestCommonInclusiveAncestor(oldCommonAncestor, false);
|
||||
}
|
||||
if (newCommonAncestor) {
|
||||
RegisterCommonAncestor(newCommonAncestor);
|
||||
RegisterClosestCommonInclusiveAncestor(newCommonAncestor);
|
||||
} else {
|
||||
NS_ASSERTION(!mIsPositioned, "unexpected disconnected nodes");
|
||||
mSelection = nullptr;
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
!mRegisteredCommonAncestor,
|
||||
!mRegisteredClosestCommonInclusiveAncestor,
|
||||
"How can we have a registered common ancestor when we "
|
||||
"didn't register ourselves?");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!isInList(),
|
||||
"Shouldn't be registered if we have no "
|
||||
"mRegisteredCommonAncestor");
|
||||
"mRegisteredClosestCommonInclusiveAncestor");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1077,16 +1093,18 @@ void nsRange::SetSelection(mozilla::dom::Selection* aSelection) {
|
||||
if (mSelection) {
|
||||
nsINode* commonAncestor = GetCommonAncestor();
|
||||
NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
|
||||
RegisterCommonAncestor(commonAncestor);
|
||||
} else if (mRegisteredCommonAncestor) {
|
||||
UnregisterCommonAncestor(mRegisteredCommonAncestor, false);
|
||||
RegisterClosestCommonInclusiveAncestor(commonAncestor);
|
||||
} else if (mRegisteredClosestCommonInclusiveAncestor) {
|
||||
UnregisterClosestCommonInclusiveAncestor(
|
||||
mRegisteredClosestCommonInclusiveAncestor, false);
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
!mRegisteredCommonAncestor,
|
||||
!mRegisteredClosestCommonInclusiveAncestor,
|
||||
"How can we have a registered common ancestor when we "
|
||||
"just unregistered?");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!isInList(),
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
!isInList(),
|
||||
"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;
|
||||
}
|
||||
|
||||
nsINode* nsRange::GetRegisteredCommonAncestor() {
|
||||
nsINode* nsRange::GetRegisteredClosestCommonInclusiveAncestor() {
|
||||
MOZ_ASSERT(IsInSelection(),
|
||||
"GetRegisteredCommonAncestor only valid for range in selection");
|
||||
MOZ_ASSERT(mRegisteredCommonAncestor);
|
||||
return mRegisteredCommonAncestor;
|
||||
"GetRegisteredClosestCommonInclusiveAncestor only valid for range "
|
||||
"in selection");
|
||||
MOZ_ASSERT(mRegisteredClosestCommonInclusiveAncestor);
|
||||
return mRegisteredClosestCommonInclusiveAncestor;
|
||||
}
|
||||
|
||||
/* static */
|
||||
@@ -2988,10 +3007,12 @@ nsRange::AutoInvalidateSelection::~AutoInvalidateSelection() {
|
||||
// we have a different common ancestor now, and if so invalidate its subtree
|
||||
// so it paints the selection it's in now.
|
||||
if (mRange->IsInSelection()) {
|
||||
nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor();
|
||||
nsINode* commonAncestor =
|
||||
mRange->GetRegisteredClosestCommonInclusiveAncestor();
|
||||
// XXXbz can commonAncestor really be null here? I wouldn't think so! If
|
||||
// it _were_, then in a debug build GetRegisteredCommonAncestor() would have
|
||||
// fatally asserted.
|
||||
// it _were_, then in a debug build
|
||||
// GetRegisteredClosestCommonInclusiveAncestor() would have fatally
|
||||
// asserted.
|
||||
if (commonAncestor && commonAncestor != mCommonAncestor) {
|
||||
::InvalidateAllFrames(commonAncestor);
|
||||
}
|
||||
|
||||
@@ -366,8 +366,15 @@ class nsRange final : public mozilla::dom::AbstractRange,
|
||||
typedef nsTHashtable<nsPtrHashKey<nsRange>> RangeHashTable;
|
||||
|
||||
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
|
||||
@@ -392,14 +399,16 @@ class nsRange final : public mozilla::dom::AbstractRange,
|
||||
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
|
||||
* 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
|
||||
* Selection. The method will assert and the behavior is undefined if called
|
||||
* on a range where IsInSelection() is false.
|
||||
*/
|
||||
nsINode* GetRegisteredCommonAncestor();
|
||||
nsINode* GetRegisteredClosestCommonInclusiveAncestor();
|
||||
|
||||
// Helper to IsNodeSelected.
|
||||
static bool IsNodeInSortedRanges(nsINode* aNode, uint32_t aStartOffset,
|
||||
@@ -432,7 +441,7 @@ class nsRange final : public mozilla::dom::AbstractRange,
|
||||
return;
|
||||
}
|
||||
sIsNested = true;
|
||||
mCommonAncestor = mRange->GetRegisteredCommonAncestor();
|
||||
mCommonAncestor = mRange->GetRegisteredClosestCommonInclusiveAncestor();
|
||||
}
|
||||
~AutoInvalidateSelection();
|
||||
nsRange* mRange;
|
||||
@@ -441,10 +450,10 @@ class nsRange final : public mozilla::dom::AbstractRange,
|
||||
};
|
||||
|
||||
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,
|
||||
// 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;
|
||||
|
||||
// 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, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
||||
if (IsCommonAncestorForRangeInSelection()) {
|
||||
if (IsClosestCommonInclusiveAncestorForRangeInSelection()) {
|
||||
const LinkedList<nsRange>* ranges = GetExistingCommonAncestorRanges();
|
||||
int32_t count = 0;
|
||||
if (ranges) {
|
||||
|
||||
Reference in New Issue
Block a user