зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
4a0fb60c89
Коммит
02669cac8a
|
@ -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
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче