Bug 1460509 - part 61: Make HTMLEditRules::SplitBlock() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato
And this patch renames it to SplitRangeOffFromBlock() for making the name
explain what it does since "split" is used as splitting to two nodes widely
in editor.
MozReview-Commit-ID: GrRu5sI4yrP
--- a/editor/libeditor/EditorUtils.h
+++ b/editor/libeditor/EditorUtils.h
@@ -354,16 +354,112 @@ private:
EditorDOMPoint mGivenSplitPoint;
nsresult mRv;
SplitNodeResult() = delete;
};
/***************************************************************************
+ * SplitRangeOffFromNodeResult class is a simple class for methods which split a
+ * node at 2 points for making part of the node split off from the node.
+ */
+class MOZ_STACK_CLASS SplitRangeOffFromNodeResult final
+{
+public:
+ bool Succeeded() const { return NS_SUCCEEDED(mRv); }
+ bool Failed() const { return NS_FAILED(mRv); }
+ nsresult Rv() const { return mRv; }
+
+ /**
+ * GetLeftContent() returns new created node before the part of quarried out.
+ * This may return nullptr if the method didn't split at start edge of
+ * the node.
+ */
+ nsIContent* GetLeftContent() const { return mLeftContent; }
+ dom::Element* GetLeftContentAsElement() const
+ {
+ return mLeftContent && mLeftContent->IsElement() ?
+ mLeftContent->AsElement() : nullptr;
+ }
+
+ /**
+ * GetMiddleContent() returns new created node between left node and right
+ * node. I.e., this is quarried out from the node. This may return nullptr
+ * if the method unwrapped the middle node.
+ */
+ nsIContent* GetMiddleContent() const { return mMiddleContent; }
+ dom::Element* GetMiddleContentAsElement() const
+ {
+ return mMiddleContent && mMiddleContent->IsElement() ?
+ mMiddleContent->AsElement() : nullptr;
+ }
+
+ /**
+ * GetRightContent() returns the right node after the part of quarried out.
+ * This may return nullptr it the method didn't split at end edge of the
+ * node.
+ */
+ nsIContent* GetRightContent() const { return mRightContent; }
+ dom::Element* GetRightContentAsElement() const
+ {
+ return mRightContent && mRightContent->IsElement() ?
+ mRightContent->AsElement() : nullptr;
+ }
+
+ SplitRangeOffFromNodeResult(nsIContent* aLeftContent, nsIContent* aMiddleContent,
+ nsIContent* aRightContent)
+ : mLeftContent(aLeftContent)
+ , mMiddleContent(aMiddleContent)
+ , mRightContent(aRightContent)
+ , mRv(NS_OK)
+ {
+ }
+
+ SplitRangeOffFromNodeResult(SplitNodeResult& aSplitResultAtLeftOfMiddleNode,
+ SplitNodeResult& aSplitResultAtRightOfMiddleNode)
+ : mRv(NS_OK)
+ {
+ if (aSplitResultAtLeftOfMiddleNode.Succeeded()) {
+ mLeftContent = aSplitResultAtLeftOfMiddleNode.GetPreviousNode();
+ }
+ if (aSplitResultAtRightOfMiddleNode.Succeeded()) {
+ mRightContent = aSplitResultAtRightOfMiddleNode.GetNextNode();
+ mMiddleContent = aSplitResultAtRightOfMiddleNode.GetPreviousNode();
+ }
+ if (!mMiddleContent && aSplitResultAtLeftOfMiddleNode.Succeeded()) {
+ mMiddleContent = aSplitResultAtLeftOfMiddleNode.GetNextNode();
+ }
+ }
+
+ explicit SplitRangeOffFromNodeResult(nsresult aRv)
+ : mRv(aRv)
+ {
+ MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(mRv));
+ }
+
+ SplitRangeOffFromNodeResult(
+ const SplitRangeOffFromNodeResult& aOther) = delete;
+ SplitRangeOffFromNodeResult&
+ operator=(const SplitRangeOffFromNodeResult& aOther) = delete;
+ SplitRangeOffFromNodeResult(SplitRangeOffFromNodeResult&& aOther) = default;
+ SplitRangeOffFromNodeResult&
+ operator=(SplitRangeOffFromNodeResult&& aOther) = default;
+
+private:
+ nsCOMPtr<nsIContent> mLeftContent;
+ nsCOMPtr<nsIContent> mMiddleContent;
+ nsCOMPtr<nsIContent> mRightContent;
+
+ nsresult mRv;
+
+ SplitRangeOffFromNodeResult() = delete;
+};
+
+/***************************************************************************
* stack based helper class for batching a collection of transactions inside a
* placeholder transaction.
*/
class MOZ_RAII AutoPlaceholderBatch final
{
private:
RefPtr<EditorBase> mEditorBase;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -5371,108 +5371,113 @@ HTMLEditRules::WillOutdent(bool* aCancel
*/
nsresult
HTMLEditRules::RemovePartOfBlock(Element& aBlock,
nsIContent& aStartChild,
nsIContent& aEndChild)
{
MOZ_ASSERT(IsEditorDataAvailable());
- SplitBlock(aBlock, aStartChild, aEndChild);
+ SplitRangeOffFromNodeResult splitResult =
+ SplitRangeOffFromBlock(aBlock, aStartChild, aEndChild);
+ if (NS_WARN_IF(splitResult.Rv() == NS_ERROR_EDITOR_DESTROYED)) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
+ NS_WARNING_ASSERTION(splitResult.Succeeded(),
+ "Failed to split the range off from the block element");
// Get rid of part of blockquote we are outdenting
nsresult rv = HTMLEditorRef().RemoveBlockContainerWithTransaction(aBlock);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
-void
-HTMLEditRules::SplitBlock(Element& aBlock,
- nsIContent& aStartChild,
- nsIContent& aEndChild,
- nsIContent** aOutLeftNode,
- nsIContent** aOutRightNode,
- nsIContent** aOutMiddleNode)
-{
- MOZ_ASSERT(IsEditorDataAvailable());
-
- // aStartChild and aEndChild must be exclusive descendants of aBlock
- MOZ_ASSERT(EditorUtils::IsDescendantOf(aStartChild, aBlock) &&
- EditorUtils::IsDescendantOf(aEndChild, aBlock));
+SplitRangeOffFromNodeResult
+HTMLEditRules::SplitRangeOffFromBlock(Element& aBlockElement,
+ nsIContent& aStartOfMiddleElement,
+ nsIContent& aEndOfMiddleElement)
+{
+ MOZ_ASSERT(IsEditorDataAvailable());
+
+ // aStartOfMiddleElement and aEndOfMiddleElement must be exclusive
+ // descendants of aBlockElement.
+ MOZ_ASSERT(EditorUtils::IsDescendantOf(aStartOfMiddleElement, aBlockElement));
+ MOZ_ASSERT(EditorUtils::IsDescendantOf(aEndOfMiddleElement, aBlockElement));
// Split at the start.
SplitNodeResult splitAtStartResult =
HTMLEditorRef().SplitNodeDeepWithTransaction(
- aBlock, EditorRawDOMPoint(&aStartChild),
+ aBlockElement, EditorRawDOMPoint(&aStartOfMiddleElement),
SplitAtEdges::eDoNotCreateEmptyContainer);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
+ }
NS_WARNING_ASSERTION(splitAtStartResult.Succeeded(),
- "Failed to split aBlock at start");
+ "Failed to split aBlockElement at start");
// Split at after the end
- EditorRawDOMPoint atAfterEnd(&aEndChild);
+ EditorRawDOMPoint atAfterEnd(&aEndOfMiddleElement);
DebugOnly<bool> advanced = atAfterEnd.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset after the end node");
SplitNodeResult splitAtEndResult =
HTMLEditorRef().SplitNodeDeepWithTransaction(
- aBlock, atAfterEnd,
+ aBlockElement, atAfterEnd,
SplitAtEdges::eDoNotCreateEmptyContainer);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
+ }
NS_WARNING_ASSERTION(splitAtEndResult.Succeeded(),
- "Failed to split aBlock at after end");
-
- if (aOutLeftNode) {
- NS_IF_ADDREF(*aOutLeftNode = splitAtStartResult.GetPreviousNode());
- }
-
- if (aOutRightNode) {
- NS_IF_ADDREF(*aOutRightNode = splitAtEndResult.GetNextNode());
- }
-
- if (aOutMiddleNode) {
- if (splitAtEndResult.GetPreviousNode()) {
- NS_IF_ADDREF(*aOutMiddleNode = splitAtEndResult.GetPreviousNode());
- } else {
- NS_IF_ADDREF(*aOutMiddleNode = splitAtStartResult.GetNextNode());
- }
- }
+ "Failed to split aBlockElement at after end");
+
+ return SplitRangeOffFromNodeResult(splitAtStartResult, splitAtEndResult);
}
nsresult
HTMLEditRules::OutdentPartOfBlock(Element& aBlock,
nsIContent& aStartChild,
nsIContent& aEndChild,
bool aIsBlockIndentedWithCSS,
nsIContent** aOutLeftNode,
nsIContent** aOutRightNode)
{
MOZ_ASSERT(IsEditorDataAvailable());
MOZ_ASSERT(aOutLeftNode && aOutRightNode);
- nsCOMPtr<nsIContent> middleNode;
- SplitBlock(aBlock, aStartChild, aEndChild, aOutLeftNode, aOutRightNode,
- getter_AddRefs(middleNode));
-
- if (NS_WARN_IF(!middleNode) || NS_WARN_IF(!middleNode->IsElement())) {
+ SplitRangeOffFromNodeResult splitResult =
+ SplitRangeOffFromBlock(aBlock, aStartChild, aEndChild);
+ if (NS_WARN_IF(splitResult.Rv() == NS_ERROR_EDITOR_DESTROYED)) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
+
+ if (aOutLeftNode) {
+ NS_IF_ADDREF(*aOutLeftNode = splitResult.GetLeftContent());
+ }
+ if (aOutRightNode) {
+ NS_IF_ADDREF(*aOutRightNode = splitResult.GetRightContent());
+ }
+
+ if (NS_WARN_IF(!splitResult.GetMiddleContentAsElement())) {
return NS_ERROR_FAILURE;
}
if (!aIsBlockIndentedWithCSS) {
nsresult rv =
HTMLEditorRef().RemoveBlockContainerWithTransaction(
- *middleNode->AsElement());
+ *splitResult.GetMiddleContentAsElement());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
- if (middleNode->IsElement()) {
- // We do nothing if middleNode isn't an element
- nsresult rv = DecreaseMarginToOutdent(*middleNode->AsElement());
+ if (splitResult.GetMiddleContentAsElement()) {
+ nsresult rv =
+ DecreaseMarginToOutdent(*splitResult.GetMiddleContentAsElement());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
return NS_OK;
}
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -526,22 +526,31 @@ protected:
* Called after handling edit action. This may adjust Selection, remove
* unnecessary empty nodes, create <br> elements if needed, etc.
*/
MOZ_MUST_USE nsresult
AfterEditInner(EditAction action, nsIEditor::EDirection aDirection);
nsresult RemovePartOfBlock(Element& aBlock, nsIContent& aStartChild,
nsIContent& aEndChild);
- void SplitBlock(Element& aBlock,
- nsIContent& aStartChild,
- nsIContent& aEndChild,
- nsIContent** aOutLeftNode = nullptr,
- nsIContent** aOutRightNode = nullptr,
- nsIContent** aOutMiddleNode = nullptr);
+
+ /**
+ * SplitRangeOffFromBlock() splits aBlock at two points, before aStartChild
+ * and after aEndChild. If they are very start or very end of aBlcok, this
+ * won't create empty block.
+ *
+ * @param aBlockElement A block element which will be split.
+ * @param aStartOfMiddleElement Start node of middle block element.
+ * @param aEndOfMiddleElement End node of middle block element.
+ */
+ MOZ_MUST_USE SplitRangeOffFromNodeResult
+ SplitRangeOffFromBlock(Element& aBlockElement,
+ nsIContent& aStartOfMiddleElement,
+ nsIContent& aEndOfMiddleElement);
+
nsresult OutdentPartOfBlock(Element& aBlock,
nsIContent& aStartChild,
nsIContent& aEndChild,
bool aIsBlockIndentedWithCSS,
nsIContent** aOutLeftNode,
nsIContent** aOutRightNode);
/**