Bug 549426: OS/2 build bustage after layers landing. r=wuno
authorRich Walsh <dragtext@e-vertise.com>
Sun, 28 Mar 2010 11:46:08 -0400
changeset 39956 b046a079a16e3f8d20ef7edfbd60fb81305994a1
parent 39955 f07fe9c3a1a7efd06d02e7e5910b9236e4f83cc8
child 39957 9e4a10b4469e32fa7e417e9229d919b891972d10
push id12471
push userme@kylehuey.com
push dateSun, 28 Mar 2010 15:54:40 +0000
treeherderautoland@f86035589b4d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswuno
bugs549426
milestone1.9.3a4pre
Bug 549426: OS/2 build bustage after layers landing. r=wuno
widget/src/os2/nsWindow.cpp
--- a/widget/src/os2/nsWindow.cpp
+++ b/widget/src/os2/nsWindow.cpp
@@ -2078,128 +2078,161 @@ PRBool nsWindow::OnReposition(PSWP pSwp)
 
   return result;
 }
 
 //-----------------------------------------------------------------------------
 
 PRBool nsWindow::OnPaint()
 {
-  PRBool rc = PR_FALSE;
+  HPS    hPS;
+  HPS    hpsDrag;
+  HRGN   hrgn;
   nsEventStatus eventStatus = nsEventStatus_eIgnore;
 
-#ifdef NS_DEBUG
+#ifdef DEBUG_PAINT
   HRGN debugPaintFlashRegion = 0;
-  HPS debugPaintFlashPS = 0;
+  HPS  debugPaintFlashPS = 0;
 
   if (debug_WantPaintFlashing()) {
     debugPaintFlashPS = WinGetPS(mWnd);
     debugPaintFlashRegion = GpiCreateRegion(debugPaintFlashPS, 0, 0);
     WinQueryUpdateRegion(mWnd, debugPaintFlashRegion);
-  } // if paint flashing
-#endif
-
-  if (mContext && mEventCallback) {
-    // Get rect to redraw and validate window
-    RECTL rcl = { 0 };
-
-    // get the current drag status;  if we're currently in a Moz-originated
-    // drag, get the special drag HPS then pass it to WinBeginPaint();
-    // if there is no hpsDrag, WinBeginPaint() will return a normal HPS
-    HPS hpsDrag = 0;
-    CheckDragStatus(ACTION_PAINT, &hpsDrag);
-    HPS hPS = WinBeginPaint(mWnd, hpsDrag, &rcl);
-
-    // if the update rect is empty, suppress the paint event
-    if (!WinIsRectEmpty(0, &rcl)) {
-      // call the event callback
-      if (mEventCallback) {
-        nsPaintEvent event(PR_TRUE, NS_PAINT, this);
-        InitEvent(event);
-
-        // build XP rect from in-ex window rect
-        nsIntRect rect;
-        rect.x = rcl.xLeft;
-        rect.y = mBounds.height - rcl.yTop;
-        rect.width = rcl.xRight - rcl.xLeft;
-        rect.height = rcl.yTop - rcl.yBottom;
-        event.rect = &rect;
-        event.region = nsnull;
-
-#ifdef NS_DEBUG
-        debug_DumpPaintEvent(stdout, this, &event, nsCAutoString("noname"),
-                             (PRInt32)mWnd);
+  }
 #endif
 
-        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;
-        }
-
-        // Try to dispatch a few times, 10 should be more than enough.
-        // In tests we get something at the second try at the latest
-        event.renderingContext = context;
-        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;
-
-        // Only update if DispatchWindowEvent returned TRUE; otherwise,
-        // nothing handled this, and we'll just end up painting with black.
-        if (rc) {
-          thebesContext->PopGroupToSource();
-          thebesContext->SetOperator(gfxContext::OPERATOR_SOURCE);
-          thebesContext->Paint();
-        }
-      } // if (mEventCallback)
-      mThebesSurface->Refresh(&rcl, hPS);
-    } // if (!WinIsRectEmpty(0, &rcl))
-
+// Use a dummy do..while(0) loop to facilitate error handling & early-outs.
+do {
+
+  // Get the current drag status.  If we're in a Moz-originated drag,
+  // it will return a special drag HPS to pass to WinBeginPaint().
+  // Oherwise, get a cached micro PS.
+  CheckDragStatus(ACTION_PAINT, &hpsDrag);
+  hPS = hpsDrag ? hpsDrag : WinGetPS(mWnd);
+
+  // If we can't get an HPS, validate the window so we don't
+  // keep getting the same WM_PAINT msg over & over again.
+  RECTL  rcl = { 0 };
+  if (!hPS) {
+    WinQueryWindowRect(mWnd, &rcl);
+    WinValidateRect(mWnd, &rcl, FALSE);
+    break;
+  }
+
+  // Get the update region before WinBeginPaint() resets it.
+  hrgn = GpiCreateRegion(hPS, 0, 0);
+  WinQueryUpdateRegion(mWnd, hrgn);
+  WinBeginPaint(mWnd, hPS, &rcl);
+
+  // Exit if the update rect is empty or mThebesSurface is null.
+  if (WinIsRectEmpty(0, &rcl) || !GetThebesSurface()) {
+    break;
+  }
+
+  // Even if there is no callback to update the content (unlikely)
+  // we still want to update the screen with whatever's available.
+  if (!mEventCallback) {
+    mThebesSurface->Refresh(&rcl, hPS);
+    break;
+  }
+
+  // Create an event & a Thebes context.
+  nsPaintEvent event(PR_TRUE, NS_PAINT, this);
+  InitEvent(event);
+  nsRefPtr<gfxContext> thebesContext = new gfxContext(mThebesSurface);
+  thebesContext->SetFlag(gfxContext::FLAG_DESTINED_FOR_SCREEN);
+
+  // See how many rects comprise the update region.  If there are 8
+  // or fewer, update them individually.  If there are more or the call
+  // failed, update the bounding rectangle returned by WinBeginPaint().
+  #define MAX_CLIPRECTS 8
+  RGNRECT rgnrect = { 1, MAX_CLIPRECTS, 0, RECTDIR_LFRT_TOPBOT };
+  RECTL   arect[MAX_CLIPRECTS];
+  RECTL*  pr = arect;
+
+  if (!GpiQueryRegionRects(hPS, hrgn, 0, &rgnrect, 0) ||
+      rgnrect.crcReturned > MAX_CLIPRECTS) {
+    rgnrect.crcReturned = 1;
+    arect[0] = rcl;
+  } else {
+    GpiQueryRegionRects(hPS, hrgn, 0, &rgnrect, arect);
+  }
+
+  // Create clipping regions for the event & the Thebes context.
+  thebesContext->NewPath();
+  for (PRUint32 i = 0; i < rgnrect.crcReturned; i++, pr++) {
+    event.region.Or(event.region, 
+                    nsIntRect(pr->xLeft,
+                              mBounds.height - pr->yTop,
+                              pr->xRight - pr->xLeft,
+                              pr->yTop - pr->yBottom));
+
+    thebesContext->Rectangle(gfxRect(pr->xLeft,
+                                     mBounds.height - pr->yTop,
+                                     pr->xRight - pr->xLeft,
+                                     pr->yTop - pr->yBottom));
+  }
+  thebesContext->Clip();
+
+#ifdef DEBUG_PAINT
+  debug_DumpPaintEvent(stdout, this, &event, nsCAutoString("noname"),
+                       (PRInt32)mWnd);
+#endif
+
+  // Init the Layers manager then dispatch the event.
+  // If it returns false there's nothing to paint, so exit.
+  AutoLayerManagerSetup setupLayerManager(this, thebesContext);
+  if (!DispatchWindowEvent(&event, eventStatus)) {
+    break;
+  }
+
+  // Paint the surface, then use Refresh() to blit each rect to the screen.
+  thebesContext->PopGroupToSource();
+  thebesContext->SetOperator(gfxContext::OPERATOR_SOURCE);
+  thebesContext->Paint();
+  pr = arect;
+  for (PRUint32 i = 0; i < rgnrect.crcReturned; i++, pr++) {
+    mThebesSurface->Refresh(pr, hPS);
+  }
+
+} while (0);
+
+  // Cleanup.
+  if (hPS) {
     WinEndPaint(hPS);
-    if (hpsDrag) {
-      ReleaseIfDragHPS(hpsDrag);
+    if (hrgn) {
+      GpiDestroyRegion(hPS, hrgn);
     }
-  } // if (mContext && mEventCallback)
-
-#ifdef NS_DEBUG
+    if (!hpsDrag || !ReleaseIfDragHPS(hpsDrag)) {
+      WinReleasePS(hPS);
+    }
+  }
+
+#ifdef DEBUG_PAINT
   if (debug_WantPaintFlashing()) {
     // Only flash paint events which have not ignored the paint message.
     // Those that ignore the paint message aren't painting anything so there
     // is only the overhead of the dispatching the paint event.
     if (eventStatus != nsEventStatus_eIgnore) {
       LONG CurMix = GpiQueryMix(debugPaintFlashPS);
       GpiSetMix(debugPaintFlashPS, FM_INVERT);
 
       GpiPaintRegion(debugPaintFlashPS, debugPaintFlashRegion);
       PR_Sleep(PR_MillisecondsToInterval(30));
       GpiPaintRegion(debugPaintFlashPS, debugPaintFlashRegion);
       PR_Sleep(PR_MillisecondsToInterval(30));
 
       GpiSetMix(debugPaintFlashPS, CurMix);
-    } // if not eIgnore
+    }
     GpiDestroyRegion(debugPaintFlashPS, debugPaintFlashRegion);
     WinReleasePS(debugPaintFlashPS);
-  } // if paint flashing
+  }
 #endif
 
-  return rc;
+  return PR_TRUE;
 }
 
 //-----------------------------------------------------------------------------
 // If MB1 & MB2 are both pressed, perform a copy or paste.
 
 PRBool nsWindow::OnMouseChord(MPARAM mp1, MPARAM mp2)
 {
   if (!isKeyDown(VK_BUTTON1) || !isKeyDown(VK_BUTTON2)) {