Bug 924679. Part 6: Remove gfxXlibNativeRender::DrawOutput and convert tmpXlibSurface from gfxXlibSurface to cairo_surface_t. r=karlt

--HG--
extra : rebase_source : 724e9b7881949c868ba528250de6ce9d24eb2752
This commit is contained in:
Robert O'Callahan 2013-10-25 23:25:40 +02:00
parent 9590eb387d
commit aa07fb8924
6 changed files with 110 additions and 171 deletions

View File

@ -2795,7 +2795,7 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext,
Visual* visual = DefaultVisualOfScreen(screen);
renderer.Draw(aContext, nsIntSize(window->width, window->height),
rendererFlags, screen, visual, nullptr);
rendererFlags, screen, visual);
}
nsresult
nsPluginInstanceOwner::Renderer::DrawWithXlib(cairo_surface_t* xsurface,

View File

@ -59,7 +59,7 @@ gfxGdkNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
Screen* screen =
gdk_x11_screen_get_xscreen(gdk_colormap_get_screen(colormap));
gfxXlibNativeRenderer::Draw(ctx, size, flags, screen, visual, nullptr);
gfxXlibNativeRenderer::Draw(ctx, size, flags, screen, visual);
}
#else

View File

@ -9,8 +9,7 @@
nsresult
gfxQtNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
uint32_t flags, Screen* screen, Visual* visual,
DrawOutput* output)
uint32_t flags, Screen* screen, Visual* visual)
{
Display *dpy = DisplayOfScreen(screen);
bool isOpaque = (flags & DRAW_IS_OPAQUE) ? true : false;

View File

@ -54,13 +54,6 @@ public:
DRAW_SUPPORTS_ALTERNATE_SCREEN = 0x20
};
struct DrawOutput {
nsRefPtr<gfxASurface> mSurface;
bool mUniformAlpha;
bool mUniformColor;
gfxRGBA mColor;
};
/**
* @param flags see above
* @param size Draw()'s drawing is guaranteed to be restricted to
@ -72,8 +65,7 @@ public:
* otherwise *resultSurface is set to nullptr.
*/
nsresult Draw(gfxContext* ctx, nsIntSize size,
uint32_t flags, Screen* screen, Visual* visual,
DrawOutput* output);
uint32_t flags, Screen* screen, Visual* visual);
};
#endif /*GFXQTNATIVERENDER_H_*/

View File

