Bug 740200 - Azure content rendering on Linux; r=roc
authorAnthony Jones <ajones@mozilla.com>
Fri, 20 Sep 2013 14:00:35 +1200
changeset 148037 cebeca8df9863637df466b5165a33f2681198757
parent 148036 e649d78553ec849a501a04ea52b538b60a933de2
child 148038 d074ae862d1679ee9c49c1ca1a798205dde20944
push id25321
push useremorley@mozilla.com
push dateFri, 20 Sep 2013 09:19:10 +0000
treeherdermozilla-central@d923570ed720 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs740200
milestone27.0a1
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 740200 - Azure content rendering on Linux; r=roc
gfx/thebes/gfxXlibNativeRenderer.cpp
gfx/thebes/gfxXlibNativeRenderer.h
--- a/gfx/thebes/gfxXlibNativeRenderer.cpp
+++ b/gfx/thebes/gfxXlibNativeRenderer.cpp
@@ -3,20 +3,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxXlibNativeRenderer.h"
 
 #include "gfxXlibSurface.h"
 #include "gfxImageSurface.h"
 #include "gfxContext.h"
+#include "gfxPlatform.h"
 #include "gfxAlphaRecovery.h"
 #include "cairo-xlib.h"
 #include "cairo-xlib-xrender.h"
 
+using namespace mozilla;
+using namespace mozilla::gfx;
+
 #if 0
 #include <stdio.h>
 #define NATIVE_DRAWING_NOTE(m) fprintf(stderr, m)
 #else
 #define NATIVE_DRAWING_NOTE(m) do {} while (0)
 #endif
 
 /* We have four basic strategies available:
@@ -129,18 +133,38 @@ FINISH:
  * Try the direct path.
  * @return True if we took the direct path
  */
 bool
 gfxXlibNativeRenderer::DrawDirect(gfxContext *ctx, nsIntSize size,
                                   uint32_t flags,
                                   Screen *screen, Visual *visual)
 {
-    cairo_t *cr = ctx->GetCairo();
+    if (ctx->IsCairo()) {
+        return DrawCairo(ctx->GetCairo(), size, flags, screen, visual);
+    }
+
+    // We need to actually borrow the context because we want to read out the
+    // clip rectangles.
+    BorrowedCairoContext borrowed(ctx->GetDrawTarget());
+    if (!borrowed.mCairo) {
+      return false;
+    }
 
+    bool direct = DrawCairo(borrowed.mCairo, size, flags, screen, visual);
+    borrowed.Finish();
+
+    return direct;
+}
+
+bool
+gfxXlibNativeRenderer::DrawCairo(cairo_t* cr, nsIntSize size,
+                                 uint32_t flags,
+                                 Screen *screen, Visual *visual)
+{
     /* Check that the target surface is an xlib surface. */
     cairo_surface_t *target = cairo_get_group_target (cr);
     if (cairo_surface_get_type (target) != CAIRO_SURFACE_TYPE_XLIB) {
         NATIVE_DRAWING_NOTE("FALLBACK: non-X surface");
         return false;
     }
 
     cairo_matrix_t matrix;
@@ -445,17 +469,16 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
                             DrawOutput* result)
 {
     if (result) {
         result->mSurface = nullptr;
         result->mUniformAlpha = false;
         result->mUniformColor = false;
     }
 
-    bool drawIsOpaque = (flags & DRAW_IS_OPAQUE) != 0;
     gfxMatrix matrix = ctx->CurrentMatrix();
 
     // We can only draw direct or onto a copied background if pixels align and
     // native drawing is compatible with the current operator.  (The matrix is
     // actually also pixel-exact for flips and right-angle rotations, which
     // would permit copying the background but not drawing direct.)
     bool matrixIsIntegerTranslation = !matrix.HasNonIntegerTranslation();
     bool canDrawOverBackground = matrixIsIntegerTranslation &&
@@ -483,17 +506,17 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
         ctx->Clip(affectedRect);
 
         clipExtents = ctx->GetClipExtents();
         if (clipExtents.IsEmpty())
             return; // nothing to do
 
         if (canDrawOverBackground &&
             DrawDirect(ctx, size, flags, screen, visual))
-            return;
+          return;
     }
 
     nsIntRect drawingRect(nsIntPoint(0, 0), size);
     // Drawing need only be performed within the clip extents
     // (and padding for the filter).
     if (!matrixIsIntegerTranslation) {
         // The source surface may need to be a little larger than the clip
         // extents due to the filter footprint.
@@ -501,39 +524,66 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
     }
     clipExtents.RoundOut();
 
     nsIntRect intExtents(int32_t(clipExtents.X()),
                          int32_t(clipExtents.Y()),
                          int32_t(clipExtents.Width()),
                          int32_t(clipExtents.Height()));
     drawingRect.IntersectRect(drawingRect, intExtents);
