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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user