Bug 1398605, keep nsContentList objects alive for awhile when generating state keys so that new objects don't need to be created all the time, r=ehsan

--HG--
extra : rebase_source : 8ba989365f0c9b5fbacc9effd4a41b628614b788
This commit is contained in:
Olli Pettay 2017-09-14 21:56:58 +03:00
parent a70175c241
commit 61679d58d1
3 changed files with 86 additions and 28 deletions

View File

@ -3054,33 +3054,10 @@ nsContentUtils::GenerateStateKey(nsIContent* aContent,
if (htmlDocument) {
nsHTMLDocument* htmlDoc = static_cast<nsHTMLDocument*> (htmlDocument.get());
// Flush our content model so it'll be up to date
// If this becomes unnecessary and the following line is removed,
// please also remove the corresponding flush operation from
// nsHtml5TreeBuilderCppSupplement.h. (Look for "See bug 497861." there.)
aContent->GetUncomposedDoc()->FlushPendingNotifications(FlushType::Content);
RefPtr<nsContentList> htmlForms = htmlDoc->GetExistingForms();
if (!htmlForms) {
// If the document doesn't have an existing forms content list, create a
// new one, but avoid creating a live list since we only need to use the
// list here and it doesn't need to listen to mutation events.
// Please keep this in sync with nsHTMLDocument::GetForms().
htmlForms = new nsContentList(aDocument, kNameSpaceID_XHTML,
nsGkAtoms::form, nsGkAtoms::form,
/* aDeep = */ true,
/* aLiveList = */ false);
}
RefPtr<nsContentList> htmlFormControls =
new nsContentList(aDocument,
nsHTMLDocument::MatchFormControls,
nullptr, nullptr,
/* aDeep = */ true,
/* aMatchAtom = */ nullptr,
/* aMatchNameSpaceId = */ kNameSpaceID_None,
/* aFuncMayDependOnAttr = */ true,
/* aLiveList = */ false);
RefPtr<nsContentList> htmlForms;
RefPtr<nsContentList> htmlFormControls;
htmlDoc->GetFormsAndFormControls(getter_AddRefs(htmlForms),
getter_AddRefs(htmlFormControls));
// If we have a form control and can calculate form information, use that
// as the key - it is more reliable than just recording position in the

View File

@ -174,6 +174,7 @@ NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData)
nsHTMLDocument::nsHTMLDocument()
: nsDocument("text/html")
, mContentListHolder(nullptr)
, mNumForms(0)
, mWriteLevel(0)
, mLoadFlags(0)
@ -3754,3 +3755,50 @@ nsHTMLDocument::WillIgnoreCharsetOverride()
}
return false;
}
void
nsHTMLDocument::GetFormsAndFormControls(nsContentList** aFormList,
nsContentList** aFormControlList)
{
RefPtr<ContentListHolder> holder = mContentListHolder;
if (!holder) {
// Flush our content model so it'll be up to date
// If this becomes unnecessary and the following line is removed,
// please also remove the corresponding flush operation from
// nsHtml5TreeBuilderCppSupplement.h. (Look for "See bug 497861." there.)
//XXXsmaug nsHtml5TreeBuilderCppSupplement doesn't seem to have such flush
// anymore.
FlushPendingNotifications(FlushType::Content);
RefPtr<nsContentList> htmlForms = GetExistingForms();
if (!htmlForms) {
// If the document doesn't have an existing forms content list, create a
// new one which will be released soon by ContentListHolder.
// Please keep this in sync with nsHTMLDocument::GetForms().
htmlForms = new nsContentList(this, kNameSpaceID_XHTML,
nsGkAtoms::form, nsGkAtoms::form,
/* aDeep = */ true,
/* aLiveList = */ true);
}
RefPtr<nsContentList> htmlFormControls =
new nsContentList(this,
nsHTMLDocument::MatchFormControls,
nullptr, nullptr,
/* aDeep = */ true,
/* aMatchAtom = */ nullptr,
/* aMatchNameSpaceId = */ kNameSpaceID_None,
/* aFuncMayDependOnAttr = */ true,
/* aLiveList = */ true);
holder = new ContentListHolder(this, htmlForms, htmlFormControls);
RefPtr<ContentListHolder> runnable = holder;
if (NS_SUCCEEDED(Dispatch(TaskCategory::GarbageCollection,
runnable.forget()))) {
mContentListHolder = holder;
}
}
NS_ADDREF(*aFormList = holder->mFormList);
NS_ADDREF(*aFormControlList = holder->mFormControlList);
}

View File

@ -17,7 +17,7 @@
#include "PLDHashTable.h"
#include "nsIHttpChannel.h"
#include "nsHTMLStyleSheet.h"
#include "nsThreadUtils.h"
#include "nsICommandManager.h"
#include "mozilla/dom/HTMLSharedElement.h"
#include "mozilla/dom/BindingDeclarations.h"
@ -266,6 +266,8 @@ public:
static bool MatchFormControls(Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData);
void GetFormsAndFormControls(nsContentList** aFormList,
nsContentList** aFormControlList);
protected:
~nsHTMLDocument();
@ -312,6 +314,37 @@ protected:
void *GenerateParserKey(void);
// A helper class to keep nsContentList objects alive for a short period of
// time. Note, when the final Release is called on an nsContentList object, it
// removes itself from MutationObserver list.
class ContentListHolder : public mozilla::Runnable
{
public:
ContentListHolder(nsHTMLDocument* aDocument,
nsContentList* aFormList,
nsContentList* aFormControlList)
: mozilla::Runnable("ContentListHolder")
, mDocument(aDocument)
, mFormList(aFormList)
, mFormControlList(aFormControlList)
{
}
~ContentListHolder()
{
MOZ_ASSERT(!mDocument->mContentListHolder ||
mDocument->mContentListHolder == this);
mDocument->mContentListHolder = nullptr;
}
RefPtr<nsHTMLDocument> mDocument;
RefPtr<nsContentList> mFormList;
RefPtr<nsContentList> mFormControlList;
};
friend class ContentListHolder;
ContentListHolder* mContentListHolder;
RefPtr<nsContentList> mImages;
RefPtr<nsEmptyContentList> mApplets;
RefPtr<nsContentList> mEmbeds;