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
This commit is contained in:
Masayuki Nakano 2017-11-09 17:08:10 +09:00
Родитель 456157300a
Коммит e28ddd6ec3
4 изменённых файлов: 112 добавлений и 62 удалений

Просмотреть файл

@ -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<nsIContent> priorNode = GetPriorNode(node, true);
nsCOMPtr<nsIContent> priorNode = GetPreviousEditableNode(*node);
if (NS_WARN_IF(!priorNode)) {
return nullptr;
}
@ -4693,7 +4701,8 @@ EditorBase::CreateTxnForDeleteRange(nsRange* aRangeToDelete,
// node to find out
nsCOMPtr<nsINode> 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);
}

Просмотреть файл

@ -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,

Просмотреть файл

@ -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<nsIContent> priorNode = htmlEditor->GetPriorNode(blockParent,
offset,
emptyBlock,
true);
EditorRawDOMPoint atEmptyBlock(emptyBlock);
nsCOMPtr<nsIContent> 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<nsIDOMNode> brParent =
EditorBase::GetNodeLocation(brNode, &selOffset);
nsCOMPtr<nsIContent> br = do_QueryInterface(brNode);
child = br;
// selection stays *before* moz-br, sticking to it
aSelection->SetInterlinePosition(true);
rv = aSelection->Collapse(brParent, selOffset);

Просмотреть файл

@ -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);
}
/**