--- a/editor/libeditor/EditorDOMPoint.h
+++ b/editor/libeditor/EditorDOMPoint.h
@@ -92,16 +92,23 @@ public:
template<typename A, typename B>
EditorDOMPointBase& operator=(const EditorDOMPointBase<A, B>& aOther)
{
RangeBoundaryBase<ParentType, RefType>::operator=(aOther);
return *this;
}
+ template<typename A, typename B>
+ EditorDOMPointBase& operator=(const RangeBoundaryBase<A, B>& aOther)
+ {
+ RangeBoundaryBase<ParentType, RefType>::operator=(aOther);
+ return *this;
+ }
+
private:
static nsIContent* GetRef(nsINode* aContainerNode, nsIContent* aPointedNode)
{
// If referring one of a child of the container, the 'ref' should be the
// previous sibling of the referring child.
if (aPointedNode) {
return aPointedNode->GetPreviousSibling();
}
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1646,41 +1646,46 @@ HTMLEditRules::WillInsertBreak(Selection
nsresult rv = SplitMailCites(&aSelection, aHandled);
NS_ENSURE_SUCCESS(rv, rv);
if (*aHandled) {
return NS_OK;
}
}
// Smart splitting rules
- NS_ENSURE_TRUE(aSelection.GetRangeAt(0) &&
- aSelection.GetRangeAt(0)->GetStartContainer(),
- NS_ERROR_FAILURE);
- OwningNonNull<nsINode> node = *aSelection.GetRangeAt(0)->GetStartContainer();
- nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
- int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
+ nsRange* firstRange = aSelection.GetRangeAt(0);
+ if (NS_WARN_IF(!firstRange)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ EditorDOMPoint atStartOfSelection(firstRange->StartRef());
+ if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
+ return NS_ERROR_FAILURE;
+ }
+ MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
// Do nothing if the node is read-only
- if (!htmlEditor->IsModifiableNode(node)) {
+ if (!htmlEditor->IsModifiableNode(atStartOfSelection.Container())) {
*aCancel = true;
return NS_OK;
}
// If the active editing host is an inline element, or if the active editing
// host is the block parent itself and we're configured to use <br> as a
// paragraph separator, just append a <br>.
nsCOMPtr<Element> host = htmlEditor->GetActiveEditingHost();
if (NS_WARN_IF(!host)) {
return NS_ERROR_FAILURE;
}
// Look for the nearest parent block. However, don't return error even if
// there is no block parent here because in such case, i.e., editing host
// is an inline element, we should insert <br> simply.
- RefPtr<Element> blockParent = HTMLEditor::GetBlock(node, host);
+ RefPtr<Element> blockParent =
+ HTMLEditor::GetBlock(*atStartOfSelection.Container(), host);
ParagraphSeparator separator = htmlEditor->GetDefaultParagraphSeparator();
bool insertBRElement;
// If there is no block parent in the editing host, i.e., the editing host
// itself is also a non-block element, we should insert a <br> element.
if (!blockParent) {
// XXX Chromium checks if the CSS box of the editing host is block.
insertBRElement = true;
@@ -1707,49 +1712,53 @@ HTMLEditRules::WillInsertBreak(Selection
blockAncestor = HTMLEditor::GetBlockNodeParent(blockAncestor, host)) {
insertBRElement = !CanContainParagraph(*blockAncestor);
}
}
// If we cannot insert a <p>/<div> element at the selection, we should insert
// a <br> element instead.
if (insertBRElement) {
- nsresult rv = StandardBreakImpl(node, offset, aSelection);
+ nsresult rv = StandardBreakImpl(*atStartOfSelection.Container(),
+ atStartOfSelection.Offset(), aSelection);
NS_ENSURE_SUCCESS(rv, rv);
*aHandled = true;
return NS_OK;
}
if (host == blockParent && separator != ParagraphSeparator::br) {
// Insert a new block first
MOZ_ASSERT(separator == ParagraphSeparator::div ||
separator == ParagraphSeparator::p);
nsresult rv = MakeBasicBlock(aSelection,
ParagraphSeparatorElement(separator));
// We warn on failure, but don't handle it, because it might be harmless.
// Instead we just check that a new block was actually created.
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditRules::MakeBasicBlock() failed");
- // Reinitialize node/offset in case they're not inside the new block
- if (NS_WARN_IF(!aSelection.GetRangeAt(0) ||
- !aSelection.GetRangeAt(0)->GetStartContainer())) {
+ firstRange = aSelection.GetRangeAt(0);
+ if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
}
- node = *aSelection.GetRangeAt(0)->GetStartContainer();
- child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
- offset = aSelection.GetRangeAt(0)->StartOffset();
-
- blockParent = mHTMLEditor->GetBlock(node, host);
+
+ atStartOfSelection = firstRange->StartRef();
+ if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
+ return NS_ERROR_FAILURE;
+ }
+ MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
+
+ blockParent = mHTMLEditor->GetBlock(*atStartOfSelection.Container(), host);
if (NS_WARN_IF(!blockParent)) {
return NS_ERROR_UNEXPECTED;
}
if (NS_WARN_IF(blockParent == host)) {
// Didn't create a new block for some reason, fall back to <br>
- rv = StandardBreakImpl(node, offset, aSelection);
+ rv = StandardBreakImpl(*atStartOfSelection.Container(),
+ atStartOfSelection.Offset(), aSelection);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
*aHandled = true;
return NS_OK;
}
}
@@ -1762,51 +1771,60 @@ HTMLEditRules::WillInsertBreak(Selection
if (isEmpty) {
nsCOMPtr<Element> br = htmlEditor->CreateBR(blockParent,
blockParent->Length());
NS_ENSURE_STATE(br);
}
nsCOMPtr<Element> listItem = IsInListItem(blockParent);
if (listItem && listItem != host) {
- ReturnInListItem(aSelection, *listItem, node, offset);
+ ReturnInListItem(aSelection, *listItem, *atStartOfSelection.Container(),
+ atStartOfSelection.Offset());
*aHandled = true;
return NS_OK;
- } else if (HTMLEditUtils::IsHeader(*blockParent)) {
+ }
+
+ if (HTMLEditUtils::IsHeader(*blockParent)) {
// Headers: close (or split) header
- ReturnInHeader(aSelection, *blockParent, node, offset);
+ ReturnInHeader(aSelection, *blockParent, *atStartOfSelection.Container(),
+ atStartOfSelection.Offset());
*aHandled = true;
return NS_OK;
}
+
// XXX Ideally, we should take same behavior with both <p> container and
// <div> container. However, we are still using <br> as default
// paragraph separator (non-standard) and we've split only <p> container
// long time. Therefore, some web apps may depend on this behavior like
// Gmail. So, let's use traditional odd behavior only when the default
// paragraph separator is <br>. Otherwise, take consistent behavior
// between <p> container and <div> container.
- else if ((separator == ParagraphSeparator::br &&
- blockParent->IsHTMLElement(nsGkAtoms::p)) ||
- (separator != ParagraphSeparator::br &&
- blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
+ if ((separator == ParagraphSeparator::br &&
+ blockParent->IsHTMLElement(nsGkAtoms::p)) ||
+ (separator != ParagraphSeparator::br &&
+ blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
// Paragraphs: special rules to look for <br>s
EditActionResult result =
- ReturnInParagraph(aSelection, *blockParent, node, offset, child);
+ ReturnInParagraph(aSelection, *blockParent,
+ atStartOfSelection.Container(),
+ atStartOfSelection.Offset(),
+ atStartOfSelection.GetChildAtOffset());
if (NS_WARN_IF(result.Failed())) {
return result.Rv();
}
*aHandled = result.Handled();
*aCancel = result.Canceled();
// Fall through, we may not have handled it in ReturnInParagraph()
}
// If not already handled then do the standard thing
if (!(*aHandled)) {
*aHandled = true;
- return StandardBreakImpl(node, offset, aSelection);
+ return StandardBreakImpl(*atStartOfSelection.Container(),
+ atStartOfSelection.Offset(), aSelection);
}
return NS_OK;
}
nsresult
HTMLEditRules::StandardBreakImpl(nsINode& aNode,
int32_t aOffset,
Selection& aSelection)