diff --git a/mozilla/content/html/style/src/nsInspectorCSSUtils.cpp b/mozilla/content/html/style/src/nsInspectorCSSUtils.cpp
index 7c44694a9ad..e2be5d262e0 100644
--- a/mozilla/content/html/style/src/nsInspectorCSSUtils.cpp
+++ b/mozilla/content/html/style/src/nsInspectorCSSUtils.cpp
@@ -145,6 +145,7 @@ nsInspectorCSSUtils::GetStyleContextForContent(nsIContent* aContent,
{
if (!aPseudo) {
nsIFrame* frame = nsnull;
+ aPresShell->FlushPendingNotifications(Flush_StyleReresolves);
aPresShell->GetPrimaryFrameFor(aContent, &frame);
if (frame) {
nsStyleContext* result = GetStyleContextForFrame(frame);
diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp
index cd14b9df8c5..c7788f4e853 100644
--- a/mozilla/layout/base/nsCSSFrameConstructor.cpp
+++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp
@@ -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 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 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);
+}
+
diff --git a/mozilla/layout/base/nsCSSFrameConstructor.h b/mozilla/layout/base/nsCSSFrameConstructor.h
index 81488c4674c..20e8e8f4a5c 100644
--- a/mozilla/layout/base/nsCSSFrameConstructor.h
+++ b/mozilla/layout/base/nsCSSFrameConstructor.h
@@ -41,6 +41,11 @@
#include "nsILayoutHistoryState.h"
#include "nsIXBLService.h"
#include "nsQuoteList.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+#include "plevent.h"
+#include "nsIEventQueueService.h"
+#include "nsIEventQueue.h"
class nsIDocument;
struct nsFrameItems;
@@ -135,6 +140,10 @@ public:
nsresult ProcessRestyledFrames(nsStyleChangeList& aRestyleArray,
nsPresContext* aPresContext);
+ void ProcessPendingRestyles();
+ void PostRestyleEvent(nsIContent* aContent, nsReStyleHint aRestyleHint,
+ nsChangeHint aMinChangeHint);
+
// Notification that we were unable to render a replaced element.
nsresult CantRenderReplacedElement(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
@@ -192,13 +201,17 @@ private:
nsIContent* aContent,
PRInt32 aStateMask);
+public:
+ /* aMinHint is the minimal change that should be made to the element */
void RestyleElement(nsPresContext* aPresContext,
nsIContent* aContent,
- nsIFrame* aPrimaryFrame);
+ nsIFrame* aPrimaryFrame,
+ nsChangeHint aMinHint);
void RestyleLaterSiblings(nsPresContext* aPresContext,
nsIContent* aContent);
+private:
nsresult InitAndRestoreFrame (nsPresContext* aPresContext,
nsFrameConstructorState& aState,
nsIContent* aContent,
@@ -1030,6 +1043,32 @@ private:
mQuoteList.RecalcAll();
}
+public:
+ struct RestyleData;
+ friend struct RestyleData;
+
+ struct RestyleData {
+ nsReStyleHint mRestyleHint; // What we want to restyle
+ nsChangeHint mChangeHint; // The minimal change hint for "self"
+ };
+
+ struct RestyleEvent;
+ friend struct RestyleEvent;
+
+ struct RestyleEvent : public PLEvent {
+ RestyleEvent(nsCSSFrameConstructor* aConstructor);
+ ~RestyleEvent() { }
+ void HandleEvent() {
+ nsCSSFrameConstructor* constructor =
+ NS_STATIC_CAST(nsCSSFrameConstructor*, owner);
+ constructor->ProcessPendingRestyles();
+ constructor->mRestyleEventQueue = nsnull;
+ }
+ };
+
+protected:
+ nsCOMPtr mRestyleEventQueue;
+
private:
nsIDocument* mDocument;
@@ -1043,6 +1082,10 @@ private:
nsCOMPtr mTempFrameTreeState;
+ nsCOMPtr mEventQueueService;
+
+ nsDataHashtable mPendingRestyles;
+
static nsIXBLService * gXBLService;
};
diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp
index 6bfeb649172..bd04e671115 100644
--- a/mozilla/layout/base/nsPresShell.cpp
+++ b/mozilla/layout/base/nsPresShell.cpp
@@ -5081,11 +5081,18 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
IsSafeToFlush(isSafeToFlush);
if (isSafeToFlush) {
+ // XXXbz we should probably do a view batch no matter what here
+ // and just change the flag for the batch end based on whether
+ // Flush_OnlyPaint is set.
PRBool batchViews = (aType & Flush_OnlyPaint);
if (batchViews && mViewManager) {
mViewManager->BeginUpdateViewBatch();
}
+ if (aType & Flush_StyleReresolves) {
+ mFrameConstructor->ProcessPendingRestyles();
+ }
+
if (aType & Flush_OnlyReflow) {
ProcessReflowCommands(PR_FALSE);
}
diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp
index 6bfeb649172..bd04e671115 100644
--- a/mozilla/layout/html/base/src/nsPresShell.cpp
+++ b/mozilla/layout/html/base/src/nsPresShell.cpp
@@ -5081,11 +5081,18 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
IsSafeToFlush(isSafeToFlush);
if (isSafeToFlush) {
+ // XXXbz we should probably do a view batch no matter what here
+ // and just change the flag for the batch end based on whether
+ // Flush_OnlyPaint is set.
PRBool batchViews = (aType & Flush_OnlyPaint);
if (batchViews && mViewManager) {
mViewManager->BeginUpdateViewBatch();
}
+ if (aType & Flush_StyleReresolves) {
+ mFrameConstructor->ProcessPendingRestyles();
+ }
+
if (aType & Flush_OnlyReflow) {
ProcessReflowCommands(PR_FALSE);
}
diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp
index cd14b9df8c5..c7788f4e853 100644
--- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp
+++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp
@@ -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 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 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);
+}
+
diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.h b/mozilla/layout/html/style/src/nsCSSFrameConstructor.h
index 81488c4674c..20e8e8f4a5c 100644
--- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.h
+++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.h
@@ -41,6 +41,11 @@
#include "nsILayoutHistoryState.h"
#include "nsIXBLService.h"
#include "nsQuoteList.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+#include "plevent.h"
+#include "nsIEventQueueService.h"
+#include "nsIEventQueue.h"
class nsIDocument;
struct nsFrameItems;
@@ -135,6 +140,10 @@ public:
nsresult ProcessRestyledFrames(nsStyleChangeList& aRestyleArray,
nsPresContext* aPresContext);
+ void ProcessPendingRestyles();
+ void PostRestyleEvent(nsIContent* aContent, nsReStyleHint aRestyleHint,
+ nsChangeHint aMinChangeHint);
+
// Notification that we were unable to render a replaced element.
nsresult CantRenderReplacedElement(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
@@ -192,13 +201,17 @@ private:
nsIContent* aContent,
PRInt32 aStateMask);
+public:
+ /* aMinHint is the minimal change that should be made to the element */
void RestyleElement(nsPresContext* aPresContext,
nsIContent* aContent,
- nsIFrame* aPrimaryFrame);
+ nsIFrame* aPrimaryFrame,
+ nsChangeHint aMinHint);
void RestyleLaterSiblings(nsPresContext* aPresContext,
nsIContent* aContent);
+private:
nsresult InitAndRestoreFrame (nsPresContext* aPresContext,
nsFrameConstructorState& aState,
nsIContent* aContent,
@@ -1030,6 +1043,32 @@ private:
mQuoteList.RecalcAll();
}
+public:
+ struct RestyleData;
+ friend struct RestyleData;
+
+ struct RestyleData {
+ nsReStyleHint mRestyleHint; // What we want to restyle
+ nsChangeHint mChangeHint; // The minimal change hint for "self"
+ };
+
+ struct RestyleEvent;
+ friend struct RestyleEvent;
+
+ struct RestyleEvent : public PLEvent {
+ RestyleEvent(nsCSSFrameConstructor* aConstructor);
+ ~RestyleEvent() { }
+ void HandleEvent() {
+ nsCSSFrameConstructor* constructor =
+ NS_STATIC_CAST(nsCSSFrameConstructor*, owner);
+ constructor->ProcessPendingRestyles();
+ constructor->mRestyleEventQueue = nsnull;
+ }
+ };
+
+protected:
+ nsCOMPtr mRestyleEventQueue;
+
private:
nsIDocument* mDocument;
@@ -1043,6 +1082,10 @@ private:
nsCOMPtr mTempFrameTreeState;
+ nsCOMPtr mEventQueueService;
+
+ nsDataHashtable mPendingRestyles;
+
static nsIXBLService * gXBLService;
};
diff --git a/mozilla/layout/style/nsInspectorCSSUtils.cpp b/mozilla/layout/style/nsInspectorCSSUtils.cpp
index 7c44694a9ad..e2be5d262e0 100644
--- a/mozilla/layout/style/nsInspectorCSSUtils.cpp
+++ b/mozilla/layout/style/nsInspectorCSSUtils.cpp
@@ -145,6 +145,7 @@ nsInspectorCSSUtils::GetStyleContextForContent(nsIContent* aContent,
{
if (!aPseudo) {
nsIFrame* frame = nsnull;
+ aPresShell->FlushPendingNotifications(Flush_StyleReresolves);
aPresShell->GetPrimaryFrameFor(aContent, &frame);
if (frame) {
nsStyleContext* result = GetStyleContextForFrame(frame);
diff --git a/mozilla/layout/xul/base/src/nsMenuFrame.cpp b/mozilla/layout/xul/base/src/nsMenuFrame.cpp
index 22f1dd68ec5..c6f3be15eca 100644
--- a/mozilla/layout/xul/base/src/nsMenuFrame.cpp
+++ b/mozilla/layout/xul/base/src/nsMenuFrame.cpp
@@ -597,8 +597,13 @@ nsMenuFrame::MarkAsGenerated()
if (child) {
nsAutoString genVal;
child->GetAttr(kNameSpaceID_None, nsXULAtoms::menugenerated, genVal);
- if (genVal.IsEmpty())
+ if (genVal.IsEmpty()) {
child->SetAttr(kNameSpaceID_None, nsXULAtoms::menugenerated, NS_LITERAL_STRING("true"), PR_TRUE);
+ // Menus assume the frame for the popup exists hereafter, so we need to
+ // flush out the style reresolve we just caused to ensure the frame gets
+ // constructed.
+ mPresContext->PresShell()->FlushPendingNotifications(Flush_StyleReresolves);
+ }
}
return NS_OK;
diff --git a/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp b/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp
index 51cc1326bfb..6ea75394467 100644
--- a/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp
+++ b/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp
@@ -492,6 +492,10 @@ nsPopupSetFrame::MarkAsGenerated(nsIContent* aPopupContent)
// Generate this element.
aPopupContent->SetAttr(kNameSpaceID_None, nsXULAtoms::menugenerated, NS_LITERAL_STRING("true"),
PR_TRUE);
+ // Menus assume the frame for the popup exists hereafter, so we need to
+ // flush out the style reresolve we just caused to ensure the frame gets
+ // constructed.
+ mPresContext->PresShell()->FlushPendingNotifications(Flush_StyleReresolves);
}
}