From d5caa7c6c03787f07e9e6fced61a0c0673b2187d Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Mon, 3 Apr 2017 20:40:48 +0300 Subject: [PATCH] Bug 1352687, try to recycle HTMLInputElement's nsTextEditorState, r=baku --HG-- extra : rebase_source : 05c8dc2bd0c29ce3064548e1cabac2d62803cabc --- dom/base/nsContentUtils.cpp | 3 +++ dom/html/HTMLInputElement.cpp | 30 +++++++++++++++++++++++++++--- dom/html/HTMLInputElement.h | 7 +++++++ dom/html/nsTextEditorState.cpp | 28 ++++++++++++++++++++++++++++ dom/html/nsTextEditorState.h | 15 ++++++++++++++- 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 21199be48e76..54460bb56782 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -44,6 +44,7 @@ #include "mozilla/dom/Element.h" #include "mozilla/dom/FileSystemSecurity.h" #include "mozilla/dom/FileBlobImpl.h" +#include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/dom/HTMLTemplateElement.h" #include "mozilla/dom/HTMLContentElement.h" @@ -1990,6 +1991,8 @@ nsContentUtils::Shutdown() sModifierSeparator = nullptr; NS_IF_RELEASE(sSameOriginChecker); + + HTMLInputElement::Shutdown(); } /** diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 9a95564416d5..8a99d8d95a15 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -1048,6 +1048,28 @@ static nsresult FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget, const nsAString& aEventType); #endif +nsTextEditorState* HTMLInputElement::sCachedTextEditorState = nullptr; +bool HTMLInputElement::sShutdown = false; + +/* static */ void +HTMLInputElement::ReleaseTextEditorState(nsTextEditorState* aState) +{ + if (!sShutdown && !sCachedTextEditorState) { + aState->PrepareForReuse(); + sCachedTextEditorState = aState; + } else { + delete aState; + } +} + +/* static */ void +HTMLInputElement::Shutdown() +{ + sShutdown = true; + delete sCachedTextEditorState; + sCachedTextEditorState = nullptr; +} + // // construction, destruction // @@ -1079,7 +1101,8 @@ HTMLInputElement::HTMLInputElement(already_AddRefed& aNo , mSelectionCached(true) { // We are in a type=text so we now we currenty need a nsTextEditorState. - mInputData.mState = new nsTextEditorState(this); + mInputData.mState = + nsTextEditorState::Construct(this, &sCachedTextEditorState); if (!gUploadLastDir) HTMLInputElement::InitUploadLastDir(); @@ -1112,7 +1135,7 @@ HTMLInputElement::FreeData() mInputData.mValue = nullptr; } else { UnbindFromFrame(nullptr); - delete mInputData.mState; + ReleaseTextEditorState(mInputData.mState); mInputData.mState = nullptr; } } @@ -5027,7 +5050,8 @@ HTMLInputElement::HandleTypeChange(uint8_t aNewType, bool aNotify) if (IsSingleLineTextControl()) { - mInputData.mState = new nsTextEditorState(this); + mInputData.mState = + nsTextEditorState::Construct(this, &sCachedTextEditorState); if (!sp.IsDefault()) { mInputData.mState->SetSelectionProperties(sp); } diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index 00b9cdebb823..094351356f60 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -858,6 +858,8 @@ public: void UpdateEntries(const nsTArray& aFilesOrDirectories); + static void Shutdown(); + protected: virtual ~HTMLInputElement(); @@ -1771,6 +1773,11 @@ private: nsCOMPtr mFilePicker; RefPtr mInput; }; + + static void ReleaseTextEditorState(nsTextEditorState* aState); + + static nsTextEditorState* sCachedTextEditorState; + static bool sShutdown; }; } // namespace dom diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index 6966c7c94b90..db30d2f80aa5 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -1068,10 +1068,38 @@ nsTextEditorState::nsTextEditorState(nsITextControlElement* aOwningElement) , mSelectionRestoreEagerInit(false) , mPlaceholderVisibility(false) , mIsCommittingComposition(false) + // When adding more member variable initializations here, add the same + // also to ::Construct. { MOZ_COUNT_CTOR(nsTextEditorState); } +nsTextEditorState* +nsTextEditorState::Construct(nsITextControlElement* aOwningElement, + nsTextEditorState** aReusedState) +{ + if (*aReusedState) { + nsTextEditorState* state = *aReusedState; + *aReusedState = nullptr; + state->mTextCtrlElement = aOwningElement; + state->mBoundFrame = nullptr; + state->mSelectionProperties = SelectionProperties(); + state->mEverInited = false; + state->mEditorInitialized = false; + state->mInitializing = false; + state->mValueTransferInProgress = false; + state->mSelectionCached = true; + state->mSelectionRestoreEagerInit = false; + state->mPlaceholderVisibility = false; + state->mIsCommittingComposition = false; + // When adding more member variable initializations here, add the same + // also to the constructor. + return state; + } + + return new nsTextEditorState(aOwningElement); +} + nsTextEditorState::~nsTextEditorState() { MOZ_COUNT_DTOR(nsTextEditorState); diff --git a/dom/html/nsTextEditorState.h b/dom/html/nsTextEditorState.h index e6a56e32c6f7..e6c8423d5134 100644 --- a/dom/html/nsTextEditorState.h +++ b/dom/html/nsTextEditorState.h @@ -135,11 +135,24 @@ class nsTextEditorState : public mozilla::SupportsWeakPtr { public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsTextEditorState) explicit nsTextEditorState(nsITextControlElement* aOwningElement); + static nsTextEditorState* + Construct(nsITextControlElement* aOwningElement, + nsTextEditorState** aReusedState); ~nsTextEditorState(); void Traverse(nsCycleCollectionTraversalCallback& cb); void Unlink(); + void PrepareForReuse() + { + Unlink(); + mValue.reset(); + mCachedValue.Truncate(); + mValueBeingSet.Truncate(); + mTextCtrlElement = nullptr; + MOZ_ASSERT(!mMutationObserver); + } + nsIEditor* GetEditor(); nsISelectionController* GetSelectionController() const; nsFrameSelection* GetConstFrameSelection(); @@ -401,7 +414,7 @@ private: // The text control element owns this object, and ensures that this object // has a smaller lifetime. - nsITextControlElement* const MOZ_NON_OWNING_REF mTextCtrlElement; + nsITextControlElement* MOZ_NON_OWNING_REF mTextCtrlElement; // mSelCon is non-null while we have an mBoundFrame. RefPtr mSelCon; RefPtr mRestoringSelection;