[OS/2]
Bug 371505: finally fix repaint issues with Thebes
--- a/gfx/thebes/public/gfxOS2Surface.h
+++ b/gfx/thebes/public/gfxOS2Surface.h
@@ -42,30 +42,37 @@
#define INCL_GPIBITMAPS
#include <os2.h>
#include <cairo-os2.h>
class THEBES_API gfxOS2Surface : public gfxASurface {
public:
- // constructor to create a cairo surface using an existing PS
- gfxOS2Surface(HPS aPS, const gfxIntSize& aSize);
// constructor used to create a memory surface of given size
gfxOS2Surface(const gfxIntSize& aSize,
gfxASurface::gfxImageFormat aImageFormat);
// constructor for surface connected to an onscreen window
gfxOS2Surface(HWND aWnd);
virtual ~gfxOS2Surface();
+ // Special functions that only make sense for the OS/2 port of cairo:
+
+ // Update the cairo surface.
+ // While gfxOS2Surface keeps track of the presentation handle itself,
+ // use the one from WinBeginPaint() here.
+ void Refresh(RECTL *aRect, HPS aPS);
+
+ // Reset the cairo surface to the given size.
+ int Resize(const gfxIntSize& aSize);
+
HPS GetPS() { return mPS; }
gfxIntSize GetSize() { return mSize; }
private:
- PRBool mOwnsPS;
PRBool mHasWnd; // indicates if created through the HWND constructor
HDC mDC; // memory device context
HPS mPS; // presentation space connected to window or memory device
HBITMAP mBitmap; // bitmap for initialization of memory surface
gfxIntSize mSize; // current size of the surface
};
#endif /* GFX_OS2_SURFACE_H */
--- a/gfx/thebes/src/gfxOS2Surface.cpp
+++ b/gfx/thebes/src/gfxOS2Surface.cpp
@@ -38,38 +38,19 @@
#include "gfxOS2Surface.h"
#include <stdio.h>
/**********************************************************************
* class gfxOS2Surface
**********************************************************************/
-gfxOS2Surface::gfxOS2Surface(HPS aPS, const gfxIntSize& aSize)
- : mOwnsPS(PR_FALSE), mHasWnd(PR_FALSE), mDC(nsnull), mPS(aPS), mBitmap(nsnull), mSize(aSize)
-{
-#ifdef DEBUG_thebes_2
- printf("gfxOS2Surface[%#x]::gfxOS2Surface(HPS=%#x, Size=%dx%d)\n", (unsigned int)this,
- (unsigned int)mPS, aSize.width, aSize.height);
-#endif
-
- // create the cairo surface on the passed PS
- cairo_surface_t *surf = cairo_os2_surface_create(mPS, mSize.width, mSize.height);
-#ifdef DEBUG_thebes_2
- printf(" type(%#x)=%d (ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
- cairo_surface_get_type(surf), (unsigned int)mPS, mSize.width, mSize.height);
-#endif
- // XXX for now uncomment the mark_dirty function, see bug 371505
- //cairo_surface_mark_dirty(surf);
- Init(surf);
-}
-
gfxOS2Surface::gfxOS2Surface(const gfxIntSize& aSize,
gfxASurface::gfxImageFormat aImageFormat)
- : mOwnsPS(PR_TRUE), mHasWnd(PR_FALSE), mSize(aSize)
+ : mHasWnd(PR_FALSE), mSize(aSize)
{
#ifdef DEBUG_thebes_2
printf("gfxOS2Surface[%#x]::gfxOS2Surface(Size=%dx%d, %d)\n", (unsigned int)this,
aSize.width, aSize.height, aImageFormat);
#endif
// in this case we don't have a window, so we create a memory presentation
// space to construct the cairo surface on
@@ -100,23 +81,28 @@ gfxOS2Surface::gfxOS2Surface(const gfxIn
GpiSetBitmap(mPS, mBitmap);
// now we can finally create the cairo surface on the in-memory PS
cairo_surface_t *surf = cairo_os2_surface_create(mPS, mSize.width, mSize.height);
#ifdef DEBUG_thebes_2
printf(" type(%#x)=%d (ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
cairo_surface_get_type(surf), (unsigned int)mPS, mSize.width, mSize.height);
#endif
- // XXX for now uncomment the mark_dirty function, see bug 371505
- //cairo_surface_mark_dirty(surf);
+ // Normally, OS/2 cairo surfaces have to be forced to redraw completely
+ // by calling cairo_surface_mark_dirty(surf), but Mozilla paints them in
+ // full, so that is not necessary here.
+
+ // manual refresh is done from nsWindow::OnPaint
+ cairo_os2_surface_set_manual_window_refresh(surf, 1);
+
Init(surf);
}
gfxOS2Surface::gfxOS2Surface(HWND aWnd)
- : mOwnsPS(PR_TRUE), mHasWnd(PR_TRUE), mDC(nsnull), mBitmap(nsnull)
+ : mHasWnd(PR_TRUE), mDC(nsnull), mBitmap(nsnull)
{
#ifdef DEBUG_thebes_2
printf("gfxOS2Surface[%#x]::gfxOS2Surface(HWND=%#x)\n", (unsigned int)this,
(unsigned int)aWnd);
#endif
mPS = WinGetPS(aWnd);
@@ -126,42 +112,69 @@ gfxOS2Surface::gfxOS2Surface(HWND aWnd)
mSize.height = rectl.yTop - rectl.yBottom;
if (mSize.width == 0) mSize.width = 1; // fake a minimal surface area to let
if (mSize.height == 0) mSize.height = 1; // cairo_os2_surface_create() return something
cairo_surface_t *surf = cairo_os2_surface_create(mPS, mSize.width, mSize.height);
#ifdef DEBUG_thebes_2
printf(" type(%#x)=%d (ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
cairo_surface_get_type(surf), (unsigned int)mPS, mSize.width, mSize.height);
#endif
+ // Normally, OS/2 cairo surfaces have to be forced to redraw completely
+ // by calling cairo_surface_mark_dirty(surf), but Mozilla paints them in
+ // full, so that is not necessary here.
+
// record the window handle in the cairo surface, so that refresh works
cairo_os2_surface_set_hwnd(surf, aWnd);
- // XXX for now uncomment the mark_dirty function, see bug 371505
- //cairo_surface_mark_dirty(surf);
+ // manual refresh is done from nsWindow::OnPaint
+ cairo_os2_surface_set_manual_window_refresh(surf, 1);
+
Init(surf);
}
gfxOS2Surface::~gfxOS2Surface()
{
#ifdef DEBUG_thebes_2
printf("gfxOS2Surface[%#x]::~gfxOS2Surface()\n", (unsigned int)this);
#endif
// Surfaces connected to a window were created using WinGetPS so we should
// release it again with WinReleasePS. Memory surfaces on the other
// hand were created on memory device contexts with the GPI functions, so
// use those to clean up stuff.
if (mHasWnd) {
- if (mOwnsPS && mPS) {
+ if (mPS) {
WinReleasePS(mPS);
}
} else {
if (mBitmap) {
GpiSetBitmap(mPS, NULL);
GpiDeleteBitmap(mBitmap);
}
- if (mOwnsPS && mPS) {
+ if (mPS) {
GpiDestroyPS(mPS);
}
if (mDC) {
DevCloseDC(mDC);
}
}
}
+
+void gfxOS2Surface::Refresh(RECTL *aRect, HPS aPS)
+{
+#ifdef DEBUG_thebes_2
+ printf("gfxOS2Surface[%#x]::Refresh(x=%ld,%ld/y=%ld,%ld, HPS=%#x), mPS=%#x\n",
+ (unsigned int)this,
+ aRect->xLeft, aRect->xRight, aRect->yBottom, aRect->yTop,
+ (unsigned int)aPS, (unsigned int)mPS);
+#endif
+ cairo_os2_surface_refresh_window(CairoSurface(), aPS, aRect);
+}
+
+int gfxOS2Surface::Resize(const gfxIntSize& aSize)
+{
+#ifdef DEBUG_thebes_2
+ printf("gfxOS2Surface[%#x]::Resize(%dx%d)\n", (unsigned int)this,
+ aSize.width, aSize.height);
+#endif
+ mSize = aSize; // record the new size
+ // hardcode mutex timeout to 50ms for now
+ return cairo_os2_surface_set_size(CairoSurface(), mSize.width, mSize.height, 50);
+}
--- a/widget/src/os2/nsWindow.cpp
+++ b/widget/src/os2/nsWindow.cpp
@@ -1120,19 +1120,16 @@ NS_METHOD nsWindow::Destroy()
// the rollup widget, rollup and turn off capture.
if (this == gRollupWidget) {
if (gRollupListener) {
gRollupListener->Rollup();
}
CaptureRollupEvents(nsnull, PR_FALSE, PR_TRUE);
}
- // Destroy thebes surface now, XXX do we need this at all??
- mThebesSurface = nsnull;
-
if (mWnd) {
HWND hwndBeingDestroyed = mFrameWnd ? mFrameWnd : mWnd;
DEBUGFOCUS(Destroy);
if (hwndBeingDestroyed == WinQueryFocus(HWND_DESKTOP)) {
WinSetFocus(HWND_DESKTOP, WinQueryWindow(hwndBeingDestroyed, QW_PARENT));
}
WinDestroyWindow(hwndBeingDestroyed);
}
@@ -3160,52 +3157,53 @@ PRBool nsWindow::OnPaint()
event.rect = ▭
event.region = nsnull;
#ifdef NS_DEBUG
debug_DumpPaintEvent(stdout, this, &event, nsCAutoString("noname"),
(PRInt32)mWnd);
#endif // NS_DEBUG
- // Thebes code version, adapted from windows/nsWindow.cpp
- // XXX as a preliminary solution for repaint problems of cairo-os2
- // builds, repaint the whole window for each paint event
- // see Bug 371505
- SWP swp;
- WinQueryWindowPos(mWnd, &swp);
- nsRefPtr<gfxASurface> targetSurface =
- new gfxOS2Surface(hPS, gfxIntSize(swp.cx, swp.cy));
- //new gfxOS2Surface(hPS, gfxIntSize(rect.width, rect.height));
- nsRefPtr<gfxContext> thebesContext = new gfxContext(targetSurface);
+ nsRefPtr<gfxContext> thebesContext = new gfxContext(mThebesSurface);
nsCOMPtr<nsIRenderingContext> context;
nsresult rv = mContext->CreateRenderingContextInstance(*getter_AddRefs(context));
if (NS_FAILED(rv)) {
NS_WARNING("CreateRenderingContextInstance failed");
return PR_FALSE;
}
rv = context->Init(mContext, thebesContext);
if (NS_FAILED(rv)) {
NS_WARNING("context::Init failed");
return PR_FALSE;
}
event.renderingContext = context;
- rc = DispatchWindowEvent(&event, eventStatus);
+ // try to dispatch a few times, 10 should be more than enough, in tests
+ // we get something at the second try at the latest
+ for (int i = 0; i < 10; i++) {
+ rc = DispatchWindowEvent(&event, eventStatus);
+ if (rc) {
+ // this was handled, so we can stop trying
+ break;
+ }
+ }
event.renderingContext = nsnull;
if (rc) {
// Only update if DispatchWindowEvent returned TRUE; otherwise, nothing handled
// this, and we'll just end up painting with black.
thebesContext->PopGroupToSource();
thebesContext->SetOperator(gfxContext::OPERATOR_SOURCE);
thebesContext->Paint();
}
+ NS_RELEASE(event.widget);
} // if (mEventCallback)
+ mThebesSurface->Refresh(&rcl, hPS);
} // if (!WinIsRectEmpty(0, &rcl))
WinEndPaint(hPS);
if (hpsDrag) {
ReleaseIfDragHPS(hpsDrag);
}
} // if (mContext && (mEventCallback || mEventListener))
@@ -3238,16 +3236,26 @@ PRBool nsWindow::OnPaint()
//
// Send a resize message to the listener
//
//-------------------------------------------------------------------------
PRBool nsWindow::OnResize(PRInt32 aX, PRInt32 aY)
{
mBounds.width = aX;
mBounds.height = aY;
+
+ // resize the thebes surface to the new size
+ if (!mThebesSurface) {
+ // So we need to create a thebes surface for this window.
+ // (This is necessary for the first resize of a window.)
+ mThebesSurface = new gfxOS2Surface(mWnd);
+ }
+
+ mThebesSurface->Resize(gfxIntSize(aX, aY));
+
return DispatchResizeEvent( aX, aY);
}
PRBool nsWindow::DispatchResizeEvent( PRInt32 aX, PRInt32 aY)
{
PRBool result;
// call the event callback
nsSizeEvent event(PR_TRUE, NS_SIZE, this);