+
+    if (ctx->IsCairo()) {
+        nsRefPtr<gfxASurface> target(ctx->CurrentSurface());
+        DrawFallback(nullptr, ctx, target, size, drawingRect, canDrawOverBackground,
+                     flags, screen, visual, result);
+    } else {
+        DrawTarget* drawTarget = ctx->GetDrawTarget();
+        if (!drawTarget) {
+            return;
+        }
+
+        nsRefPtr<gfxASurface> target = gfxPlatform::GetPlatform()->
+            GetThebesSurfaceForDrawTarget(drawTarget);
+        if (!target) {
+            return;
+        }
+        DrawFallback(drawTarget, ctx, target, size, drawingRect, canDrawOverBackground,
+                     flags, screen, visual, result);
+    }
+}
+
+void
+gfxXlibNativeRenderer::DrawFallback(DrawTarget* drawTarget, gfxContext* ctx, gfxASurface* target,
+                                    nsIntSize& size, nsIntRect& drawingRect,
+                                    bool canDrawOverBackground, uint32_t flags,
+                                    Screen* screen, Visual* visual, DrawOutput* result)
+{
     gfxPoint offset(drawingRect.x, drawingRect.y);
 
     DrawingMethod method;
-    nsRefPtr<gfxASurface> target = ctx->CurrentSurface();
     nsRefPtr<gfxXlibSurface> tempXlibSurface = 
         CreateTempXlibSurface(target, drawingRect.Size(),
                               canDrawOverBackground, flags, screen, visual,
                               &method);
     if (!tempXlibSurface)
         return;
-  
+
     if (drawingRect.Size() != size || method == eCopyBackground) {
         // Only drawing a portion, or copying background,
         // so won't return a result.
         result = nullptr;
     }
-
+  
     nsRefPtr<gfxContext> tmpCtx;
+    bool drawIsOpaque = (flags & DRAW_IS_OPAQUE) != 0;
     if (!drawIsOpaque) {
         tmpCtx = new gfxContext(tempXlibSurface);
         if (method == eCopyBackground) {
             tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
-            tmpCtx->SetSource(target, -(offset + matrix.GetTranslation()));
+            tmpCtx->SetSource(target, -(offset + ctx->CurrentMatrix().GetTranslation()));
             // The copy from the tempXlibSurface to the target context should
             // use operator SOURCE, but that would need a mask to bound the
             // operation.  Here we only copy opaque backgrounds so operator
             // OVER will behave like SOURCE masked by the surface.
             NS_ASSERTION(tempXlibSurface->GetContentType()
                          == gfxASurface::CONTENT_COLOR,
                          "Don't copy background with a transparent surface");
         } else {
@@ -542,18 +592,26 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
         tmpCtx->Paint();
     }
 
     if (!DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft())) {
         return;
     }
   
     if (method != eAlphaExtraction) {
-        ctx->SetSource(tempXlibSurface, offset);
-        ctx->Paint();
+        if (drawTarget) {
+            RefPtr<SourceSurface> sourceSurface = gfxPlatform::GetPlatform()->
+                GetSourceSurfaceForSurface(drawTarget, tempXlibSurface);
+            drawTarget->DrawSurface(sourceSurface,
+                Rect(offset.x, offset.y, size.width, size.height),
+                Rect(0, 0, size.width, size.height));
+        } else {
+            ctx->SetSource(tempXlibSurface, offset);
+            ctx->Paint();
+        }
         if (result) {
             result->mSurface = tempXlibSurface;
             /* fill in the result with what we know, which is really just what our
                assumption was */
             result->mUniformAlpha = true;
             result->mColor.a = 1.0;
         }
         return;
@@ -571,18 +629,17 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
   
     if (blackImage->CairoStatus() == CAIRO_STATUS_SUCCESS &&
         whiteImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
         gfxAlphaRecovery::Analysis analysis;
         if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage,
                                             result ? &analysis : nullptr))
             return;
 
-        ctx->SetSource(blackImage, offset);
-
+        gfxASurface* paintSurface = blackImage;
         /* if the caller wants to retrieve the rendered image, put it into
            a 'similar' surface, and use that as the source for the drawing right
            now. This means we always return a surface similar to the surface
            used for 'cr', which is ideal if it's going to be cached and reused.
            We do not return an image if the result has uniform color (including
            alpha). */
         if (result) {
             if (analysis.uniformAlpha) {
@@ -599,15 +656,23 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
                     CreateSimilarSurface(gfxASurface::CONTENT_COLOR_ALPHA,
                                          gfxIntSize(size.width, size.height));
 
                 gfxContext copyCtx(result->mSurface);
                 copyCtx.SetSource(blackImage);
                 copyCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
                 copyCtx.Paint();
 
-                ctx->SetSource(result->mSurface);
+                paintSurface = result->mSurface;
             }
         }
-        
-        ctx->Paint();
+        if (drawTarget) {
+            RefPtr<SourceSurface> sourceSurface = gfxPlatform::GetPlatform()->
+                GetSourceSurfaceForSurface(drawTarget, paintSurface);
+            drawTarget->DrawSurface(sourceSurface,
+                Rect(offset.x, offset.y, size.width, size.height),
+                Rect(0, 0, size.width, size.height));
+        } else {
+            ctx->SetSource(paintSurface, offset);
+            ctx->Paint();
+        }
     }
 }
