Bug 1460509 - part 47: Make HTMLEditRules::ExpandSelectionForDeletion() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato
MozReview-Commit-ID: BdumFS7Rluv
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -6106,19 +6106,16 @@ HTMLEditRules::GetInnerContent(
GetInnerContent(*node, aOutArrayOfNodes, aIndex, aLists, aTables);
} else {
aOutArrayOfNodes.InsertElementAt(*aIndex, *node);
(*aIndex)++;
}
}
}
-/**
- * Promotes selection to include blocks that have all their children selected.
- */
nsresult
HTMLEditRules::ExpandSelectionForDeletion()
{
MOZ_ASSERT(IsEditorDataAvailable());
// Don't need to touch collapsed selections
if (SelectionRef().IsCollapsed()) {
return NS_OK;
@@ -6137,33 +6134,33 @@ HTMLEditRules::ExpandSelectionForDeletio
}
nsCOMPtr<nsINode> selStartNode = firstRange->GetStartContainer();
int32_t selStartOffset = firstRange->StartOffset();
nsCOMPtr<nsINode> selEndNode = firstRange->GetEndContainer();
int32_t selEndOffset = firstRange->EndOffset();
// Find current selection common block parent
- nsCOMPtr<Element> selCommon =
+ RefPtr<Element> selCommon =
HTMLEditor::GetBlock(*firstRange->GetCommonAncestor());
if (NS_WARN_IF(!selCommon)) {
return NS_ERROR_FAILURE;
}
// Set up for loops and cache our root element
nsCOMPtr<nsINode> firstBRParent;
nsCOMPtr<nsINode> unused;
int32_t visOffset = 0, firstBROffset = 0;
WSType wsType;
RefPtr<Element> root = HTMLEditorRef().GetActiveEditingHost();
if (NS_WARN_IF(!root)) {
return NS_ERROR_FAILURE;
}
- // Find previous visible thingy before start of selection
+ // Find previous visible things before start of selection
if (selStartNode != selCommon && selStartNode != root) {
while (true) {
WSRunObject wsObj(&HTMLEditorRef(), selStartNode, selStartOffset);
wsObj.PriorVisibleNode(EditorRawDOMPoint(selStartNode, selStartOffset),
address_of(unused), &visOffset, &wsType);
if (wsType != WSType::thisBlock) {
break;
}
@@ -6175,17 +6172,17 @@ HTMLEditRules::ExpandSelectionForDeletio
break;
}
selStartNode = wsObj.mStartReasonNode->GetParentNode();
selStartOffset = selStartNode ?
selStartNode->ComputeIndexOf(wsObj.mStartReasonNode) : -1;
}
}
- // Find next visible thingy after end of selection
+ // Find next visible things after end of selection
if (selEndNode != selCommon && selEndNode != root) {
for (;;) {
WSRunObject wsObj(&HTMLEditorRef(), selEndNode, selEndOffset);
wsObj.NextVisibleNode(EditorRawDOMPoint(selEndNode, selEndOffset),
address_of(unused), &visOffset, &wsType);
if (wsType == WSType::br) {
if (HTMLEditorRef().IsVisibleBRElement(wsObj.mEndReasonNode)) {
break;
@@ -6210,52 +6207,61 @@ HTMLEditRules::ExpandSelectionForDeletio
} else {
break;
}
}
}
// Now set the selection to the new range
DebugOnly<nsresult> rv =
SelectionRef().Collapse(selStartNode, selStartOffset);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to collapse selection");
- // Expand selection endpoint only if we didn't pass a br, or if we really
- // needed to pass that br (i.e., its block is now totally selected)
+ // Expand selection endpoint only if we didn't pass a <br>, or if we really
+ // needed to pass that <br> (i.e., its block is now totally selected).
bool doEndExpansion = true;
if (firstBRParent) {
- // Find block node containing br
+ // Find block node containing <br>.
nsCOMPtr<Element> brBlock = HTMLEditor::GetBlock(*firstBRParent);
bool nodeBefore = false, nodeAfter = false;
// Create a range that represents expanded selection
RefPtr<nsRange> range = new nsRange(selStartNode);
nsresult rv = range->SetStartAndEnd(selStartNode, selStartOffset,
selEndNode, selEndOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Check if block is entirely inside range
if (brBlock) {
nsRange::CompareNodeToRange(brBlock, range, &nodeBefore, &nodeAfter);
}
- // If block isn't contained, forgo grabbing the br in expanded selection
+ // If block isn't contained, forgo grabbing the <br> in expanded selection.
if (nodeBefore || nodeAfter) {
doEndExpansion = false;
}
}
if (doEndExpansion) {
nsresult rv = SelectionRef().Extend(selEndNode, selEndOffset);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
- // Only expand to just before br
+ // Only expand to just before <br>.
nsresult rv = SelectionRef().Extend(firstBRParent, firstBROffset);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return NS_OK;
}
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -464,17 +464,24 @@ protected:
bool IsEmptyBlockElement(Element& aElement,
IgnoreSingleBR aIgnoreSingleBR);
nsresult CheckForEmptyBlock(nsINode* aStartNode, Element* aBodyNode,
nsIEditor::EDirection aAction, bool* aHandled);
enum class BRLocation { beforeBlock, blockEnd };
Element* CheckForInvisibleBR(Element& aBlock, BRLocation aWhere,
int32_t aOffset = 0);
- nsresult ExpandSelectionForDeletion();
+
+ /**
+ * ExpandSelectionForDeletion() may expand Selection range if it's not
+ * collapsed and there is only one range. This may expand to include
+ * invisible <br> element for preventing delete action handler to keep
+ * unexpected nodes.
+ */
+ MOZ_MUST_USE nsresult ExpandSelectionForDeletion();
/**
* NormalizeSelection() adjust Selection if it's not collapsed and there is
* only one range. If range start and/or end point is <br> node or something
* non-editable point, they should be moved to nearest text node or something
* where the other methods easier to handle edit action.
*/
MOZ_MUST_USE nsresult NormalizeSelection();