@ -13,6 +13,7 @@
#include "cairo-xlib.h"
#include "cairo-xlib-xrender.h"
#include "mozilla/gfx/BorrowedContext.h"
#include "gfx2DGlue.h"
using namespace mozilla;
using namespace mozilla::gfx;
@ -308,31 +309,34 @@ enum DrawingMethod {
eAlphaExtraction
};
static already_AddRefed<gfxXlibSurface>
CreateTempXlibSurface (gfxASurface *destination, nsIntSize size,
static cairo_surface_t*
CreateTempXlibSurface (cairo_surface_t* cairoTarget,
DrawTarget* drawTarget,
nsIntSize size,
bool canDrawOverBackground,
uint32_t flags, Screen *screen, Visual *visual,
DrawingMethod *method)
{
NS_ASSERTION(cairoTarget || drawTarget, "Must have some type");
bool drawIsOpaque = (flags & gfxXlibNativeRenderer::DRAW_IS_OPAQUE) != 0;
bool supportsAlternateVisual =
(flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
bool supportsAlternateScreen = supportsAlternateVisual &&
(flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_SCREEN);
cairo_surface_t *target = destination->CairoSurface();
cairo_surface_type_t target_type = cairo_surface_get_type (target);
cairo_content_t target_content = cairo_surface_get_content (target);
cairo_surface_type_t cairoTargetType =
cairoTarget ? cairo_surface_get_type (cairoTarget) : (cairo_surface_type_t)0xFF;
Screen *target_screen = target_type == CAIRO_SURFACE_TYPE_XLIB ?
cairo_xlib_surface_get_screen (target) : screen;
Screen *target_screen = cairoTargetType == CAIRO_SURFACE_TYPE_XLIB ?
cairo_xlib_surface_get_screen (cairoTarget) : screen;
// When the background has an alpha channel, we need to draw with an alpha
// channel anyway, so there is no need to copy the background. If
// doCopyBackground is set here, we'll also need to check below that the
// background can copied without any loss in format conversions.
bool doCopyBackground = !drawIsOpaque && canDrawOverBackground &&
target_content == CAIRO_CONTENT_COLOR;
cairoTarget && cairo_surface_get_content (cairoTarget) == CAIRO_CONTENT_COLOR;
if (supportsAlternateScreen && screen != target_screen && drawIsOpaque) {
// Prefer a visual on the target screen.
@ -346,14 +350,13 @@ CreateTempXlibSurface (gfxASurface *destination, nsIntSize size,
// opaque drawing.
Visual *target_visual = nullptr;
XRenderPictFormat *target_format = nullptr;
switch (target_type) {
case CAIRO_SURFACE_TYPE_XLIB:
target_visual = cairo_xlib_surface_get_visual (target);
target_format = cairo_xlib_surface_get_xrender_format (target);
break;
case CAIRO_SURFACE_TYPE_IMAGE: {
if (cairoTargetType == CAIRO_SURFACE_TYPE_XLIB) {
target_visual = cairo_xlib_surface_get_visual (cairoTarget);
target_format = cairo_xlib_surface_get_xrender_format (cairoTarget);
} else if (cairoTargetType == CAIRO_SURFACE_TYPE_IMAGE || drawTarget) {
gfxImageFormat imageFormat =
static_cast<gfxImageSurface*>(destination)->Format();
drawTarget ? SurfaceFormatToImageFormat(drawTarget->GetFormat()) :
(gfxImageFormat)cairo_image_surface_get_format(cairoTarget);
target_visual = gfxXlibSurface::FindVisual(screen, imageFormat);
Display *dpy = DisplayOfScreen(screen);
if (target_visual) {
@ -362,10 +365,6 @@ CreateTempXlibSurface (gfxASurface *destination, nsIntSize size,
target_format =
gfxXlibSurface::FindRenderFormat(dpy, imageFormat);
}
break;
}
default:
break;
}
if (supportsAlternateVisual &&
@ -412,16 +411,19 @@ CreateTempXlibSurface (gfxASurface *destination, nsIntSize size,
}
Drawable drawable =
(screen == target_screen && target_type == CAIRO_SURFACE_TYPE_XLIB) ?
cairo_xlib_surface_get_drawable (target) : RootWindowOfScreen(screen);
(screen == target_screen && cairoTargetType == CAIRO_SURFACE_TYPE_XLIB) ?
cairo_xlib_surface_get_drawable (cairoTarget) : RootWindowOfScreen(screen);
nsRefPtr<gfxXlibSurface> surface =
gfxXlibSurface::Create(screen, visual,
gfxIntSize(size.width, size.height),
drawable);
cairo_surface_t *surface =
gfxXlibSurface::CreateCairoSurface(screen, visual,
gfxIntSize(size.width, size.height),
drawable);
if (!surface) {
return nullptr;
}
if (drawIsOpaque ||
surface->GetContentType() == GFX_CONTENT_COLOR_ALPHA) {
cairo_surface_get_content(surface) == CAIRO_CONTENT_COLOR_ALPHA) {
NATIVE_DRAWING_NOTE(drawIsOpaque ?
", SIMPLE OPAQUE\n" : ", SIMPLE WITH ALPHA");
*method = eSimple;
@ -433,47 +435,41 @@ CreateTempXlibSurface (gfxASurface *destination, nsIntSize size,
*method = eAlphaExtraction;
}
return surface.forget();
return surface;
}
bool
gfxXlibNativeRenderer::DrawOntoTempSurface(gfxXlibSurface *tempXlibSurface,
gfxXlibNativeRenderer::DrawOntoTempSurface(cairo_surface_t *tempXlibSurface,
nsIntPoint offset)
{
tempXlibSurface->Flush();
cairo_surface_flush(tempXlibSurface);
/* no clipping is needed because the callback can't draw outside the native
surface anyway */
nsresult rv = DrawWithXlib(tempXlibSurface->CairoSurface(), offset, nullptr, 0);
tempXlibSurface->MarkDirty();
nsresult rv = DrawWithXlib(tempXlibSurface, offset, nullptr, 0);
cairo_surface_mark_dirty(tempXlibSurface);
return NS_SUCCEEDED(rv);
}
static already_AddRefed<gfxImageSurface>
CopyXlibSurfaceToImage(gfxXlibSurface *tempXlibSurface,
CopyXlibSurfaceToImage(cairo_surface_t *tempXlibSurface,
gfxIntSize size,
gfxImageFormat format)
{
nsRefPtr<gfxImageSurface> result =
new gfxImageSurface(tempXlibSurface->GetSize(), format);
nsRefPtr<gfxImageSurface> result = new gfxImageSurface(size, format);
gfxContext copyCtx(result);
copyCtx.SetSource(tempXlibSurface);
copyCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
copyCtx.Paint();
cairo_t* copyCtx = cairo_create(result->CairoSurface());
cairo_set_source_surface(copyCtx, tempXlibSurface, 0, 0);
cairo_set_operator(copyCtx, CAIRO_OPERATOR_SOURCE);
cairo_paint(copyCtx);
cairo_destroy(copyCtx);
return result.forget();
}
void
gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
uint32_t flags, Screen *screen, Visual *visual,
DrawOutput* result)
uint32_t flags, Screen *screen, Visual *visual)
{
if (result) {
result->mSurface = nullptr;
result->mUniformAlpha = false;
result->mUniformColor = false;
}
gfxMatrix matrix = ctx->CurrentMatrix();
// We can only draw direct or onto a copied background if pixels align and
@ -530,149 +526,110 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
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<gfxXlibSurface> tempXlibSurface =
CreateTempXlibSurface(target, drawingRect.Size(),
cairo_surface_t* cairoTarget = nullptr;
DrawTarget* drawTarget = nullptr;
if (ctx->IsCairo()) {
cairoTarget = cairo_get_group_target(ctx->GetCairo());
} else {
drawTarget = ctx->GetDrawTarget();
cairoTarget = static_cast<cairo_surface_t*>
(drawTarget->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE));
}
cairo_surface_t* tempXlibSurface =
CreateTempXlibSurface(cairoTarget, drawTarget, 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);
cairo_t* tmpCtx = cairo_create(tempXlibSurface);
if (method == eCopyBackground) {
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->SetSource(target, -(offset + ctx->CurrentMatrix().GetTranslation()));
NS_ASSERTION(cairoTarget, "eCopyBackground only used when there's a cairoTarget");
cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
gfxPoint pt = -(offset + ctx->CurrentMatrix().GetTranslation());
cairo_set_source_surface(tmpCtx, cairoTarget, pt.x, pt.y);
// 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()
== GFX_CONTENT_COLOR,
NS_ASSERTION(cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR,
"Don't copy background with a transparent surface");
} else {
tmpCtx->SetOperator(gfxContext::OPERATOR_CLEAR);
cairo_set_operator(tmpCtx, CAIRO_OPERATOR_CLEAR);
}
tmpCtx->Paint();
cairo_paint(tmpCtx);
cairo_destroy(tmpCtx);
}
if (!DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft())) {
cairo_surface_destroy(tempXlibSurface);
return;
}
SurfaceFormat moz2DFormat =
cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR ?
FORMAT_B8G8R8A8 : FORMAT_B8G8R8X8;
if (method != eAlphaExtraction) {
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));
// It doesn't matter if moz2DFormat doesn't exactly match the format
// of tempXlibSurface, since this DrawTarget just wraps the cairo
// drawing.
RefPtr<SourceSurface> sourceSurface =
Factory::CreateSourceSurfaceForCairoSurface(tempXlibSurface,
moz2DFormat);
if (sourceSurface) {
drawTarget->DrawSurface(sourceSurface,
Rect(offset.x, offset.y, size.width, size.height),
Rect(0, 0, size.width, size.height));
}
} else {
ctx->SetSource(tempXlibSurface, offset);
nsRefPtr<gfxASurface> tmpSurf = gfxASurface::Wrap(tempXlibSurface);
ctx->SetSource(tmpSurf, 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;
}
cairo_surface_destroy(tempXlibSurface);
return;
}
nsRefPtr<gfxImageSurface> blackImage =
CopyXlibSurfaceToImage(tempXlibSurface, gfxImageFormatARGB32);
CopyXlibSurfaceToImage(tempXlibSurface, size, gfxImageFormatARGB32);
tmpCtx->SetDeviceColor(gfxRGBA(1.0, 1.0, 1.0));
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->Paint();
cairo_t* tmpCtx = cairo_create(tempXlibSurface);
cairo_set_source_rgba(tmpCtx, 1.0, 1.0, 1.0, 1.0);
cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
cairo_paint(tmpCtx);
cairo_destroy(tmpCtx);
DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft());
nsRefPtr<gfxImageSurface> whiteImage =
CopyXlibSurfaceToImage(tempXlibSurface, gfxImageFormatRGB24);
CopyXlibSurfaceToImage(tempXlibSurface, size, gfxImageFormatRGB24);
if (blackImage->CairoStatus() == CAIRO_STATUS_SUCCESS &&
whiteImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
gfxAlphaRecovery::Analysis analysis;
if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage,
result ? &analysis : nullptr))
if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage, nullptr)) {
cairo_surface_destroy(tempXlibSurface);
return;
}
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) {
result->mUniformAlpha = true;
result->mColor.a = analysis.alpha;
}
if (analysis.uniformColor) {
result->mUniformColor = true;
result->mColor.r = analysis.r;
result->mColor.g = analysis.g;
result->mColor.b = analysis.b;
} else {
result->mSurface = target->
CreateSimilarSurface(GFX_CONTENT_COLOR_ALPHA,
gfxIntSize(size.width, size.height));
gfxContext copyCtx(result->mSurface);
copyCtx.SetSource(blackImage);
copyCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
copyCtx.Paint();
paintSurface = result->mSurface;
}
}
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));
RefPtr<SourceSurface> sourceSurface =
Factory::CreateSourceSurfaceForCairoSurface(paintSurface->CairoSurface(),
moz2DFormat);
if (sourceSurface) {
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();
}
}
cairo_surface_destroy(tempXlibSurface);
}

