From 269747bcb6e12560609f0a47ec2eab1e48bd6cb3 Mon Sep 17 00:00:00 2001 From: Anthony Jones Date: Thu, 19 Sep 2013 16:29:51 +1200 Subject: [PATCH] Bug 740200 - Azure content rendering on Linux; r=roc --- gfx/thebes/gfxXlibNativeRenderer.cpp | 93 +++++++++++++++++++++++----- gfx/thebes/gfxXlibNativeRenderer.h | 16 +++++ 2 files changed, 95 insertions(+), 14 deletions(-) diff --git a/gfx/thebes/gfxXlibNativeRenderer.cpp b/gfx/thebes/gfxXlibNativeRenderer.cpp index 5c3a7f2bb0a7..0d4651bc2723 100644 --- a/gfx/thebes/gfxXlibNativeRenderer.cpp +++ b/gfx/thebes/gfxXlibNativeRenderer.cpp @@ -8,10 +8,14 @@ #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 #define NATIVE_DRAWING_NOTE(m) fprintf(stderr, m) @@ -134,8 +138,28 @@ 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) { @@ -450,7 +474,6 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size, 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 @@ -488,7 +511,7 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size, if (canDrawOverBackground && DrawDirect(ctx, size, flags, screen, visual)) - return; + return; } nsIntRect drawingRect(nsIntPoint(0, 0), size); @@ -506,29 +529,56 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size, int32_t(clipExtents.Width()), int32_t(clipExtents.Height())); drawingRect.IntersectRect(drawingRect, intExtents); + + if (ctx->IsCairo()) { + nsRefPtr target(ctx->CurrentSurface()); + DrawFallback(nullptr, ctx, target, size, drawingRect, canDrawOverBackground, + flags, screen, visual, result); + } else { + DrawTarget* drawTarget = ctx->GetDrawTarget(); + if (!drawTarget) { + return; + } + + nsRefPtr 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 target = ctx->CurrentSurface(); nsRefPtr 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 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 @@ -547,8 +597,16 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size, } if (method != eAlphaExtraction) { - ctx->SetSource(tempXlibSurface, offset); - ctx->Paint(); + if (drawTarget) { + RefPtr 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 @@ -576,8 +634,7 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size, 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 @@ -604,10 +661,18 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size, copyCtx.SetOperator(gfxContext::OPERATOR_SOURCE); copyCtx.Paint(); - ctx->SetSource(result->mSurface); + paintSurface = result->mSurface; } } - - ctx->Paint(); + if (drawTarget) { + RefPtr 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(); + } } } diff --git a/gfx/thebes/gfxXlibNativeRenderer.h b/gfx/thebes/gfxXlibNativeRenderer.h index 4dd8e8524bf9..1e0d0f1be3b2 100644 --- a/gfx/thebes/gfxXlibNativeRenderer.h +++ b/gfx/thebes/gfxXlibNativeRenderer.h @@ -10,12 +10,19 @@ #include "nsAutoPtr.h" #include +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 @@ -91,6 +98,15 @@ 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);