Bug 1574852 - part 108: Move `TextEditRules::WillOutputText()` to `TextEditor` r=m_kato

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2019-09-13 03:44:33 +00:00
Родитель af80a20e09
Коммит 75507785e6
5 изменённых файлов: 75 добавлений и 111 удалений

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

@ -754,12 +754,6 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
*aCancel = false;
*aHandled = false;
// Deal with actions for which we don't need to check whether the selection is
// editable.
if (aInfo.mEditSubAction == EditSubAction::eComputeTextToOutput) {
return TextEditRules::WillDoAction(aInfo, aCancel, aHandled);
}
AutoSafeEditorData setData(*this, *mHTMLEditor);
EditActionResult result = HTMLEditorRef().CanHandleHTMLEditSubAction();
@ -786,6 +780,7 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
return NS_OK;
}
case EditSubAction::eComputeTextToOutput:
case EditSubAction::eCreateOrChangeDefinitionListItem:
case EditSubAction::eCreateOrChangeList:
case EditSubAction::eCreateOrRemoveBlock:
@ -825,6 +820,7 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo,
case EditSubAction::eInsertElement:
case EditSubAction::eInsertQuotedText:
return NS_OK;
case EditSubAction::eComputeTextToOutput:
case EditSubAction::eCreateOrChangeDefinitionListItem:
case EditSubAction::eCreateOrChangeList:
case EditSubAction::eCreateOrRemoveBlock:

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

