Bug 629799, part 4: Fix alpha-recovery fallback on windows and try to use the SIMD path when possible. r=roc a=b
authorChris Jones <jones.chris.g@gmail.com>
Wed, 16 Feb 2011 16:43:30 -0600
changeset 62695 663d27e9098c3e6a8af9f439b02e427305f4bd1a
parent 62694 7e8fb5a646dae92615a816e856b8f403b5cd3a77
child 62696 aa7b2f04d225f08c59d830fdaf41575ce71d1334
push id18833
push usercjones@mozilla.com
push dateWed, 16 Feb 2011 22:44:38 +0000
treeherdermozilla-central@0f777e59d48c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, b
bugs629799
milestone2.0b12pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 629799, part 4: Fix alpha-recovery fallback on windows and try to use the SIMD path when possible. r=roc a=b
dom/plugins/PluginInstanceChild.cpp
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -2552,18 +2552,18 @@ PluginInstanceChild::UpdateWindowAttribu
         }
     }
 #endif // MAEMO
 #endif // MOZ_X11
 #ifdef XP_WIN
     HDC dc = NULL;
 
     if (curSurface) {
-        NS_ASSERTION(SharedDIBSurface::IsSharedDIBSurface(curSurface),
-                     "Expected (SharedDIB) image surface.");
+        if (!SharedDIBSurface::IsSharedDIBSurface(curSurface))
+            NS_RUNTIMEABORT("Expected SharedDIBSurface!");
 
         SharedDIBSurface* dibsurf = static_cast<SharedDIBSurface*>(curSurface.get());
         dc = dibsurf->GetHDC();
     }
     if (mWindow.window != dc) {
         mWindow.window = dc;
         needWindowUpdate = true;
     }