View File

@ -6,8 +6,8 @@
#ifndef GFXXLIBNATIVERENDER_H_
#define GFXXLIBNATIVERENDER_H_
#include "gfxColor.h"
#include "nsAutoPtr.h"
#include "nsPoint.h"
#include "nsRect.h"
#include <X11/Xlib.h>
namespace mozilla {
@ -17,12 +17,12 @@ namespace gfx {
}
class gfxASurface;
class gfxXlibSurface;
class gfxContext;
struct nsIntRect;
struct nsIntPoint;
struct nsIntSize;
typedef struct _cairo cairo_t;
typedef struct _cairo_surface cairo_surface_t;
/**
* This class lets us take code that draws into an X drawable and lets us
@ -70,13 +70,6 @@ public:
DRAW_SUPPORTS_ALTERNATE_SCREEN = 0x20
};
struct DrawOutput {
nsRefPtr<gfxASurface> mSurface;
bool mUniformAlpha;
bool mUniformColor;
gfxRGBA mColor;
};
/**
* @param flags see above
* @param size the size of the rectangle being drawn;
@ -90,8 +83,7 @@ public:
* otherwise *resultSurface is set to nullptr.
*/
void Draw(gfxContext* ctx, nsIntSize size,
uint32_t flags, Screen *screen, Visual *visual,
DrawOutput* result);
uint32_t flags, Screen *screen, Visual *visual);
private:
bool DrawDirect(gfxContext *ctx, nsIntSize bounds,
@ -103,10 +95,9 @@ private:
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);
uint32_t flags, Screen* screen, Visual* visual);
bool DrawOntoTempSurface(gfxXlibSurface *tempXlibSurface,
bool DrawOntoTempSurface(cairo_surface_t *tempXlibSurface,
nsIntPoint offset);
};