--- a/gfx/thebes/gfxXlibNativeRenderer.h
+++ b/gfx/thebes/gfxXlibNativeRenderer.h
@@ -5,22 +5,29 @@
 
 #ifndef GFXXLIBNATIVERENDER_H_
 #define GFXXLIBNATIVERENDER_H_
 
 #include "gfxColor.h"
 #include "nsAutoPtr.h"
 #include <X11/Xlib.h>
 
+namespace mozilla {
+namespace gfx {
+  class DrawTarget;
+}
+}
+
 class gfxASurface;
 class gfxXlibSurface;
 class gfxContext;
 struct nsIntRect;
 struct nsIntPoint;
 struct nsIntSize;
+typedef struct _cairo cairo_t;
 
 /**
  * This class lets us take code that draws into an X drawable and lets us
  * use it to draw into any Thebes context. The user should subclass this class,
  * override DrawWithXib, and then call Draw(). The drawing will be subjected
  * to all Thebes transformations, clipping etc.
  */
 class gfxXlibNativeRenderer {
@@ -86,14 +93,23 @@ public:
     void Draw(gfxContext* ctx, nsIntSize size,
               uint32_t flags, Screen *screen, Visual *visual,
               DrawOutput* result);
 
 private:
     bool DrawDirect(gfxContext *ctx, nsIntSize bounds,
                     uint32_t flags, Screen *screen, Visual *visual);
 
+    bool DrawCairo(cairo_t* cr, nsIntSize size,
+                   uint32_t flags, Screen *screen, Visual *visual);
+
+    void DrawFallback(mozilla::gfx::DrawTarget* dt, gfxContext* ctx,
+                      gfxASurface* aSurface, nsIntSize& size,
+                      nsIntRect& drawingRect, bool canDrawOverBackground,
+                      uint32_t flags, Screen* screen, Visual* visual,
+                      DrawOutput* result);
+
     bool DrawOntoTempSurface(gfxXlibSurface *tempXlibSurface,
                              nsIntPoint offset);
 
 };
 
 #endif /*GFXXLIBNATIVERENDER_H_*/