From c51a96b82582955c5eabc86fa6f1b24cc9c309c8 Mon Sep 17 00:00:00 2001 From: "hyatt%netscape.com" Date: Wed, 25 Apr 2001 19:52:49 +0000 Subject: [PATCH] Fix for 77002. reviewers=jst,waterson,hixie,shaver,brendan,pavlov git-svn-id: svn://10.0.0.236/trunk@93083 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/base/src/nsDocumentViewer.cpp | 9 ++ mozilla/dom/src/base/nsGlobalWindow.cpp | 27 +++++ mozilla/layout/base/nsCSSFrameConstructor.cpp | 18 ++- mozilla/layout/base/nsCaret.cpp | 8 ++ mozilla/layout/base/nsDocumentViewer.cpp | 9 ++ mozilla/layout/base/nsIPresShell.h | 12 ++ mozilla/layout/base/nsPresShell.cpp | 106 +++++++++++++++++- mozilla/layout/base/public/nsIPresShell.h | 12 ++ mozilla/layout/base/src/nsCaret.cpp | 8 ++ mozilla/layout/forms/nsListControlFrame.cpp | 8 ++ mozilla/layout/generic/nsBlockFrame.cpp | 7 ++ mozilla/layout/generic/nsBlockReflowState.cpp | 7 ++ mozilla/layout/generic/nsBlockReflowState.h | 7 ++ mozilla/layout/generic/nsFrame.cpp | 13 +++ .../layout/generic/nsHTMLContainerFrame.cpp | 14 +++ mozilla/layout/generic/nsImageFrame.cpp | 10 ++ mozilla/layout/html/base/src/nsBlockFrame.cpp | 7 ++ .../html/base/src/nsBlockReflowState.cpp | 7 ++ .../layout/html/base/src/nsBlockReflowState.h | 7 ++ mozilla/layout/html/base/src/nsFrame.cpp | 13 +++ .../html/base/src/nsHTMLContainerFrame.cpp | 14 +++ mozilla/layout/html/base/src/nsImageFrame.cpp | 10 ++ mozilla/layout/html/base/src/nsPresShell.cpp | 106 +++++++++++++++++- .../html/forms/src/nsListControlFrame.cpp | 8 ++ .../html/style/src/nsCSSFrameConstructor.cpp | 18 ++- mozilla/layout/xul/base/src/nsBox.cpp | 7 ++ mozilla/layout/xul/base/src/nsBoxFrame.cpp | 18 +++ .../layout/xul/base/src/nsImageBoxFrame.cpp | 5 +- .../libpr0n/decoders/gif/nsGIFDecoder2.cpp | 30 ++++- .../libpr0n/decoders/gif/nsGIFDecoder2.h | 4 +- .../modules/libpr0n/src/imgRequestProxy.cpp | 12 +- .../browser/resources/content/navigator.js | 15 ++- 32 files changed, 536 insertions(+), 20 deletions(-) diff --git a/mozilla/content/base/src/nsDocumentViewer.cpp b/mozilla/content/base/src/nsDocumentViewer.cpp index badc03af80d..30e2581138c 100644 --- a/mozilla/content/base/src/nsDocumentViewer.cpp +++ b/mozilla/content/base/src/nsDocumentViewer.cpp @@ -527,6 +527,7 @@ protected: nsCOMPtr mFocusListener; PRBool mEnableRendering; + PRBool mStopped; PRInt16 mNumURLStarts; nsIPageSequenceFrame* mPageSeqFrame; @@ -793,6 +794,7 @@ DocumentViewerImpl::DocumentViewerImpl() { NS_INIT_ISUPPORTS(); mEnableRendering = PR_TRUE; + mStopped = PR_FALSE; mPrt = nsnull; mIsPrinting = PR_FALSE; @@ -1060,6 +1062,11 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) } else { // XXX: Should fire error event to the document... } + + // Now that the document has loaded, we can tell the presshell + // to unsuppress painting. + if (mPresShell) + mPresShell->UnsuppressPainting(!mStopped); return rv; } @@ -1123,6 +1130,8 @@ DocumentViewerImpl::Stop(void) // stop everything but the chrome. mPresContext->Stop(PR_FALSE); } + + mStopped = PR_TRUE; return NS_OK; } diff --git a/mozilla/dom/src/base/nsGlobalWindow.cpp b/mozilla/dom/src/base/nsGlobalWindow.cpp index b4d5a6c855f..60f9330683a 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.cpp +++ b/mozilla/dom/src/base/nsGlobalWindow.cpp @@ -1553,6 +1553,24 @@ NS_IMETHODIMP GlobalWindowImpl::Dump(const nsAReadableString& aStr) return NS_OK; } +static void EnsureReflowFlushAndPaint(nsIDocShell* aDocShell) +{ + if (!aDocShell) + return; + + nsCOMPtr presShell; + aDocShell->GetPresShell(getter_AddRefs(presShell)); + + if (!presShell) + return; + + // Flush pending reflows. + presShell->FlushPendingNotifications(); + + // Unsuppress painting. + presShell->UnsuppressPainting(PR_TRUE); +} + NS_IMETHODIMP GlobalWindowImpl::Alert(JSContext* cx, jsval* argv, PRUint32 argc) { NS_ENSURE_STATE(mDocShell); @@ -1565,6 +1583,9 @@ NS_IMETHODIMP GlobalWindowImpl::Alert(JSContext* cx, jsval* argv, PRUint32 argc) nsCOMPtr prompter(do_GetInterface(mDocShell)); NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE); + // Before bringing up the window, unsuppress painting and flush pending reflows. + EnsureReflowFlushAndPaint(mDocShell); + return prompter->Alert(nsnull, str.GetUnicode()); } @@ -1582,6 +1603,9 @@ NS_IMETHODIMP GlobalWindowImpl::Confirm(JSContext* cx, jsval* argv, nsCOMPtr prompter(do_GetInterface(mDocShell)); NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE); + // Before bringing up the window, unsuppress painting and flush pending reflows. + EnsureReflowFlushAndPaint(mDocShell); + return prompter->Confirm(nsnull, str.GetUnicode(), aReturn); } @@ -1614,6 +1638,9 @@ NS_IMETHODIMP GlobalWindowImpl::Prompt(JSContext* cx, jsval* argv, NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE); + // Before bringing up the window, unsuppress painting and flush pending reflows. + EnsureReflowFlushAndPaint(mDocShell); + PRBool b; PRUnichar *uniResult = nsnull; ret = prompter->Prompt(title.GetUnicode(), message.GetUnicode(), nsnull, diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 3ab12063911..363892fcdff 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -3275,6 +3275,15 @@ IsCanvasFrame(nsIFrame* aFrame) return parentType.get() == nsLayoutAtoms::canvasFrame; } +static PRBool +IsRootFrame(nsIFrame* aFrame) +{ + nsCOMPtr parentType; + + aFrame->GetFrameType(getter_AddRefs(parentType)); + return parentType.get() == nsLayoutAtoms::rootFrame; +} + static void PropagateBackgroundToParent(nsIStyleContext* aStyleContext, const nsStyleColor* aColor, @@ -3593,7 +3602,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsIPresShell* aPresShell, // Section 14.2 of the CSS2 spec says that the background of the root element // covers the entire canvas. See if a background was specified for the root // element - if (!color->BackgroundIsTransparent() && IsCanvasFrame(aParentFrame)) { + if (!color->BackgroundIsTransparent() && (IsCanvasFrame(aParentFrame) || IsRootFrame(aParentFrame))) { nsIStyleContext* parentContext; // Propagate the document element's background to the canvas so that it @@ -9402,6 +9411,13 @@ ApplyRenderingChangeToTree(nsIPresContext* aPresContext, nsIFrame* aFrame, nsIViewManager* aViewManager) { + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + PRBool isPaintingSuppressed = PR_FALSE; + shell->IsPaintingSuppressed(&isPaintingSuppressed); + if (isPaintingSuppressed) + return; // Don't allow synchronous rendering changes when painting is turned off. + nsIViewManager* viewManager = aViewManager; // Trigger rendering updates by damaging this frame and any diff --git a/mozilla/layout/base/nsCaret.cpp b/mozilla/layout/base/nsCaret.cpp index 60d7ec659e6..17b5879f516 100644 --- a/mozilla/layout/base/nsCaret.cpp +++ b/mozilla/layout/base/nsCaret.cpp @@ -845,6 +845,14 @@ void nsCaret::GetViewForRendering(nsIFrame *caretFrame, EViewCoordinates coordTy ----------------------------------------------------------------------------- */ PRBool nsCaret::MustDrawCaret() { + nsCOMPtr presShell = do_QueryReferent(mPresShell); + if (presShell) { + PRBool isPaintingSuppressed; + presShell->IsPaintingSuppressed(&isPaintingSuppressed); + if (isPaintingSuppressed) + return PR_FALSE; + } + if (mDrawn) return PR_TRUE; diff --git a/mozilla/layout/base/nsDocumentViewer.cpp b/mozilla/layout/base/nsDocumentViewer.cpp index badc03af80d..30e2581138c 100644 --- a/mozilla/layout/base/nsDocumentViewer.cpp +++ b/mozilla/layout/base/nsDocumentViewer.cpp @@ -527,6 +527,7 @@ protected: nsCOMPtr mFocusListener; PRBool mEnableRendering; + PRBool mStopped; PRInt16 mNumURLStarts; nsIPageSequenceFrame* mPageSeqFrame; @@ -793,6 +794,7 @@ DocumentViewerImpl::DocumentViewerImpl() { NS_INIT_ISUPPORTS(); mEnableRendering = PR_TRUE; + mStopped = PR_FALSE; mPrt = nsnull; mIsPrinting = PR_FALSE; @@ -1060,6 +1062,11 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) } else { // XXX: Should fire error event to the document... } + + // Now that the document has loaded, we can tell the presshell + // to unsuppress painting. + if (mPresShell) + mPresShell->UnsuppressPainting(!mStopped); return rv; } @@ -1123,6 +1130,8 @@ DocumentViewerImpl::Stop(void) // stop everything but the chrome. mPresContext->Stop(PR_FALSE); } + + mStopped = PR_TRUE; return NS_OK; } diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h index 3b41c5a5ca3..f8d1433b23c 100644 --- a/mozilla/layout/base/nsIPresShell.h +++ b/mozilla/layout/base/nsIPresShell.h @@ -503,6 +503,18 @@ public: */ NS_IMETHOD ReleaseAnonymousContent() = 0; + /** + * Called to find out if painting is suppressed for this presshell. If it is suppressd, + * we don't allow the painting of any layer but the background, and we don't + * recur into our children. + */ + NS_IMETHOD IsPaintingSuppressed(PRBool* aResult)=0; + + /** + * Unsuppress painting. + */ + NS_IMETHOD UnsuppressPainting(PRBool aCancelTimer) = 0; + enum InterruptType {Timeout}; /** * Notify aFrame via a reflow command when an aInterruptType event occurs diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 95a563faa19..9f76068ce4e 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -918,6 +918,9 @@ public: NS_IMETHOD GetAnonymousContentFor(nsIContent* aContent, nsISupportsArray** aAnonymousElements); NS_IMETHOD ReleaseAnonymousContent(); + NS_IMETHOD IsPaintingSuppressed(PRBool* aResult); + NS_IMETHOD UnsuppressPainting(PRBool aCancelTimer); + NS_IMETHOD HandleEventWithTarget(nsEvent* aEvent, nsIFrame* aFrame, nsIContent* aContent, PRUint32 aFlags, nsEventStatus* aStatus); NS_IMETHOD GetEventTargetFrame(nsIFrame** aFrame); @@ -1049,6 +1052,8 @@ protected: void HandlePostedAttributeChanges(); void HandlePostedReflowCallbacks(); + void UnsuppressAndInvalidate(); + /** notify all external reflow observers that reflow of type "aData" is about * to begin. */ @@ -1167,6 +1172,19 @@ protected: nsCallbackEventRequest* mFirstCallbackEventRequest; nsCallbackEventRequest* mLastCallbackEventRequest; + PRBool mPaintingSuppressed; // For all documents we initially lock down painting. + // We will refuse to paint the document until either + // (a) our timer fires or (b) all frames are constructed. + PRBool mShouldUnsuppressPainting; // Indicates that it is safe to unlock painting once all pending + // reflows have been processed. + nsCOMPtr mPaintSuppressionTimer; // This timer controls painting suppression. Until it fires + // or all frames are constructed, we won't paint anything but + // our background and scrollbars. +#define PAINTLOCK_EVENT_DELAY 1200 // 1200 ms. This is actually pref-controlled, but we use this + // value if we fail to get the pref for any reason. + + static void sPaintSuppressionCallback(nsITimer* aTimer, void* aPresShell); // A callback for the timer. + // subshell map nsDST* mSubShellMap; // map of content/subshell pairs nsDST::NodeArena* mDSTNodeArena; // weak link. DST owns (mSubShellMap object) @@ -1312,7 +1330,9 @@ PresShell::PresShell():mAnonymousContentTable(nsnull), mFirstAttributeRequest(nsnull), mLastAttributeRequest(nsnull), mFirstCallbackEventRequest(nsnull), - mLastCallbackEventRequest(nsnull) + mLastCallbackEventRequest(nsnull), + mPaintingSuppressed(PR_FALSE), + mShouldUnsuppressPainting(PR_FALSE) { NS_INIT_REFCNT(); mIsDestroying = PR_FALSE; @@ -1400,6 +1420,12 @@ PresShell::~PresShell() } #endif + // If our paint suppression timer is still active, kill it. + if (mPaintSuppressionTimer) { + mPaintSuppressionTimer->Cancel(); + mPaintSuppressionTimer = nsnull; + } + // release our pref style sheet, if we have one still ClearPreferenceStyleRules(); @@ -2594,9 +2620,34 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) } } + mPaintingSuppressed = PR_TRUE; + // Kick off a one-shot timer based off our pref value. When this timer + // fires, if painting is still locked down, then we will go ahead and + // trigger a full invalidate and allow painting to proceed normally. + mPaintSuppressionTimer = do_CreateInstance("@mozilla.org/timer;1"); + if (!mPaintSuppressionTimer) + // Uh-oh. We must be out of memory. No point in keeping painting locked down. + mPaintingSuppressed = PR_FALSE; + else { + // Initialize the timer. + PRInt32 delay = PAINTLOCK_EVENT_DELAY; // Use this value if we fail to get the pref value. + nsCOMPtr prefs(do_GetService(kPrefServiceCID)); + if (prefs) + prefs->GetIntPref("nglayout.initialpaint.delay", &delay); + mPaintSuppressionTimer->Init(sPaintSuppressionCallback, this, delay, NS_PRIORITY_HIGH); + } + return NS_OK; //XXX this needs to be real. MMP } +void +PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell) +{ + PresShell* self = NS_STATIC_CAST(PresShell*, aPresShell); + if (self) + self->UnsuppressPainting(PR_TRUE); +} + NS_IMETHODIMP PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) { @@ -4402,6 +4453,47 @@ PresShell::ReleaseAnonymousContent() return NS_OK; } +NS_IMETHODIMP +PresShell::IsPaintingSuppressed(PRBool* aResult) +{ + *aResult = mPaintingSuppressed; + return NS_OK; +} + +void +PresShell::UnsuppressAndInvalidate() +{ + mPaintingSuppressed = PR_FALSE; + nsIFrame* rootFrame; + mFrameManager->GetRootFrame(&rootFrame); + if (rootFrame) { + nsRect rect; + rootFrame->GetRect(rect); + ((nsFrame*)rootFrame)->Invalidate(mPresContext, rect, PR_FALSE); + } +} + +NS_IMETHODIMP +PresShell::UnsuppressPainting(PRBool aCancelTimer) +{ + if (mPaintSuppressionTimer && aCancelTimer) { + mPaintSuppressionTimer->Cancel(); + mPaintSuppressionTimer = nsnull; + } + + if (!mPaintingSuppressed || !aCancelTimer) + return NS_OK; + + // If we have reflows pending, just wait until we process + // the reflows and get all the frames where we want them + // before actually unlocking the painting. Otherwise + // go ahead and unlock now. + if (mReflowCommands.Count() > 0) + mShouldUnsuppressPainting = PR_TRUE; + else + UnsuppressAndInvalidate(); + return NS_OK; +} // Post a request to handle an arbitrary callback after reflow has finished. NS_IMETHODIMP @@ -5119,7 +5211,7 @@ PresShell::Paint(nsIView *aView, aView->GetClientData(clientData); frame = (nsIFrame *)clientData; - + if (nsnull != frame) { mCaret->EraseCaret(); @@ -5728,6 +5820,16 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) HandlePostedDOMEvents(); HandlePostedAttributeChanges(); HandlePostedReflowCallbacks(); + + if (mShouldUnsuppressPainting && mReflowCommands.Count() == 0) { + // We only unlock if we're out of reflows. It's pointless + // to unlock if reflows are still pending, since reflows + // are just going to thrash the frames around some more. By + // waiting we avoid an overeager "jitter" effect. + mShouldUnsuppressPainting = PR_FALSE; + UnsuppressAndInvalidate(); + } + return NS_OK; } diff --git a/mozilla/layout/base/public/nsIPresShell.h b/mozilla/layout/base/public/nsIPresShell.h index 3b41c5a5ca3..f8d1433b23c 100644 --- a/mozilla/layout/base/public/nsIPresShell.h +++ b/mozilla/layout/base/public/nsIPresShell.h @@ -503,6 +503,18 @@ public: */ NS_IMETHOD ReleaseAnonymousContent() = 0; + /** + * Called to find out if painting is suppressed for this presshell. If it is suppressd, + * we don't allow the painting of any layer but the background, and we don't + * recur into our children. + */ + NS_IMETHOD IsPaintingSuppressed(PRBool* aResult)=0; + + /** + * Unsuppress painting. + */ + NS_IMETHOD UnsuppressPainting(PRBool aCancelTimer) = 0; + enum InterruptType {Timeout}; /** * Notify aFrame via a reflow command when an aInterruptType event occurs diff --git a/mozilla/layout/base/src/nsCaret.cpp b/mozilla/layout/base/src/nsCaret.cpp index 60d7ec659e6..17b5879f516 100644 --- a/mozilla/layout/base/src/nsCaret.cpp +++ b/mozilla/layout/base/src/nsCaret.cpp @@ -845,6 +845,14 @@ void nsCaret::GetViewForRendering(nsIFrame *caretFrame, EViewCoordinates coordTy ----------------------------------------------------------------------------- */ PRBool nsCaret::MustDrawCaret() { + nsCOMPtr presShell = do_QueryReferent(mPresShell); + if (presShell) { + PRBool isPaintingSuppressed; + presShell->IsPaintingSuppressed(&isPaintingSuppressed); + if (isPaintingSuppressed) + return PR_FALSE; + } + if (mDrawn) return PR_TRUE; diff --git a/mozilla/layout/forms/nsListControlFrame.cpp b/mozilla/layout/forms/nsListControlFrame.cpp index 4eed2c46566..985ae49ba48 100644 --- a/mozilla/layout/forms/nsListControlFrame.cpp +++ b/mozilla/layout/forms/nsListControlFrame.cpp @@ -301,6 +301,14 @@ nsListControlFrame::Paint(nsIPresContext* aPresContext, return PR_FALSE; } + // Don't allow painting of list controls when painting is suppressed. + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + // Start by assuming we are visible and need to be painted PRBool isVisible = PR_TRUE; diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 7f5997d4c3a..081daa01e26 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -6451,6 +6451,13 @@ nsBlockFrame::Paint(nsIPresContext* aPresContext, aDirtyRect, rect, *border, *outline, mStyleContext, 0); } + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + const nsStyleDisplay* disp = (const nsStyleDisplay*) mStyleContext->GetStyleData(eStyleStruct_Display); diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index 7f5997d4c3a..081daa01e26 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -6451,6 +6451,13 @@ nsBlockFrame::Paint(nsIPresContext* aPresContext, aDirtyRect, rect, *border, *outline, mStyleContext, 0); } + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + const nsStyleDisplay* disp = (const nsStyleDisplay*) mStyleContext->GetStyleData(eStyleStruct_Display); diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index 7f5997d4c3a..081daa01e26 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -6451,6 +6451,13 @@ nsBlockFrame::Paint(nsIPresContext* aPresContext, aDirtyRect, rect, *border, *outline, mStyleContext, 0); } + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + const nsStyleDisplay* disp = (const nsStyleDisplay*) mStyleContext->GetStyleData(eStyleStruct_Display); diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 407cba19903..ee59b0aa569 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -2139,6 +2139,19 @@ nsFrame::Invalidate(nsIPresContext* aPresContext, const nsRect& aDamageRect, PRBool aImmediate) const { + if (aPresContext) { + // Don't allow invalidates to do anything when + // painting is suppressed. + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + PRBool suppressed = PR_FALSE; + shell->IsPaintingSuppressed(&suppressed); + if (suppressed) + return; + } + } + nsIViewManager* viewManager = nsnull; nsRect damageRect(aDamageRect); diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.cpp b/mozilla/layout/generic/nsHTMLContainerFrame.cpp index a42c06b9be1..f538b29e7a7 100644 --- a/mozilla/layout/generic/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/generic/nsHTMLContainerFrame.cpp @@ -99,6 +99,20 @@ nsHTMLContainerFrame::Paint(nsIPresContext* aPresContext, } } + if (frameType.get() == nsLayoutAtoms::canvasFrame) { + // We are wrapping the root frame of a document. We + // need to check the pres shell to find out if painting is locked + // down (because we're still in the early stages of document + // and frame construction. If painting is locked down, then we + // do not paint our children. + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + } + // Now paint the kids. Note that child elements have the opportunity to // override the visibility property and display even if their parent is // hidden diff --git a/mozilla/layout/generic/nsImageFrame.cpp b/mozilla/layout/generic/nsImageFrame.cpp index b97882025b9..238fc1baf89 100644 --- a/mozilla/layout/generic/nsImageFrame.cpp +++ b/mozilla/layout/generic/nsImageFrame.cpp @@ -1048,6 +1048,16 @@ nsImageFrame::Paint(nsIPresContext* aPresContext, PRBool isVisible; if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && isVisible && mRect.width && mRect.height) { + // If painting is suppressed, we need to stop image painting. We + // have to cover here because of input image controls. + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + + // First paint background and borders nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index 7f5997d4c3a..081daa01e26 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -6451,6 +6451,13 @@ nsBlockFrame::Paint(nsIPresContext* aPresContext, aDirtyRect, rect, *border, *outline, mStyleContext, 0); } + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + const nsStyleDisplay* disp = (const nsStyleDisplay*) mStyleContext->GetStyleData(eStyleStruct_Display); diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index 7f5997d4c3a..081daa01e26 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -6451,6 +6451,13 @@ nsBlockFrame::Paint(nsIPresContext* aPresContext, aDirtyRect, rect, *border, *outline, mStyleContext, 0); } + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + const nsStyleDisplay* disp = (const nsStyleDisplay*) mStyleContext->GetStyleData(eStyleStruct_Display); diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index 7f5997d4c3a..081daa01e26 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -6451,6 +6451,13 @@ nsBlockFrame::Paint(nsIPresContext* aPresContext, aDirtyRect, rect, *border, *outline, mStyleContext, 0); } + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + const nsStyleDisplay* disp = (const nsStyleDisplay*) mStyleContext->GetStyleData(eStyleStruct_Display); diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 407cba19903..ee59b0aa569 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -2139,6 +2139,19 @@ nsFrame::Invalidate(nsIPresContext* aPresContext, const nsRect& aDamageRect, PRBool aImmediate) const { + if (aPresContext) { + // Don't allow invalidates to do anything when + // painting is suppressed. + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + PRBool suppressed = PR_FALSE; + shell->IsPaintingSuppressed(&suppressed); + if (suppressed) + return; + } + } + nsIViewManager* viewManager = nsnull; nsRect damageRect(aDamageRect); diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp index a42c06b9be1..f538b29e7a7 100644 --- a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp @@ -99,6 +99,20 @@ nsHTMLContainerFrame::Paint(nsIPresContext* aPresContext, } } + if (frameType.get() == nsLayoutAtoms::canvasFrame) { + // We are wrapping the root frame of a document. We + // need to check the pres shell to find out if painting is locked + // down (because we're still in the early stages of document + // and frame construction. If painting is locked down, then we + // do not paint our children. + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + } + // Now paint the kids. Note that child elements have the opportunity to // override the visibility property and display even if their parent is // hidden diff --git a/mozilla/layout/html/base/src/nsImageFrame.cpp b/mozilla/layout/html/base/src/nsImageFrame.cpp index b97882025b9..238fc1baf89 100644 --- a/mozilla/layout/html/base/src/nsImageFrame.cpp +++ b/mozilla/layout/html/base/src/nsImageFrame.cpp @@ -1048,6 +1048,16 @@ nsImageFrame::Paint(nsIPresContext* aPresContext, PRBool isVisible; if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && isVisible && mRect.width && mRect.height) { + // If painting is suppressed, we need to stop image painting. We + // have to cover here because of input image controls. + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + + // First paint background and borders nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index 95a563faa19..9f76068ce4e 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -918,6 +918,9 @@ public: NS_IMETHOD GetAnonymousContentFor(nsIContent* aContent, nsISupportsArray** aAnonymousElements); NS_IMETHOD ReleaseAnonymousContent(); + NS_IMETHOD IsPaintingSuppressed(PRBool* aResult); + NS_IMETHOD UnsuppressPainting(PRBool aCancelTimer); + NS_IMETHOD HandleEventWithTarget(nsEvent* aEvent, nsIFrame* aFrame, nsIContent* aContent, PRUint32 aFlags, nsEventStatus* aStatus); NS_IMETHOD GetEventTargetFrame(nsIFrame** aFrame); @@ -1049,6 +1052,8 @@ protected: void HandlePostedAttributeChanges(); void HandlePostedReflowCallbacks(); + void UnsuppressAndInvalidate(); + /** notify all external reflow observers that reflow of type "aData" is about * to begin. */ @@ -1167,6 +1172,19 @@ protected: nsCallbackEventRequest* mFirstCallbackEventRequest; nsCallbackEventRequest* mLastCallbackEventRequest; + PRBool mPaintingSuppressed; // For all documents we initially lock down painting. + // We will refuse to paint the document until either + // (a) our timer fires or (b) all frames are constructed. + PRBool mShouldUnsuppressPainting; // Indicates that it is safe to unlock painting once all pending + // reflows have been processed. + nsCOMPtr mPaintSuppressionTimer; // This timer controls painting suppression. Until it fires + // or all frames are constructed, we won't paint anything but + // our background and scrollbars. +#define PAINTLOCK_EVENT_DELAY 1200 // 1200 ms. This is actually pref-controlled, but we use this + // value if we fail to get the pref for any reason. + + static void sPaintSuppressionCallback(nsITimer* aTimer, void* aPresShell); // A callback for the timer. + // subshell map nsDST* mSubShellMap; // map of content/subshell pairs nsDST::NodeArena* mDSTNodeArena; // weak link. DST owns (mSubShellMap object) @@ -1312,7 +1330,9 @@ PresShell::PresShell():mAnonymousContentTable(nsnull), mFirstAttributeRequest(nsnull), mLastAttributeRequest(nsnull), mFirstCallbackEventRequest(nsnull), - mLastCallbackEventRequest(nsnull) + mLastCallbackEventRequest(nsnull), + mPaintingSuppressed(PR_FALSE), + mShouldUnsuppressPainting(PR_FALSE) { NS_INIT_REFCNT(); mIsDestroying = PR_FALSE; @@ -1400,6 +1420,12 @@ PresShell::~PresShell() } #endif + // If our paint suppression timer is still active, kill it. + if (mPaintSuppressionTimer) { + mPaintSuppressionTimer->Cancel(); + mPaintSuppressionTimer = nsnull; + } + // release our pref style sheet, if we have one still ClearPreferenceStyleRules(); @@ -2594,9 +2620,34 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) } } + mPaintingSuppressed = PR_TRUE; + // Kick off a one-shot timer based off our pref value. When this timer + // fires, if painting is still locked down, then we will go ahead and + // trigger a full invalidate and allow painting to proceed normally. + mPaintSuppressionTimer = do_CreateInstance("@mozilla.org/timer;1"); + if (!mPaintSuppressionTimer) + // Uh-oh. We must be out of memory. No point in keeping painting locked down. + mPaintingSuppressed = PR_FALSE; + else { + // Initialize the timer. + PRInt32 delay = PAINTLOCK_EVENT_DELAY; // Use this value if we fail to get the pref value. + nsCOMPtr prefs(do_GetService(kPrefServiceCID)); + if (prefs) + prefs->GetIntPref("nglayout.initialpaint.delay", &delay); + mPaintSuppressionTimer->Init(sPaintSuppressionCallback, this, delay, NS_PRIORITY_HIGH); + } + return NS_OK; //XXX this needs to be real. MMP } +void +PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell) +{ + PresShell* self = NS_STATIC_CAST(PresShell*, aPresShell); + if (self) + self->UnsuppressPainting(PR_TRUE); +} + NS_IMETHODIMP PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) { @@ -4402,6 +4453,47 @@ PresShell::ReleaseAnonymousContent() return NS_OK; } +NS_IMETHODIMP +PresShell::IsPaintingSuppressed(PRBool* aResult) +{ + *aResult = mPaintingSuppressed; + return NS_OK; +} + +void +PresShell::UnsuppressAndInvalidate() +{ + mPaintingSuppressed = PR_FALSE; + nsIFrame* rootFrame; + mFrameManager->GetRootFrame(&rootFrame); + if (rootFrame) { + nsRect rect; + rootFrame->GetRect(rect); + ((nsFrame*)rootFrame)->Invalidate(mPresContext, rect, PR_FALSE); + } +} + +NS_IMETHODIMP +PresShell::UnsuppressPainting(PRBool aCancelTimer) +{ + if (mPaintSuppressionTimer && aCancelTimer) { + mPaintSuppressionTimer->Cancel(); + mPaintSuppressionTimer = nsnull; + } + + if (!mPaintingSuppressed || !aCancelTimer) + return NS_OK; + + // If we have reflows pending, just wait until we process + // the reflows and get all the frames where we want them + // before actually unlocking the painting. Otherwise + // go ahead and unlock now. + if (mReflowCommands.Count() > 0) + mShouldUnsuppressPainting = PR_TRUE; + else + UnsuppressAndInvalidate(); + return NS_OK; +} // Post a request to handle an arbitrary callback after reflow has finished. NS_IMETHODIMP @@ -5119,7 +5211,7 @@ PresShell::Paint(nsIView *aView, aView->GetClientData(clientData); frame = (nsIFrame *)clientData; - + if (nsnull != frame) { mCaret->EraseCaret(); @@ -5728,6 +5820,16 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) HandlePostedDOMEvents(); HandlePostedAttributeChanges(); HandlePostedReflowCallbacks(); + + if (mShouldUnsuppressPainting && mReflowCommands.Count() == 0) { + // We only unlock if we're out of reflows. It's pointless + // to unlock if reflows are still pending, since reflows + // are just going to thrash the frames around some more. By + // waiting we avoid an overeager "jitter" effect. + mShouldUnsuppressPainting = PR_FALSE; + UnsuppressAndInvalidate(); + } + return NS_OK; } diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.cpp b/mozilla/layout/html/forms/src/nsListControlFrame.cpp index 4eed2c46566..985ae49ba48 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsListControlFrame.cpp @@ -301,6 +301,14 @@ nsListControlFrame::Paint(nsIPresContext* aPresContext, return PR_FALSE; } + // Don't allow painting of list controls when painting is suppressed. + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + // Start by assuming we are visible and need to be painted PRBool isVisible = PR_TRUE; diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp index 3ab12063911..363892fcdff 100644 --- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -3275,6 +3275,15 @@ IsCanvasFrame(nsIFrame* aFrame) return parentType.get() == nsLayoutAtoms::canvasFrame; } +static PRBool +IsRootFrame(nsIFrame* aFrame) +{ + nsCOMPtr parentType; + + aFrame->GetFrameType(getter_AddRefs(parentType)); + return parentType.get() == nsLayoutAtoms::rootFrame; +} + static void PropagateBackgroundToParent(nsIStyleContext* aStyleContext, const nsStyleColor* aColor, @@ -3593,7 +3602,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsIPresShell* aPresShell, // Section 14.2 of the CSS2 spec says that the background of the root element // covers the entire canvas. See if a background was specified for the root // element - if (!color->BackgroundIsTransparent() && IsCanvasFrame(aParentFrame)) { + if (!color->BackgroundIsTransparent() && (IsCanvasFrame(aParentFrame) || IsRootFrame(aParentFrame))) { nsIStyleContext* parentContext; // Propagate the document element's background to the canvas so that it @@ -9402,6 +9411,13 @@ ApplyRenderingChangeToTree(nsIPresContext* aPresContext, nsIFrame* aFrame, nsIViewManager* aViewManager) { + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + PRBool isPaintingSuppressed = PR_FALSE; + shell->IsPaintingSuppressed(&isPaintingSuppressed); + if (isPaintingSuppressed) + return; // Don't allow synchronous rendering changes when painting is turned off. + nsIViewManager* viewManager = aViewManager; // Trigger rendering updates by damaging this frame and any diff --git a/mozilla/layout/xul/base/src/nsBox.cpp b/mozilla/layout/xul/base/src/nsBox.cpp index 8175868f8fa..d617c6f15ef 100644 --- a/mozilla/layout/xul/base/src/nsBox.cpp +++ b/mozilla/layout/xul/base/src/nsBox.cpp @@ -1082,6 +1082,13 @@ nsBox::Redraw(nsBoxLayoutState& aState, return NS_OK; } + nsCOMPtr shell; + presContext->GetShell(getter_AddRefs(shell)); + PRBool suppressed = PR_FALSE; + shell->IsPaintingSuppressed(&suppressed); + if (suppressed) + return NS_OK; // Don't redraw. Painting is still suppressed. + nsIFrame* frame = nsnull; GetFrame(&frame); diff --git a/mozilla/layout/xul/base/src/nsBoxFrame.cpp b/mozilla/layout/xul/base/src/nsBoxFrame.cpp index 1ce6c618eec..4322b770297 100644 --- a/mozilla/layout/xul/base/src/nsBoxFrame.cpp +++ b/mozilla/layout/xul/base/src/nsBoxFrame.cpp @@ -1283,6 +1283,10 @@ nsBoxFrame::Paint(nsIPresContext* aPresContext, if (NS_FRAME_IS_UNFLOWABLE & mState) { return NS_OK; } + + nsCOMPtr frameType; + GetFrameType(getter_AddRefs(frameType)); + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { if (disp->IsVisible() && mRect.width && mRect.height) { // Paint our background and border @@ -1324,6 +1328,20 @@ nsBoxFrame::Paint(nsIPresContext* aPresContext, } } + if (frameType.get() == nsLayoutAtoms::rootFrame) { + // We are wrapping the root frame of a XUL document. We + // need to check the pres shell to find out if painting is locked + // down (because we're still in the early stages of document + // and frame construction. If painting is locked down, then we + // do not paint our children. + PRBool paintingSuppressed = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + shell->IsPaintingSuppressed(&paintingSuppressed); + if (paintingSuppressed) + return NS_OK; + } + // Now paint the kids. Note that child elements have the opportunity to // override the visibility property and display even if their parent is // hidden diff --git a/mozilla/layout/xul/base/src/nsImageBoxFrame.cpp b/mozilla/layout/xul/base/src/nsImageBoxFrame.cpp index 3c64b231c02..41478dd0fce 100644 --- a/mozilla/layout/xul/base/src/nsImageBoxFrame.cpp +++ b/mozilla/layout/xul/base/src/nsImageBoxFrame.cpp @@ -668,9 +668,6 @@ NS_IMETHODIMP nsImageBoxFrame::OnStartFrame(imgIRequest *request, nsIPresContext NS_IMETHODIMP nsImageBoxFrame::OnDataAvailable(imgIRequest *request, nsIPresContext *aPresContext, gfxIImageFrame *frame, const nsRect * rect) { - nsBoxLayoutState state(aPresContext); - this->Redraw(state); - return NS_OK; } @@ -681,6 +678,8 @@ NS_IMETHODIMP nsImageBoxFrame::OnStopFrame(imgIRequest *request, nsIPresContext NS_IMETHODIMP nsImageBoxFrame::OnStopContainer(imgIRequest *request, nsIPresContext *aPresContext, imgIContainer *image) { + nsBoxLayoutState state(aPresContext); + this->Redraw(state); return NS_OK; } diff --git a/mozilla/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp b/mozilla/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp index c628700c629..1d6bc75c430 100644 --- a/mozilla/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp +++ b/mozilla/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp @@ -45,6 +45,9 @@ nsGIFDecoder2::nsGIFDecoder2() mGIFStruct = nsnull; mAlphaLine = nsnull; + + mCurrentRow = -1; + mLastFlushedRow = -1; } nsGIFDecoder2::~nsGIFDecoder2(void) @@ -157,6 +160,17 @@ PRUint32 nsGIFDecoder2::ProcessData(unsigned char *data, PRUint32 count) gif_write(mGIFStruct, data, count); } + if (mImageFrame && mObserver) { + PRInt32 remainingRows = mCurrentRow-mLastFlushedRow; + if (remainingRows) { + PRInt32 width; + mImageFrame->GetWidth(&width); + nsRect r(0, mLastFlushedRow+1, width, remainingRows); + mObserver->OnDataAvailable(nsnull, nsnull, mImageFrame, &r); + mLastFlushedRow = mCurrentRow; + } + } + return count; // we always consume all the data } @@ -291,8 +305,18 @@ int EndImageFrame( // decoder->mImageFrame->SetTimeout(aDelayTimeout); decoder->mImageContainer->EndFrameDecode(aFrameNumber, aDelayTimeout); - if (decoder->mObserver) + if (decoder->mObserver) { + PRInt32 remainingRows = decoder->mCurrentRow-decoder->mLastFlushedRow; + if (remainingRows) { + PRInt32 width; + decoder->mImageFrame->GetWidth(&width); + nsRect r(0, decoder->mLastFlushedRow+1, width, remainingRows); + decoder->mObserver->OnDataAvailable(nsnull, nsnull, decoder->mImageFrame, &r); + decoder->mCurrentRow = decoder->mLastFlushedRow = -1; + } + decoder->mObserver->OnStopFrame(nsnull, nsnull, decoder->mImageFrame); + } decoder->mImageFrame = nsnull; return 0; @@ -453,9 +477,7 @@ int HaveDecodedRow( } - nsRect r(0, aRowNumber, width, 1); - - decoder->mObserver->OnDataAvailable(nsnull, nsnull, decoder->mImageFrame, &r); + decoder->mCurrentRow = aRowNumber; } return 0; diff --git a/mozilla/modules/libpr0n/decoders/gif/nsGIFDecoder2.h b/mozilla/modules/libpr0n/decoders/gif/nsGIFDecoder2.h index ef284b52b13..9b8d1135dc4 100644 --- a/mozilla/modules/libpr0n/decoders/gif/nsGIFDecoder2.h +++ b/mozilla/modules/libpr0n/decoders/gif/nsGIFDecoder2.h @@ -62,7 +62,9 @@ public: nsCOMPtr mImageFrame; nsCOMPtr mImageRequest; nsCOMPtr mObserver; // this is just qi'd from mRequest for speed - + PRInt32 mCurrentRow; + PRInt32 mLastFlushedRow; + gif_struct *mGIFStruct; PRUint8 *mAlphaLine; diff --git a/mozilla/modules/libpr0n/src/imgRequestProxy.cpp b/mozilla/modules/libpr0n/src/imgRequestProxy.cpp index 4efced12bb6..8664939dab9 100644 --- a/mozilla/modules/libpr0n/src/imgRequestProxy.cpp +++ b/mozilla/modules/libpr0n/src/imgRequestProxy.cpp @@ -84,12 +84,16 @@ nsresult imgRequestProxy::Init(imgRequest *request, nsILoadGroup *aLoadGroup, im mContext = cx; if (aLoadGroup) { - aLoadGroup->AddRequest(this, cx); - mLoadGroup = aLoadGroup; + PRUint32 imageStatus; + nsresult rv = GetImageStatus(&imageStatus); + if (NS_FAILED(rv)) return rv; + if (!(imageStatus & STATUS_LOAD_COMPLETE)) { + aLoadGroup->AddRequest(this, cx); + mLoadGroup = aLoadGroup; + } } - request->AddProxy(this); - + request->AddProxy(this); return NS_OK; } diff --git a/mozilla/xpfe/browser/resources/content/navigator.js b/mozilla/xpfe/browser/resources/content/navigator.js index 848fffcafe2..a2b87c89c34 100644 --- a/mozilla/xpfe/browser/resources/content/navigator.js +++ b/mozilla/xpfe/browser/resources/content/navigator.js @@ -166,8 +166,19 @@ function UpdateBackForwardButtons() var forwardBroadcaster = document.getElementById("canGoForward"); var webNavigation = getWebNavigation(); - backBroadcaster.setAttribute("disabled", !webNavigation.canGoBack); - forwardBroadcaster.setAttribute("disabled", !webNavigation.canGoForward); + // Avoid setting attributes on broadcasters if the value hasn't changed! + // Remember, guys, setting attributes on elements is expensive! They + // get inherited into anonymous content, broadcast to other widgets, etc.! + // Don't do it if the value hasn't changed! - dwh + + var backDisabled = (backBroadcaster.getAttribute("disabled") == "true"); + var forwardDisabled = (forwardBroadcaster.getAttribute("disabled") == "true"); + + if (backDisabled == webNavigation.canGoBack) + backBroadcaster.setAttribute("disabled", !backDisabled); + + if (forwardDisabled == webNavigation.canGoForward) + forwardBroadcaster.setAttribute("disabled", !forwardDisabled); }