@ -205,9 +205,6 @@ nsresult TextEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
case EditSubAction::eSetText:
TextEditorRef().UndefineCaretBidiLevel();
return WillSetText(aCancel, aHandled, aInfo.inString, aInfo.maxLength);
case EditSubAction::eComputeTextToOutput:
return WillOutputText(aInfo.outputFormat, aInfo.outString, aInfo.flags,
aCancel, aHandled);
case EditSubAction::eInsertQuotedText: {
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
@ -221,6 +218,7 @@ nsresult TextEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
"Failed to remove padding <br> element");
return rv;
}
case EditSubAction::eComputeTextToOutput:
case EditSubAction::eDeleteSelectedContent:
case EditSubAction::eInsertElement:
case EditSubAction::eInsertLineBreak:
@ -242,6 +240,7 @@ nsresult TextEditRules::DidDoAction(EditSubActionInfo& aInfo,
}
switch (aInfo.mEditSubAction) {
case EditSubAction::eComputeTextToOutput:
case EditSubAction::eDeleteSelectedContent:
case EditSubAction::eInsertElement:
case EditSubAction::eInsertLineBreak:
@ -900,61 +899,35 @@ EditActionResult TextEditor::HandleDeleteSelectionInternal(
return EditActionHandled(rv);
}
nsresult TextEditRules::WillOutputText(const nsAString* aOutputFormat,
nsAString* aOutString, uint32_t aFlags,
bool* aCancel, bool* aHandled) {
MOZ_ASSERT(IsEditorDataAvailable());
// null selection ok
if (NS_WARN_IF(!aOutString) || NS_WARN_IF(!aOutputFormat) ||
NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
return NS_ERROR_NULL_POINTER;
}
// initialize out param
*aCancel = false;
*aHandled = false;
if (!aOutputFormat->LowerCaseEqualsLiteral("text/plain")) {
return NS_OK;
}
EditActionResult TextEditor::ComputeValueFromTextNodeAndPaddingBRElement(
nsAString& aValue) const {
MOZ_ASSERT(IsEditActionDataAvailable());
// If there is a padding <br> element, there's no content. So output empty
// string.
if (TextEditorRef().HasPaddingBRElementForEmptyEditor()) {
aOutString->Truncate();
*aHandled = true;
return NS_OK;
}
// If it's necessary to check selection range or the editor wraps hard,
// we need some complicated handling. In such case, we need to use the
// expensive path.
// XXX Anything else what we cannot return plain text simply?
if (aFlags & nsIDocumentEncoder::OutputSelectionOnly ||
aFlags & nsIDocumentEncoder::OutputWrap) {
return NS_OK;
if (HasPaddingBRElementForEmptyEditor()) {
aValue.Truncate();
return EditActionHandled();
}
// If it's neither <input type="text"> nor <textarea>, e.g., an HTML editor
// which is in plaintext mode (e.g., plaintext email composer on Thunderbird),
// it should be handled by the expensive path.
if (TextEditorRef().AsHTMLEditor()) {
return NS_OK;
if (AsHTMLEditor()) {
return EditActionIgnored();
}
Element* root = TextEditorRef().GetRoot();
if (!root) { // Don't warn it, this is possible, e.g., 997805.html
aOutString->Truncate();
*aHandled = true;
return NS_OK;
Element* anonymousDivElement = GetRoot();
if (!anonymousDivElement) {
// Don't warn this case, this is possible, e.g., 997805.html
aValue.Truncate();
return EditActionHandled();
}
nsIContent* firstChild = root->GetFirstChild();
if (!firstChild) {
aOutString->Truncate();
*aHandled = true;
return NS_OK;
nsIContent* textNodeOrPaddingBRElement = anonymousDivElement->GetFirstChild();
if (!textNodeOrPaddingBRElement) {
aValue.Truncate();
return EditActionHandled();
}
// If it's an <input type="text"> element, the DOM tree should be:
@ -970,9 +943,17 @@ nsresult TextEditRules::WillOutputText(const nsAString* aOutputFormat,
// ...
// </div>
Text* text = firstChild->GetAsText();
Text* textNode = textNodeOrPaddingBRElement->GetAsText();
if (!textNode) {
// If there is no text node in the expected DOM tree, we can say that it's
// just empty.
aValue.Truncate();
return EditActionHandled();
}
nsIContent* firstChildExceptText =
text ? firstChild->GetNextSibling() : firstChild;
textNode ? textNodeOrPaddingBRElement->GetNextSibling()
: textNodeOrPaddingBRElement;
// If the DOM tree is unexpected, fall back to the expensive path.
bool isInput = IsSingleLineEditor();
bool isTextarea = !isInput;
@ -982,22 +963,12 @@ nsresult TextEditRules::WillOutputText(const nsAString* aOutputFormat,
!EditorBase::IsPaddingBRElementForEmptyLastLine(
*firstChildExceptText) &&
!firstChildExceptText->IsXULElement(nsGkAtoms::scrollbar))) {
return NS_OK;
return EditActionIgnored();
}
// If there is no text node in the expected DOM tree, we can say that it's
// just empty.
if (!text) {
aOutString->Truncate();
*aHandled = true;
return NS_OK;
}
// Otherwise, the text is the value.
text->GetData(*aOutString);
*aHandled = true;
return NS_OK;
// Otherwise, the text data is the value.
textNode->GetData(aValue);
return EditActionHandled();
}
nsresult TextEditRules::CreateTrailingBRIfNeeded() {

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

@ -122,17 +122,6 @@ class TextEditRules {
const nsAString* inString,
int32_t aMaxLength);
/**
* Called prior to nsIEditor::OutputToString.
*
* @param aInFormat The format requested for the output, a MIME type.
* @param aOutText The string to use for output, if aCancel is set to true.
* @param aOutCancel If set to true, the caller should cancel the operation
* and use aOutText as the result.
*/
nsresult WillOutputText(const nsAString* aInFormat, nsAString* aOutText,
uint32_t aFlags, bool* aOutCancel, bool* aHandled);
/**
* Creates a trailing break in the text doc if there is not one already.
*/

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

@ -1851,12 +1851,10 @@ TextEditor::OutputToString(const nsAString& aFormatType,
nsresult rv =
ComputeValueInternal(aFormatType, aDocumentEncoderFlags, aOutputString);
if (NS_WARN_IF(NS_FAILED(rv))) {
// This is low level API for XUL applcation. So, we should return raw
// error code here.
return rv;
}
return NS_OK;
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ComputeValueInternal() failed");
// This is low level API for XUL application. So, we should return raw
// error code here.
return rv;
}
nsresult TextEditor::ComputeValueInternal(const nsAString& aFormatType,
@ -1864,27 +1862,26 @@ nsresult TextEditor::ComputeValueInternal(const nsAString& aFormatType,
nsAString& aOutputString) const {
MOZ_ASSERT(IsEditActionDataAvailable());
// Protect the edit rules object from dying
RefPtr<TextEditRules> rules(mRules);
EditSubActionInfo subActionInfo(EditSubAction::eComputeTextToOutput);
subActionInfo.outString = &aOutputString;
subActionInfo.flags = aDocumentEncoderFlags;
subActionInfo.outputFormat = &aFormatType;
bool cancel{false};
bool handled{false};
nsresult rv = rules->WillDoAction(subActionInfo, &cancel, &handled);
if (NS_FAILED(rv) || cancel) {
return rv;
}
if (handled) {
// This case will get triggered by password fields or single text node only.
return rv;
// First, let's try to get the value simply only from text node if the
// caller wants plaintext value.
if (aFormatType.LowerCaseEqualsLiteral("text/plain")) {
// If it's necessary to check selection range or the editor wraps hard,
// we need some complicated handling. In such case, we need to use the
// expensive path.
// XXX Anything else what we cannot return the text node data simply?
if (!(aDocumentEncoderFlags & (nsIDocumentEncoder::OutputSelectionOnly |
nsIDocumentEncoder::OutputWrap))) {
EditActionResult result =
ComputeValueFromTextNodeAndPaddingBRElement(aOutputString);
if (NS_WARN_IF(result.Failed()) || result.Canceled() ||
result.Handled()) {
return result.Rv();
}
}
}
nsAutoCString charset;
rv = GetDocumentCharsetInternal(charset);
nsresult rv = GetDocumentCharsetInternal(charset);
if (NS_FAILED(rv) || charset.IsEmpty()) {
charset.AssignLiteral("windows-1252");
}
@ -1895,12 +1892,10 @@ nsresult TextEditor::ComputeValueInternal(const nsAString& aFormatType,
return NS_ERROR_FAILURE;
}
// XXX Why don't we call TextEditRules::DidDoAction() here?
rv = encoder->EncodeToString(aOutputString);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"nsIDocumentEncoder::EncodeToString() failed");
return rv;
}
nsresult TextEditor::PasteAsQuotationAsAction(int32_t aClipboardType,
@ -2010,7 +2005,7 @@ nsresult TextEditor::InsertWithQuotationsAsSubAction(
}
nsresult TextEditor::SharedOutputString(uint32_t aFlags, bool* aIsCollapsed,
nsAString& aResult) {
nsAString& aResult) const {
MOZ_ASSERT(IsEditActionDataAvailable());
*aIsCollapsed = SelectionRefPtr()->IsCollapsed();
@ -2019,7 +2014,10 @@ nsresult TextEditor::SharedOutputString(uint32_t aFlags, bool* aIsCollapsed,
aFlags |= nsIDocumentEncoder::OutputSelectionOnly;
}
// If the selection isn't collapsed, we'll use the whole document.
return ComputeValueInternal(NS_LITERAL_STRING("text/plain"), aFlags, aResult);
nsresult rv =
ComputeValueInternal(NS_LITERAL_STRING("text/plain"), aFlags, aResult);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ComputeValueInternal() failed");
return rv;
}
void TextEditor::OnStartToHandleTopLevelEditSubAction(

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

@ -650,6 +650,16 @@ class TextEditor : public EditorBase,
HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
nsIEditor::EStripWrappers aStripWrappers);
/**
* ComputeValueFromTextNodeAndPaddingBRElement() tries to compute "value" of
* this editor content only with text node and padding `<br>` element.
* If this succeeds to compute the value, it's returned with aValue and
* the result is marked as "handled". Otherwise, the caller needs to
* compute it with another way.
*/
EditActionResult ComputeValueFromTextNodeAndPaddingBRElement(
nsAString& aValue) const;
protected: // Called by helper classes.
virtual void OnStartToHandleTopLevelEditSubAction(
EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;
@ -821,7 +831,7 @@ class TextEditor : public EditorBase,
* string.
*/
nsresult SharedOutputString(uint32_t aFlags, bool* aIsCollapsed,
nsAString& aResult);
nsAString& aResult) const;
/**
* See comment of IsCopyToClipboardAllowed() for the detail.