Do style reresolves and restyles due to attribute changes asynchronously so

that pages that modify two or more style properties of the same object in a row
work faster.  Bug 230170, r+sr=dbaron


git-svn-id: svn://10.0.0.236/trunk@160587 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bzbarsky%mit.edu
2004-08-10 03:24:41 +00:00
parent dda1e6cda9
commit bc3dc7ebe0
10 changed files with 402 additions and 93 deletions

View File

@@ -115,6 +115,7 @@
#include "nsBoxFrame.h"
static NS_DEFINE_CID(kTextNodeCID, NS_TEXTNODE_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
#include "nsIDOMWindowInternal.h"
#include "nsIMenuFrame.h"
@@ -1303,6 +1304,14 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument)
nsContentUtils::GetBoolPref("nglayout.debug.enable_xbl_forms");
}
// XXXbz this should be in Init() or something!
if (!mPendingRestyles.Init()) {
// now what?
}
// XXXbz this should be in Init() or something!
mEventQueueService = do_GetService(kEventQueueServiceCID);
#ifdef DEBUG
static PRBool gFirstTime = PR_TRUE;
if (gFirstTime) {
@@ -9888,12 +9897,18 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList,
void
nsCSSFrameConstructor::RestyleElement(nsPresContext *aPresContext,
nsIContent *aContent,
nsIFrame *aPrimaryFrame)
nsIFrame *aPrimaryFrame,
nsChangeHint aMinHint)
{
if (aPrimaryFrame) {
if (aMinHint & nsChangeHint_ReconstructFrame) {
RecreateFramesForContent(aPresContext, aContent);
} else if (aPrimaryFrame) {
nsStyleChangeList changeList;
if (aMinHint != NS_STYLE_HINT_NONE) {
changeList.AppendChange(aPrimaryFrame, aContent, aMinHint);
}
nsChangeHint frameChange = aPresContext->GetPresShell()->FrameManager()->
ComputeStyleChangeFor(aPrimaryFrame, &changeList, NS_STYLE_HINT_NONE);
ComputeStyleChangeFor(aPrimaryFrame, &changeList, aMinHint);
if (frameChange & nsChangeHint_ReconstructFrame) {
RecreateFramesForContent(aPresContext, aContent);
@@ -9926,7 +9941,7 @@ nsCSSFrameConstructor::RestyleLaterSiblings(nsPresContext *aPresContext,
nsIFrame* primaryFrame = nsnull;
shell->GetPrimaryFrameFor(child, &primaryFrame);
RestyleElement(aPresContext, child, primaryFrame);
RestyleElement(aPresContext, child, primaryFrame, NS_STYLE_HINT_NONE);
}
}
@@ -9973,12 +9988,8 @@ nsCSSFrameConstructor::DoContentStateChanged(nsPresContext* aPresContext,
nsReStyleHint rshint =
styleSet->HasStateDependentStyle(aPresContext, aContent, aStateMask);
if (rshint & eReStyle_Self) {
RestyleElement(aPresContext, aContent, primaryFrame);
}
if (rshint & eReStyle_LaterSiblings) {
RestyleLaterSiblings(aPresContext, aContent);
}
PostRestyleEvent(aContent, rshint, NS_STYLE_HINT_NONE);
}
}
}
@@ -10068,43 +10079,19 @@ nsCSSFrameConstructor::AttributeChanged(nsPresContext* aPresContext,
aAttribute,
aModType);
if (reframe) {
result = RecreateFramesForContent(aPresContext, aContent);
} else if (primaryFrame) {
nsStyleChangeList changeList;
// put primary frame on list to deal with, re-resolve may update or add next in flows
changeList.AppendChange(primaryFrame, aContent, hint);
// there is an effect, so compute it
if (rshint & eReStyle_Self) {
hint = frameManager->ComputeStyleChangeFor(primaryFrame, &changeList,
hint);
}
// hint is for primary only
if (hint & nsChangeHint_ReconstructFrame) {
result = RecreateFramesForContent(aPresContext, aContent);
changeList.Clear();
} else {
// let the frame deal with it, since we don't know how to
result = primaryFrame->AttributeChanged(aPresContext, aContent,
aNameSpaceID, aAttribute,
aModType);
// XXXwaterson should probably check for special IB siblings
// here, and propagate the AttributeChanged notification to
// them, as well. Currently, inline frames don't do anything on
// this notification, so it's not that big a deal.
// handle any children (primary may be on list too)
ProcessRestyledFrames(changeList, aPresContext);
}
} else if (rshint & eReStyle_Self) {
result = MaybeRecreateFramesForContent(aPresContext, aContent);
// let the frame deal with it now, so we don't have to deal later
if (primaryFrame) {
result = primaryFrame->AttributeChanged(aPresContext, aContent,
aNameSpaceID, aAttribute,
aModType);
// XXXwaterson should probably check for special IB siblings
// here, and propagate the AttributeChanged notification to
// them, as well. Currently, inline frames don't do anything on
// this notification, so it's not that big a deal.
}
if (rshint & eReStyle_LaterSiblings) {
RestyleLaterSiblings(aPresContext, aContent);
}
PostRestyleEvent(aContent, rshint, hint);
return result;
}
@@ -10125,6 +10112,13 @@ nsCSSFrameConstructor::WillDestroyFrameTree()
{
// Prevent frame tree destruction from being O(N^2)
mQuoteList.Clear();
// Cancel all pending reresolves
mRestyleEventQueue = nsnull;
nsCOMPtr<nsIEventQueue> eventQueue;
mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
getter_AddRefs(eventQueue));
eventQueue->RevokeEvents(this);
}
//STATIC
@@ -13312,3 +13306,108 @@ nsresult nsCSSFrameConstructor::RemoveFixedItems(nsPresContext* aPresContext,
return rv;
}
PR_STATIC_CALLBACK(PLDHashOperator)
ProcessRestyle(nsISupports* aContent,
nsCSSFrameConstructor::RestyleData& aData,
void* aPresContext)
{
nsPresContext* context = NS_STATIC_CAST(nsPresContext*, aPresContext);
nsIContent* content = NS_STATIC_CAST(nsIContent*, aContent);
if (!content->GetDocument() ||
content->GetDocument() != context->GetDocument()) {
// Content node has been removed from our document; nothing else to do here
return PL_DHASH_NEXT;
}
nsIPresShell* shell = context->PresShell();
nsIFrame* primaryFrame = nsnull;
shell->GetPrimaryFrameFor(content, &primaryFrame);
if (aData.mRestyleHint & eReStyle_Self) {
shell->FrameConstructor()->RestyleElement(context, content, primaryFrame,
aData.mChangeHint);
} else if (aData.mChangeHint != NS_STYLE_HINT_NONE) {
// Don't need to recompute style; just apply the hint
nsStyleChangeList changeList;
changeList.AppendChange(primaryFrame, content, aData.mChangeHint);
shell->FrameConstructor()->ProcessRestyledFrames(changeList, context);
}
if (aData.mRestyleHint & eReStyle_LaterSiblings) {
shell->FrameConstructor()->RestyleLaterSiblings(context, content);
}
return PL_DHASH_NEXT;
}
void
nsCSSFrameConstructor::ProcessPendingRestyles()
{
NS_PRECONDITION(mDocument, "No document? Pshaw!\n");
nsIPresShell* shell = mDocument->GetShellAt(0);
nsPresContext* context = shell->GetPresContext();
mPendingRestyles.Enumerate(ProcessRestyle, context);
mPendingRestyles.Clear();
}
void
nsCSSFrameConstructor::PostRestyleEvent(nsIContent* aContent,
nsReStyleHint aRestyleHint,
nsChangeHint aMinChangeHint)
{
if (aRestyleHint == 0 && aMinChangeHint == NS_STYLE_HINT_NONE) {
// Nothing to do here
return;
}
RestyleData existingData;
existingData.mRestyleHint = nsReStyleHint(0);
existingData.mChangeHint = NS_STYLE_HINT_NONE;
mPendingRestyles.Get(aContent, &existingData);
existingData.mRestyleHint =
nsReStyleHint(existingData.mRestyleHint | aRestyleHint);
NS_UpdateHint(existingData.mChangeHint, aMinChangeHint);
mPendingRestyles.Put(aContent, existingData);
nsCOMPtr<nsIEventQueue> eventQueue;
mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
getter_AddRefs(eventQueue));
if (eventQueue != mRestyleEventQueue) {
RestyleEvent* ev = new RestyleEvent(this);
if (NS_FAILED(eventQueue->PostEvent(ev))) {
PL_DestroyEvent(ev);
// XXXbz and what?
} else {
mRestyleEventQueue = eventQueue;
}
}
}
PR_STATIC_CALLBACK(void*)
HandleRestyleEvent(PLEvent* aEvent)
{
nsCSSFrameConstructor::RestyleEvent* evt =
NS_STATIC_CAST(nsCSSFrameConstructor::RestyleEvent*, aEvent);
evt->HandleEvent();
return nsnull;
}
PR_STATIC_CALLBACK(void)
DestroyRestyleEvent(PLEvent* aEvent)
{
delete NS_STATIC_CAST(nsCSSFrameConstructor::RestyleEvent*, aEvent);
}
nsCSSFrameConstructor::RestyleEvent::RestyleEvent(nsCSSFrameConstructor* aConstructor)
{
NS_PRECONDITION(aConstructor, "Must have a constructor!");
PL_InitEvent(this, aConstructor,
::HandleRestyleEvent, ::DestroyRestyleEvent);
}