b=326738, move thebes doublebuffering/transparent window handling into widget, sr=roc

git-svn-id: svn://10.0.0.236/trunk@190158 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
vladimir%pobox.com
2006-02-15 23:35:53 +00:00
parent e9d103a8a2
commit 882fa2e266
11 changed files with 161 additions and 156 deletions

View File

@@ -67,6 +67,7 @@ struct nsBoundingMetrics;
#ifdef MOZ_CAIRO_GFX
class gfxASurface;
class gfxContext;
#endif
/* gfx2 */
@@ -137,6 +138,14 @@ public:
* @result The result of the initialization, NS_Ok if no errors
*/
NS_IMETHOD Init(nsIDeviceContext* aContext, gfxASurface* aThebesSurface) = 0;
/**
* Initialize the RenderingContext
* @param aContext the device context to use for the drawing.
* @param aThebesContext an existing thebes context to use for the drawing
* @result The result of the initialization, NS_Ok if no errors
*/
NS_IMETHOD Init(nsIDeviceContext* aContext, gfxContext* aThebesContext) = 0;
#endif
/**

View File

@@ -112,6 +112,22 @@ nsThebesRenderingContext::Init(nsIDeviceContext* aContext, gfxASurface *aThebesS
return (CommonInit());
}
NS_IMETHODIMP
nsThebesRenderingContext::Init(nsIDeviceContext* aContext, gfxContext *aThebesContext)
{
PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::Init ctx %p thebesContext %p\n", this, aContext, aThebesContext));
mDeviceContext = aContext;
mWidget = nsnull;
mLocalDrawingSurface = nsnull;
mDrawingSurface = nsnull;
mThebes = aThebesContext;
return (CommonInit());
}
NS_IMETHODIMP
nsThebesRenderingContext::Init(nsIDeviceContext* aContext, nsIWidget *aWidget)
{
@@ -160,11 +176,8 @@ nsThebesRenderingContext::CommonInit(void)
NS_IMETHODIMP
nsThebesRenderingContext::Reset(void)
{
PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::Reset\n", this));
mThebes = new gfxContext(mDrawingSurface->GetThebesSurface());
return (CommonInit());
NS_ERROR("nsThebesRenderingContext::Reset called!\n");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
@@ -178,22 +191,15 @@ nsThebesRenderingContext::GetDeviceContext(nsIDeviceContext *& aDeviceContext)
NS_IMETHODIMP
nsThebesRenderingContext::SelectOffScreenDrawingSurface(nsIDrawingSurface *aSurface)
{
if (aSurface)
mDrawingSurface = NS_STATIC_CAST(nsThebesDrawingSurface*, aSurface);
else
mDrawingSurface = mLocalDrawingSurface;
mThebes->SetTarget(mDrawingSurface->GetThebesSurface());
return NS_OK;
NS_ERROR("nsThebesRenderingContext::SelectOffScreenDrawingSurface called!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsThebesRenderingContext::GetDrawingSurface(nsIDrawingSurface **aSurface)
{
*aSurface = mDrawingSurface;
// don't addref! this isn't an xpcom call even though it sure looks like one
return NS_OK;
NS_ERROR("nsThebesRenderingContext::GetDrawingSurface called!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
@@ -773,7 +779,7 @@ nsThebesRenderingContext::GetNativeGraphicData(GraphicDataType aType)
if (aType == NATIVE_WINDOWS_DC) {
nsRefPtr<gfxASurface> surf = mThebes->CurrentGroupSurface();
if (!surf)
mThebes->CurrentSurface();
surf = mThebes->CurrentSurface();
return cairo_win32_surface_get_dc(surf->CairoSurface());
}
@@ -1083,10 +1089,6 @@ nsThebesRenderingContext::DrawTile(imgIContainer *aImage,
nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
if (!img) return NS_ERROR_FAILURE;
nsIDrawingSurface *surface = nsnull;
GetDrawingSurface(&surface);
if (!surface) return NS_ERROR_FAILURE;
/* bug 113561 - frame can be smaller than container */
nsIntRect pxImgFrameRect;
imgFrame->GetRect(pxImgFrameRect);
@@ -1098,7 +1100,7 @@ nsThebesRenderingContext::DrawTile(imgIContainer *aImage,
NSToIntRound(FROM_TWIPS(twDr.width)),
NSToIntRound(FROM_TWIPS(twDr.height)));
return img->DrawTile(*this, surface,
return img->DrawTile(*this, NULL,
pxXOffset - pxImgFrameRect.x, pxYOffset - pxImgFrameRect.y,
pxPadX, pxPadY,
pxDr);

View File

@@ -71,6 +71,7 @@ public:
NS_DECL_ISUPPORTS
NS_IMETHOD Init(nsIDeviceContext* aContext, gfxASurface* aThebesSurface);
NS_IMETHOD Init(nsIDeviceContext* aContext, gfxContext* aThebesContext);
NS_IMETHOD Init(nsIDeviceContext* aContext, nsIWidget *aWidget);
NS_IMETHOD Init(nsIDeviceContext* aContext, nsIDrawingSurface *aSurface);

View File

@@ -48,7 +48,9 @@ class NS_EXPORT gfxWindowsSurface : public gfxASurface {
public:
gfxWindowsSurface(HWND wnd);
gfxWindowsSurface(HDC dc, PRBool deleteDC = PR_FALSE);
gfxWindowsSurface(HDC dc, unsigned long width, unsigned long height);
gfxWindowsSurface(HDC dc,
unsigned long width, unsigned long height,
gfxImageFormat imageFormat = ImageFormatRGB24);
virtual ~gfxWindowsSurface();
HDC GetDC() { return mDC; }

View File

@@ -303,7 +303,13 @@ gfxWindowsTextRun::MeasureOrDrawUniscribe(gfxContext *aContext,
const PRUnichar *aString, PRUint32 aLength,
PRBool aDraw, PRInt32 aX, PRInt32 aY, const PRInt32 *aSpacing)
{
HDC aDC = static_cast<gfxWindowsSurface*>(aContext->CurrentSurface())->GetDC();
nsRefPtr<gfxASurface> surf = aContext->CurrentGroupSurface();
if (!surf)
surf = aContext->CurrentSurface();
HDC aDC = cairo_win32_surface_get_dc(surf->CairoSurface());
int knownGoodDCState = SaveDC(aDC);
int loops = 0;
@@ -507,7 +513,17 @@ TRY_AGAIN_SAME_SCRIPT:
RestoreDC(aDC, -1);
#else
/* Draw using cairo */
/* XXX cairo sets a world transform in order to get subpixel accuracy in some cases;
* this breaks it there's a surface fallback that happens with clipping, because
* the clip gets applied with the world transform and the world breaks. Doing this
* RestoreDC fixes things until we can fix the win32 font stuff.
*/
RestoreDC(aDC, knownGoodDCState);
cairo_show_glyphs(cr, cglyphs, numGlyphs);
knownGoodDCState = SaveDC(aDC);
#endif
free(cglyphs);

View File

@@ -49,7 +49,7 @@ gfxWindowsPlatform::CreateOffscreenSurface(PRUint32 width,
PRUint32 height,
gfxASurface::gfxImageFormat imageFormat)
{
return new gfxWindowsSurface(nsnull, width, height);
return new gfxWindowsSurface(nsnull, width, height, imageFormat);
}
nsresult

View File

@@ -53,51 +53,19 @@ gfxWindowsSurface::gfxWindowsSurface(HDC dc, PRBool deleteDC) :
Init(cairo_win32_surface_create(mDC));
}
gfxWindowsSurface::gfxWindowsSurface(HDC dc, unsigned long width, unsigned long height) :
mOwnsDC(PR_TRUE), mWnd(nsnull)
gfxWindowsSurface::gfxWindowsSurface(HDC dc, unsigned long width, unsigned long height, gfxImageFormat imageFormat) :
mOwnsDC(PR_FALSE), mWnd(nsnull)
{
mDC = ::CreateCompatibleDC(dc);
// set the clip region on it so that cairo knows the surface
// dimensions
HRGN clipRegion = ::CreateRectRgn(0, 0, width, height);
if (::SelectClipRgn(mDC, clipRegion) == ERROR) {
NS_ERROR("gfxWindowsSurface: SelectClipRgn failed\n");
}
::DeleteObject(clipRegion);
HBITMAP bmp = nsnull;
if (dc) {
// Create a DDB if we can -- this is faster.
// Creating with width or height of 0 will create a
// 1x1 monotone bitmap, which isn't what we want
bmp = ::CreateCompatibleBitmap(dc, PR_MAX(2, width), PR_MAX(2, height));
} else {
// Otherwise, create a DIB -- this is slower.
BITMAPINFO bmpInfo;
unsigned char *bits = NULL;
// At some point we might want to revisit creating a DDB
// with CreateCompatibleDC, but from stuff that I've read
// that's only useful for terminal services clients.
/* initialize the bitmapinfoheader */
memset(&bmpInfo.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = width;
bmpInfo.bmiHeader.biHeight = -(long)height;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24;
bmpInfo.bmiHeader.biCompression = BI_RGB;
Init(cairo_win32_surface_create_dib((cairo_format_t)imageFormat,
width, height));
/* create a DIBSection */
bmp = CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
/* Flush GDI to make sure the DIBSection is actually created */
GdiFlush();
}
/* Select the bitmap in to the DC */
mOrigBitmap = (HBITMAP)::SelectObject(mDC, bmp);
Init(cairo_win32_surface_create(mDC));
mDC = cairo_win32_surface_get_dc(CairoSurface());
}
gfxWindowsSurface::~gfxWindowsSurface()

View File

@@ -610,34 +610,13 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
float t2p = mContext->AppUnitsToDevUnits();
#ifdef MOZ_CAIRO_GFX
nsRefPtr<gfxContext> ctx = (gfxContext*) localcx->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
PRBool usingDoubleBuffer = (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER);
nsRefPtr<gfxContext> ctx =
(gfxContext*) localcx->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
ctx->Save();
ctx->Translate(gfxPoint(NSToIntRound(viewRect.x * t2p), NSToIntRound(viewRect.y * t2p)));
ctx->NewPath();
if (aRegion) {
nsRegionRectSet *rs = nsnull;
aRegion->GetRects(&rs);
for (int i = 0; i < rs->mNumRects; i++) {
ctx->Rectangle(gfxRect(rs->mRects[i].x,
rs->mRects[i].y,
rs->mRects[i].width,
rs->mRects[i].height));
}
aRegion->FreeRects(rs);
}
ctx->Rectangle(gfxRect(NSToIntRound(damageRect.x * t2p),
NSToIntRound(damageRect.y * t2p),
NSToIntRound(damageRect.width * t2p),
NSToIntRound(damageRect.height * t2p)));
ctx->Clip();
if (usingDoubleBuffer)
ctx->PushGroup(gfxContext::CONTENT_COLOR);
ctx->Translate(gfxPoint(NSToIntRound(viewRect.x * t2p),
NSToIntRound(viewRect.y * t2p)));
nsRegion opaqueRegion;
AddCoveringWidgetsToOpaqueRegion(opaqueRegion, mContext, aView);
@@ -645,12 +624,6 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
RenderViews(aView, *localcx, damageRegion, ds);
if (usingDoubleBuffer) {
ctx->PopGroupToSource();
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint();
}
ctx->Restore();
#else
// widgetDamageRectInPixels is the clipped damage area bounds,
@@ -857,6 +830,7 @@ void nsViewManager::AddCoveringWidgetsToOpaqueRegion(nsRegion &aRgn, nsIDeviceCo
void nsViewManager::RenderViews(nsView *aView, nsIRenderingContext& aRC,
const nsRegion& aRegion, nsIDrawingSurface* aRCSurface)
{
#ifndef MOZ_CAIRO_GFX
nsIWidget* widget = aView->GetWidget();
PRBool translucentWindow = PR_FALSE;
if (widget) {
@@ -873,6 +847,7 @@ void nsViewManager::RenderViews(nsView *aView, nsIRenderingContext& aRC,
NS_ASSERTION(buffers, "Failed to create rendering buffers");
if (!buffers)
return;
#endif
if (mObserver) {
nsView* displayRoot = GetDisplayRootFor(aView);
@@ -886,6 +861,7 @@ void nsViewManager::RenderViews(nsView *aView, nsIRenderingContext& aRC,
aRC.PopState();
}
#ifndef MOZ_CAIRO_GFX
if (translucentWindow) {
// Get the alpha channel into an array so we can send it to the widget
nsRect r = aRegion.GetBounds();
@@ -902,6 +878,7 @@ void nsViewManager::RenderViews(nsView *aView, nsIRenderingContext& aRC,
}
delete buffers;
#endif
}
static nsresult NewOffscreenContext(nsIDeviceContext* deviceContext, nsIDrawingSurface* surface,

View File

@@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@@ -855,10 +855,6 @@ class nsIWidget : public nsISupports {
virtual nsIRenderingContext* GetRenderingContext() = 0;
virtual nsIDeviceContext* GetDeviceContext() = 0;
virtual nsIAppShell *GetAppShell() = 0;
#ifdef MOZ_CAIRO_GFX
virtual gfxASurface *GetThebesSurface() = 0;
#endif
//@}
/**
@@ -1043,6 +1039,12 @@ class nsIWidget : public nsISupports {
*/
NS_IMETHOD GetLastInputEventTime(PRUint32& aTime) = 0;
#ifdef MOZ_CAIRO_GFX
/**
* Get the Thebes surface associated with this widget.
*/
virtual gfxASurface *GetThebesSurface() = 0;
#endif
protected:
// keep the list of children. We also keep track of our siblings.

View File

@@ -87,8 +87,10 @@
#include "resource.h"
#include <commctrl.h>
#include "prtime.h"
#ifdef MOZ_THEBES
#ifdef MOZ_CAIRO_GFX
#include "nsIThebesRenderingContext.h"
#include "gfxContext.h"
#include "gfxWindowsSurface.h"
#else
#include "nsIRenderingContextWin.h"
#endif
@@ -5637,21 +5639,54 @@ PRBool nsWindow::OnPaint(HDC aDC)
#endif // NS_DEBUG
#ifdef MOZ_CAIRO_GFX
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
nsRefPtr<gfxASurface> targetSurface = new gfxWindowsSurface(hDC);
nsRefPtr<gfxContext> thebesContext = new gfxContext(targetSurface);
#ifdef MOZ_XUL
if (mIsTranslucent && IsAlphaTranslucencySupported()) {
// If we're rendering with translucency, we're going to be
// rendering the whole window; make sure we clear it first
thebesContext->SetOperator(gfxContext::OPERATOR_CLEAR);
thebesContext->Paint();
thebesContext->SetOperator(gfxContext::OPERATOR_OVER);
} else {
// If we're not doing translucency, then double buffer
thebesContext->PushGroup(gfxContext::CONTENT_COLOR);
}
#endif
nsCOMPtr<nsIRenderingContext> rc;
nsresult rv = mContext->CreateRenderingContextInstance (*getter_AddRefs(rc));
if (NS_FAILED(rv)) {
NS_WARNING("CreateRenderingContextInstance failed");
return PR_FALSE;
}
rv = rc->Init(mContext, thebesContext);
if (NS_FAILED(rv)) {
NS_WARNING("RC::Init failed");
return PR_FALSE;
}
event.renderingContext = rc;
result = DispatchWindowEvent(&event, eventStatus);
event.renderingContext = nsnull;
if (mIsTranslucent && IsAlphaTranslucencySupported())
{
#ifdef MOZ_XUL
if (mIsTranslucent && IsAlphaTranslucencySupported()) {
// Data from offscreen drawing surface was copied to memory bitmap of transparent
// bitmap. Now it can be read from memory bitmap to apply alpha channel and after
// that displayed on the screen.
UpdateTranslucentWindow();
} else {
thebesContext->PopGroupToSource();
thebesContext->SetOperator(gfxContext::OPERATOR_SOURCE);
thebesContext->Paint();
}
rc = nsnull;
#else
#endif
#else
/* Non-cairo GFX */
if (NS_SUCCEEDED(CallCreateInstance(kRenderingContextCID, &event.renderingContext)))
{
nsIRenderingContextWin *winrc;
@@ -8002,8 +8037,6 @@ nsWindow* nsWindow::GetTopLevelWindow()
}
#ifdef MOZ_CAIRO_GFX
#include "gfxWindowsSurface.h"
gfxASurface *nsWindow::GetThebesSurface()
{
if (mPaintDC)
@@ -8013,11 +8046,12 @@ gfxASurface *nsWindow::GetThebesSurface()
}
#endif
void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight)
void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force)
{
if (aNewWidth == mBounds.width && aNewHeight == mBounds.height)
if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height)
return;
#ifndef MOZ_CAIRO_GFX
// resize the alpha mask
PRUint8* pBits;
@@ -8025,7 +8059,7 @@ void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight)
{
pBits = new PRUint8 [aNewWidth * aNewHeight];
if (pBits)
if (pBits && mAlphaMask)
{
PRInt32 copyWidth, copyHeight;
PRInt32 growWidth, growHeight;
@@ -8072,15 +8106,23 @@ void nsWindow::ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight)
delete [] mAlphaMask;
mAlphaMask = pBits;
#endif
if (IsAlphaTranslucencySupported())
{
// Always use at least 24-bit bitmaps regardless of the device context.
if (!w2k.mMemoryDC)
w2k.mMemoryDC = ::CreateCompatibleDC(NULL);
// Always use at least 24-bit (32 with cairo) bitmaps regardless of the device context.
int depth = ::GetDeviceCaps(w2k.mMemoryDC, BITSPIXEL);
#ifdef MOZ_CAIRO_GFX
if (depth < 32)
depth = 32;
#else
if (depth < 24)
depth = 24;
#endif
// resize the memory bitmap
BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
@@ -8192,52 +8234,26 @@ nsresult nsWindow::SetWindowTranslucencyInner(PRBool aTranslucent)
nsresult nsWindow::SetupTranslucentWindowMemoryBitmap(PRBool aTranslucent)
{
nsresult rv = NS_ERROR_FAILURE;
if (aTranslucent)
{
w2k.mMemoryDC = ::CreateCompatibleDC(NULL);
if (aTranslucent) {
ResizeTranslucentWindow(mBounds.width, mBounds.height, PR_TRUE);
} else {
if (w2k.mMemoryDC)
{
// Always use at least 24-bit bitmaps regardless of the device context.
int depth = ::GetDeviceCaps(w2k.mMemoryDC, BITSPIXEL);
if (depth < 24)
depth = 24;
BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
bi.bmiHeader.biWidth = mBounds.width;
bi.bmiHeader.biHeight = -mBounds.height;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = depth;
bi.bmiHeader.biCompression = BI_RGB;
w2k.mMemoryBitmap = ::CreateDIBSection(w2k.mMemoryDC, &bi, DIB_RGB_COLORS, (void**)&w2k.mMemoryBits, NULL, 0);
if (w2k.mMemoryBitmap)
{
::SelectObject(w2k.mMemoryDC, w2k.mMemoryBitmap);
rv = NS_OK;
}
}
} else
{
::DeleteDC(w2k.mMemoryDC);
::DeleteObject(w2k.mMemoryBitmap);
::DeleteDC(w2k.mMemoryDC);
if (w2k.mMemoryBitmap)
::DeleteObject(w2k.mMemoryBitmap);
w2k.mMemoryDC = NULL;
w2k.mMemoryBitmap = NULL;
rv = NS_OK;
}
return rv;
return NS_OK;
}
void nsWindow::UpdateTranslucentWindowAlphaInner(const nsRect& aRect, PRUint8* aAlphas)
{
#ifdef MOZ_CAIRO_GFX
NS_ERROR("nsWindow::UpdateTranslucentWindowAlphaInner called, when it sholdn't be!");
#else
NS_ASSERTION(mIsTranslucent, "Window is not transparent");
NS_ASSERTION(aRect.x >= 0 && aRect.y >= 0 &&
aRect.XMost() <= mBounds.width && aRect.YMost() <= mBounds.height,
@@ -8292,6 +8308,7 @@ void nsWindow::UpdateTranslucentWindowAlphaInner(const nsRect& aRect, PRUint8* a
if (transparencyMaskChanged)
SetWindowRegionToAlphaMask();
}
#endif
}
nsresult nsWindow::UpdateTranslucentWindow()
@@ -8303,13 +8320,24 @@ nsresult nsWindow::UpdateTranslucentWindow()
::GdiFlush();
HDC hMemoryDC;
HBITMAP hAlphaBitmap;
PRBool needConversion;
#ifdef MOZ_CAIRO_GFX
hMemoryDC = w2k.mMemoryDC;
needConversion = PR_FALSE;
rv = NS_OK;
#else
int depth = ::GetDeviceCaps(w2k.mMemoryDC, BITSPIXEL);
if (depth < 24)
depth = 24;
HDC hMemoryDC;
HBITMAP hAlphaBitmap;
PRBool needConversion = (depth == 24);
needConversion = (depth == 24);
if (needConversion)
{
@@ -8372,7 +8400,7 @@ nsresult nsWindow::UpdateTranslucentWindow()
rv = NS_OK;
}
}
#endif /* MOZ_CAIRO_GFX */
if (rv == NS_OK)
{

View File

@@ -212,7 +212,7 @@ private:
nsresult SetWindowTranslucencyInner(PRBool aTransparent);
PRBool GetWindowTranslucencyInner() { return mIsTranslucent; }
void UpdateTranslucentWindowAlphaInner(const nsRect& aRect, PRUint8* aAlphas);
void ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight);
void ResizeTranslucentWindow(PRInt32 aNewWidth, PRInt32 aNewHeight, PRBool force = PR_FALSE);
nsresult UpdateTranslucentWindow();
nsresult SetupTranslucentWindowMemoryBitmap(PRBool aTranslucent);
void SetWindowRegionToAlphaMask();