Bug 1503473 - part 2: Make TextEditRules::WillInsertBreak() and HTMLEditRules::WillInsertBreak() return EditActionResult r=m_kato

With this cleaning up, we can know when they return NS_OK with both
aCanceled is false and aHandled is false.  (Look for EditActionIgnored().)

Additionally, this patch renames HTMLEditRules::WillInsertBreak() to
WillInsertParagraphSeparator() and TextEditRules::WillInsertBreak() to
TextEditRules::WillInsertLineBreak().

Differential Revision: https://phabricator.services.mozilla.com/D10522

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2018-11-02 07:48:25 +00:00
Родитель 6ba637600b
Коммит 5ed27c4ca6
5 изменённых файлов: 130 добавлений и 142 удалений

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

@ -48,6 +48,7 @@ public:
nsresult Rv() const { return mRv; }
bool Canceled() const { return mCanceled; }
bool Handled() const { return mHandled; }
bool Ignored() const { return !mCanceled && !mHandled; }
bool EditorDestroyed() const { return mRv == NS_ERROR_EDITOR_DESTROYED; }
EditActionResult SetResult(nsresult aRv)

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

@ -716,9 +716,17 @@ HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo,
aInfo.maxLength);
case EditSubAction::eInsertHTMLSource:
return WillLoadHTML();
case EditSubAction::eInsertParagraphSeparator:
case EditSubAction::eInsertParagraphSeparator: {
UndefineCaretBidiLevel();
return WillInsertBreak(aCancel, aHandled);
EditActionResult result = WillInsertParagraphSeparator();
if (NS_WARN_IF(result.Failed())) {
return result.Rv();
}
*aCancel = result.Canceled();
*aHandled = result.Handled();
MOZ_ASSERT(!result.Ignored());
return NS_OK;
}
case EditSubAction::eDeleteSelectedContent:
return WillDeleteSelection(aInfo.collapsedAction, aInfo.stripWrappers,
aCancel, aHandled);
@ -1696,64 +1704,58 @@ HTMLEditRules::CanContainParagraph(Element& aElement) const
return false;
}
nsresult
HTMLEditRules::WillInsertBreak(bool* aCancel,
bool* aHandled)
EditActionResult
HTMLEditRules::WillInsertParagraphSeparator()
{
MOZ_ASSERT(IsEditorDataAvailable());
MOZ_ASSERT(aCancel && aHandled);
*aCancel = false;
*aHandled = false;
// If the selection isn't collapsed, delete it.
if (!SelectionRefPtr()->IsCollapsed()) {
nsresult rv =
HTMLEditorRef().DeleteSelectionAsSubAction(nsIEditor::eNone,
nsIEditor::eStrip);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
}
// FYI: Ignore cancel result of WillInsert().
nsresult rv = WillInsert();
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
// Split any mailcites in the way. Should we abort this if we encounter
// table cell boundaries?
if (IsMailEditor()) {
nsresult rv = SplitMailCites(aHandled);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
EditActionResult result = SplitMailCites();
if (NS_WARN_IF(result.Failed())) {
return result;
}
if (*aHandled) {
return NS_OK;
if (result.Handled()) {
return result;
}
}
// Smart splitting rules
nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
EditorDOMPoint atStartOfSelection(firstRange->StartRef());
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
// Do nothing if the node is read-only
if (!HTMLEditorRef().IsModifiableNode(*atStartOfSelection.GetContainer())) {
*aCancel = true;
return NS_OK;
return EditActionCanceled();
}
// If the active editing host is an inline element, or if the active editing
@ -1761,7 +1763,7 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
// paragraph separator, just append a <br>.
RefPtr<Element> host = HTMLEditorRef().GetActiveEditingHost();
if (NS_WARN_IF(!host)) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
// Look for the nearest parent block. However, don't return error even if
@ -1807,10 +1809,9 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
if (insertBRElement) {
nsresult rv = InsertBRElement(atStartOfSelection);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
*aHandled = true;
return NS_OK;
return EditActionHandled();
}
if (host == blockParent && separator != ParagraphSeparator::br) {
@ -1823,7 +1824,7 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
nsresult rv = MakeBasicBlock(ParagraphSeparatorElement(separator));
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED) ||
NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
// 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.
@ -1832,28 +1833,27 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
firstRange = SelectionRefPtr()->GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
atStartOfSelection = firstRange->StartRef();
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
blockParent =
HTMLEditor::GetBlock(*atStartOfSelection.GetContainer(), host);
if (NS_WARN_IF(!blockParent)) {
return NS_ERROR_UNEXPECTED;
return EditActionIgnored(NS_ERROR_UNEXPECTED);
}
if (NS_WARN_IF(blockParent == host)) {
// Didn't create a new block for some reason, fall back to <br>
rv = InsertBRElement(atStartOfSelection);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
*aHandled = true;
return NS_OK;
return EditActionHandled();
}
// Now, mNewBlock is last created block element for wrapping inline
// elements around the caret position and AfterEditInner() will move
@ -1876,10 +1876,10 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
RefPtr<Element> brElement =
HTMLEditorRef().InsertBrElementWithTransaction(endOfBlockParent);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
}
@ -1889,12 +1889,11 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
ReturnInListItem(*listItem, *atStartOfSelection.GetContainer(),
atStartOfSelection.Offset());
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to insert break into list item");
*aHandled = true;
return NS_OK;
return EditActionHandled();
}
if (HTMLEditUtils::IsHeader(*blockParent)) {
@ -1903,12 +1902,11 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
ReturnInHeader(*blockParent, *atStartOfSelection.GetContainer(),
atStartOfSelection.Offset());
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to handle insertParagraph in the heading element");
*aHandled = true;
return NS_OK;
return EditActionHandled();
}
// XXX Ideally, we should take same behavior with both <p> container and
@ -1926,31 +1924,27 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
// Paragraphs: special rules to look for <br>s
EditActionResult result = ReturnInParagraph(*blockParent);
if (NS_WARN_IF(result.Failed())) {
return result.Rv();
return result;
}
*aHandled = result.Handled();
*aCancel = result.Canceled();
if (result.Handled()) {
// Now, atStartOfSelection may be invalid because the left paragraph
// may have less children than its offset. For avoiding warnings of
// validation of EditorDOMPoint, we should not touch it anymore.
lockOffset.Cancel();
return NS_OK;
return result;
}
// Fall through, if ReturnInParagraph() didn't handle it.
MOZ_ASSERT(!*aCancel, "ReturnInParagraph canceled this edit action, "
"WillInsertBreak() needs to handle such case");
MOZ_ASSERT(!result.Canceled(),
"ReturnInParagraph canceled this edit action, "
"WillInsertBreak() needs to handle such case");
}
// If nobody handles this edit action, let's insert new <br> at the selection.
MOZ_ASSERT(!*aHandled, "Reached last resort of WillInsertBreak() "
"after the edit action is handled");
rv = InsertBRElement(atStartOfSelection);
*aHandled = true;
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
return NS_OK;
return EditActionHandled();
}
nsresult
@ -2101,24 +2095,20 @@ HTMLEditRules::InsertBRElement(const EditorDOMPoint& aPointToBreak)
return NS_OK;
}
nsresult
HTMLEditRules::SplitMailCites(bool* aHandled)
EditActionResult
HTMLEditRules::SplitMailCites()
{
MOZ_ASSERT(IsEditorDataAvailable());
if (NS_WARN_IF(!aHandled)) {
return NS_ERROR_INVALID_ARG;
}
EditorRawDOMPoint pointToSplit(EditorBase::GetStartPoint(*SelectionRefPtr()));
if (NS_WARN_IF(!pointToSplit.IsSet())) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
RefPtr<Element> citeNode =
GetTopEnclosingMailCite(*pointToSplit.GetContainer());
if (!citeNode) {
return NS_OK;
return EditActionIgnored();
}
// If our selection is just before a break, nudge it to be just after it.
@ -2145,7 +2135,7 @@ HTMLEditRules::SplitMailCites(bool* aHandled)
}
if (NS_WARN_IF(!pointToSplit.GetContainerAsContent())) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
SplitNodeResult splitCiteNodeResult =
@ -2153,10 +2143,10 @@ HTMLEditRules::SplitMailCites(bool* aHandled)
*citeNode, pointToSplit,
SplitAtEdges::eDoNotCreateEmptyContainer);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(splitCiteNodeResult.Failed())) {
return splitCiteNodeResult.Rv();
return EditActionIgnored(splitCiteNodeResult.Rv());
}
pointToSplit.Clear();
@ -2186,7 +2176,7 @@ HTMLEditRules::SplitMailCites(bool* aHandled)
HTMLEditorRef().InsertBrElementWithTransaction(
endOfPreviousNodeOfSplitPoint);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(invisibleBrElement,
"Failed to create an invisible <br> element");
@ -2200,10 +2190,10 @@ HTMLEditRules::SplitMailCites(bool* aHandled)
RefPtr<Element> brElement =
HTMLEditorRef().InsertBrElementWithTransaction(pointToInsertBrNode);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
// Now, offset of pointToInsertBrNode is invalid. Let's clear it.
pointToInsertBrNode.Clear();
@ -2219,10 +2209,10 @@ HTMLEditRules::SplitMailCites(bool* aHandled)
SelectionRefPtr()->Collapse(atBrNode, error);
if (NS_WARN_IF(!CanHandleEditAction())) {
error.SuppressException();
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
return EditActionIgnored(error.StealNSResult());
}
// if citeNode wasn't a block, we might also want another break before it.
@ -2254,10 +2244,10 @@ HTMLEditRules::SplitMailCites(bool* aHandled)
HTMLEditorRef().InsertBrElementWithTransaction(
pointToCreateNewBrNode);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
return EditActionIgnored(NS_ERROR_FAILURE);
}
// Now, those points may be invalid.
pointToCreateNewBrNode.Clear();
@ -2273,15 +2263,15 @@ HTMLEditRules::SplitMailCites(bool* aHandled)
HTMLEditorRef().IsEmptyNode(previousNodeOfSplitPoint, &bEmptyCite,
true, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
if (bEmptyCite) {
rv = HTMLEditorRef().DeleteNodeWithTransaction(*previousNodeOfSplitPoint);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
}
}
@ -2290,21 +2280,20 @@ HTMLEditRules::SplitMailCites(bool* aHandled)
nsresult rv =
HTMLEditorRef().IsEmptyNode(citeNode, &bEmptyCite, true, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
if (bEmptyCite) {
rv = HTMLEditorRef().DeleteNodeWithTransaction(*citeNode);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
}
}
*aHandled = true;
return NS_OK;
return EditActionHandled();
}

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

@ -100,6 +100,7 @@ public:
nsIEditor::EDirection aDirection) override;
virtual nsresult AfterEdit(EditSubAction aEditSubAction,
nsIEditor::EDirection aDirection) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual nsresult WillDoAction(EditSubActionInfo& aInfo,
bool* aCancel,
bool* aHandled) override;
@ -212,14 +213,12 @@ protected:
MOZ_MUST_USE nsresult WillLoadHTML();
/**
* WillInsertBreak() is called when insertParagraph command is executed
* or something equivalent. This method actually tries to insert new
* paragraph or <br> element, etc.
*
* @param aCancel Returns true if target node is not editable.
* @param aHandled Returns true if actually insert new break.
* WillInsertParagraphSeparator() is called when insertParagraph command is
* executed or something equivalent. This method actually tries to insert
* new paragraph or <br> element, etc.
*/
nsresult WillInsertBreak(bool* aCancel, bool* aHandled);
MOZ_CAN_RUN_SCRIPT
MOZ_MUST_USE EditActionResult WillInsertParagraphSeparator();
/**
* If aNode is a text node that contains only collapsed whitespace, delete
@ -244,11 +243,9 @@ protected:
* Selection starts from inside a mail-cite element. Of course, if it's
* necessary, this inserts <br> node to new left nodes or existing right
* nodes.
*
* @param aHandled Returns true if succeeded to split mail-cite
* elements.
*/
MOZ_MUST_USE nsresult SplitMailCites(bool* aHandled);
MOZ_CAN_RUN_SCRIPT
MOZ_MUST_USE EditActionResult SplitMailCites();
/**
* Called before deleting selected contents. This method actually removes

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

@ -52,11 +52,15 @@ TextEditRules::CreateBRInternal(const EditorRawDOMPoint& aPointToInsert,
bool aCreateMozBR);
#define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
if (IsReadonly() || IsDisabled()) \
{ \
if (IsReadonly() || IsDisabled()) {\
*aCancel = true; \
return NS_OK; \
};
return NS_OK; \
}
#define CANCEL_OPERATION_AND_RETURN_EDIT_ACTION_RESULT_IF_READONLY_OF_DISABLED \
if (IsReadonly() || IsDisabled()) { \
return EditActionCanceled(NS_OK); \
}
/********************************************************
* mozilla::TextEditRules
@ -318,9 +322,17 @@ TextEditRules::WillDoAction(EditSubActionInfo& aInfo,
// my kingdom for dynamic cast
switch (aInfo.mEditSubAction) {
case EditSubAction::eInsertParagraphSeparator:
case EditSubAction::eInsertParagraphSeparator: {
UndefineCaretBidiLevel();
return WillInsertBreak(aCancel, aHandled, aInfo.maxLength);
EditActionResult result = WillInsertLineBreak(aInfo.maxLength);
if (NS_WARN_IF(result.Failed())) {
return result.Rv();
}
*aCancel = result.Canceled();
*aHandled = result.Handled();
MOZ_ASSERT(!result.Ignored());
return NS_OK;
}
case EditSubAction::eInsertText:
case EditSubAction::eInsertTextComingFromIME:
UndefineCaretBidiLevel();
@ -424,56 +436,47 @@ TextEditRules::WillInsert(bool* aCancel)
return NS_OK;
}
nsresult
TextEditRules::WillInsertBreak(bool* aCancel,
bool* aHandled,
int32_t aMaxLength)
EditActionResult
TextEditRules::WillInsertLineBreak(int32_t aMaxLength)
{
MOZ_ASSERT(IsEditorDataAvailable());
if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
return NS_ERROR_INVALID_ARG;
MOZ_ASSERT(!IsSingleLineEditor());
CANCEL_OPERATION_AND_RETURN_EDIT_ACTION_RESULT_IF_READONLY_OF_DISABLED
// handle docs with a max length
// NOTE, this function copies inString into outString for us.
NS_NAMED_LITERAL_STRING(inString, "\n");
nsAutoString outString;
bool didTruncate;
nsresult rv =
TruncateInsertionIfNeeded(&inString.AsString(),
&outString, aMaxLength, &didTruncate);
if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionIgnored(rv);
}
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
*aHandled = false;
if (IsSingleLineEditor()) {
*aCancel = true;
} else {
// handle docs with a max length
// NOTE, this function copies inString into outString for us.
NS_NAMED_LITERAL_STRING(inString, "\n");
nsAutoString outString;
bool didTruncate;
nsresult rv =
TruncateInsertionIfNeeded(&inString.AsString(),
&outString, aMaxLength, &didTruncate);
if (didTruncate) {
return EditActionCanceled();
}
// if the selection isn't collapsed, delete it.
if (!SelectionRefPtr()->IsCollapsed()) {
rv = TextEditorRef().DeleteSelectionAsSubAction(nsIEditor::eNone,
nsIEditor::eStrip);
if (NS_WARN_IF(!CanHandleEditAction())) {
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (didTruncate) {
*aCancel = true;
return NS_OK;
}
*aCancel = false;
// if the selection isn't collapsed, delete it.
if (!SelectionRefPtr()->IsCollapsed()) {
rv = TextEditorRef().DeleteSelectionAsSubAction(nsIEditor::eNone,
nsIEditor::eStrip);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
rv = WillInsert();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionIgnored(rv);
}
}
return NS_OK;
rv = WillInsert();
if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionIgnored(rv);
}
return EditActionIgnored();
}
nsresult

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

@ -185,13 +185,11 @@ protected:
* This method removes selected text if selection isn't collapsed.
* Therefore, this might cause destroying the editor.
*
* @param aCancel Returns true if the operation is canceled.
* @param aHandled Returns true if the edit action is handled.
* @param aMaxLength The maximum string length which the editor
* allows to set.
*/
MOZ_MUST_USE nsresult
WillInsertBreak(bool* aCancel, bool* aHandled, int32_t aMaxLength);
MOZ_CAN_RUN_SCRIPT
MOZ_MUST_USE EditActionResult WillInsertLineBreak(int32_t aMaxLength);
/**
* Called before setting text to the text editor.