From c43b1f1f74c8cf287d0a426c6335f45cba6a6c7b Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Sun, 6 Apr 2003 02:49:40 +0000 Subject: [PATCH] Bug 113232. Support translucent chrome. Relanding, fingers crossed. r+sr=bzbarsky git-svn-id: svn://10.0.0.236/trunk@140762 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/gfx/public/nsIBlender.h | 9 + mozilla/gfx/public/nsIRenderingContext.h | 11 +- mozilla/gfx/src/nsBlender.cpp | 179 ++++++++- mozilla/gfx/src/nsBlender.h | 3 + mozilla/layout/base/nsCSSRendering.cpp | 58 ++- mozilla/layout/generic/nsContainerFrame.cpp | 32 +- .../layout/html/base/src/nsContainerFrame.cpp | 32 +- .../layout/html/style/src/nsCSSRendering.cpp | 58 ++- mozilla/view/src/nsViewManager.cpp | 376 +++++++++++------- mozilla/view/src/nsViewManager.h | 24 +- mozilla/widget/public/nsIWidget.h | 38 ++ mozilla/widget/src/gtk/nsWindow.cpp | 268 +++++++++++-- mozilla/widget/src/gtk/nsWindow.h | 50 ++- mozilla/widget/src/xpwidgets/nsBaseWidget.cpp | 20 + mozilla/widget/src/xpwidgets/nsBaseWidget.h | 3 + 15 files changed, 898 insertions(+), 263 deletions(-) diff --git a/mozilla/gfx/public/nsIBlender.h b/mozilla/gfx/public/nsIBlender.h index 2ee3fe77db1..f39364b5b68 100644 --- a/mozilla/gfx/public/nsIBlender.h +++ b/mozilla/gfx/public/nsIBlender.h @@ -95,6 +95,15 @@ public: nsIRenderingContext *aDest, PRInt32 aDX, PRInt32 aDY, float aSrcOpacity, nsIRenderingContext *aSecondSrc = nsnull, nscolor aSrcBackColor = NS_RGB(0, 0, 0), nscolor aSecondSrcBackColor = NS_RGB(0, 0, 0)) = 0; + + /** + GetAlphas computes an array of alpha values for a rectangle of pixels, using + the drawn-onto-black and the drawn-onto-white images. The pixels are + returned in a new'ed array of aRect.width*aRect.height elements, in row-major + order. This array must be freed by the caller. + */ + NS_IMETHOD GetAlphas(const nsRect& aRect, nsDrawingSurface aBlack, + nsDrawingSurface aWhite, PRUint8** aAlphas) = 0; }; #endif diff --git a/mozilla/gfx/public/nsIRenderingContext.h b/mozilla/gfx/public/nsIRenderingContext.h index b8922cddec2..c35c731811a 100644 --- a/mozilla/gfx/public/nsIRenderingContext.h +++ b/mozilla/gfx/public/nsIRenderingContext.h @@ -198,7 +198,8 @@ public: NS_IMETHOD IsVisibleRect(const nsRect& aRect, PRBool &aIsVisible) = 0; /** - * Sets the clipping for the RenderingContext to the passed in rectangle + * Sets the clipping for the RenderingContext to the passed in rectangle. + * The rectangle is in app units! * @param aRect The rectangle to set the clipping rectangle to * @param aCombine how to combine this rect with the current clip region. * see the bottom of nsIRenderingContext.h @@ -207,7 +208,8 @@ public: NS_IMETHOD SetClipRect(const nsRect& aRect, nsClipCombine aCombine, PRBool &aClipEmpty) = 0; /** - * Gets the bounds of the clip region of the RenderingContext + * Gets the bounds of the clip region of the RenderingContext. The bounds are returned + * in device units! * @param aRect out parameter to contain the clip region bounds * for the RenderingContext * @return PR_TRUE if the rendering context has a local cliprect set @@ -245,7 +247,8 @@ public: /** - * Sets the clipping for the RenderingContext to the passed in region + * Sets the clipping for the RenderingContext to the passed in region. + * The region is in device coordinates! * @param aRegion The region to set the clipping area to, IN DEVICE COORDINATES * @param aCombine how to combine this region with the current clip region. * see the bottom of nsIRenderingContext.h @@ -255,6 +258,7 @@ public: /** * Gets a copy of the current clipping region for the RenderingContext + * The region is in device coordinates! * @param aRegion inout parameter representing the clip region. * if SetClipRegion() is called, do not assume that GetClipRegion() * will return the same object. @@ -263,6 +267,7 @@ public: /** * Gets the current clipping region for the RenderingContext + * The region is in device coordinates! * @param aRegion out parameter representing the clip region. * if SetClipRegion() is called, do not assume that GetClipRegion() * will return the same object. diff --git a/mozilla/gfx/src/nsBlender.cpp b/mozilla/gfx/src/nsBlender.cpp index 3f3c112306d..55f9c1e3690 100644 --- a/mozilla/gfx/src/nsBlender.cpp +++ b/mozilla/gfx/src/nsBlender.cpp @@ -75,6 +75,7 @@ NS_IMPL_ISUPPORTS1(nsBlender, nsIBlender); #define BLEND_RED_SHIFT 7 #define BLEND_GREEN_SHIFT 2 #define BLEND_BLUE_SHIFT 3 +#define BLEND_GREEN_BITS 5 #else // XP_WIN, XP_UNIX, ??? @@ -87,6 +88,7 @@ NS_IMPL_ISUPPORTS1(nsBlender, nsIBlender); #define BLEND_RED_SHIFT 8 #define BLEND_GREEN_SHIFT 3 #define BLEND_BLUE_SHIFT 3 +#define BLEND_GREEN_BITS 6 #endif @@ -102,6 +104,10 @@ nsBlender::Init(nsIDeviceContext *aContext) return NS_OK; } +#define RED16(x) (((x) & BLEND_RED_MASK) >> BLEND_RED_SHIFT) +#define GREEN16(x) (((x) & BLEND_GREEN_MASK) >> BLEND_GREEN_SHIFT) +#define BLUE16(x) (((x) & BLEND_BLUE_MASK) << BLEND_BLUE_SHIFT) + static void rangeCheck(nsIDrawingSurface* surface, PRInt32& aX, PRInt32& aY, PRInt32& aWidth, PRInt32& aHeight) { PRUint32 width, height; @@ -228,6 +234,174 @@ NS_IMETHODIMP nsBlender::Blend(PRInt32 aSX, PRInt32 aSY, PRInt32 aWidth, PRInt32 aSecondSrcBackColor); } +#ifndef MOZ_XUL +NS_IMETHODIMP nsBlender::GetAlphas(const nsRect& aRect, nsDrawingSurface aBlack, + nsDrawingSurface aWhite, PRUint8** aAlphas) { + NS_ERROR("GetAlphas not implemented because XUL support not built"); + return NS_ERROR_NOT_IMPLEMENTED; +} +#else +/** + * Let A be the unknown source pixel's alpha value and let C be its (unknown) color. + * Let S be the value painted onto black and T be the value painted onto white. + * Then S = C*(A/255) and T = 255*(1 - A/255) + C*(A/255). + * Therefore A = 255 - (T - S) + * This is true no matter what color component we look at. + */ +static void ComputeAlphasByByte(PRInt32 aNumLines, PRInt32 aBytesPerLine, + PRInt32 aBytesPerPixel, + PRUint8 *aOnBlackImage, PRUint8 *aOnWhiteImage, + PRInt32 aBytesLineSpan, PRUint8 *aAlphas, + PRUint32 aAlphasSize) +{ + NS_ASSERTION(aBytesPerPixel == 3 || aBytesPerPixel == 4, + "Only 24 or 32 bits per pixel supported here"); + + PRIntn y; + PRUint8* alphas = aAlphas; + for (y = 0; y < aNumLines; y++) { + // Look at component #1. It must be a real color no matter what + // RGBA ordering is used. + PRUint8 *s1 = aOnBlackImage + 1; + PRUint8 *s2 = aOnWhiteImage + 1; + + PRIntn i; + for (i = 1; i < aBytesPerLine; i += aBytesPerPixel) { + *alphas++ = (PRUint8)(255 - (*s2 - *s1)); + s1 += aBytesPerPixel; + s2 += aBytesPerPixel; + } + + aOnBlackImage += aBytesLineSpan; + aOnWhiteImage += aBytesLineSpan; + } + + NS_ASSERTION(alphas - aAlphas == aAlphasSize, "alpha24/32 calculation error"); +} + +/** Use the green channel to work out the alpha value, + since green has the most bits in most divisions of 16-bit color. + + The green values range from 0 to (1 << BLEND_GREEN_BITS) - 1. + Therefore we multiply a green value by 255/((1 << BLEND_GREEN_BITS) - 1) + to get a real alpha value. +*/ +static void ComputeAlphas16(PRInt32 aNumLines, PRInt32 aBytesPerLine, + PRUint8 *aOnBlackImage, PRUint8 *aOnWhiteImage, + PRInt32 aBytesLineSpan, PRUint8 *aAlphas, + PRUint32 aAlphasSize) +{ + PRIntn y; + PRUint8* alphas = aAlphas; + for (y = 0; y < aNumLines; y++) { + PRUint16 *s1 = (PRUint16*)aOnBlackImage; + PRUint16 *s2 = (PRUint16*)aOnWhiteImage; + + // GREEN16 returns a value between 0 and 255 representing the + // green value of the pixel. It only has BLEND_GREEN_BITS of + // precision (so the values are typically 0, 8, 16, ..., 248). + // If we just used the GREEN16 values + // directly in the same equations that we use for the 24-bit case, + // we'd lose because (e.g.) a completely transparent pixel would + // have GREEN16(pix1) = 0, GREEN16(pix2) = 248, and the resulting + // alpha value would just be 248, but we need 255. So we need to + // do some rescaling. + const PRUint32 SCALE_DENOMINATOR = // usually 248 + ((1 << BLEND_GREEN_BITS) - 1) << (8 - BLEND_GREEN_BITS); + + PRIntn i; + for (i = 0; i < aBytesPerLine; i += 2) { + PRUint32 pix1 = GREEN16(*s1); + PRUint32 pix2 = GREEN16(*s2); + *alphas++ = (PRUint8)(255 - ((pix2 - pix1)*255)/SCALE_DENOMINATOR); + s1++; + s2++; + } + + aOnBlackImage += aBytesLineSpan; + aOnWhiteImage += aBytesLineSpan; + } + + NS_ASSERTION(alphas - aAlphas == aAlphasSize, "alpha16 calculation error"); +} + +static void ComputeAlphas(PRInt32 aNumLines, PRInt32 aBytesPerLine, + PRInt32 aDepth, + PRUint8 *aOnBlackImage, PRUint8 *aOnWhiteImage, + PRInt32 aBytesLineSpan, PRUint8 *aAlphas, + PRUint32 aAlphasSize) +{ + switch (aDepth) { + case 32: + case 24: + ComputeAlphasByByte(aNumLines, aBytesPerLine, aDepth/8, + aOnBlackImage, aOnWhiteImage, + aBytesLineSpan, aAlphas, aAlphasSize); + break; + + case 16: + ComputeAlphas16(aNumLines, aBytesPerLine, aOnBlackImage, aOnWhiteImage, + aBytesLineSpan, aAlphas, aAlphasSize); + break; + + default: + NS_ERROR("Unknown depth for alpha calculation"); + // make them all opaque + memset(aAlphas, 255, aAlphasSize); + } +} + +NS_IMETHODIMP nsBlender::GetAlphas(const nsRect& aRect, nsDrawingSurface aBlack, + nsDrawingSurface aWhite, PRUint8** aAlphas) { + nsresult result; + + nsIDrawingSurface* blackSurface = (nsIDrawingSurface *)aBlack; + nsIDrawingSurface* whiteSurface = (nsIDrawingSurface *)aWhite; + + nsRect r = aRect; + + rangeCheck(blackSurface, r.x, r.y, r.width, r.height); + rangeCheck(whiteSurface, r.x, r.y, r.width, r.height); + + PRUint8* blackBytes = nsnull; + PRUint8* whiteBytes = nsnull; + PRInt32 blackSpan, whiteSpan; + PRInt32 blackBytesPerLine, whiteBytesPerLine; + + result = blackSurface->Lock(r.x, r.y, r.width, r.height, + (void**)&blackBytes, &blackSpan, + &blackBytesPerLine, NS_LOCK_SURFACE_READ_ONLY); + if (NS_SUCCEEDED(result)) { + result = whiteSurface->Lock(r.x, r.y, r.width, r.height, + (void**)&whiteBytes, &whiteSpan, + &whiteBytesPerLine, NS_LOCK_SURFACE_READ_ONLY); + if (NS_SUCCEEDED(result)) { + NS_ASSERTION(blackSpan == whiteSpan && + blackBytesPerLine == whiteBytesPerLine, + "Mismatched bitmap formats (black/white) in Blender"); + if (blackSpan == whiteSpan && blackBytesPerLine == whiteBytesPerLine) { + *aAlphas = new PRUint8[r.width*r.height]; + if (*aAlphas) { + PRUint32 depth; + mContext->GetDepth(depth); + ComputeAlphas(r.height, blackBytesPerLine, depth, + blackBytes, whiteBytes, blackSpan, + *aAlphas, r.width*r.height); + } else { + result = NS_ERROR_FAILURE; + } + } + + whiteSurface->Unlock(); + } + + blackSurface->Unlock(); + } + + return result; +} +#endif // MOZ_XUL + /** --------------------------------------------------- * See documentation in nsBlender.h * @update 2/25/00 dwc @@ -526,10 +700,6 @@ nsBlender::Do24Blend(float aOpacity, PRInt32 aNumLines, PRInt32 aNumBytes, -#define RED16(x) (((x) & BLEND_RED_MASK) >> BLEND_RED_SHIFT) -#define GREEN16(x) (((x) & BLEND_GREEN_MASK) >> BLEND_GREEN_SHIFT) -#define BLUE16(x) (((x) & BLEND_BLUE_MASK) << BLEND_BLUE_SHIFT) - #define MAKE16(r, g, b) \ (PRUint16)(((r) & BLEND_RED_SET_MASK) << BLEND_RED_SHIFT) \ | (((g) & BLEND_GREEN_SET_MASK) << BLEND_GREEN_SHIFT) \ @@ -573,7 +743,6 @@ nsBlender::Do16Blend(float aOpacity, PRInt32 aNumLines, PRInt32 aNumBytes, *d2 = MAKE16(destPixR + (((RED16(srcPix) - destPixR)*opacity256) >> 8), destPixG + (((GREEN16(srcPix) - destPixG)*opacity256) >> 8), destPixB + (((BLUE16(srcPix) - destPixB)*opacity256) >> 8)); - d2++; s2++; } diff --git a/mozilla/gfx/src/nsBlender.h b/mozilla/gfx/src/nsBlender.h index 23a012d9af9..6c3b9df215e 100644 --- a/mozilla/gfx/src/nsBlender.h +++ b/mozilla/gfx/src/nsBlender.h @@ -60,6 +60,9 @@ public: nsIRenderingContext *aSecondSrc = nsnull, nscolor aSrcBackColor = NS_RGB(0, 0, 0), nscolor aSecondSrcBackColor = NS_RGB(0, 0, 0)); + NS_IMETHOD GetAlphas(const nsRect& aRect, nsDrawingSurface aBlack, + nsDrawingSurface aWhite, PRUint8** aAlphas); + protected: /** -------------------------------------------------------------------------- diff --git a/mozilla/layout/base/nsCSSRendering.cpp b/mozilla/layout/base/nsCSSRendering.cpp index d9a0dae7bd9..9db1d63e0a7 100644 --- a/mozilla/layout/base/nsCSSRendering.cpp +++ b/mozilla/layout/base/nsCSSRendering.cpp @@ -2615,14 +2615,32 @@ nsCSSRendering::FindNonTransparentBackground(nsStyleContext* aContext, * canvas. */ -inline PRBool -IsCanvasFrame(nsIFrame *aFrame) +// Returns nsnull if aFrame is not a canvas frame. +// Otherwise, it returns the frame we should look for the background on. +// This is normally aFrame but if aFrame is the viewport, we need to +// look for the background starting at the scroll root (which shares +// style context with the document root) or the document root itself. +// We need to treat the viewport as canvas because, even though +// it does not actually paint a background, we need to get the right +// background style so we correctly detect transparent documents. +inline nsIFrame* +IsCanvasFrame(nsIPresContext* aPresContext, nsIFrame *aFrame) { nsCOMPtr frameType; aFrame->GetFrameType(getter_AddRefs(frameType)); - return (frameType == nsLayoutAtoms::canvasFrame || - frameType == nsLayoutAtoms::rootFrame || - frameType == nsLayoutAtoms::pageFrame); + if (frameType == nsLayoutAtoms::canvasFrame || + frameType == nsLayoutAtoms::rootFrame || + frameType == nsLayoutAtoms::pageFrame) { + return aFrame; + } else if (frameType == nsLayoutAtoms::viewportFrame) { + nsIFrame* firstChild; + aFrame->FirstChild(aPresContext, nsnull, &firstChild); + if (firstChild) { + return firstChild; + } + } + + return nsnull; } inline PRBool @@ -2719,7 +2737,7 @@ FindElementBackground(nsIPresContext* aPresContext, nsIFrame *parentFrame; aForFrame->GetParent(&parentFrame); // XXXldb We shouldn't have to null-check |parentFrame| here. - if (parentFrame && IsCanvasFrame(parentFrame)) { + if (parentFrame && IsCanvasFrame(aPresContext, parentFrame) == parentFrame) { // Check that we're really the root (rather than in another child list). nsIFrame *childFrame; parentFrame->FirstChild(aPresContext, nsnull, &childFrame); @@ -2761,10 +2779,10 @@ nsCSSRendering::FindBackground(nsIPresContext* aPresContext, const nsStyleBackground** aBackground, PRBool* aIsCanvas) { - PRBool isCanvas = IsCanvasFrame(aForFrame); - *aIsCanvas = isCanvas; - return isCanvas - ? FindCanvasBackground(aPresContext, aForFrame, aBackground) + nsIFrame* canvasFrame = IsCanvasFrame(aPresContext, aForFrame); + *aIsCanvas = canvasFrame != nsnull; + return canvasFrame + ? FindCanvasBackground(aPresContext, canvasFrame, aBackground) : FindElementBackground(aPresContext, aForFrame, aBackground); } @@ -2836,11 +2854,21 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, vm->GetRootView(rootView); nsIView* rootParent; rootView->GetParent(rootParent); - if (nsnull == rootParent) { - // Ensure that we always paint a color for the root (in case there's - // no background at all or a partly transparent image). - canvasColor.mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; - aPresContext->GetDefaultBackgroundColor(&canvasColor.mBackgroundColor); + if (!rootParent) { + PRBool widgetIsTranslucent = PR_FALSE; + + nsCOMPtr rootWidget; + rootView->GetWidget(*getter_AddRefs(rootWidget)); + if (rootWidget) { + rootWidget->GetWindowTranslucency(widgetIsTranslucent); + } + + if (!widgetIsTranslucent) { + // Ensure that we always paint a color for the root (in case there's + // no background at all or a partly transparent image). + canvasColor.mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; + aPresContext->GetDefaultBackgroundColor(&canvasColor.mBackgroundColor); + } } } diff --git a/mozilla/layout/generic/nsContainerFrame.cpp b/mozilla/layout/generic/nsContainerFrame.cpp index f4006fb69d3..b173b99195a 100644 --- a/mozilla/layout/generic/nsContainerFrame.cpp +++ b/mozilla/layout/generic/nsContainerFrame.cpp @@ -37,6 +37,7 @@ * ***** END LICENSE BLOCK ***** */ #include "nsContainerFrame.h" #include "nsIContent.h" +#include "nsIDocument.h" #include "nsIPresContext.h" #include "nsIRenderingContext.h" #include "nsStyleContext.h" @@ -558,15 +559,42 @@ SyncFrameViewGeometryDependentProperties(nsIPresContext* aPresContext, (bg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) || !aFrame->CanPaintBackground() || HasNonZeroBorderRadius(aStyleContext); - if (isCanvas && viewHasTransparentContent) { + + if (isCanvas) { nsIView* rootView; vm->GetRootView(rootView); nsIView* rootParent; rootView->GetParent(rootParent); - if (nsnull == rootParent) { + if (!rootParent) { + // We're the root of a view manager hierarchy. We will have to + // paint something. NOTE: this can be overridden below. viewHasTransparentContent = PR_FALSE; } + + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + nsCOMPtr doc; + shell->GetDocument(getter_AddRefs(doc)); + if (doc) { + nsCOMPtr parentDoc; + doc->GetParentDocument(getter_AddRefs(parentDoc)); + nsCOMPtr rootElem; + doc->GetRootContent(getter_AddRefs(rootElem)); + if (!parentDoc && rootElem && rootElem->IsContentOfType(nsIContent::eXUL)) { + // we're XUL at the root of the document hierarchy. Try to make our + // window translucent. + nsCOMPtr widget; + aView->GetWidget(*getter_AddRefs(widget)); + // don't proceed unless this is the root view + // (sometimes the non-root-view is a canvas) + if (widget && aView == rootView) { + viewHasTransparentContent = hasBG && (bg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT); + widget->SetWindowTranslucency(viewHasTransparentContent); + } + } + } } + // XXX we should also set widget transparency for XUL popups const nsStyleDisplay* display; ::GetStyleData(aStyleContext, &display); diff --git a/mozilla/layout/html/base/src/nsContainerFrame.cpp b/mozilla/layout/html/base/src/nsContainerFrame.cpp index f4006fb69d3..b173b99195a 100644 --- a/mozilla/layout/html/base/src/nsContainerFrame.cpp +++ b/mozilla/layout/html/base/src/nsContainerFrame.cpp @@ -37,6 +37,7 @@ * ***** END LICENSE BLOCK ***** */ #include "nsContainerFrame.h" #include "nsIContent.h" +#include "nsIDocument.h" #include "nsIPresContext.h" #include "nsIRenderingContext.h" #include "nsStyleContext.h" @@ -558,15 +559,42 @@ SyncFrameViewGeometryDependentProperties(nsIPresContext* aPresContext, (bg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) || !aFrame->CanPaintBackground() || HasNonZeroBorderRadius(aStyleContext); - if (isCanvas && viewHasTransparentContent) { + + if (isCanvas) { nsIView* rootView; vm->GetRootView(rootView); nsIView* rootParent; rootView->GetParent(rootParent); - if (nsnull == rootParent) { + if (!rootParent) { + // We're the root of a view manager hierarchy. We will have to + // paint something. NOTE: this can be overridden below. viewHasTransparentContent = PR_FALSE; } + + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + nsCOMPtr doc; + shell->GetDocument(getter_AddRefs(doc)); + if (doc) { + nsCOMPtr parentDoc; + doc->GetParentDocument(getter_AddRefs(parentDoc)); + nsCOMPtr rootElem; + doc->GetRootContent(getter_AddRefs(rootElem)); + if (!parentDoc && rootElem && rootElem->IsContentOfType(nsIContent::eXUL)) { + // we're XUL at the root of the document hierarchy. Try to make our + // window translucent. + nsCOMPtr widget; + aView->GetWidget(*getter_AddRefs(widget)); + // don't proceed unless this is the root view + // (sometimes the non-root-view is a canvas) + if (widget && aView == rootView) { + viewHasTransparentContent = hasBG && (bg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT); + widget->SetWindowTranslucency(viewHasTransparentContent); + } + } + } } + // XXX we should also set widget transparency for XUL popups const nsStyleDisplay* display; ::GetStyleData(aStyleContext, &display); diff --git a/mozilla/layout/html/style/src/nsCSSRendering.cpp b/mozilla/layout/html/style/src/nsCSSRendering.cpp index d9a0dae7bd9..9db1d63e0a7 100644 --- a/mozilla/layout/html/style/src/nsCSSRendering.cpp +++ b/mozilla/layout/html/style/src/nsCSSRendering.cpp @@ -2615,14 +2615,32 @@ nsCSSRendering::FindNonTransparentBackground(nsStyleContext* aContext, * canvas. */ -inline PRBool -IsCanvasFrame(nsIFrame *aFrame) +// Returns nsnull if aFrame is not a canvas frame. +// Otherwise, it returns the frame we should look for the background on. +// This is normally aFrame but if aFrame is the viewport, we need to +// look for the background starting at the scroll root (which shares +// style context with the document root) or the document root itself. +// We need to treat the viewport as canvas because, even though +// it does not actually paint a background, we need to get the right +// background style so we correctly detect transparent documents. +inline nsIFrame* +IsCanvasFrame(nsIPresContext* aPresContext, nsIFrame *aFrame) { nsCOMPtr frameType; aFrame->GetFrameType(getter_AddRefs(frameType)); - return (frameType == nsLayoutAtoms::canvasFrame || - frameType == nsLayoutAtoms::rootFrame || - frameType == nsLayoutAtoms::pageFrame); + if (frameType == nsLayoutAtoms::canvasFrame || + frameType == nsLayoutAtoms::rootFrame || + frameType == nsLayoutAtoms::pageFrame) { + return aFrame; + } else if (frameType == nsLayoutAtoms::viewportFrame) { + nsIFrame* firstChild; + aFrame->FirstChild(aPresContext, nsnull, &firstChild); + if (firstChild) { + return firstChild; + } + } + + return nsnull; } inline PRBool @@ -2719,7 +2737,7 @@ FindElementBackground(nsIPresContext* aPresContext, nsIFrame *parentFrame; aForFrame->GetParent(&parentFrame); // XXXldb We shouldn't have to null-check |parentFrame| here. - if (parentFrame && IsCanvasFrame(parentFrame)) { + if (parentFrame && IsCanvasFrame(aPresContext, parentFrame) == parentFrame) { // Check that we're really the root (rather than in another child list). nsIFrame *childFrame; parentFrame->FirstChild(aPresContext, nsnull, &childFrame); @@ -2761,10 +2779,10 @@ nsCSSRendering::FindBackground(nsIPresContext* aPresContext, const nsStyleBackground** aBackground, PRBool* aIsCanvas) { - PRBool isCanvas = IsCanvasFrame(aForFrame); - *aIsCanvas = isCanvas; - return isCanvas - ? FindCanvasBackground(aPresContext, aForFrame, aBackground) + nsIFrame* canvasFrame = IsCanvasFrame(aPresContext, aForFrame); + *aIsCanvas = canvasFrame != nsnull; + return canvasFrame + ? FindCanvasBackground(aPresContext, canvasFrame, aBackground) : FindElementBackground(aPresContext, aForFrame, aBackground); } @@ -2836,11 +2854,21 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, vm->GetRootView(rootView); nsIView* rootParent; rootView->GetParent(rootParent); - if (nsnull == rootParent) { - // Ensure that we always paint a color for the root (in case there's - // no background at all or a partly transparent image). - canvasColor.mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; - aPresContext->GetDefaultBackgroundColor(&canvasColor.mBackgroundColor); + if (!rootParent) { + PRBool widgetIsTranslucent = PR_FALSE; + + nsCOMPtr rootWidget; + rootView->GetWidget(*getter_AddRefs(rootWidget)); + if (rootWidget) { + rootWidget->GetWindowTranslucency(widgetIsTranslucent); + } + + if (!widgetIsTranslucent) { + // Ensure that we always paint a color for the root (in case there's + // no background at all or a partly transparent image). + canvasColor.mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; + aPresContext->GetDefaultBackgroundColor(&canvasColor.mBackgroundColor); + } } } diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index edfe268829c..a357cf988a5 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -99,6 +99,33 @@ static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); #define SUPPORT_TRANSLUCENT_VIEWS +/* + This class encapsulates all the offscreen buffers we might want to + render into. mOffscreen is the basic buffer for doing + double-buffering. mBlack and mWhite are buffers for collecting an + individual view drawn onto black and drawn onto white, from which we + can recover the alpha values of the view's pixels. mOffscreenWhite + is only for when the widget being rendered is transparent; it's an + alternative double-buffer buffer that starts off white instead of + black, and allows us to recover alpha values for the widget. +*/ +class BlendingBuffers { +public: + BlendingBuffers(nsIRenderingContext* aCleanupContext); + ~BlendingBuffers(); + + nsCOMPtr mCleanupContext; + nsCOMPtr mOffScreenCX; + nsCOMPtr mOffScreenWhiteCX; + nsCOMPtr mBlackCX; + nsCOMPtr mWhiteCX; + + nsDrawingSurface mOffScreen; + nsDrawingSurface mOffScreenWhite; + nsDrawingSurface mBlack; + nsDrawingSurface mWhite; +}; + // A DisplayListElement2 records the information needed to paint one view. // Note that child views get their own DisplayListElement2s; painting a view // paints that view's frame and all its child frames EXCEPT for the child frames @@ -291,10 +318,6 @@ nsViewManager::PostInvalidateEvent() PRInt32 nsViewManager::mVMCount = 0; nsIRenderingContext* nsViewManager::gCleanupContext = nsnull; -nsDrawingSurface nsViewManager::gOffScreen = nsnull; -nsDrawingSurface nsViewManager::gBlack = nsnull; -nsDrawingSurface nsViewManager::gWhite = nsnull; -nsSize nsViewManager::gOffScreenSize = nsSize(0, 0); // Weakly held references to all of the view managers nsVoidArray* nsViewManager::gViewManagers = nsnull; @@ -366,37 +389,16 @@ nsViewManager::~nsViewManager() if (gCleanupContext) { gCleanupContext->DestroyCachedBackbuffer(); - - if (nsnull != gOffScreen) - gCleanupContext->DestroyDrawingSurface(gOffScreen); - - if (nsnull != gWhite) - gCleanupContext->DestroyDrawingSurface(gWhite); - - if (nsnull != gBlack) - gCleanupContext->DestroyDrawingSurface(gBlack); - } else { NS_ASSERTION(PR_FALSE, "Cleanup of drawing surfaces + offscreen buffer failed"); } - gOffScreen = nsnull; - gWhite = nsnull; - gBlack = nsnull; - gOffScreenSize.SizeTo(0, 0); - NS_IF_RELEASE(gCleanupContext); } mObserver = nsnull; mContext = nsnull; - NS_IF_RELEASE(mBlender); - - NS_IF_RELEASE(mOffScreenCX); - NS_IF_RELEASE(mBlackCX); - NS_IF_RELEASE(mWhiteCX); - if (nsnull != mCompositeListeners) { mCompositeListeners->Clear(); NS_RELEASE(mCompositeListeners); @@ -637,15 +639,15 @@ static void ConvertNativeRegionToAppRegion(nsIRegion* aIn, nsRegion* aOut, float p2t; context->GetDevUnitsToAppUnits(p2t); - // roc says: - // we mustn't introduce any off by one errors here, so stick to integer arithmetic - // this assumes that p2t is an integer, but if it isn't, all kinds of other stuff breaks anyway - int pt2i = (int)floor(p2t+0.5); PRUint32 i; for (i = 0; i < rects->mNumRects; i++) { const nsRegionRect& inR = rects->mRects[i]; - nsRect outR(inR.x*pt2i, inR.y*pt2i, inR.width*pt2i, inR.height*pt2i); + nsRect outR; + outR.x = NSToIntRound(inR.x * p2t); + outR.y = NSToIntRound(inR.y * p2t); + outR.width = NSToIntRound(inR.width * p2t); + outR.height = NSToIntRound(inR.height * p2t); aOut->Or(*aOut, outR); } @@ -1028,13 +1030,11 @@ static void PushStateAndClip(nsIRenderingContext **aRCs, PRInt32 aRCCount, nsRec PRInt32 aDX, PRInt32 aDY) { PRBool clipEmpty; nsRect rect = aRect; + rect.x -= aDX; + rect.y -= aDY; for (PRInt32 i = 0; i < aRCCount; i++) { aRCs[i]->PushState(); - if (i == 1) { - rect.x -= aDX; - rect.y -= aDY; - } - aRCs[i]->SetClipRect(rect, nsClipCombine_kIntersect, clipEmpty); + aRCs[i]->SetClipRect(i == 0 ? aRect : rect, nsClipCombine_kIntersect, clipEmpty); } } @@ -1150,15 +1150,30 @@ void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, // We keep a list of all the rendering contexts whose clip rects // need to be updated. - nsIRenderingContext* RCList[4]; + nsIRenderingContext* RCList[5]; PRInt32 RCCount = 1; RCList[0] = &aRC; + nsCOMPtr widget; + aRootView->GetWidget(*getter_AddRefs(widget)); + PRBool translucentWindow = PR_FALSE; + if (widget) { + widget->GetWindowTranslucency(translucentWindow); + if (translucentWindow) { + NS_WARNING("Transparent window enabled"); + // for a translucent window, we'll pretend the whole area is + // translucent. + mTranslucentArea = aRegion.GetBounds(); + } + } + + BlendingBuffers* buffers = nsnull; + // create blending buffers, if necessary. - if (mTranslucentViewCount > 0) { - nsresult rv = CreateBlendingBuffers(aRC); - NS_ASSERTION(NS_SUCCEEDED(rv), "not enough memory to blend"); - if (NS_FAILED(rv)) { + if (mTranslucentViewCount > 0 || translucentWindow) { + buffers = CreateBlendingBuffers(&aRC, translucentWindow); + NS_ASSERTION(buffers, "not enough memory to blend"); + if (!buffers) { // fall back by just rendering with transparency. mTranslucentViewCount = 0; for (PRInt32 i = mDisplayListCount - 1; i>= 0; --i) { @@ -1166,18 +1181,23 @@ void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, element->mFlags &= ~VIEW_TRANSLUCENT; } } else { - RCCount = 4; - RCList[1] = mBlackCX; - RCList[2] = mWhiteCX; - RCList[3] = mOffScreenCX; + RCList[RCCount++] = buffers->mOffScreenCX; + if (translucentWindow) { + RCList[RCCount++] = buffers->mOffScreenWhiteCX; + } + if (mTranslucentViewCount > 0) { + RCList[RCCount++] = buffers->mBlackCX; + RCList[RCCount++] = buffers->mWhiteCX; + } + + if (!translucentWindow && !finalTransparentRect.IsEmpty()) { + // There are some bits that aren't going to be completely painted, so + // make sure we don't leave garbage in the offscreen context + buffers->mOffScreenCX->SetColor(NS_RGB(128, 128, 128)); + buffers->mOffScreenCX->FillRect(nsRect(0, 0, mTranslucentArea.width, mTranslucentArea.height)); + } } - if (!finalTransparentRect.IsEmpty()) { - // There are some bits that aren't going to be completely painted, so - // make sure we don't leave garbage in the offscreen context - mOffScreenCX->SetColor(NS_RGB(128, 128, 128)); - mOffScreenCX->FillRect(nsRect(0, 0, gOffScreenSize.width, gOffScreenSize.height)); - } // DEBUGGING: fill in complete offscreen image in green, to see if we've got a blending bug. // mOffScreenCX->SetColor(NS_RGB(0, 255, 0)); // mOffScreenCX->FillRect(nsRect(0, 0, gOffScreenSize.width, gOffScreenSize.height)); @@ -1192,10 +1212,10 @@ void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, if (element->mFlags & VIEW_CLIPPED) { //Render the view using the clip rect set by it's ancestors PushStateAndClip(RCList, RCCount, element->mBounds, mTranslucentArea.x, mTranslucentArea.y); - RenderDisplayListElement(element, aRC); + RenderDisplayListElement(element, aRC, buffers); PopState(RCList, RCCount); } else { - RenderDisplayListElement(element, aRC); + RenderDisplayListElement(element, aRC, buffers); } } else { @@ -1214,31 +1234,52 @@ void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, // flush bits back to screen. // Must flush back when no clipping is in effect. - if (mTranslucentViewCount > 0) { + if (buffers) { + if (translucentWindow) { + // Set window alphas + nsRect r = mTranslucentArea; + r *= mTwipsToPixels; + nsRect bufferRect(0, 0, r.width, r.height); + PRUint8* alphas = nsnull; + nsresult rv = mBlender->GetAlphas(bufferRect, buffers->mOffScreen, + buffers->mOffScreenWhite, &alphas); + + if (NS_SUCCEEDED(rv)) { + widget->UpdateTranslucentWindowAlpha(r, alphas); + } + delete[] alphas; + } + // DEBUG: is this getting through? // mOffScreenCX->SetColor(NS_RGB(177, 177, 0)); // mOffScreenCX->FillRect(nsRect(1, 1, mTranslucentArea.width-2, mTranslucentArea.height-2)); - aRC.CopyOffScreenBits(gOffScreen, 0, 0, mTranslucentArea, + aRC.CopyOffScreenBits(buffers->mOffScreen, 0, 0, mTranslucentArea, NS_COPYBITS_XFORM_DEST_VALUES | NS_COPYBITS_TO_BACK_BUFFER); // DEBUG: what rectangle are we blitting? // aRC.SetColor(NS_RGB(0, 177, 177)); // aRC.DrawRect(mTranslucentArea); + + delete buffers; } mDisplayList.Clear(); } -void nsViewManager::RenderDisplayListElement(DisplayListElement2* element, nsIRenderingContext &aRC) +void nsViewManager::RenderDisplayListElement(DisplayListElement2* element, + nsIRenderingContext &aRC, + BlendingBuffers* aBuffers) { - PRBool isTranslucent = (element->mFlags & VIEW_TRANSLUCENT) != 0; PRBool clipEmpty; nsRect r; nsView* view = element->mView; view->GetDimensions(r); - if (!isTranslucent) { + // if this element is contained by the translucent area, then + // there's no point in drawing it here because it will be + // overwritten by the final copy of the composited offscreen area + if (!aBuffers || !mTranslucentArea.Contains(element->mBounds)) { aRC.PushState(); nscoord x = element->mAbsX - r.x, y = element->mAbsY - r.y; @@ -1253,11 +1294,7 @@ void nsViewManager::RenderDisplayListElement(DisplayListElement2* element, nsIRe } #if defined(SUPPORT_TRANSLUCENT_VIEWS) - if (mTranslucentViewCount > 0 && (isTranslucent || mTranslucentArea.Intersects(element->mBounds))) { - // transluscency case. if this view is transluscent, have to use the nsIBlender, otherwise, just - // render in the offscreen. when we reach the last transluscent view, then we flush the bits - // to the onscreen rendering context. - + if (aBuffers && mTranslucentArea.Intersects(element->mBounds)) { // compute the origin of the view, relative to the offscreen buffer, which has the // same dimensions as mTranslucentArea. nscoord x = element->mAbsX - r.x, y = element->mAbsY - r.y; @@ -1267,16 +1304,21 @@ void nsViewManager::RenderDisplayListElement(DisplayListElement2* element, nsIRe damageRect.IntersectRect(damageRect, mTranslucentArea); // -> coordinates relative to element->mView origin damageRect.x -= x, damageRect.y -= y; + + // the element must be rendered into mOffscreenCX and also + // mOffScreenWhiteCX if the window is transparent/translucent. + nsIRenderingContext* targets[2] = + { aBuffers->mOffScreenCX, aBuffers->mOffScreenWhiteCX }; if (element->mFlags & VIEW_TRANSLUCENT) { // paint the view twice, first in the black buffer, then the white; // the blender will pick up the touched pixels only. - PaintView(view, *mBlackCX, viewX, viewY, damageRect); + PaintView(view, *aBuffers->mBlackCX, viewX, viewY, damageRect); // DEBUGGING ONLY //aRC.CopyOffScreenBits(gBlack, 0, 0, element->mBounds, // NS_COPYBITS_XFORM_DEST_VALUES | NS_COPYBITS_TO_BACK_BUFFER); - PaintView(view, *mWhiteCX, viewX, viewY, damageRect); + PaintView(view, *aBuffers->mWhiteCX, viewX, viewY, damageRect); // DEBUGGING ONLY //aRC.CopyOffScreenBits(gWhite, 0, 0, element->mBounds, // NS_COPYBITS_XFORM_DEST_VALUES | NS_COPYBITS_TO_BACK_BUFFER); @@ -1293,17 +1335,22 @@ void nsViewManager::RenderDisplayListElement(DisplayListElement2* element, nsIRe nsRect damageRectInPixels = damageRect; damageRectInPixels *= mTwipsToPixels; if (damageRectInPixels.width > 0 && damageRectInPixels.height > 0) { - nsresult rv = mBlender->Blend(damageRectInPixels.x, damageRectInPixels.y, - damageRectInPixels.width, damageRectInPixels.height, - mBlackCX, mOffScreenCX, - damageRectInPixels.x, damageRectInPixels.y, - opacity, mWhiteCX, - NS_RGB(0, 0, 0), NS_RGB(255, 255, 255)); - if (NS_FAILED(rv)) { - NS_WARNING("Blend failed!"); - // let's paint SOMETHING. Paint opaquely - damageRect.MoveBy(-viewX, -viewY); - PaintView(view, *mOffScreenCX, viewX, viewY, damageRect); + PRIntn i; + for (i = 0; i < 2; i++) { + if (targets[i]) { + nsresult rv = mBlender->Blend(damageRectInPixels.x, damageRectInPixels.y, + damageRectInPixels.width, damageRectInPixels.height, + aBuffers->mBlackCX, targets[i], + damageRectInPixels.x, damageRectInPixels.y, + opacity, aBuffers->mWhiteCX, + NS_RGB(0, 0, 0), NS_RGB(255, 255, 255)); + if (NS_FAILED(rv)) { + NS_WARNING("Blend failed!"); + // let's paint SOMETHING. Paint opaquely + damageRect.MoveBy(-viewX, -viewY); + PaintView(view, *targets[i], viewX, viewY, damageRect); + } + } } } @@ -1311,12 +1358,17 @@ void nsViewManager::RenderDisplayListElement(DisplayListElement2* element, nsIRe // We do that here because we know that whatever the clip region is, // everything we just painted is within the clip region so we are // sure to be able to overwrite it now. - mBlackCX->SetColor(NS_RGB(0, 0, 0)); - mBlackCX->FillRect(damageRect); - mWhiteCX->SetColor(NS_RGB(255, 255, 255)); - mWhiteCX->FillRect(damageRect); + aBuffers->mBlackCX->SetColor(NS_RGB(0, 0, 0)); + aBuffers->mBlackCX->FillRect(damageRect); + aBuffers->mWhiteCX->SetColor(NS_RGB(255, 255, 255)); + aBuffers->mWhiteCX->FillRect(damageRect); } else { - PaintView(view, *mOffScreenCX, viewX, viewY, damageRect); + PRIntn i; + for (i = 0; i < 2; i++) { + if (targets[i]) { + PaintView(view, *targets[i], viewX, viewY, damageRect); + } + } } } #endif @@ -1332,14 +1384,6 @@ void nsViewManager::PaintView(nsView *aView, nsIRenderingContext &aRC, nscoord x aRC.PopState(unused); } -inline PRInt32 nextPowerOf2(PRInt32 value) -{ - PRInt32 result = 1; - while (value > result) - result <<= 1; - return result; -} - static nsresult NewOffscreenContext(nsIDeviceContext* deviceContext, nsDrawingSurface surface, const nsSize& size, nsIRenderingContext* *aResult) { @@ -1359,87 +1403,119 @@ static nsresult NewOffscreenContext(nsIDeviceContext* deviceContext, nsDrawingSu return NS_OK; } -nsresult nsViewManager::CreateBlendingBuffers(nsIRenderingContext &aRC) +BlendingBuffers::BlendingBuffers(nsIRenderingContext* aCleanupContext) { + mCleanupContext = aCleanupContext; + + mOffScreen = nsnull; + mOffScreenWhite = nsnull; + mWhite = nsnull; + mBlack = nsnull; +} + +BlendingBuffers::~BlendingBuffers() { + if (mOffScreen) + mCleanupContext->DestroyDrawingSurface(mOffScreen); + + if (mOffScreenWhite) + mCleanupContext->DestroyDrawingSurface(mOffScreenWhite); + + if (mWhite) + mCleanupContext->DestroyDrawingSurface(mWhite); + + if (mBlack) + mCleanupContext->DestroyDrawingSurface(mBlack); +} + +BlendingBuffers* nsViewManager::CreateBlendingBuffers(nsIRenderingContext *aRC, + PRBool aTranslucentWindow) { - nsresult rv = NS_OK; + nsresult rv; // create a blender, if none exists already. - if (nsnull == mBlender) { - rv = nsComponentManager::CreateInstance(kBlenderCID, nsnull, NS_GET_IID(nsIBlender), (void **)&mBlender); + if (!mBlender) { + mBlender = do_CreateInstance(kBlenderCID, &rv); if (NS_FAILED(rv)) - return rv; + return nsnull; rv = mBlender->Init(mContext); if (NS_FAILED(rv)) - return rv; + return nsnull; } - // ensure that the global drawing surfaces are large enough. - if (mTranslucentArea.width > gOffScreenSize.width || mTranslucentArea.height > gOffScreenSize.height) { - nsRect offscreenBounds(0, 0, mTranslucentArea.width, mTranslucentArea.height); - offscreenBounds.ScaleRoundOut(mTwipsToPixels); - offscreenBounds.width = nextPowerOf2(offscreenBounds.width); - offscreenBounds.height = nextPowerOf2(offscreenBounds.height); + BlendingBuffers* buffers = new BlendingBuffers(aRC); + if (!buffers) + return nsnull; - NS_IF_RELEASE(mOffScreenCX); - NS_IF_RELEASE(mBlackCX); - NS_IF_RELEASE(mWhiteCX); + nsRect offscreenBounds(0, 0, mTranslucentArea.width, mTranslucentArea.height); + offscreenBounds.ScaleRoundOut(mTwipsToPixels); + nsSize offscreenSize(mTranslucentArea.width, mTranslucentArea.height); - if (nsnull != gOffScreen) { - aRC.DestroyDrawingSurface(gOffScreen); - gOffScreen = nsnull; + rv = aRC->CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, buffers->mOffScreen); + if (NS_FAILED(rv)) { + delete buffers; + return nsnull; + } + + rv = NewOffscreenContext(mContext, buffers->mOffScreen, offscreenSize, getter_AddRefs(buffers->mOffScreenCX)); + if (NS_FAILED(rv)) { + delete buffers; + return nsnull; + } + + if (mTranslucentViewCount > 0) { + rv = aRC->CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, buffers->mBlack); + if (NS_FAILED(rv)) { + delete buffers; + return nsnull; } - rv = aRC.CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gOffScreen); - if (NS_FAILED(rv)) - return rv; - if (nsnull != gBlack) { - aRC.DestroyDrawingSurface(gBlack); - gBlack = nsnull; + rv = aRC->CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, buffers->mWhite); + if (NS_FAILED(rv)) { + delete buffers; + return nsnull; } - rv = aRC.CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gBlack); - if (NS_FAILED(rv)) - return rv; - - if (nsnull != gWhite) { - aRC.DestroyDrawingSurface(gWhite); - gWhite = nsnull; + + rv = NewOffscreenContext(mContext, buffers->mBlack, offscreenSize, getter_AddRefs(buffers->mBlackCX)); + if (NS_FAILED(rv)) { + delete buffers; + return nsnull; } - rv = aRC.CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gWhite); - if (NS_FAILED(rv)) - return rv; - offscreenBounds.ScaleRoundIn(mPixelsToTwips); - gOffScreenSize.width = offscreenBounds.width; - gOffScreenSize.height = offscreenBounds.height; + rv = NewOffscreenContext(mContext, buffers->mWhite, offscreenSize, getter_AddRefs(buffers->mWhiteCX)); + if (NS_FAILED(rv)) { + delete buffers; + return nsnull; + } + + nsRect fillArea(0, 0, mTranslucentArea.width, mTranslucentArea.height); + + buffers->mBlackCX->SetColor(NS_RGB(0, 0, 0)); + buffers->mBlackCX->FillRect(fillArea); + buffers->mWhiteCX->SetColor(NS_RGB(255, 255, 255)); + buffers->mWhiteCX->FillRect(fillArea); } - // recreate local offscreen & blending contexts, if necessary. - if (mOffScreenCX == nsnull) { - rv = NewOffscreenContext(mContext, gOffScreen, gOffScreenSize, &mOffScreenCX); - if (NS_FAILED(rv)) - return rv; - } - if (mBlackCX == nsnull) { - rv = NewOffscreenContext(mContext, gBlack, gOffScreenSize, &mBlackCX); - if (NS_FAILED(rv)) - return rv; - } - if (mWhiteCX == nsnull) { - rv = NewOffscreenContext(mContext, gWhite, gOffScreenSize, &mWhiteCX); - if (NS_FAILED(rv)) - return rv; + if (aTranslucentWindow) { + rv = aRC->CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, buffers->mOffScreenWhite); + if (NS_FAILED(rv)) { + delete buffers; + return nsnull; + } + + rv = NewOffscreenContext(mContext, buffers->mOffScreenWhite, offscreenSize, getter_AddRefs(buffers->mOffScreenWhiteCX)); + if (NS_FAILED(rv)) { + delete buffers; + return nsnull; + } + + nsRect fillArea(0, 0, mTranslucentArea.width, mTranslucentArea.height); + + buffers->mOffScreenCX->SetColor(NS_RGB(0, 0, 0)); + buffers->mOffScreenCX->FillRect(fillArea); + buffers->mOffScreenWhiteCX->SetColor(NS_RGB(255, 255, 255)); + buffers->mOffScreenWhiteCX->FillRect(fillArea); } - nsRect fillArea = mTranslucentArea; - fillArea.x = 0; - fillArea.y = 0; - - mBlackCX->SetColor(NS_RGB(0, 0, 0)); - mBlackCX->FillRect(fillArea); - mWhiteCX->SetColor(NS_RGB(255, 255, 255)); - mWhiteCX->FillRect(fillArea); - - return NS_OK; + return buffers; } void nsViewManager::ProcessPendingUpdates(nsView* aView) diff --git a/mozilla/view/src/nsViewManager.h b/mozilla/view/src/nsViewManager.h index e51ae7654d9..26df759ffe1 100644 --- a/mozilla/view/src/nsViewManager.h +++ b/mozilla/view/src/nsViewManager.h @@ -60,6 +60,7 @@ class nsIPresContext; class nsISupportsArray; struct DisplayListElement2; struct DisplayZTreeNode; +class BlendingBuffers; //Uncomment the following line to enable generation of viewmanager performance data. #ifdef MOZ_PERF_METRICS @@ -255,17 +256,20 @@ private: void RenderViews(nsView *aRootView, nsIRenderingContext& aRC, const nsRegion& aRegion, PRBool &aResult); - void RenderDisplayListElement(DisplayListElement2* element, nsIRenderingContext &aRC); + void RenderDisplayListElement(DisplayListElement2* element, + nsIRenderingContext &aRC, + BlendingBuffers* aBuffers); void PaintView(nsView *aView, nsIRenderingContext &aRC, nscoord x, nscoord y, - const nsRect &aDamageRect); + const nsRect &aDamageRect); void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut, PRUint32 aUpdateFlags); void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut, PRUint32 aUpdateFlags, nscoord aY1, nscoord aY2, PRBool aInCutOut); - nsresult CreateBlendingBuffers(nsIRenderingContext &aRC); - + BlendingBuffers* CreateBlendingBuffers(nsIRenderingContext *aRC, + PRBool aTranslucentWindow); + void ReparentViews(DisplayZTreeNode* aNode); void BuildDisplayList(nsView* aView, const nsRect& aRect, PRBool aEventProcessing, PRBool aCaptured); void BuildEventTargetList(nsAutoVoidArray &aTargets, nsView* aView, nsGUIEvent* aEvent, PRBool aCaptured); @@ -392,23 +396,13 @@ private: //from here to public should be static and locked... MMP static PRInt32 mVMCount; //number of viewmanagers - //blending buffers - static nsDrawingSurface gOffScreen; - static nsDrawingSurface gBlack; - static nsDrawingSurface gWhite; - static nsSize gOffScreenSize; - //Rendering context used to cleanup the blending buffers static nsIRenderingContext* gCleanupContext; //list of view managers static nsVoidArray *gViewManagers; - nsIBlender *mBlender; - - nsIRenderingContext *mOffScreenCX; - nsIRenderingContext *mBlackCX; - nsIRenderingContext *mWhiteCX; + nsCOMPtr mBlender; nsISupportsArray *mCompositeListeners; void DestroyZTreeNode(DisplayZTreeNode* aNode); diff --git a/mozilla/widget/public/nsIWidget.h b/mozilla/widget/public/nsIWidget.h index bc78e28b101..43c148c4b24 100644 --- a/mozilla/widget/public/nsIWidget.h +++ b/mozilla/widget/public/nsIWidget.h @@ -593,6 +593,44 @@ class nsIWidget : public nsISupports { */ NS_IMETHOD GetWindowType(nsWindowType& aWindowType) = 0; + /** + * Set the translucency of the top-level window containing this widget. + * So, e.g., if you call this on the widget for an IFRAME, the top level + * browser window containing the IFRAME actually gets set. Be careful. + * + * This can fail if the platform doesn't support + * transparency/translucency. By default widgets are not + * transparent. This will also fail if the toplevel window is not + * a Mozilla window, e.g., if the widget is in an embedded + * context. + * + * After translucency has been enabled, the initial alpha channel + * value for all pixels is 1, i.e., opaque. + * If the window is resized then the alpha channel values for + * all pixels are reset to 1. + * @param aTranslucent true if the window may have translucent + * or transparent pixels + */ + NS_IMETHOD SetWindowTranslucency(PRBool aTranslucent) = 0; + + /** + * Get the translucency of the top-level window that contains this + * widget. + * @param aTranslucent true if the window may have translucent or + * transparent pixels + */ + NS_IMETHOD GetWindowTranslucency(PRBool& aTranslucent) = 0; + + /** + * Update the alpha channel for some pixels of the top-level window + * that contains this widget. + * The window must have been made translucent using SetWindowTranslucency. + * @param aRect the rect to update + * @param aAlphas the alpha values, in w x h array, row-major order, + * in units of 1/255. nsBlender::GetAlphas is a good way to compute this array. + */ + NS_IMETHOD UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas) = 0; + /** * Hide window chrome (borders, buttons) for this widget. * diff --git a/mozilla/widget/src/gtk/nsWindow.cpp b/mozilla/widget/src/gtk/nsWindow.cpp index 0148588d161..1d63c17eef0 100644 --- a/mozilla/widget/src/gtk/nsWindow.cpp +++ b/mozilla/widget/src/gtk/nsWindow.cpp @@ -266,6 +266,9 @@ nsWindow::nsWindow() mIMECompositionUniString = nsnull; mIMECompositionUniStringSize = 0; + mIsTranslucent = PR_FALSE; + mTransparencyBitmap = nsnull; + #ifdef USE_XIM mIMEEnable = PR_TRUE; //currently will not be used mIMEShellWindow = 0; @@ -354,6 +357,9 @@ nsWindow::~nsWindow() Destroy(); + delete[] mTransparencyBitmap; + mTransparencyBitmap = nsnull; + if (mIsUpdating) UnqueueDraw(); } @@ -809,12 +815,23 @@ nsWindow::DoPaint (nsIRegion *aClipRegion) nsRect boundsRect; aClipRegion->GetBoundingBox(&boundsRect.x, &boundsRect.y, &boundsRect.width, &boundsRect.height); event.rect = &boundsRect; - event.region = aClipRegion; + event.region = nsnull; // aClipRegion; // Don't paint anything if our window isn't visible. - if (!mSuperWin || mSuperWin->visibility == GDK_VISIBILITY_FULLY_OBSCURED) + if (!mSuperWin) return; + if (mSuperWin->visibility == GDK_VISIBILITY_FULLY_OBSCURED) { + // if our window has translucent pixels, then we can't trust the obscured + // check; it's possible that no pixels of the window are *currently* showing, + // but maybe after the paint new non-transparent pixels will appear in visible + // positions. + PRBool isTranslucent; + GetWindowTranslucency(isTranslucent); + if (!isTranslucent) + return; + } + event.renderingContext = GetRenderingContext(); if (!event.renderingContext) return; @@ -2724,6 +2741,8 @@ NS_IMETHODIMP nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint) aWidth, aHeight); #endif + ResizeTransparencyBitmap(aWidth, aHeight); + mBounds.width = aWidth; mBounds.height = aHeight; @@ -4216,15 +4235,210 @@ NS_IMETHODIMP nsWindow::ResetInputState() return NS_OK; } +nsWindow* nsWindow::FindTopLevelWindow() { + if (!mShell) { + GtkWidget *top_mozarea = GetOwningWidget(); + void *data = gtk_object_get_data(GTK_OBJECT(top_mozarea), "nsWindow"); + return NS_STATIC_CAST(nsWindow *, data); + } else { + return nsnull; + } +} + +static void +gdk_wmspec_change_state (gboolean add, + GdkWindow *window, + GdkAtom state1, + GdkAtom state2) +{ + XEvent xev; + +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = GDK_WINDOW_XWINDOW(window); + xev.xclient.message_type = gdk_atom_intern("_NET_WM_STATE", FALSE); + xev.xclient.format = 32; + xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xev.xclient.data.l[1] = state1; + xev.xclient.data.l[2] = state2; + + XSendEvent(gdk_display, GDK_ROOT_WINDOW(), False, + SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + +#ifndef MOZ_XUL +void nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight) { +} +#else +NS_IMETHODIMP nsWindow::SetWindowTranslucency(PRBool aTranslucent) { + nsWindow* top = FindTopLevelWindow(); + if (top) { + return top->SetWindowTranslucency(aTranslucent); + } + + if (!mShell) { + // we must be embedded + NS_WARNING("Trying to use transparent chrome in an embedded context"); + return NS_ERROR_FAILURE; + } + + if (mIsTranslucent == aTranslucent) + return NS_OK; + + if (!aTranslucent) { + if (mTransparencyBitmap) { + delete[] mTransparencyBitmap; + mTransparencyBitmap = nsnull; + gtk_widget_reset_shapes(mShell); + } + } // else the new default alpha values are "all 1", so we don't + // need to change anything yet + + mIsTranslucent = aTranslucent; + return NS_OK; +} + +NS_IMETHODIMP nsWindow::GetWindowTranslucency(PRBool& aTranslucent) { + nsWindow* top = FindTopLevelWindow(); + if (top) { + return top->GetWindowTranslucency(aTranslucent); + } + + aTranslucent = mIsTranslucent; + return NS_OK; +} + +void nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight) { + if (!mTransparencyBitmap) + return; + + PRInt32 newSize = ((aNewWidth+7)/8)*aNewHeight; + gchar* newBits = new gchar[newSize]; + if (!newBits) { + delete[] mTransparencyBitmap; + mTransparencyBitmap = nsnull; + return; + } + // fill new mask with "opaque", first + memset(newBits, 255, newSize); + + // Now copy the intersection of the old and new areas into the new mask + PRInt32 copyWidth = PR_MIN(aNewWidth, mBounds.width); + PRInt32 copyHeight = PR_MIN(aNewHeight, mBounds.height); + PRInt32 oldRowBytes = (mBounds.width+7)/8; + PRInt32 newRowBytes = (aNewWidth+7)/8; + PRInt32 copyBytes = (copyWidth+7)/8; + + PRInt32 i; + gchar* fromPtr = mTransparencyBitmap; + gchar* toPtr = newBits; + for (i = 0; i < copyHeight; i++) { + memcpy(toPtr, fromPtr, copyBytes); + fromPtr += oldRowBytes; + toPtr += newRowBytes; + } + + delete[] mTransparencyBitmap; + mTransparencyBitmap = newBits; +} + +static PRBool ChangedMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight, + const nsRect& aRect, PRUint8* aAlphas) { + PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost(); + PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8; + for (y = aRect.y; y < yMax; y++) { + gchar* maskBytes = aMaskBits + y*maskBytesPerRow; + for (x = aRect.x; x < xMax; x++) { + PRBool newBit = *aAlphas > 0; + aAlphas++; + + gchar maskByte = maskBytes[x >> 3]; + PRBool maskBit = (maskByte & (1 << (x & 7))) != 0; + + if (maskBit != newBit) { + return PR_TRUE; + } + } + } + + return PR_FALSE; +} + +static void UpdateMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight, + const nsRect& aRect, PRUint8* aAlphas) { + PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost(); + PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8; + for (y = aRect.y; y < yMax; y++) { + gchar* maskBytes = aMaskBits + y*maskBytesPerRow; + for (x = aRect.x; x < xMax; x++) { + PRBool newBit = *aAlphas > 0; + aAlphas++; + + gchar mask = 1 << (x & 7); + gchar maskByte = maskBytes[x >> 3]; + // Note: '-newBit' turns 0 into 00...00 and 1 into 11...11 + maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask); + } + } +} + +NS_IMETHODIMP nsWindow::UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas) { + nsWindow* top = FindTopLevelWindow(); + if (top) { + return top->UpdateTranslucentWindowAlpha(aRect, aAlphas); + } + + NS_ASSERTION(mIsTranslucent, "Window is not transparent"); + + if (mTransparencyBitmap == nsnull) { + PRInt32 size = ((mBounds.width+7)/8)*mBounds.height; + mTransparencyBitmap = new gchar[size]; + if (mTransparencyBitmap == nsnull) + return NS_ERROR_FAILURE; + memset(mTransparencyBitmap, 255, size); + } + + NS_ASSERTION(aRect.x >= 0 && aRect.y >= 0 + && aRect.XMost() <= mBounds.width && aRect.YMost() <= mBounds.height, + "Rect is out of window bounds"); + + if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, aRect, aAlphas)) + // skip the expensive stuff if the mask bits haven't changed; hopefully + // this is the common case + return NS_OK; + + UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, aRect, aAlphas); + + gtk_widget_reset_shapes(mShell); + GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(mShell->window, + mTransparencyBitmap, + mBounds.width, mBounds.height); + if (!maskBitmap) + return NS_ERROR_FAILURE; + + gtk_widget_shape_combine_mask(mShell, maskBitmap, 0, 0); + gdk_bitmap_unref(maskBitmap); + + return NS_OK; +} + NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide) { + nsWindow* top = FindTopLevelWindow(); + if (top) { + return top->HideWindowChrome(aShouldHide); + } + if (!mShell) { - // Pass the request to the toplevel window. - GtkWidget *top_mozarea = GetOwningWidget(); - void *data = gtk_object_get_data(GTK_OBJECT(top_mozarea), "nsWindow"); - nsWindow *mozAreaWindow = NS_STATIC_CAST(nsWindow *, data); - return mozAreaWindow->HideWindowChrome(aShouldHide); + // we must be embedded + NS_WARNING("Trying to hide window decorations in an embedded context"); + return NS_ERROR_FAILURE; } // Sawfish, metacity, and presumably other window managers get @@ -4255,41 +4469,18 @@ nsWindow::HideWindowChrome(PRBool aShouldHide) return NS_OK; } -static void -gdk_wmspec_change_state (gboolean add, - GdkWindow *window, - GdkAtom state1, - GdkAtom state2) -{ - XEvent xev; - -#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ -#define _NET_WM_STATE_ADD 1 /* add/set property */ -#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ - - xev.xclient.type = ClientMessage; - xev.xclient.serial = 0; - xev.xclient.send_event = True; - xev.xclient.window = GDK_WINDOW_XWINDOW(window); - xev.xclient.message_type = gdk_atom_intern("_NET_WM_STATE", FALSE); - xev.xclient.format = 32; - xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; - xev.xclient.data.l[1] = state1; - xev.xclient.data.l[2] = state2; - - XSendEvent(gdk_display, GDK_ROOT_WINDOW(), False, - SubstructureRedirectMask | SubstructureNotifyMask, &xev); -} - NS_IMETHODIMP nsWindow::MakeFullScreen(PRBool aFullScreen) { + nsWindow* top = FindTopLevelWindow(); + if (top) { + return top->MakeFullScreen(aFullScreen); + } + if (!mShell) { - // Pass the request to the toplevel window. - GtkWidget *top_mozarea = GetOwningWidget(); - void *data = gtk_object_get_data(GTK_OBJECT(top_mozarea), "nsWindow"); - nsWindow *mozAreaWindow = NS_STATIC_CAST(nsWindow *, data); - return mozAreaWindow->MakeFullScreen(aFullScreen); + // we must be embedded + NS_WARNING("Trying to go fullscreen in an embedded context"); + return NS_ERROR_FAILURE; } gdk_wmspec_change_state(aFullScreen, mShell->window, @@ -4297,6 +4488,7 @@ nsWindow::MakeFullScreen(PRBool aFullScreen) GDK_NONE); return NS_OK; } +#endif PRBool PR_CALLBACK nsWindow::IconEntryMatches(PLDHashTable* aTable, diff --git a/mozilla/widget/src/gtk/nsWindow.h b/mozilla/widget/src/gtk/nsWindow.h index 6e2646eff6d..efed4ef4691 100644 --- a/mozilla/widget/src/gtk/nsWindow.h +++ b/mozilla/widget/src/gtk/nsWindow.h @@ -115,8 +115,15 @@ public: NS_IMETHOD SetFocus(PRBool aRaise); NS_IMETHOD GetAttention(void); NS_IMETHOD Destroy(); + nsWindow* FindTopLevelWindow(); // returns nsnull if WE are top level + void ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight); +#ifdef INCLUDE_XUL + NS_IMETHOD SetWindowTranslucency(PRBool aTransparent); + NS_IMETHOD GetWindowTranslucency(PRBool& aTransparent); + NS_IMETHOD UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas); NS_IMETHOD HideWindowChrome(PRBool aShouldHide); NS_IMETHOD MakeFullScreen(PRBool aFullScreen); +#endif NS_IMETHOD SetIcon(const nsAString& aIcon); GdkCursor *GtkCreateCursor(nsCursor aCursorType); virtual void LoseFocus(void); @@ -337,14 +344,14 @@ protected: #ifdef USE_XIM protected: - PRBool mIMEEnable; static GdkFont *gPreeditFontset; static GdkFont *gStatusFontset; static GdkIMStyle gInputStyle; static PLDHashTable gXICLookupTable; - PRBool mIMECallComposeStart; - PRBool mIMECallComposeEnd; - PRBool mIMEIsBeingActivate; + PRPackedBool mIMEEnable; + PRPackedBool mIMECallComposeStart; + PRPackedBool mIMECallComposeEnd; + PRPackedBool mIMEIsBeingActivate; nsWindow* mIMEShellWindow; void SetXICSpotLocation(nsIMEGtkIC* aXIC, nsPoint aPoint); void SetXICBaseFontSize(nsIMEGtkIC* aXIC, int height); @@ -356,18 +363,18 @@ protected: int mXICFontSize; public: - nsIMEGtkIC* IMEGetInputContext(PRBool aCreate); + nsIMEGtkIC* IMEGetInputContext(PRBool aCreate); - void ime_preedit_start(); - void ime_preedit_draw(nsIMEGtkIC* aXIC); - void ime_preedit_done(); - void ime_status_draw(); + void ime_preedit_start(); + void ime_preedit_draw(nsIMEGtkIC* aXIC); + void ime_preedit_done(); + void ime_status_draw(); - void IMEUnsetFocusWindow(); - void IMESetFocusWindow(); - void IMEGetShellWindow(); - void IMEDestroyIC(); - void IMEBeingActivate(PRBool aActive); + void IMEUnsetFocusWindow(); + void IMESetFocusWindow(); + void IMEGetShellWindow(); + void IMEDestroyIC(); + void IMEBeingActivate(PRBool aActive); #endif // USE_XIM protected: @@ -389,17 +396,24 @@ private: GdkBitmap *window_mask); nsresult SetIcon(GdkPixmap *window_pixmap, GdkBitmap *window_mask); - PRBool mLastGrabFailed; + void NativeGrab(PRBool aGrab); - PRBool mIsUpdating; + PRPackedBool mLastGrabFailed; + PRPackedBool mIsUpdating; + PRPackedBool mLeavePending; + PRPackedBool mRestoreFocus; + + PRPackedBool mIsTranslucent; + // This bitmap tracks which pixels are transparent. We don't support + // full translucency at this time; each pixel is either fully opaque + // or fully transparent. + gchar* mTransparencyBitmap; void DestroyNativeChildren(void); GtkWindow *mTransientParent; - PRBool mLeavePending; - PRBool mRestoreFocus; }; // diff --git a/mozilla/widget/src/xpwidgets/nsBaseWidget.cpp b/mozilla/widget/src/xpwidgets/nsBaseWidget.cpp index 80d35f2edaf..8268fd19d01 100644 --- a/mozilla/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/mozilla/widget/src/xpwidgets/nsBaseWidget.cpp @@ -482,6 +482,26 @@ NS_IMETHODIMP nsBaseWidget::SetWindowType(nsWindowType aWindowType) return NS_OK; } +//------------------------------------------------------------------------- +// +// Window transparency methods +// +//------------------------------------------------------------------------- + +NS_IMETHODIMP nsBaseWidget::SetWindowTranslucency(PRBool aTranslucent) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsBaseWidget::GetWindowTranslucency(PRBool& aTranslucent) { + aTranslucent = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP nsBaseWidget::UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas) { + NS_ASSERTION(PR_FALSE, "Window is not translucent"); + return NS_ERROR_NOT_IMPLEMENTED; +} + //------------------------------------------------------------------------- // // Hide window borders/decorations for this widget diff --git a/mozilla/widget/src/xpwidgets/nsBaseWidget.h b/mozilla/widget/src/xpwidgets/nsBaseWidget.h index 2a6d5c87a33..1b2da268b1a 100644 --- a/mozilla/widget/src/xpwidgets/nsBaseWidget.h +++ b/mozilla/widget/src/xpwidgets/nsBaseWidget.h @@ -99,6 +99,9 @@ public: NS_IMETHOD SetCursor(nsCursor aCursor); NS_IMETHOD GetWindowType(nsWindowType& aWindowType); NS_IMETHOD SetWindowType(nsWindowType aWindowType); + NS_IMETHOD SetWindowTranslucency(PRBool aTranslucent); + NS_IMETHOD GetWindowTranslucency(PRBool& aTranslucent); + NS_IMETHOD UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas); NS_IMETHOD HideWindowChrome(PRBool aShouldHide); NS_IMETHOD MakeFullScreen(PRBool aFullScreen); virtual nsIRenderingContext* GetRenderingContext();