From e28ddd6ec3d0784f1129d567c03a584de7e41f0f Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Thu, 9 Nov 2017 17:08:10 +0900 Subject: [PATCH] Bug 1415800 - part 1: Redesign EditorBase::GetPriorNode() with EditorRawDOMPoint r=m_kato An overload of EditorBase::GetPriorNode() takes a set of container, child node and offset of the child in the container. Replacing it with EditorRawDOMPoint makes the caller simpler. Additionally, it has two bool arguments, one is for searching if editable node, the other is for searching if in same block. So, they can be hidden with some human readable inline methods. Finally, "Prior" isn't a term of DOM. So, let's use "Previous" instead. MozReview-Commit-ID: A9uKzHaikY9 --HG-- extra : rebase_source : 15bfdfde0ad89a5331d6c8a24351741eeef476d5 --- editor/libeditor/EditorBase.cpp | 73 +++++++++++++++------------ editor/libeditor/EditorBase.h | 81 +++++++++++++++++++++--------- editor/libeditor/HTMLEditRules.cpp | 10 ++-- editor/libeditor/HTMLEditor.cpp | 10 +++- 4 files changed, 112 insertions(+), 62 deletions(-) diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp index d89658bc5e4b..eb51bdd9cbeb 100644 --- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -3285,38 +3285,60 @@ EditorBase::GetLengthOfDOMNode(nsIDOMNode* aNode, } nsIContent* -EditorBase::GetPriorNode(nsINode* aParentNode, - int32_t aOffset, - nsINode* aChildAtOffset, - bool aEditableNode, - bool aNoBlockCrossing) +EditorBase::GetPreviousNodeInternal(nsINode& aNode, + bool aFindEditableNode, + bool aNoBlockCrossing) { - MOZ_ASSERT(aParentNode); + if (!IsDescendantOfEditorRoot(&aNode)) { + return nullptr; + } + return FindNode(&aNode, false, aFindEditableNode, aNoBlockCrossing); +} + +nsIContent* +EditorBase::GetPreviousNodeInternal(const EditorRawDOMPoint& aPoint, + bool aFindEditableNode, + bool aNoBlockCrossing) +{ + MOZ_ASSERT(aPoint.IsSetAndValid()); + NS_WARNING_ASSERTION(!aPoint.Container()->IsNodeOfType(nsINode::eDATA_NODE) || + aPoint.Container()->IsNodeOfType(nsINode::eTEXT), + "GetPreviousNodeInternal() doesn't assume that the start point is a " + "data node except text node"); // If we are at the beginning of the node, or it is a text node, then just // look before it. - if (!aOffset || aParentNode->NodeType() == nsIDOMNode::TEXT_NODE) { - if (aNoBlockCrossing && IsBlockNode(aParentNode)) { + if (aPoint.IsStartOfContainer() || + aPoint.Container()->IsNodeOfType(nsINode::eTEXT)) { + if (aNoBlockCrossing && IsBlockNode(aPoint.Container())) { // If we aren't allowed to cross blocks, don't look before this block. return nullptr; } - return GetPriorNode(aParentNode, aEditableNode, aNoBlockCrossing); + return GetPreviousNodeInternal(*aPoint.Container(), + aFindEditableNode, aNoBlockCrossing); } // else look before the child at 'aOffset' - if (aChildAtOffset) { - return GetPriorNode(aChildAtOffset, aEditableNode, aNoBlockCrossing); + if (aPoint.GetChildAtOffset()) { + return GetPreviousNodeInternal(*aPoint.GetChildAtOffset(), + aFindEditableNode, aNoBlockCrossing); } // unless there isn't one, in which case we are at the end of the node // and want the deep-right child. - nsIContent* resultNode = GetRightmostChild(aParentNode, aNoBlockCrossing); - if (!resultNode || !aEditableNode || IsEditable(resultNode)) { - return resultNode; + nsIContent* rightMostNode = + GetRightmostChild(aPoint.Container(), aNoBlockCrossing); + if (!rightMostNode) { + return nullptr; + } + + if (!aFindEditableNode || IsEditable(rightMostNode)) { + return rightMostNode; } // restart the search from the non-editable node we just found - return GetPriorNode(resultNode, aEditableNode, aNoBlockCrossing); + return GetPreviousNodeInternal(*rightMostNode, + aFindEditableNode, aNoBlockCrossing); } nsIContent* @@ -3371,20 +3393,6 @@ EditorBase::GetNextNode(nsINode* aParentNode, return GetNextNode(aParentNode, aEditableNode, aNoBlockCrossing); } -nsIContent* -EditorBase::GetPriorNode(nsINode* aCurrentNode, - bool aEditableNode, - bool aNoBlockCrossing /* = false */) -{ - MOZ_ASSERT(aCurrentNode); - - if (!IsDescendantOfEditorRoot(aCurrentNode)) { - return nullptr; - } - - return FindNode(aCurrentNode, false, aEditableNode, aNoBlockCrossing); -} - nsIContent* EditorBase::FindNextLeafNode(nsINode* aCurrentNode, bool aGoForward, @@ -4599,7 +4607,7 @@ EditorBase::CreateTxnForDeleteRange(nsRange* aRangeToDelete, if (aAction == ePrevious && isFirst) { // we're backspacing from the beginning of the node. Delete the first // thing to our left - nsCOMPtr priorNode = GetPriorNode(node, true); + nsCOMPtr priorNode = GetPreviousEditableNode(*node); if (NS_WARN_IF(!priorNode)) { return nullptr; } @@ -4693,7 +4701,8 @@ EditorBase::CreateTxnForDeleteRange(nsRange* aRangeToDelete, // node to find out nsCOMPtr selectedNode; if (aAction == ePrevious) { - selectedNode = GetPriorNode(node, offset, child, true); + selectedNode = + GetPreviousEditableNode(EditorRawDOMPoint(node, child, offset)); } else if (aAction == eNext) { selectedNode = GetNextNode(node, offset, child, true); } @@ -4703,7 +4712,7 @@ EditorBase::CreateTxnForDeleteRange(nsRange* aRangeToDelete, !selectedNode->Length()) { // Can't delete an empty chardata node (bug 762183) if (aAction == ePrevious) { - selectedNode = GetPriorNode(selectedNode, true); + selectedNode = GetPreviousEditableNode(*selectedNode); } else if (aAction == eNext) { selectedNode = GetNextNode(selectedNode, true); } diff --git a/editor/libeditor/EditorBase.h b/editor/libeditor/EditorBase.h index 71b60fda1fd3..3bccc2bc469f 100644 --- a/editor/libeditor/EditorBase.h +++ b/editor/libeditor/EditorBase.h @@ -607,12 +607,34 @@ protected: virtual bool IsBlockNode(nsINode* aNode); /** - * Helper for GetPriorNode() and GetNextNode(). + * Helper for GetPreviousNodeInternal() and GetNextNode(). */ nsIContent* FindNextLeafNode(nsINode* aCurrentNode, bool aGoForward, bool bNoBlockCrossing); + /** + * Get the node immediately previous node of aNode. + * @param atNode The node from which we start the search. + * @param aFindEditableNode If true, only return an editable node. + * @param aNoBlockCrossing If true, don't move across "block" nodes, + * whatever that means. + * @return The node that occurs before aNode in + * the tree, skipping non-editable nodes if + * aFindEditableNode is true. If there is no + * previous node, returns nullptr. + */ + nsIContent* GetPreviousNodeInternal(nsINode& aNode, + bool aFindEditableNode, + bool aNoBlockCrossing); + + /** + * And another version that takes a point in DOM tree rather than a node. + */ + nsIContent* GetPreviousNodeInternal(const EditorRawDOMPoint& aPoint, + bool aFindEditableNode, + bool aNoBlockCrossing); + virtual nsresult InstallEventListeners(); virtual void CreateEventListeners(); virtual void RemoveEventListeners(); @@ -737,28 +759,41 @@ public: static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, uint32_t &aCount); /** - * Get the node immediately prior to aCurrentNode. - * @param aCurrentNode the node from which we start the search - * @param aEditableNode if true, only return an editable node - * @param aResultNode [OUT] the node that occurs before aCurrentNode in - * the tree, skipping non-editable nodes if - * aEditableNode is true. If there is no prior - * node, aResultNode will be nullptr. - * @param bNoBlockCrossing If true, don't move across "block" nodes, - * whatever that means. + * Get the previous node. */ - nsIContent* GetPriorNode(nsINode* aCurrentNode, bool aEditableNode, - bool aNoBlockCrossing = false); - - /** - * And another version that takes a {parent,offset} pair rather than a node. - */ - nsIContent* GetPriorNode(nsINode* aParentNode, - int32_t aOffset, - nsINode* aChildAtOffset, - bool aEditableNode, - bool aNoBlockCrossing = false); - + nsIContent* GetPreviousNode(const EditorRawDOMPoint& aPoint) + { + return GetPreviousNodeInternal(aPoint, false, false); + } + nsIContent* GetPreviousEditableNode(const EditorRawDOMPoint& aPoint) + { + return GetPreviousNodeInternal(aPoint, true, false); + } + nsIContent* GetPreviousNodeInBlock(const EditorRawDOMPoint& aPoint) + { + return GetPreviousNodeInternal(aPoint, false, true); + } + nsIContent* GetPreviousEditableNodeInBlock( + const EditorRawDOMPoint& aPoint) + { + return GetPreviousNodeInternal(aPoint, true, true); + } + nsIContent* GetPreviousNode(nsINode& aNode) + { + return GetPreviousNodeInternal(aNode, false, false); + } + nsIContent* GetPreviousEditableNode(nsINode& aNode) + { + return GetPreviousNodeInternal(aNode, true, false); + } + nsIContent* GetPreviousNodeInBlock(nsINode& aNode) + { + return GetPreviousNodeInternal(aNode, false, true); + } + nsIContent* GetPreviousEditableNodeInBlock(nsINode& aNode) + { + return GetPreviousNodeInternal(aNode, true, true); + } /** * Get the node immediately after to aCurrentNode. @@ -783,7 +818,7 @@ public: bool aNoBlockCrossing = false); /** - * Helper for GetNextNode() and GetPriorNode(). + * Helper for GetNextNode() and GetPreviousNodeInternal(). */ nsIContent* FindNode(nsINode* aCurrentNode, bool aGoForward, diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp index 692dcb929246..8da88ce57954 100644 --- a/editor/libeditor/HTMLEditRules.cpp +++ b/editor/libeditor/HTMLEditRules.cpp @@ -5273,11 +5273,9 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode, aAction == nsIEditor::ePreviousWord || aAction == nsIEditor::eToBeginningOfLine) { // Move to the end of the previous node - int32_t offset = blockParent->IndexOf(emptyBlock); - nsCOMPtr priorNode = htmlEditor->GetPriorNode(blockParent, - offset, - emptyBlock, - true); + EditorRawDOMPoint atEmptyBlock(emptyBlock); + nsCOMPtr priorNode = + htmlEditor->GetPreviousEditableNode(atEmptyBlock); if (priorNode) { EditorDOMPoint pt = GetGoodSelPointForNode(*priorNode, aAction); nsresult rv = aSelection->Collapse(pt.AsRaw()); @@ -7940,6 +7938,8 @@ HTMLEditRules::AdjustSelection(Selection* aSelection, NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr brParent = EditorBase::GetNodeLocation(brNode, &selOffset); + nsCOMPtr br = do_QueryInterface(brNode); + child = br; // selection stays *before* moz-br, sticking to it aSelection->SetInterlinePosition(true); rv = aSelection->Collapse(brParent, selOffset); diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 8e23decf855e..0579e2f33b06 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -3881,7 +3881,8 @@ HTMLEditor::GetPriorHTMLNode(nsINode* aNode, return nullptr; } - return GetPriorNode(aNode, true, aNoBlockCrossing); + return aNoBlockCrossing ? GetPreviousEditableNodeInBlock(*aNode) : + GetPreviousEditableNode(*aNode); } /** @@ -3900,7 +3901,12 @@ HTMLEditor::GetPriorHTMLNode(nsINode* aParent, return nullptr; } - return GetPriorNode(aParent, aOffset, aChildAtOffset, true, aNoBlockCrossing); + EditorRawDOMPoint point(aParent, + aChildAtOffset && aChildAtOffset->IsContent() ? + aChildAtOffset->AsContent() : nullptr, + aOffset); + return aNoBlockCrossing ? GetPreviousEditableNodeInBlock(point) : + GetPreviousEditableNode(point); } /**