@@ -2774,56 +2774,110 @@ PluginInstanceChild::PaintRectToSurface(
         ctx->Fill();
     }
 }
 
 void
 PluginInstanceChild::PaintRectWithAlphaExtraction(const nsIntRect& aRect,
                                                   gfxASurface* aSurface)
 {
-    // Paint onto black image
-    bool needImageSurface = true;
-    nsRefPtr<gfxImageSurface> blackImage;
-    gfxIntSize clipSize(aRect.width, aRect.height);
-    gfxPoint deviceOffset(-aRect.x, -aRect.y);
-    // Try to re-use existing image surface, and avoid one copy
-    if (aSurface->GetType() == gfxASurface::SurfaceTypeImage) {
-        gfxImageSurface *surface = static_cast<gfxImageSurface*>(aSurface);
-        if (surface->Format() == gfxASurface::ImageFormatARGB32) {
-            needImageSurface = false;
-            blackImage = surface->GetSubimage(GfxFromNsRect(aRect));
+    NS_ABORT_IF_FALSE(aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA,
+                      "Refusing to pointlessly recover alpha");
+
+    nsIntRect rect(aRect);
+    // If |aSurface| can be used to paint and can have alpha values
+    // recovered directly to it, do that to save a tmp surface and
+    // copy.
+    bool useSurfaceSubimageForBlack = false;
+    if (gfxASurface::SurfaceTypeImage == aSurface->GetType()) {
+        gfxImageSurface* surfaceAsImage =
+            static_cast<gfxImageSurface*>(aSurface);
+        useSurfaceSubimageForBlack =
+            (surfaceAsImage->Format() == gfxASurface::ImageFormatARGB32);
+        // If we're going to use a subimage, nudge the rect so that we
+        // can use optimal alpha recovery.  If we're not using a
+        // subimage, the temporaries should automatically get
+        // fast-path alpha recovery so we don't need to do anything.
+        if (useSurfaceSubimageForBlack) {
+            rect =
+                gfxAlphaRecovery::AlignRectForSubimageRecovery(aRect,
+                                                               surfaceAsImage);
         }
     }
-    // otherwise create new helper surface
-    if (needImageSurface) {
-        blackImage = new gfxImageSurface(clipSize, gfxASurface::ImageFormatARGB32);
+
+    nsRefPtr<gfxImageSurface> whiteImage;
+    nsRefPtr<gfxImageSurface> blackImage;
+    gfxRect targetRect(rect.x, rect.y, rect.width, rect.height);
+    gfxIntSize targetSize(rect.width, rect.height);
+    gfxPoint deviceOffset = -targetRect.pos;
+
+    // We always use a temporary "white image"
+    whiteImage = new gfxImageSurface(targetSize, gfxASurface::ImageFormatRGB24);
+
+#ifdef XP_WIN
+    // On windows, we need an HDC and so can't paint directly to
+    // vanilla image surfaces.  Bifurcate this painting code so that
+    // we don't accidentally attempt that.
+    if (!SharedDIBSurface::IsSharedDIBSurface(aSurface))
+        NS_RUNTIMEABORT("Expected SharedDIBSurface!");
+
+    // Paint the plugin directly onto the target, with a white
+    // background and copy the result
+    PaintRectToSurface(rect, aSurface, gfxRGBA(1.0, 1.0, 1.0));
+    {
+        gfxRect copyRect(gfxPoint(0, 0), targetRect.size);
+        nsRefPtr<gfxContext> ctx = new gfxContext(whiteImage);
+        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+        ctx->SetSource(aSurface, deviceOffset);
+        ctx->Rectangle(copyRect);
+        ctx->Fill();
     }
 
-    // Paint to black image
+    // Paint the plugin directly onto the target, with a black
+    // background
+    PaintRectToSurface(rect, aSurface, gfxRGBA(0.0, 0.0, 0.0));
+
+    // Don't copy the result, just extract a subimage so that we can
+    // recover alpha directly into the target
+    gfxImageSurface *image = static_cast<gfxImageSurface*>(aSurface);
+    blackImage = image->GetSubimage(targetRect);
+
+#else
+    // Paint onto white background
+    whiteImage->SetDeviceOffset(deviceOffset);
+    PaintRectToSurface(rect, whiteImage, gfxRGBA(1.0, 1.0, 1.0));
+
+    if (useSurfaceSubimageForBlack) {
+        gfxImageSurface *surface = static_cast<gfxImageSurface*>(aSurface);
+        blackImage = surface->GetSubimage(targetRect);
+    } else {
+        blackImage = new gfxImageSurface(targetSize,
+                                         gfxASurface::ImageFormatARGB32);
+    }
+
+    // Paint onto black background
     blackImage->SetDeviceOffset(deviceOffset);
-    PaintRectToSurface(aRect, blackImage, gfxRGBA(0.0, 0.0, 0.0));
-
-    // Paint onto white image
-    nsRefPtr<gfxImageSurface> whiteImage =
-        new gfxImageSurface(clipSize, gfxASurface::ImageFormatRGB24);
-
-    whiteImage->SetDeviceOffset(deviceOffset);
-    PaintRectToSurface(aRect, whiteImage, gfxRGBA(1.0, 1.0, 1.0));
-
-    // Extract Alpha from black and white image and store to black Image
-    gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height);
-    if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage, nsnull)) {
+    PaintRectToSurface(rect, blackImage, gfxRGBA(0.0, 0.0, 0.0));
+#endif
+
+    NS_ABORT_IF_FALSE(whiteImage && blackImage, "Didn't paint enough!");
+
+    // Extract alpha from black and white image and store to black
+    // image
+    if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) {
         return;
     }
 
-    if (needImageSurface) {
+    // If we had to use a temporary black surface, copy the pixels
+    // with alpha back to the target
+    if (!useSurfaceSubimageForBlack) {
         nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
         ctx->SetSource(blackImage);
-        ctx->Rectangle(GfxFromNsRect(aRect));
+        ctx->Rectangle(targetRect);
         ctx->Fill();
     }
 }
 
 bool
 PluginInstanceChild::ShowPluginFrame()
 {
     if (mPendingPluginCall) {