diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 323e626eb2e1..37646433a3a2 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -6493,8 +6493,6 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) } nscolor bgcolor = NS_RGBA(0, 0, 0, 0); - PRBool bgSet = PR_FALSE; - // Ensure that the content viewer is destroyed *after* the GC - bug 71515 nsCOMPtr kungfuDeathGrip = mContentViewer; if (mContentViewer) { @@ -6502,8 +6500,8 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) // releasing it... mContentViewer->Stop(); - // Try to extract the default background color from the old - // view manager, so we can use it for the next document. + // Try to extract the canvas background color from the old + // presentation shell, so we can use it for the next document. nsCOMPtr docviewer = do_QueryInterface(mContentViewer); @@ -6512,13 +6510,7 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) docviewer->GetPresShell(getter_AddRefs(shell)); if (shell) { - nsIViewManager* vm = shell->GetViewManager(); - - if (vm) { - vm->GetDefaultBackgroundColor(&bgcolor); - // If the background color is not known, don't propagate it. - bgSet = NS_GET_A(bgcolor) != 0; - } + bgcolor = shell->GetCanvasBackground(); } } @@ -6579,23 +6571,18 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) focusController->SetSuppressFocus(PR_FALSE, "Win32-Only Link Traversal Issue"); - if (bgSet && widget) { - // Stuff the bgcolor from the last view manager into the new - // view manager. This improves page load continuity. - nsCOMPtr docviewer = - do_QueryInterface(mContentViewer); - if (docviewer) { - nsCOMPtr shell; - docviewer->GetPresShell(getter_AddRefs(shell)); + // Stuff the bgcolor from the old pres shell into the new + // pres shell. This improves page load continuity. + nsCOMPtr docviewer = + do_QueryInterface(mContentViewer); - if (shell) { - nsIViewManager* vm = shell->GetViewManager(); + if (docviewer) { + nsCOMPtr shell; + docviewer->GetPresShell(getter_AddRefs(shell)); - if (vm) { - vm->SetDefaultBackgroundColor(bgcolor); - } - } + if (shell) { + shell->SetCanvasBackground(bgcolor); } } diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 724e594e210f..ab6c0df45bd8 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -722,12 +722,6 @@ DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow, PRBool aReena mPresContext->SetTextZoom(mTextZoom); mPresContext->SetFullZoom(mPageZoom); - // Setup default view manager background color - - // This may be overridden by the docshell with the background color - // for the last document loaded into the docshell - mViewManager->SetDefaultBackgroundColor(mPresContext->DefaultBackgroundColor()); - if (aDoInitialReflow) { nsCOMPtr htmlDoc = do_QueryInterface(mDocument); if (htmlDoc) { diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 3af8be2cf800..f61209f5aca6 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -101,10 +101,10 @@ class gfxContext; typedef short SelectionType; typedef PRUint32 nsFrameState; -// 780d34b0-00c3-4bbd-b57d-c600aaf53613 -#define NS_IPRESSHELL_IID \ -{ 0x780d34b0, 0xc3, 0x4bbd, \ - { 0xb5, 0x7d, 0xc6, 0x0, 0xaa, 0xf5, 0x36, 0x13 } } +// 445e6184-5e7e-4a9b-97f7-c9391e6773d2 +#define NS_IPRESSHELL_IID \ +{ 0x445e6184, 0x5e7e, 0x4a9b, \ + { 0x97, 0xf7, 0xc9, 0x39, 0x1e, 0x67, 0x73, 0xd2 } } // Constants for ScrollContentIntoView() function #define NS_PRESSHELL_SCROLL_TOP 0 @@ -776,11 +776,20 @@ public: * Stop or restart non synthetic test mouse event handling on *all* * presShells. * - * @param aDisable If true, disable all non synthetic test mouse events on all - * presShells. Otherwise, enable them. + * @param aDisable If true, disable all non synthetic test mouse + * events on all presShells. Otherwise, enable them. */ NS_IMETHOD DisableNonTestMouseEvents(PRBool aDisable) = 0; + /* Record the background color of the most recently loaded canvas. + * This color is composited on top of the user's default background + * color whenever we need to provide an "ultimate" background color. + * See PresShell::Paint, PresShell::PaintDefaultBackground, and + * nsDocShell::SetupNewViewer; bug 476557 and other bugs mentioned there. + */ + void SetCanvasBackground(nscolor aColor) { mCanvasBackgroundColor = aColor; } + nscolor GetCanvasBackground() { return mCanvasBackgroundColor; } + protected: // IMPORTANT: The ownership implicit in the following member variables // has been explicitly checked. If you add any members to this class, @@ -819,6 +828,9 @@ protected: // A list of weak frames. This is a pointer to the last item in the list. nsWeakFrame* mWeakFrames; + + // Most recent canvas background color. + nscolor mCanvasBackgroundColor; }; /** diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 20c4ae111eaf..5280549a6c96 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -901,6 +901,9 @@ public: NS_IMETHOD Paint(nsIView *aView, nsIRenderingContext* aRenderingContext, const nsRegion& aDirtyRegion); + NS_IMETHOD PaintDefaultBackground(nsIView *aView, + nsIRenderingContext* aRenderingContext, + const nsRect& aDirtyRect); NS_IMETHOD ComputeRepaintRegionForCopy(nsIView* aRootView, nsIView* aMovingView, nsPoint aDelta, @@ -5377,68 +5380,64 @@ PresShell::Paint(nsIView* aView, NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell"); NS_ASSERTION(aView, "null view"); - // Compute the backstop color for the view. This color must be - // totally transparent if the view is within a glass or transparent - // widget; otherwise it must be totally opaque. The user's default - // background color as recorded in the prescontext is guaranteed to - // be opaque. - - PRBool needTransparency = PR_FALSE; - nscolor backgroundColor = mPresContext->DefaultBackgroundColor(); - for (nsIView *view = aView; view; view = view->GetParent()) { - if (view->HasWidget() && - view->GetWidget()->GetTransparencyMode() != eTransparencyOpaque) { - needTransparency = PR_TRUE; - break; - } - } - - // Check whether the view manager knows the background color of the - // canvas. We set this below, and the docshell propagates it across - // page loads; using it in preference to the user's default color - // avoids screen flashing in between pages that use the same - // non-default background. - // - // If we're called at some weird moment when there is no view - // manager, default to transparent. - nscolor viewDefaultColor = NS_RGBA(0,0,0,0); - if (mViewManager) - mViewManager->GetDefaultBackgroundColor(&viewDefaultColor); - - // If we don't have a frame tree yet, all we can do is paint the - // backstop colors. - nsIFrame* frame = static_cast(aView->GetClientData()); - if (!frame) { - if (!needTransparency) { - backgroundColor = NS_ComposeColors(backgroundColor, viewDefaultColor); - aRenderingContext->SetColor(backgroundColor); - aRenderingContext->FillRect(aDirtyRegion.GetBounds()); - } - return NS_OK; - } - - // If we do have a frame tree, check whether it specifies a canvas - // background color yet. If it does, use that instead of whatever - // color the view manager reported, and update the view manager - // accordingly. + // If we have a frame tree and it has style information that + // specifies the background color of the canvas, update our local + // cache of that color. nsIFrame* rootFrame = FrameConstructor()->GetRootElementStyleFrame(); if (rootFrame) { const nsStyleBackground* bgStyle = nsCSSRendering::FindRootFrameBackground(rootFrame); - // XXX ideally we would set the view manager default to - // bgStyle->mBackgroundColor, and nsViewManager::DefaultRefresh would - // be able to cope with partial transparency. But it can't so we can't. - // -- zwol 2009-02-11 - backgroundColor = NS_ComposeColors(backgroundColor, - bgStyle->mBackgroundColor); - mViewManager->SetDefaultBackgroundColor(backgroundColor); - } else { - backgroundColor = NS_ComposeColors(backgroundColor, viewDefaultColor); + mCanvasBackgroundColor = bgStyle->mBackgroundColor; } - nsLayoutUtils::PaintFrame(aRenderingContext, frame, aDirtyRegion, - needTransparency ? NS_RGBA(0,0,0,0) - : backgroundColor); + // Compute the backstop color for the view. + nscolor bgcolor; + nsIWidget* widget = aView->GetNearestWidget(nsnull); + if (widget && widget->GetTransparencyMode() != eTransparencyOpaque) { + // Within a transparent widget, so the backstop color must be + // totally transparent. + bgcolor = NS_RGBA(0,0,0,0); + } else { + // Within an opaque widget (or no widget at all), so the backstop + // color must be totally opaque. The cached canvas background + // color is not guaranteed to be opaque, but the user's default + // background as reported by the prescontext is. Composing the + // former on top of the latter prevents window flashing in between + // pages that use the same non-default background. + bgcolor = NS_ComposeColors(mPresContext->DefaultBackgroundColor(), + mCanvasBackgroundColor); + } + + nsIFrame* frame = static_cast(aView->GetClientData()); + if (frame) { + nsLayoutUtils::PaintFrame(aRenderingContext, frame, aDirtyRegion, bgcolor); + } else { + aRenderingContext->SetColor(bgcolor); + aRenderingContext->FillRect(aDirtyRegion.GetBounds()); + } + return NS_OK; +} + +NS_IMETHODIMP +PresShell::PaintDefaultBackground(nsIView* aView, + nsIRenderingContext* aRenderingContext, + const nsRect& aDirtyRect) +{ + AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint); + + NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell"); + NS_ASSERTION(aView, "null view"); + + // The view manager does not call this function if there is no + // widget or it is transparent. We must not look at the frame tree, + // so all we have to use is the canvas default color as set above, + // or failing that, the user's default color. + + nscolor bgcolor = NS_ComposeColors(mPresContext->DefaultBackgroundColor(), + mCanvasBackgroundColor); + + aRenderingContext->SetColor(bgcolor); + aRenderingContext->FillRect(aDirtyRect); return NS_OK; } diff --git a/view/public/nsIViewManager.h b/view/public/nsIViewManager.h index 926770fecd61..f8472199e9ed 100644 --- a/view/public/nsIViewManager.h +++ b/view/public/nsIViewManager.h @@ -40,7 +40,6 @@ #include "nscore.h" #include "nsIView.h" -#include "nsColor.h" #include "nsEvent.h" #include "nsIRenderingContext.h" @@ -60,10 +59,10 @@ enum nsRectVisibility { nsRectVisibility_kZeroAreaRect }; -// de2a2d24-9753-4488-9fdc-dd0accb484f7 +// fa490965-ebd0-4203-836c-51c42d01fedb #define NS_IVIEWMANAGER_IID \ -{ 0xde2a2d24, 0x9753, 0x4488, \ - { 0x9f, 0xdc, 0xdd, 0x0a, 0xcc, 0xb4, 0x84, 0xf7 } } +{ 0xfa490965, 0xebd0, 0x4203, \ + { 0x83, 0x6c, 0x51, 0xc4, 0x2d, 0x01, 0xfe, 0xdb } } class nsIViewManager : public nsISupports { @@ -441,22 +440,6 @@ public: */ NS_IMETHOD IsPainting(PRBool& aIsPainting)=0; - /** - * Set the default background color that the view manager should use - * to paint otherwise unowned areas. If the color isn't known, just set - * it to zero (which means 'transparent' since the color is RGBA). - * - * @param aColor the default background color - */ - NS_IMETHOD SetDefaultBackgroundColor(nscolor aColor)=0; - - /** - * Retrieve the default background color. - * - * @param aColor the default background color - */ - NS_IMETHOD GetDefaultBackgroundColor(nscolor* aColor)=0; - /** * Retrieve the time of the last user event. User events * include mouse and keyboard events. The viewmanager diff --git a/view/public/nsIViewObserver.h b/view/public/nsIViewObserver.h index 093a2e0a42fc..d10c2e136653 100644 --- a/view/public/nsIViewObserver.h +++ b/view/public/nsIViewObserver.h @@ -46,10 +46,10 @@ class nsIRenderingContext; class nsGUIEvent; -// cb03e6e3-9d14-4018-85f8-7d46af878c98 -#define NS_IVIEWOBSERVER_IID \ -{ 0xcb03e6e3, 0x9d14, 0x4018, \ - { 0x85, 0xf8, 0x7d, 0x46, 0xaf, 0x87, 0x8c, 0x98 } } +// 52b3b616-23a9-4516-a8d3-452b4126eb2b +#define NS_IVIEWOBSERVER_IID \ +{ 0x52b3b616, 0x23a9, 0x4516, \ + { 0xa8, 0xd3, 0x45, 0x2b, 0x41, 0x26, 0xeb, 0x2b } } class nsIViewObserver : public nsISupports { @@ -64,13 +64,33 @@ public: * of the view is painted at (0,0) in the rendering context's current * transform. For best results this should transform to pixel-aligned * coordinates. - * @param aDirtyRegion the region to be painted, in the coordinates of aRootView + * @param aDirtyRegion the region to be painted, in the coordinates of + * aRootView * @return error status */ NS_IMETHOD Paint(nsIView* aRootView, nsIRenderingContext* aRenderingContext, const nsRegion& aDirtyRegion) = 0; + /* called when the observer needs to paint something, but the view + * tree is unstable, so it must *not* paint, or even examine, the + * frame subtree rooted at the view. (It is, however, safe to inspect + * the state of the view itself, and any associated widget.) The name + * illustrates the expected behavior, which is to paint some default + * background color over the dirty rect. + * + * @param aRenderingContext rendering context to paint to; the origin + * of the view is painted at (0,0) in the rendering context's current + * transform. For best results this should transform to pixel-aligned + * coordinates. + * @param aDirtyRect the rectangle to be painted, in the coordinates + * of aRootView + * @return error status + */ + NS_IMETHOD PaintDefaultBackground(nsIView* aRootView, + nsIRenderingContext* aRenderingContext, + const nsRect& aDirtyRect) = 0; + /** * @see nsLayoutUtils::ComputeRepaintRegionForCopy */ diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index efb0db41121f..a7854c98d4dc 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -180,7 +180,6 @@ nsViewManager::nsViewManager() } // NOTE: we use a zeroing operator new, so all data members are // assumed to be cleared here. - mDefaultBackgroundColor = NS_RGBA(0, 0, 0, 0); mHasPendingUpdates = PR_FALSE; mRecursiveRefreshPending = PR_FALSE; mUpdateBatchFlags = 0; @@ -532,44 +531,6 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, } -// aRect is in app units and relative to the top-left of the aView->GetWidget() -void nsViewManager::DefaultRefresh(nsView* aView, - nsIRenderingContext *aContext, - const nsRect* aRect) -{ - NS_PRECONDITION(aView, "Must have a view to work with!"); - - // Don't draw anything if there's no widget or it's transparent. - nsIWidget* widget = aView->GetNearestWidget(nsnull); - if (!widget || widget->GetTransparencyMode() != eTransparencyOpaque) - return; - - nsCOMPtr context = aContext; - if (!context) - context = CreateRenderingContext(*aView); - - // XXXzw I think this can only happen if we don't have a widget, in - // which case we bailed out above. - if (!context) { - NS_WARNING("nsViewManager: No rendering context for DefaultRefresh"); - return; - } - - nscolor bgcolor = mDefaultBackgroundColor; - // If we somehow get here before any default background color has - // been set, warn and use white. - if (bgcolor == NS_RGBA(0,0,0,0)) { - NS_WARNING("nsViewManager: DefaultRefresh called with no background set"); - bgcolor = NS_RGB(255,255,255); - } - - NS_ASSERTION(NS_GET_A(bgcolor) == 255, - "nsViewManager: non-opaque background color snuck in"); - - context->SetColor(bgcolor); - context->FillRect(*aRect); -} - void nsViewManager::AddCoveringWidgetsToOpaqueRegion(nsRegion &aRgn, nsIDeviceContext* aContext, nsView* aRootView) { NS_PRECONDITION(aRootView, "Must have root view"); @@ -1134,11 +1095,25 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS } } else { // since we got an NS_PAINT event, we need to - // draw something so we don't get blank areas. + // draw something so we don't get blank areas, + // unless there's no widget or it's transparent. nsIntRect damIntRect; - region->GetBoundingBox(&damIntRect.x, &damIntRect.y, &damIntRect.width, &damIntRect.height); - nsRect damRect = nsIntRect::ToAppUnits(damIntRect, mContext->AppUnitsPerDevPixel()); - DefaultRefresh(view, event->renderingContext, &damRect); + region->GetBoundingBox(&damIntRect.x, &damIntRect.y, + &damIntRect.width, &damIntRect.height); + nsRect damRect = + nsIntRect::ToAppUnits(damIntRect, mContext->AppUnitsPerDevPixel()); + + nsIWidget* widget = view->GetNearestWidget(nsnull); + if (widget && widget->GetTransparencyMode() == eTransparencyOpaque) { + nsCOMPtr context = event->renderingContext; + if (!context) + context = CreateRenderingContext(*view); + + if (context) + mObserver->PaintDefaultBackground(view, context, damRect); + else + NS_WARNING("nsViewManager: no rc for default refresh"); + } // Clients like the editor can trigger multiple // reflows during what the user perceives as a single @@ -1163,7 +1138,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS // async paint event for the *entire* ScrollPort or // ScrollingView's viewable area. (See bug 97674 for this // alternate patch.) - + UpdateView(view, damRect, NS_VMREFRESH_NO_SYNC); } @@ -2231,22 +2206,6 @@ nsViewManager::ProcessInvalidateEvent() } } -NS_IMETHODIMP -nsViewManager::SetDefaultBackgroundColor(nscolor aColor) -{ - NS_ASSERTION(NS_GET_A(aColor) == 255, "default background must be opaque"); - mDefaultBackgroundColor = aColor; - return NS_OK; -} - -NS_IMETHODIMP -nsViewManager::GetDefaultBackgroundColor(nscolor* aColor) -{ - *aColor = mDefaultBackgroundColor; - return NS_OK; -} - - NS_IMETHODIMP nsViewManager::GetLastUserEventTime(PRUint32& aTime) { diff --git a/view/src/nsViewManager.h b/view/src/nsViewManager.h index 4e55e56a7cfa..d252bd1ab045 100644 --- a/view/src/nsViewManager.h +++ b/view/src/nsViewManager.h @@ -176,8 +176,6 @@ public: NS_IMETHOD ForceUpdate(); NS_IMETHOD IsPainting(PRBool& aIsPainting); - NS_IMETHOD SetDefaultBackgroundColor(nscolor aColor); - NS_IMETHOD GetDefaultBackgroundColor(nscolor* aColor); NS_IMETHOD GetLastUserEventTime(PRUint32& aTime); void ProcessInvalidateEvent(); static PRUint32 gLastUserEventTime; @@ -262,10 +260,6 @@ private: void Refresh(nsView *aView, nsIRenderingContext *aContext, nsIRegion *region, PRUint32 aUpdateFlags); - /** - * Refresh aView (which must be non-null) with our default background color - */ - void DefaultRefresh(nsView* aView, nsIRenderingContext *aContext, const nsRect* aRect); void RenderViews(nsView *aRootView, nsIRenderingContext& aRC, const nsRegion& aRegion); @@ -427,7 +421,6 @@ private: nsIDeviceContext *mContext; nsIViewObserver *mObserver; nsIScrollableView *mRootScrollable; - nscolor mDefaultBackgroundColor; nsIntPoint mMouseLocation; // device units, relative to mRootView // The size for a resize that we delayed until the root view becomes