Bug 327874. Update GTK2 widget code to handle all double-buffering and window translucency, in cairo/Thebes builds. r=vlad

This commit is contained in:
roc+%cs.cmu.edu 2006-02-20 22:43:44 +00:00
Родитель 4a0fb60c89
Коммит 02669cac8a
2 изменённых файлов: 98 добавлений и 16 удалений

Просмотреть файл

@ -98,6 +98,8 @@ static const char sAccessibilityKey [] = "config.use_system_prefs.accessibility"
#ifdef MOZ_CAIRO_GFX #ifdef MOZ_CAIRO_GFX
#include "gfxPlatformGtk.h" #include "gfxPlatformGtk.h"
#include "gfxXlibSurface.h" #include "gfxXlibSurface.h"
#include "gfxContext.h"
#include "gfxImageSurface.h"
#ifdef MOZ_ENABLE_GLITZ #ifdef MOZ_ENABLE_GLITZ
#include "gfxGlitzSurface.h" #include "gfxGlitzSurface.h"
@ -433,6 +435,10 @@ nsWindow::Destroy(void)
// window this isn't going to harm anything. // window this isn't going to harm anything.
mWindowGroup = nsnull; mWindowGroup = nsnull;
// Destroy thebes surface now. Badness can happen if we destroy
// the surface after its X Window.
mThebesSurface = nsnull;
if (mShell) { if (mShell) {
gtk_widget_destroy(mShell); gtk_widget_destroy(mShell);
mShell = nsnull; mShell = nsnull;
@ -1338,8 +1344,6 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
if (aEvent->window != mDrawingarea->inner_window) if (aEvent->window != mDrawingarea->inner_window)
return FALSE; return FALSE;
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
static NS_DEFINE_CID(kRegionCID, NS_REGION_CID); static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
nsCOMPtr<nsIRegion> updateRegion = do_CreateInstance(kRegionCID); nsCOMPtr<nsIRegion> updateRegion = do_CreateInstance(kRegionCID);
@ -1355,11 +1359,48 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
(void *)this, (void *)aEvent->window, (void *)this, (void *)aEvent->window,
GDK_WINDOW_XWINDOW(aEvent->window))); GDK_WINDOW_XWINDOW(aEvent->window)));
for (GdkRectangle *r = rects, *r_end = rects + nrects; r < r_end; ++r) { GdkRectangle *r;
GdkRectangle *r_end = rects + nrects;
for (r = rects; r < r_end; ++r) {
updateRegion->Union(r->x, r->y, r->width, r->height); updateRegion->Union(r->x, r->y, r->width, r->height);
LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height)); LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
} }
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
#ifdef MOZ_CAIRO_GFX
PRBool translucent;
GetWindowTranslucency(translucent);
GdkRectangle collapsedRect;
// do double-buffering and clipping here
nsRefPtr<gfxContext> ctx =
(gfxContext*)rc->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
ctx->Save();
// clip to Gdk region
ctx->NewPath();
if (translucent) {
// Collapse update area to the bounding box. This is so we only have to
// call UpdateTranslucentWindowAlpha once. After we have dropped
// support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
// our private interface so we can rework things to avoid this.
updateRegion->GetBoundingBox(&collapsedRect.x, &collapsedRect.y,
&collapsedRect.width, &collapsedRect.height);
ctx->Rectangle(gfxRect(collapsedRect.x, collapsedRect.y,
collapsedRect.width, collapsedRect.height));
} else {
for (r = rects; r < r_end; ++r) {
ctx->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
}
}
ctx->Clip();
// double buffer
ctx->PushGroup(translucent ? gfxContext::CONTENT_COLOR_ALPHA : gfxContext::CONTENT_COLOR);
#endif
nsPaintEvent event(PR_TRUE, NS_PAINT, this); nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.refPoint.x = aEvent->area.x; event.refPoint.x = aEvent->area.x;
event.refPoint.y = aEvent->area.y; event.refPoint.y = aEvent->area.y;
@ -1370,6 +1411,33 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
nsEventStatus status; nsEventStatus status;
DispatchEvent(&event, status); DispatchEvent(&event, status);
#ifdef MOZ_CAIRO_GFX
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
if (!translucent) {
ctx->PopGroupToSource();
ctx->Paint();
} else {
nsRefPtr<gfxPattern> pattern = ctx->PopGroup();
ctx->SetPattern(pattern);
ctx->Paint();
nsRefPtr<gfxImageSurface> img =
new gfxImageSurface(gfxImageSurface::ImageFormatA8,
collapsedRect.width, collapsedRect.height);
img->SetDeviceOffset(-collapsedRect.x, -collapsedRect.y);
nsRefPtr<gfxContext> imgCtx = new gfxContext(img);
imgCtx->SetPattern(pattern);
imgCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
imgCtx->Paint();
UpdateTranslucentWindowAlphaInternal(nsRect(collapsedRect.x, collapsedRect.y,
collapsedRect.width, collapsedRect.height),
img->Data(), img->Stride());
}
ctx->Restore();
#endif
g_free(rects); g_free(rects);
// check the return value! // check the return value!
@ -2859,15 +2927,16 @@ nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight)
static PRBool static PRBool
ChangedMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight, ChangedMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
const nsRect& aRect, PRUint8* aAlphas) const nsRect& aRect, PRUint8* aAlphas, PRInt32 aStride)
{ {
PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost(); PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8; PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8;
for (y = aRect.y; y < yMax; y++) { for (y = aRect.y; y < yMax; y++) {
gchar* maskBytes = aMaskBits + y*maskBytesPerRow; gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
PRUint8* alphas = aAlphas;
for (x = aRect.x; x < xMax; x++) { for (x = aRect.x; x < xMax; x++) {
PRBool newBit = *aAlphas > 0; PRBool newBit = *alphas > 0;
aAlphas++; alphas++;
gchar maskByte = maskBytes[x >> 3]; gchar maskByte = maskBytes[x >> 3];
PRBool maskBit = (maskByte & (1 << (x & 7))) != 0; PRBool maskBit = (maskByte & (1 << (x & 7))) != 0;
@ -2876,6 +2945,7 @@ ChangedMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
return PR_TRUE; return PR_TRUE;
} }
} }
aAlphas += aStride;
} }
return PR_FALSE; return PR_FALSE;
@ -2883,21 +2953,23 @@ ChangedMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
static static
void UpdateMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight, void UpdateMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
const nsRect& aRect, PRUint8* aAlphas) const nsRect& aRect, PRUint8* aAlphas, PRInt32 aStride)
{ {
PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost(); PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8; PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8;
for (y = aRect.y; y < yMax; y++) { for (y = aRect.y; y < yMax; y++) {
gchar* maskBytes = aMaskBits + y*maskBytesPerRow; gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
PRUint8* alphas = aAlphas;
for (x = aRect.x; x < xMax; x++) { for (x = aRect.x; x < xMax; x++) {
PRBool newBit = *aAlphas > 0; PRBool newBit = *alphas > 0;
aAlphas++; alphas++;
gchar mask = 1 << (x & 7); gchar mask = 1 << (x & 7);
gchar maskByte = maskBytes[x >> 3]; gchar maskByte = maskBytes[x >> 3];
// Note: '-newBit' turns 0 into 00...00 and 1 into 11...11 // Note: '-newBit' turns 0 into 00...00 and 1 into 11...11
maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask); maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask);
} }
aAlphas += aStride;
} }
} }
@ -2915,8 +2987,9 @@ nsWindow::ApplyTransparencyBitmap()
gdk_bitmap_unref(maskBitmap); gdk_bitmap_unref(maskBitmap);
} }
NS_IMETHODIMP nsresult
nsWindow::UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas) nsWindow::UpdateTranslucentWindowAlphaInternal(const nsRect& aRect,
PRUint8* aAlphas, PRInt32 aStride)
{ {
if (!mShell) { if (!mShell) {
// Pass the request to the toplevel window // Pass the request to the toplevel window
@ -2929,7 +3002,7 @@ nsWindow::UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas)
if (!topWindow) if (!topWindow)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
return topWindow->UpdateTranslucentWindowAlpha(aRect, aAlphas); return topWindow->UpdateTranslucentWindowAlphaInternal(aRect, aAlphas, aStride);
} }
NS_ASSERTION(mIsTranslucent, "Window is not transparent"); NS_ASSERTION(mIsTranslucent, "Window is not transparent");
@ -2946,19 +3019,26 @@ nsWindow::UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas)
&& aRect.XMost() <= mBounds.width && aRect.YMost() <= mBounds.height, && aRect.XMost() <= mBounds.width && aRect.YMost() <= mBounds.height,
"Rect is out of window bounds"); "Rect is out of window bounds");
if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, aRect, aAlphas)) if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height,
aRect, aAlphas, aStride))
// skip the expensive stuff if the mask bits haven't changed; hopefully // skip the expensive stuff if the mask bits haven't changed; hopefully
// this is the common case // this is the common case
return NS_OK; return NS_OK;
UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, aRect, aAlphas); UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height,
aRect, aAlphas, aStride);
if (!mNeedsShow) { if (!mNeedsShow) {
ApplyTransparencyBitmap(); ApplyTransparencyBitmap();
} }
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsWindow::UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas)
{
return UpdateTranslucentWindowAlphaInternal(aRect, aAlphas, aRect.width);
}
#endif #endif
void void

Просмотреть файл

@ -284,6 +284,8 @@ public:
#ifdef MOZ_XUL #ifdef MOZ_XUL
NS_IMETHOD SetWindowTranslucency(PRBool aTransparent); NS_IMETHOD SetWindowTranslucency(PRBool aTransparent);
NS_IMETHOD GetWindowTranslucency(PRBool& aTransparent); NS_IMETHOD GetWindowTranslucency(PRBool& aTransparent);
nsresult UpdateTranslucentWindowAlphaInternal(const nsRect& aRect,
PRUint8* aAlphas, PRInt32 aStride);
NS_IMETHOD UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas); NS_IMETHOD UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas);
#endif #endif