mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 1415062 - part 2: Editor should use Selection::Collapse(const RawRangeBoundary&) as far as possible r=m_kato
In some places, editor computes index from child node for collapsing selection at the child node. However, it's expensive. Therefore, editor should use Selection::Collapse(const RawRangeBoundary&) as far as possible. MozReview-Commit-ID: LF2MwASuXzZ --HG-- extra : rebase_source : b7afc35c0d9d88845391b6f18de57cbff1935ae4
This commit is contained in:
parent
898bbb3137
commit
806668b21a
@ -216,9 +216,13 @@ public:
|
||||
mOffset = mozilla::Some(aOffset);
|
||||
}
|
||||
void
|
||||
Set(const nsIContent* aChild)
|
||||
Set(const nsINode* aChild)
|
||||
{
|
||||
MOZ_ASSERT(aChild);
|
||||
if (!aChild->IsContent()) {
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
mParent = aChild->GetParentNode();
|
||||
mRef = aChild->GetPreviousSibling();
|
||||
if (!mRef) {
|
||||
@ -246,12 +250,14 @@ public:
|
||||
* If the container can have children and there is no next sibling, this
|
||||
* outputs warning and does nothing. So, callers need to check if there is
|
||||
* next sibling which you need to refer.
|
||||
*
|
||||
* @return true if there is a next sibling to refer.
|
||||
*/
|
||||
void
|
||||
bool
|
||||
AdvanceOffset()
|
||||
{
|
||||
if (NS_WARN_IF(!mParent)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
EnsureRef();
|
||||
if (!mRef) {
|
||||
@ -260,30 +266,31 @@ public:
|
||||
MOZ_ASSERT(mOffset.isSome());
|
||||
if (NS_WARN_IF(mOffset.value() == mParent->Length())) {
|
||||
// Already referring the end of the node.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
mOffset = mozilla::Some(mOffset.value() + 1);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
mRef = mParent->GetFirstChild();
|
||||
if (NS_WARN_IF(!mRef)) {
|
||||
// No children in the container.
|
||||
mOffset = mozilla::Some(0);
|
||||
} else {
|
||||
mOffset = mozilla::Some(1);
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
mOffset = mozilla::Some(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIContent* nextSibling = mRef->GetNextSibling();
|
||||
if (NS_WARN_IF(!nextSibling)) {
|
||||
// Already referring the end of the container.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
mRef = nextSibling;
|
||||
if (mOffset.isSome()) {
|
||||
mOffset = mozilla::Some(mOffset.value() + 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -293,34 +300,37 @@ public:
|
||||
* If the container can have children and there is no next previous, this
|
||||
* outputs warning and does nothing. So, callers need to check if there is
|
||||
* previous sibling which you need to refer.
|
||||
*
|
||||
* @return true if there is a previous sibling to refer.
|
||||
*/
|
||||
void
|
||||
bool
|
||||
RewindOffset()
|
||||
{
|
||||
if (NS_WARN_IF(!mParent)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
EnsureRef();
|
||||
if (!mRef) {
|
||||
if (NS_WARN_IF(mParent->IsContainerNode())) {
|
||||
// Already referring the start of the container
|
||||
mOffset = mozilla::Some(0);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// In text node or something, just decrement the offset.
|
||||
MOZ_ASSERT(mOffset.isSome());
|
||||
if (NS_WARN_IF(mOffset.value() == 0)) {
|
||||
// Already referring the start of the node.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
mOffset = mozilla::Some(mOffset.value() - 1);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
mRef = mRef->GetPreviousSibling();
|
||||
if (mOffset.isSome()) {
|
||||
mOffset = mozilla::Some(mOffset.value() - 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/EditorBase.h"
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsAString.h"
|
||||
@ -103,7 +104,14 @@ CreateElementTransaction::DoTransaction()
|
||||
RefPtr<Selection> selection = mEditorBase->GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
||||
|
||||
rv = selection->Collapse(mParent, mParent->IndexOf(mNewNode) + 1);
|
||||
EditorRawDOMPoint afterNewNode(mNewNode);
|
||||
if (NS_WARN_IF(!afterNewNode.AdvanceOffset())) {
|
||||
// If mutation observer or mutation event listener moved or removed the
|
||||
// new node, we hit this case. Should we use script blocker while we're
|
||||
// in this method?
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = selection->Collapse(afterNewNode);
|
||||
NS_ASSERTION(!rv.Failed(),
|
||||
"selection could not be collapsed after insert");
|
||||
return NS_OK;
|
||||
|
@ -4278,22 +4278,30 @@ EditorBase::DeleteSelectionAndPrepareToCreateNode()
|
||||
uint32_t offset = selection->AnchorOffset();
|
||||
|
||||
if (!offset) {
|
||||
nsresult rv = selection->Collapse(node->GetParentNode(),
|
||||
node->GetParentNode()->IndexOf(node));
|
||||
EditorRawDOMPoint atNode(node);
|
||||
if (NS_WARN_IF(!atNode.IsSetAndValid())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = selection->Collapse(atNode);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (offset == node->Length()) {
|
||||
nsresult rv =
|
||||
selection->Collapse(node->GetParentNode(),
|
||||
node->GetParentNode()->IndexOf(node) + 1);
|
||||
EditorRawDOMPoint afterNode(node);
|
||||
if (NS_WARN_IF(!afterNode.AdvanceOffset())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = selection->Collapse(afterNode);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
nsresult rv = SplitNode(node->AsDOMNode(), offset, getter_AddRefs(tmp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = selection->Collapse(node->GetParentNode(),
|
||||
node->GetParentNode()->IndexOf(node));
|
||||
EditorRawDOMPoint atNode(node);
|
||||
if (NS_WARN_IF(!atNode.IsSetAndValid())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = selection->Collapse(atNode);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
@ -49,15 +49,17 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Different from RangeBoundary, aReferenceChild should be a child node
|
||||
* Different from RangeBoundary, aPointedNode should be a child node
|
||||
* which you want to refer. So, set non-nullptr if offset is
|
||||
* 0 - Length() - 1. Otherwise, set nullptr, i.e., if offset is same as
|
||||
* Length().
|
||||
*/
|
||||
EditorDOMPointBase(nsINode* aContainer,
|
||||
nsIContent* aPointedNode)
|
||||
: RangeBoundaryBase<ParentType, RefType>(aContainer,
|
||||
GetRef(aPointedNode))
|
||||
explicit EditorDOMPointBase(nsINode* aPointedNode)
|
||||
: RangeBoundaryBase<ParentType, RefType>(
|
||||
aPointedNode && aPointedNode->IsContent() ?
|
||||
aPointedNode->GetParentNode() : nullptr,
|
||||
aPointedNode && aPointedNode->IsContent() ?
|
||||
GetRef(aPointedNode->AsContent()) : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1265,9 +1265,8 @@ HTMLEditRules::WillInsert(Selection& aSelection,
|
||||
// If we are here then the selection is right after a mozBR that is in
|
||||
// the same block as the selection. We need to move the selection start
|
||||
// to be before the mozBR.
|
||||
selNode = priorNode->GetParentNode();
|
||||
selOffset = selNode->IndexOf(priorNode);
|
||||
nsresult rv = aSelection.Collapse(selNode, selOffset);
|
||||
EditorRawDOMPoint point(priorNode);
|
||||
nsresult rv = aSelection.Collapse(point.AsRaw());
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}
|
||||
}
|
||||
@ -1493,7 +1492,9 @@ HTMLEditRules::WillInsertText(EditAction aAction,
|
||||
}
|
||||
}
|
||||
aSelection->SetInterlinePosition(false);
|
||||
if (curNode) aSelection->Collapse(curNode, curOffset);
|
||||
if (curNode) {
|
||||
aSelection->Collapse(curNode, curOffset);
|
||||
}
|
||||
// manually update the doc changed range so that AfterEdit will clean up
|
||||
// the correct portion of the document.
|
||||
if (!mDocChangeRange) {
|
||||
@ -1802,15 +1803,16 @@ HTMLEditRules::StandardBreakImpl(nsINode& aNode,
|
||||
}
|
||||
node = brNode->GetParentNode();
|
||||
NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
|
||||
int32_t offset = node->IndexOf(brNode);
|
||||
if (bAfterBlock && bBeforeBlock) {
|
||||
// We just placed a br between block boundaries. This is the one case
|
||||
// where we want the selection to be before the br we just placed, as the
|
||||
// br will be on a new line, rather than at end of prior line.
|
||||
aSelection.SetInterlinePosition(true);
|
||||
nsresult rv = aSelection.Collapse(node, offset);
|
||||
EditorRawDOMPoint point(brNode);
|
||||
nsresult rv = aSelection.Collapse(point.AsRaw());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
int32_t offset = node->IndexOf(brNode);
|
||||
WSRunObject wsObj(htmlEditor, node, offset + 1);
|
||||
nsCOMPtr<nsINode> secondBR;
|
||||
int32_t visOffset = 0;
|
||||
@ -2309,7 +2311,7 @@ HTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Fix up selection
|
||||
rv = aSelection->Collapse(pt.Container(), pt.Offset());
|
||||
rv = aSelection->Collapse(pt.AsRaw());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
rv = InsertBRIfNeeded(aSelection);
|
||||
@ -2380,7 +2382,7 @@ HTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
if (NS_WARN_IF(!newSel.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aSelection->Collapse(newSel.Container(), newSel.Offset());
|
||||
aSelection->Collapse(newSel.AsRaw());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2572,7 +2574,7 @@ HTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Fix up selection
|
||||
rv = aSelection->Collapse(pt.Container(), pt.Offset());
|
||||
rv = aSelection->Collapse(pt.AsRaw());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2792,7 +2794,7 @@ HTMLEditRules::GetGoodSelPointForNode(nsINode& aNode,
|
||||
return EditorDOMPoint();
|
||||
}
|
||||
|
||||
EditorDOMPoint ret(aNode.GetParentNode(), aNode.AsContent());
|
||||
EditorDOMPoint ret(&aNode);
|
||||
if ((!aNode.IsHTMLElement(nsGkAtoms::br) ||
|
||||
mHTMLEditor->IsVisibleBRElement(&aNode)) && isPreviousAction) {
|
||||
ret.AdvanceOffset();
|
||||
@ -4552,25 +4554,22 @@ HTMLEditRules::WillOutdent(Selection& aSelection,
|
||||
NS_ENSURE_TRUE(aSelection.GetRangeAt(0), NS_OK);
|
||||
nsCOMPtr<nsINode> startNode =
|
||||
aSelection.GetRangeAt(0)->GetStartContainer();
|
||||
int32_t startOffset = aSelection.GetRangeAt(0)->StartOffset();
|
||||
if (rememberedLeftBQ &&
|
||||
(startNode == rememberedLeftBQ ||
|
||||
EditorUtils::IsDescendantOf(*startNode, *rememberedLeftBQ))) {
|
||||
// Selection is inside rememberedLeftBQ - push it past it.
|
||||
startNode = rememberedLeftBQ->GetParentNode();
|
||||
startOffset = startNode ? 1 + startNode->IndexOf(rememberedLeftBQ) : 0;
|
||||
aSelection.Collapse(startNode, startOffset);
|
||||
EditorRawDOMPoint afterRememberedLeftBQ(rememberedLeftBQ);
|
||||
afterRememberedLeftBQ.AdvanceOffset();
|
||||
aSelection.Collapse(afterRememberedLeftBQ);
|
||||
}
|
||||
// And pull selection before beginning of rememberedRightBQ
|
||||
startNode = aSelection.GetRangeAt(0)->GetStartContainer();
|
||||
startOffset = aSelection.GetRangeAt(0)->StartOffset();
|
||||
if (rememberedRightBQ &&
|
||||
(startNode == rememberedRightBQ ||
|
||||
EditorUtils::IsDescendantOf(*startNode, *rememberedRightBQ))) {
|
||||
// Selection is inside rememberedRightBQ - push it before it.
|
||||
startNode = rememberedRightBQ->GetParentNode();
|
||||
startOffset = startNode ? startNode->IndexOf(rememberedRightBQ) : -1;
|
||||
aSelection.Collapse(startNode, startOffset);
|
||||
EditorRawDOMPoint atRememberedRightBQ(rememberedRightBQ);
|
||||
aSelection.Collapse(atRememberedRightBQ);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -5188,37 +5187,45 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
|
||||
// AfterEdit()
|
||||
}
|
||||
} else {
|
||||
int32_t offset = blockParent->IndexOf(emptyBlock);
|
||||
|
||||
if (aAction == nsIEditor::eNext || aAction == nsIEditor::eNextWord ||
|
||||
aAction == nsIEditor::eToEndOfLine) {
|
||||
// Move to the start of the next node, if any
|
||||
nsINode* child = emptyBlock->GetNextSibling();
|
||||
int32_t offset = blockParent->IndexOf(emptyBlock);
|
||||
nsCOMPtr<nsIContent> nextNode =
|
||||
htmlEditor->GetNextNode(blockParent, offset + 1, child, true);
|
||||
if (nextNode) {
|
||||
EditorDOMPoint pt = GetGoodSelPointForNode(*nextNode, aAction);
|
||||
nsresult rv = aSelection->Collapse(pt.Container(), pt.Offset());
|
||||
nsresult rv = aSelection->Collapse(pt.AsRaw());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
// Adjust selection to be right after it.
|
||||
nsresult rv = aSelection->Collapse(blockParent, offset + 1);
|
||||
EditorRawDOMPoint afterEmptyBlock(emptyBlock);
|
||||
if (NS_WARN_IF(!afterEmptyBlock.AdvanceOffset())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = aSelection->Collapse(afterEmptyBlock);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} else if (aAction == nsIEditor::ePrevious ||
|
||||
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);
|
||||
if (priorNode) {
|
||||
EditorDOMPoint pt = GetGoodSelPointForNode(*priorNode, aAction);
|
||||
nsresult rv = aSelection->Collapse(pt.Container(), pt.Offset());
|
||||
nsresult rv = aSelection->Collapse(pt.AsRaw());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
nsresult rv = aSelection->Collapse(blockParent, offset + 1);
|
||||
EditorRawDOMPoint afterEmptyBlock(emptyBlock);
|
||||
if (NS_WARN_IF(!afterEmptyBlock.AdvanceOffset())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = aSelection->Collapse(afterEmptyBlock);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} else if (aAction != nsIEditor::eNone) {
|
||||
@ -6625,10 +6632,12 @@ HTMLEditRules::ReturnInHeader(Selection& aSelection,
|
||||
rv = aSelection.Collapse(pNode, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
headerParent = sibling->GetParentNode();
|
||||
offset = headerParent ? headerParent->IndexOf(sibling) : -1;
|
||||
EditorRawDOMPoint afterSibling(sibling);
|
||||
if (NS_WARN_IF(!afterSibling.AdvanceOffset())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Put selection after break
|
||||
rv = aSelection.Collapse(headerParent, offset + 1);
|
||||
rv = aSelection.Collapse(afterSibling);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} else {
|
||||
@ -6825,15 +6834,13 @@ HTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
|
||||
// look inside any containers that are up front.
|
||||
nsCOMPtr<nsINode> rightParaNode = do_QueryInterface(rightPara);
|
||||
NS_ENSURE_STATE(mHTMLEditor && rightParaNode);
|
||||
nsCOMPtr<nsIDOMNode> child =
|
||||
GetAsDOMNode(mHTMLEditor->GetLeftmostChild(rightParaNode, true));
|
||||
nsIContent* child = mHTMLEditor->GetLeftmostChild(rightParaNode, true);
|
||||
if (EditorBase::IsTextNode(child) ||
|
||||
mHTMLEditor->IsContainer(child)) {
|
||||
aSelection->Collapse(child,0);
|
||||
} else {
|
||||
int32_t offset;
|
||||
nsCOMPtr<nsIDOMNode> parent = EditorBase::GetNodeLocation(child, &offset);
|
||||
aSelection->Collapse(parent,offset);
|
||||
EditorRawDOMPoint atChild(child);
|
||||
aSelection->Collapse(atChild);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -6959,9 +6966,11 @@ HTMLEditRules::ReturnInListItem(Selection& aSelection,
|
||||
getter_AddRefs(brNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (brNode) {
|
||||
nsCOMPtr<nsINode> brParent = brNode->GetParentNode();
|
||||
int32_t offset = brParent ? brParent->IndexOf(brNode) : -1;
|
||||
rv = aSelection.Collapse(brParent, offset);
|
||||
EditorRawDOMPoint atBrNode(brNode);
|
||||
if (NS_WARN_IF(!atBrNode.IsSetAndValid())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = aSelection.Collapse(atBrNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -6974,9 +6983,11 @@ HTMLEditRules::ReturnInListItem(Selection& aSelection,
|
||||
&visOffset, &wsType);
|
||||
if (wsType == WSType::special || wsType == WSType::br ||
|
||||
visNode->IsHTMLElement(nsGkAtoms::hr)) {
|
||||
nsCOMPtr<nsINode> parent = visNode->GetParentNode();
|
||||
int32_t offset = parent ? parent->IndexOf(visNode) : -1;
|
||||
rv = aSelection.Collapse(parent, offset);
|
||||
EditorRawDOMPoint atVisNode(visNode);
|
||||
if (NS_WARN_IF(!atVisNode.IsSetAndValid())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = aSelection.Collapse(atVisNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
} else {
|
||||
@ -7681,36 +7692,42 @@ HTMLEditRules::PinSelectionToNewBlock(Selection* aSelection)
|
||||
|
||||
if (nodeBefore && nodeAfter) {
|
||||
return NS_OK; // selection is inside block
|
||||
} else if (nodeBefore) {
|
||||
}
|
||||
|
||||
if (nodeBefore) {
|
||||
// selection is after block. put at end of block.
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<nsINode> tmp = mHTMLEditor->GetLastEditableChild(*mNewBlock);
|
||||
if (!tmp) {
|
||||
tmp = mNewBlock;
|
||||
}
|
||||
uint32_t endPoint;
|
||||
EditorRawDOMPoint endPoint;
|
||||
if (EditorBase::IsTextNode(tmp) ||
|
||||
mHTMLEditor->IsContainer(tmp)) {
|
||||
endPoint = tmp->Length();
|
||||
endPoint.Set(tmp, tmp->Length());
|
||||
} else {
|
||||
tmp = EditorBase::GetNodeLocation(tmp, (int32_t*)&endPoint);
|
||||
endPoint++; // want to be after this node
|
||||
endPoint.Set(tmp);
|
||||
if (NS_WARN_IF(!endPoint.AdvanceOffset())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return aSelection->Collapse(tmp, (int32_t)endPoint);
|
||||
} else {
|
||||
// selection is before block. put at start of block.
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<nsINode> tmp = mHTMLEditor->GetFirstEditableChild(*mNewBlock);
|
||||
if (!tmp) {
|
||||
tmp = mNewBlock;
|
||||
}
|
||||
int32_t offset;
|
||||
if (EditorBase::IsTextNode(tmp) ||
|
||||
mHTMLEditor->IsContainer(tmp)) {
|
||||
tmp = EditorBase::GetNodeLocation(tmp, &offset);
|
||||
}
|
||||
return aSelection->Collapse(tmp, 0);
|
||||
return aSelection->Collapse(endPoint);
|
||||
}
|
||||
|
||||
// selection is before block. put at start of block.
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<nsINode> tmp = mHTMLEditor->GetFirstEditableChild(*mNewBlock);
|
||||
if (!tmp) {
|
||||
tmp = mNewBlock;
|
||||
}
|
||||
EditorRawDOMPoint atStartOfBlock;
|
||||
if (EditorBase::IsTextNode(tmp) ||
|
||||
mHTMLEditor->IsContainer(tmp)) {
|
||||
atStartOfBlock.Set(tmp);
|
||||
} else {
|
||||
atStartOfBlock.Set(tmp, 0);
|
||||
}
|
||||
return aSelection->Collapse(atStartOfBlock);
|
||||
}
|
||||
|
||||
void
|
||||
@ -7904,7 +7921,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
||||
return NS_OK;
|
||||
}
|
||||
EditorDOMPoint pt = GetGoodSelPointForNode(*nearNode, aAction);
|
||||
rv = aSelection->Collapse(pt.Container(), pt.Offset());
|
||||
rv = aSelection->Collapse(pt.AsRaw());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1086,10 +1086,18 @@ HTMLEditor::InsertBR(nsCOMPtr<nsIDOMNode>* outBRNode)
|
||||
rv = CreateBR(selNode, selOffset, outBRNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// position selection after br
|
||||
selNode = GetNodeLocation(*outBRNode, &selOffset);
|
||||
selection->SetInterlinePosition(true);
|
||||
return selection->Collapse(selNode, selOffset+1);
|
||||
|
||||
// position selection after br
|
||||
nsCOMPtr<nsINode> brNode = do_QueryInterface(*outBRNode);
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
EditorRawDOMPoint afterBrNode(brNode);
|
||||
if (NS_WARN_IF(!afterBrNode.AdvanceOffset())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return selection->Collapse(afterBrNode);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1692,9 +1700,12 @@ HTMLEditor::SetCaretAfterElement(nsIDOMElement* aElement)
|
||||
nsresult rv = aElement->GetParentNode(getter_AddRefs(parent));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
|
||||
int32_t offsetInParent = GetChildOffset(aElement, parent);
|
||||
// Collapse selection to just after desired element,
|
||||
return selection->Collapse(parent, offsetInParent + 1);
|
||||
EditorRawDOMPoint afterElement(element);
|
||||
if (NS_WARN_IF(!afterElement.AdvanceOffset())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return selection->Collapse(afterElement);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
#include "mozilla/EditorUtils.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -657,8 +658,10 @@ HTMLEditor::DoInsertHTMLWithContext(const nsAString& aInputString,
|
||||
SplitNodeDeep(*linkContent, *selContent, selOffset,
|
||||
EmptyContainers::no, getter_AddRefs(leftLink));
|
||||
if (leftLink) {
|
||||
selNode = GetNodeLocation(GetAsDOMNode(leftLink), &selOffset);
|
||||
selection->Collapse(selNode, selOffset+1);
|
||||
EditorRawDOMPoint afterLeftLink(leftLink);
|
||||
if (afterLeftLink.AdvanceOffset()) {
|
||||
selection->Collapse(afterLeftLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1898,10 +1901,9 @@ HTMLEditor::InsertAsPlaintextQuotation(const nsAString& aQuotedText,
|
||||
|
||||
// Set the selection to just after the inserted node:
|
||||
if (NS_SUCCEEDED(rv) && newNode) {
|
||||
nsCOMPtr<nsINode> parent = newNode->GetParentNode();
|
||||
int32_t offset = parent ? parent->IndexOf(newNode) : -1;
|
||||
if (parent) {
|
||||
selection->Collapse(parent, offset + 1);
|
||||
EditorRawDOMPoint afterNewNode(newNode);
|
||||
if (afterNewNode.AdvanceOffset()) {
|
||||
selection->Collapse(afterNewNode);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
@ -1978,10 +1980,9 @@ HTMLEditor::InsertAsCitedQuotation(const nsAString& aQuotedText,
|
||||
|
||||
// Set the selection to just after the inserted node:
|
||||
if (NS_SUCCEEDED(rv) && newNode) {
|
||||
nsCOMPtr<nsINode> parent = newNode->GetParentNode();
|
||||
int32_t offset = parent ? parent->IndexOf(newNode) : -1;
|
||||
if (parent) {
|
||||
selection->Collapse(parent, offset + 1);
|
||||
EditorRawDOMPoint afterNewNode(newNode);
|
||||
if (afterNewNode.AdvanceOffset()) {
|
||||
selection->Collapse(afterNewNode);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "HTMLEditUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
#include "mozilla/EditorUtils.h"
|
||||
#include "mozilla/FlushType.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
@ -3157,8 +3158,15 @@ HTMLEditor::SetSelectionAfterTableEdit(nsIDOMElement* aTable,
|
||||
nsCOMPtr<nsIDOMNode> tableParent;
|
||||
nsresult rv = aTable->GetParentNode(getter_AddRefs(tableParent));
|
||||
if (NS_SUCCEEDED(rv) && tableParent) {
|
||||
int32_t tableOffset = GetChildOffset(aTable, tableParent);
|
||||
selection->Collapse(tableParent, tableOffset);
|
||||
nsCOMPtr<nsIContent> table = do_QueryInterface(aTable);
|
||||
if (NS_WARN_IF(!table)) {
|
||||
return;
|
||||
}
|
||||
EditorRawDOMPoint atTable(table);
|
||||
if (NS_WARN_IF(!atTable.IsSetAndValid())) {
|
||||
return;
|
||||
}
|
||||
selection->Collapse(atTable);
|
||||
return;
|
||||
}
|
||||
// Last resort: Set selection to start of doc
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "TextEditUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
#include "mozilla/EditorUtils.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -494,8 +495,11 @@ TextEditRules::CollapseSelectionToTrailingBRIfNeeded(Selection* aSelection)
|
||||
|
||||
nsINode* nextNode = selNode->GetNextSibling();
|
||||
if (nextNode && TextEditUtils::IsMozBR(nextNode)) {
|
||||
int32_t offsetInParent = EditorBase::GetChildOffset(selNode, parentNode);
|
||||
rv = aSelection->Collapse(parentNode, offsetInParent + 1);
|
||||
EditorRawDOMPoint afterSelNode(selNode);
|
||||
if (NS_WARN_IF(!afterSelNode.AdvanceOffset())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = aSelection->Collapse(afterSelNode);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -778,6 +782,8 @@ TextEditRules::WillInsertText(EditAction aAction,
|
||||
!outString->IsEmpty() && outString->Last() == nsCRT::LF;
|
||||
aSelection->SetInterlinePosition(endsWithLF);
|
||||
|
||||
MOZ_ASSERT(!selChild,
|
||||
"After inserting text into a text node, selChild should be nullptr");
|
||||
aSelection->Collapse(curNode, curOffset);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "TextEditUtils.h"
|
||||
#include "gfxFontUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
#include "mozilla/EditorUtils.h" // AutoPlaceholderBatch, AutoRules
|
||||
#include "mozilla/HTMLEditor.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
@ -476,19 +477,24 @@ TextEditor::CreateBRImpl(nsCOMPtr<nsIDOMNode>* aInOutParent,
|
||||
|
||||
*outBRNode = GetAsDOMNode(brNode);
|
||||
if (*outBRNode && (aSelect != eNone)) {
|
||||
int32_t offset;
|
||||
nsCOMPtr<nsINode> parent = GetNodeLocation(brNode, &offset);
|
||||
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
NS_ENSURE_STATE(selection);
|
||||
if (aSelect == eNext) {
|
||||
selection->SetInterlinePosition(true);
|
||||
// position selection after br
|
||||
selection->SetInterlinePosition(true);
|
||||
selection->Collapse(parent, offset + 1);
|
||||
EditorRawDOMPoint afterBrNode(brNode);
|
||||
if (NS_WARN_IF(!afterBrNode.AdvanceOffset())) {
|
||||
return NS_OK;
|
||||
}
|
||||
selection->Collapse(afterBrNode);
|
||||
} else if (aSelect == ePrevious) {
|
||||
// position selection before br
|
||||
selection->SetInterlinePosition(true);
|
||||
selection->Collapse(parent, offset);
|
||||
// position selection before br
|
||||
EditorRawDOMPoint atBrNode(brNode);
|
||||
if (NS_WARN_IF(!atBrNode.IsSetAndValid())) {
|
||||
return NS_OK;
|
||||
}
|
||||
selection->Collapse(atBrNode);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -729,7 +735,9 @@ TextEditor::InsertLineBreak()
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// set the selection to the correct location
|
||||
rv = selection->Collapse(selNode, selOffset);
|
||||
MOZ_ASSERT(!selChild,
|
||||
"After inserting text into a text node, selChild should be nullptr");
|
||||
rv = selection->Collapse(EditorRawDOMPoint(selNode, selOffset));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// see if we're at the end of the editor range
|
||||
nsCOMPtr<nsIDOMNode> endNode;
|
||||
|
Loading…
Reference in New Issue
Block a user