Bug 1540037 - part 31: Move `TextEditor::GetAndIniitDocEncoder()` into `EditorBase` r=m_kato

It's a helper method of `TextEditor::ComputeValueInternal()` which is used by
`TextEditor` and `HTMLEditor::Rewrap()`.  So, before we move
`ComputeValueInternal()`, we need to move this first.

Depends on D116347

Differential Revision: https://phabricator.services.mozilla.com/D116348
This commit is contained in:
Masayuki Nakano 2021-05-31 23:41:00 +00:00
Родитель d762ddd8ca
Коммит 11f319ab64
4 изменённых файлов: 95 добавлений и 91 удалений

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

@ -94,6 +94,7 @@
#include "nsGkAtoms.h" // for nsGkAtoms, nsGkAtoms::dir
#include "nsIClipboard.h" // for nsIClipboard
#include "nsIContent.h" // for nsIContent
#include "nsIDocumentEncoder.h" // for nsIDocumentEncoder
#include "nsIDocumentStateListener.h" // for nsIDocumentStateListener
#include "nsIEditActionListener.h" // for nsIEditActionListener
#include "nsIEditorObserver.h" // for nsIEditorObserver
@ -214,6 +215,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EditorBase)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocStateListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaceholderTransaction)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedDocumentEncoder)
NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -239,6 +241,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EditorBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaceholderTransaction)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedDocumentEncoder)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EditorBase)
@ -1408,6 +1411,77 @@ NS_IMETHODIMP EditorBase::SetDocumentCharacterSet(
return NS_ERROR_NOT_AVAILABLE;
}
already_AddRefed<nsIDocumentEncoder> EditorBase::GetAndInitDocEncoder(
const nsAString& aFormatType, uint32_t aDocumentEncoderFlags,
const nsACString& aCharset) const {
MOZ_ASSERT(IsEditActionDataAvailable());
nsCOMPtr<nsIDocumentEncoder> docEncoder;
if (!mCachedDocumentEncoder ||
!mCachedDocumentEncoderType.Equals(aFormatType)) {
nsAutoCString formatType;
LossyAppendUTF16toASCII(aFormatType, formatType);
docEncoder = do_createDocumentEncoder(PromiseFlatCString(formatType).get());
if (NS_WARN_IF(!docEncoder)) {
return nullptr;
}
mCachedDocumentEncoder = docEncoder;
mCachedDocumentEncoderType = aFormatType;
} else {
docEncoder = mCachedDocumentEncoder;
}
RefPtr<Document> doc = GetDocument();
NS_ASSERTION(doc, "Need a document");
nsresult rv = docEncoder->NativeInit(
doc, aFormatType,
aDocumentEncoderFlags | nsIDocumentEncoder::RequiresReinitAfterOutput);
if (NS_FAILED(rv)) {
NS_WARNING("nsIDocumentEncoder::NativeInit() failed");
return nullptr;
}
if (!aCharset.IsEmpty() && !aCharset.EqualsLiteral("null")) {
DebugOnly<nsresult> rvIgnored = docEncoder->SetCharset(aCharset);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored),
"nsIDocumentEncoder::SetCharset() failed, but ignored");
}
const int32_t wrapWidth = std::max(WrapWidth(), 0);
DebugOnly<nsresult> rvIgnored = docEncoder->SetWrapColumn(wrapWidth);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored),
"nsIDocumentEncoder::SetWrapColumn() failed, but ignored");
// Set the selection, if appropriate.
// We do this either if the OutputSelectionOnly flag is set,
// in which case we use our existing selection ...
if (aDocumentEncoderFlags & nsIDocumentEncoder::OutputSelectionOnly) {
if (NS_FAILED(docEncoder->SetSelection(&SelectionRef()))) {
NS_WARNING("nsIDocumentEncoder::SetSelection() failed");
return nullptr;
}
}
// ... or if the root element is not a body,
// in which case we set the selection to encompass the root.
else {
Element* rootElement = GetRoot();
if (NS_WARN_IF(!rootElement)) {
return nullptr;
}
if (!rootElement->IsHTMLElement(nsGkAtoms::body)) {
if (NS_FAILED(docEncoder->SetContainerNode(rootElement))) {
NS_WARNING("nsIDocumentEncoder::SetContainerNode() failed");
return nullptr;
}
}
}
return docEncoder.forget();
}
bool EditorBase::AreClipboardCommandsUnconditionallyEnabled() const {
Document* document = GetDocument();
return document && document->AreClipboardCommandsUnconditionallyEnabled();

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

@ -44,6 +44,7 @@ class mozInlineSpellChecker;
class nsAtom;
class nsCaret;
class nsIContent;
class nsIDocumentEncoder;
class nsIDocumentStateListener;
class nsIEditActionListener;
class nsIEditorObserver;
@ -2240,6 +2241,19 @@ class EditorBase : public nsIEditor,
*/
nsresult GetDocumentCharsetInternal(nsACString& aCharset) const;
/**
* GetAndInitDocEncoder() returns a document encoder instance for aFormatType
* after initializing it. The result may be cached for saving recreation
* cost.
*
* @param aFormatType MIME type like "text/plain".
* @param aDocumentEncoderFlags Flags of nsIDocumentEncoder.
* @param aCharset Encoding of the document.
*/
already_AddRefed<nsIDocumentEncoder> GetAndInitDocEncoder(
const nsAString& aFormatType, uint32_t aDocumentEncoderFlags,
const nsACString& aCharset) const;
/**
* SelectAllInternal() should be used instead of SelectAll() in editor
* because SelectAll() creates AutoEditActionSetter but we should avoid
@ -2726,6 +2740,12 @@ class EditorBase : public nsIEditor,
RefPtr<IMEContentObserver> mIMEContentObserver;
// These members cache last encoder and its type for the performance in
// TextEditor::ComputeTextValue() which is the implementation of
// `<input>.value` and `<textarea>.value`. See `GetAndInitDocEncoder()`.
mutable nsCOMPtr<nsIDocumentEncoder> mCachedDocumentEncoder;
mutable nsString mCachedDocumentEncoderType;
// Listens to all low level actions on the doc.
// Edit action listener is currently used by highlighter of the findbar and
// the spellchecker. So, we should reserve only 2 items.

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

@ -95,12 +95,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TextEditor, EditorBase)
if (tmp->mMaskTimer) {
tmp->mMaskTimer->Cancel();
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedDocumentEncoder)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMaskTimer)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TextEditor, EditorBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedDocumentEncoder)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMaskTimer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -480,77 +478,6 @@ bool TextEditor::IsCopyToClipboardAllowedInternal() const {
return mUnmaskedStart <= selectionStart && UnmaskedEnd() >= selectionEnd;
}
already_AddRefed<nsIDocumentEncoder> TextEditor::GetAndInitDocEncoder(
const nsAString& aFormatType, uint32_t aDocumentEncoderFlags,
const nsACString& aCharset) const {
MOZ_ASSERT(IsEditActionDataAvailable());
nsCOMPtr<nsIDocumentEncoder> docEncoder;
if (!mCachedDocumentEncoder ||
!mCachedDocumentEncoderType.Equals(aFormatType)) {
nsAutoCString formatType;
LossyAppendUTF16toASCII(aFormatType, formatType);
docEncoder = do_createDocumentEncoder(PromiseFlatCString(formatType).get());
if (NS_WARN_IF(!docEncoder)) {
return nullptr;
}
mCachedDocumentEncoder = docEncoder;
mCachedDocumentEncoderType = aFormatType;
} else {
docEncoder = mCachedDocumentEncoder;
}
RefPtr<Document> doc = GetDocument();
NS_ASSERTION(doc, "Need a document");
nsresult rv = docEncoder->NativeInit(
doc, aFormatType,
aDocumentEncoderFlags | nsIDocumentEncoder::RequiresReinitAfterOutput);
if (NS_FAILED(rv)) {
NS_WARNING("nsIDocumentEncoder::NativeInit() failed");
return nullptr;
}
if (!aCharset.IsEmpty() && !aCharset.EqualsLiteral("null")) {
DebugOnly<nsresult> rvIgnored = docEncoder->SetCharset(aCharset);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored),
"nsIDocumentEncoder::SetCharset() failed, but ignored");
}
const int32_t wrapWidth = std::max(WrapWidth(), 0);
DebugOnly<nsresult> rvIgnored = docEncoder->SetWrapColumn(wrapWidth);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored),
"nsIDocumentEncoder::SetWrapColumn() failed, but ignored");
// Set the selection, if appropriate.
// We do this either if the OutputSelectionOnly flag is set,
// in which case we use our existing selection ...
if (aDocumentEncoderFlags & nsIDocumentEncoder::OutputSelectionOnly) {
if (NS_FAILED(docEncoder->SetSelection(&SelectionRef()))) {
NS_WARNING("nsIDocumentEncoder::SetSelection() failed");
return nullptr;
}
}
// ... or if the root element is not a body,
// in which case we set the selection to encompass the root.
else {
dom::Element* rootElement = GetRoot();
if (NS_WARN_IF(!rootElement)) {
return nullptr;
}
if (!rootElement->IsHTMLElement(nsGkAtoms::body)) {
if (NS_FAILED(docEncoder->SetContainerNode(rootElement))) {
NS_WARNING("nsIDocumentEncoder::SetContainerNode() failed");
return nullptr;
}
}
}
return docEncoder.forget();
}
NS_IMETHODIMP TextEditor::OutputToString(const nsAString& aFormatType,
uint32_t aDocumentEncoderFlags,
nsAString& aOutputString) {
@ -602,7 +529,7 @@ nsresult TextEditor::ComputeValueInternal(const nsAString& aFormatType,
nsCOMPtr<nsIDocumentEncoder> encoder =
GetAndInitDocEncoder(aFormatType, aDocumentEncoderFlags, charset);
if (!encoder) {
NS_WARNING("TextEditor::GetAndInitDocEncoder() failed");
NS_WARNING("EditorBase::GetAndInitDocEncoder() failed");
return NS_ERROR_FAILURE;
}

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

@ -522,19 +522,6 @@ class TextEditor : public EditorBase, public nsITimerCallback, public nsINamed {
*/
bool IsSafeToInsertData(const Document* aSourceDoc) const;
/**
* GetAndInitDocEncoder() returns a document encoder instance for aFormatType
* after initializing it. The result may be cached for saving recreation
* cost.
*
* @param aFormatType MIME type like "text/plain".
* @param aDocumentEncoderFlags Flags of nsIDocumentEncoder.
* @param aCharset Encoding of the document.
*/
already_AddRefed<nsIDocumentEncoder> GetAndInitDocEncoder(
const nsAString& aFormatType, uint32_t aDocumentEncoderFlags,
const nsACString& aCharset) const;
/**
* ComputeValueInternal() computes string value of this editor for given
* format. This may be too expensive if it's in hot path.
@ -573,14 +560,10 @@ class TextEditor : public EditorBase, public nsITimerCallback, public nsINamed {
bool aForceStartMasking);
protected:
mutable nsCOMPtr<nsIDocumentEncoder> mCachedDocumentEncoder;
// Timer to mask unmasked characters automatically. Used only when it's
// a password field.
nsCOMPtr<nsITimer> mMaskTimer;
mutable nsString mCachedDocumentEncoderType;
int32_t mMaxTextLength;
// Unmasked character range. Used only when it's a password field.