Bug 1127752 - fixes for using Skia and OMTC with GTK3. r=jrmuizel

This commit is contained in:
Lee Salzman 2015-05-01 14:08:04 -04:00 committed by Mike Hommey
parent b2771ec52f
commit cfd509b083
17 changed files with 466 additions and 147 deletions

View File

@ -8,6 +8,11 @@
#include "2D.h"
#ifdef MOZ_X11
#include <X11/extensions/Xrender.h>
#include <X11/Xlib.h>
#endif
struct _cairo;
typedef struct _cairo cairo_t;
@ -69,6 +74,69 @@ private:
DrawTarget *mDT;
};
#ifdef MOZ_X11
/* This is a helper class that let's you borrow an Xlib drawable from
* a DrawTarget. This is used for drawing themed widgets.
*
* Callers should check the Xlib drawable after constructing the object
* to see if it succeeded. The DrawTarget should not be used while
* the drawable is borrowed. */
class BorrowedXlibDrawable
{
public:
BorrowedXlibDrawable()
: mDT(nullptr),
mDisplay(nullptr),
mDrawable(None),
mScreen(nullptr),
mVisual(nullptr),
mXRenderFormat(nullptr)
{}
explicit BorrowedXlibDrawable(DrawTarget *aDT)
: mDT(nullptr),
mDisplay(nullptr),
mDrawable(None),
mScreen(nullptr),
mVisual(nullptr),
mXRenderFormat(nullptr)
{
Init(aDT);
}
// We can optionally Init after construction in
// case we don't know what the DT will be at construction
// time.
bool Init(DrawTarget *aDT);
// The caller needs to call Finish if drawable is non-zero when
// they are done with the context. This is currently explicit
// instead of happening implicitly in the destructor to make
// what's happening in the caller more clear. It also
// let's you resume using the DrawTarget in the same scope.
void Finish();
~BorrowedXlibDrawable() {
MOZ_ASSERT(!mDrawable);
}
Display *GetDisplay() const { return mDisplay; }
Drawable GetDrawable() const { return mDrawable; }
Screen *GetScreen() const { return mScreen; }
Visual *GetVisual() const { return mVisual; }
XRenderPictFormat* GetXRenderFormat() const { return mXRenderFormat; }
private:
DrawTarget *mDT;
Display *mDisplay;
Drawable mDrawable;
Screen *mScreen;
Visual *mVisual;
XRenderPictFormat *mXRenderFormat;
};
#endif
#ifdef XP_MACOSX
/* This is a helper class that let's you borrow a CGContextRef from a
* DrawTargetCG. This is used for drawing themed widgets.

View File

@ -1714,5 +1714,50 @@ BorrowedCairoContext::ReturnCairoContextToDrawTarget(DrawTarget* aDT,
cairoDT->mContext = aCairo;
}
#ifdef MOZ_X11
bool
BorrowedXlibDrawable::Init(DrawTarget* aDT)
{
MOZ_ASSERT(aDT, "Caller should check for nullptr");
MOZ_ASSERT(!mDT, "Can't initialize twice!");
mDT = aDT;
mDrawable = None;
#ifdef CAIRO_HAS_XLIB_SURFACE
if (aDT->GetBackendType() != BackendType::CAIRO ||
aDT->IsDualDrawTarget() ||
aDT->IsTiledDrawTarget()) {
return false;
}
DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(aDT);
cairo_surface_t* surf = cairoDT->mSurface;
if (cairo_surface_get_type(surf) != CAIRO_SURFACE_TYPE_XLIB) {
return false;
}
cairoDT->WillChange();
mDisplay = cairo_xlib_surface_get_display(surf);
mDrawable = cairo_xlib_surface_get_drawable(surf);
mScreen = cairo_xlib_surface_get_screen(surf);
mVisual = cairo_xlib_surface_get_visual(surf);
mXRenderFormat = cairo_xlib_surface_get_xrender_format(surf);
return true;
#else
return false;
#endif
}
void
BorrowedXlibDrawable::Finish()
{
if (mDrawable) {
mDrawable = None;
}
}
#endif
}
}

View File

@ -54,6 +54,7 @@ class DrawTargetCairo final : public DrawTarget
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetCairo, override)
friend class BorrowedCairoContext;
friend class BorrowedXlibDrawable;
DrawTargetCairo();
virtual ~DrawTargetCairo();

View File

@ -148,6 +148,35 @@ DrawTargetSkia::Snapshot()
return snapshot.forget();
}
bool
DrawTargetSkia::LockBits(uint8_t** aData, IntSize* aSize,
int32_t* aStride, SurfaceFormat* aFormat)
{
const SkBitmap &bitmap = mCanvas->getDevice()->accessBitmap(false);
if (!bitmap.lockPixelsAreWritable()) {
return false;
}
MarkChanged();
bitmap.lockPixels();
*aData = reinterpret_cast<uint8_t*>(bitmap.getPixels());
*aSize = IntSize(bitmap.width(), bitmap.height());
*aStride = int32_t(bitmap.rowBytes());
*aFormat = SkiaColorTypeToGfxFormat(bitmap.colorType());
return true;
}
void
DrawTargetSkia::ReleaseBits(uint8_t* aData)
{
const SkBitmap &bitmap = mCanvas->getDevice()->accessBitmap(false);
MOZ_ASSERT(bitmap.lockPixelsAreWritable());
bitmap.unlockPixels();
bitmap.notifyPixelsChanged();
}
static void
SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap,
Float aAlpha = 1.0)
@ -688,10 +717,10 @@ DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurfa
cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface);
return new SourceSurfaceCairo(surf, aSurface.mSize, aSurface.mFormat);
#if USE_SKIA_GPU
} else if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE) {
} else if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE && UsingSkiaGPU()) {
RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
unsigned int texture = (unsigned int)((uintptr_t)aSurface.mSurface);
if (UsingSkiaGPU() && newSurf->InitFromTexture((DrawTargetSkia*)this, texture, aSurface.mSize, aSurface.mFormat)) {
if (newSurf->InitFromTexture((DrawTargetSkia*)this, texture, aSurface.mSize, aSurface.mFormat)) {
return newSurf;
}
return nullptr;

View File

@ -36,6 +36,9 @@ public:
virtual BackendType GetBackendType() const override { return BackendType::SKIA; }
virtual TemporaryRef<SourceSurface> Snapshot() override;
virtual IntSize GetSize() override { return mSize; }
virtual bool LockBits(uint8_t** aData, IntSize* aSize,
int32_t* aStride, SurfaceFormat* aFormat) override;
virtual void ReleaseBits(uint8_t* aData) override;
virtual void Flush() override;
virtual void DrawSurface(SourceSurface *aSurface,
const Rect &aDest,

View File

@ -79,6 +79,7 @@ if CONFIG['MOZ_ENABLE_SKIA']:
'image_operations.cpp', # Uses _USE_MATH_DEFINES
]
EXPORTS.mozilla.gfx += [
'HelpersCairo.h',
'HelpersSkia.h',
]

View File

@ -517,7 +517,7 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
RefPtr<CompositingRenderTarget> target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR);
if (!target) {
if (!mTarget) {
mWidget->EndRemoteDrawing();
mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
}
return;
}
@ -579,7 +579,7 @@ BasicCompositor::EndFrame()
IntPoint(r->x - offset.x, r->y - offset.y));
}
if (!mTarget) {
mWidget->EndRemoteDrawing();
mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
}
mDrawTarget = nullptr;

View File

@ -715,6 +715,12 @@ public:
return This();
}
Derived& ScaleInverseRoundOut (float aXScale, float aYScale)
{
mImpl.ScaleInverseRoundOut(aXScale, aYScale);
return This();
}
Derived& Transform (const gfx3DMatrix &aTransform)
{
mImpl.Transform(aTransform);

View File

@ -618,6 +618,23 @@ gfxContext::GetClipExtents()
return ThebesRect(rect);
}
bool
gfxContext::HasComplexClip() const
{
for (int i = mStateStack.Length() - 1; i >= 0; i--) {
for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
const AzureState::PushedClip &clip = mStateStack[i].pushedClips[c];
if (clip.path || !clip.transform.IsRectilinear()) {
return true;
}
}
if (mStateStack[i].clipWasReset) {
break;
}
}
return false;
}
bool
gfxContext::ClipContainsRect(const gfxRect& aRect)
{

View File

@ -445,6 +445,11 @@ public:
*/
gfxRect GetClipExtents();
/**
* Whether the current clip is not a simple rectangle.
*/
bool HasComplexClip() const;
/**
* Returns true if the given rectangle is fully contained in the current clip.
* This is conservative; it may return false even when the given rectangle is

View File

@ -33,6 +33,18 @@
#include "gfxContext.h"
#include "gfxPlatformGtk.h"
#include "gfxGdkNativeRenderer.h"
#include "mozilla/gfx/BorrowedContext.h"
#include "mozilla/gfx/HelpersCairo.h"
#ifdef MOZ_X11
# ifdef CAIRO_HAS_XLIB_SURFACE
# include "cairo-xlib.h"
# endif
# ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE
# include "cairo-xlib-xrender.h"
# endif
#endif
#include <algorithm>
#include <dlfcn.h>
@ -702,6 +714,158 @@ ThemeRenderer::DrawWithGDK(GdkDrawable * drawable, gint offsetX,
return NS_OK;
}
#else
static void
DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
GtkWidgetState aState, GtkThemeWidgetType aGTKWidgetType,
gint aFlags, GtkTextDirection aDirection, gint aScaleFactor,
bool aSnapped, const Point& aDrawOrigin, const nsIntSize& aDrawSize,
GdkRectangle& aGDKRect, nsITheme::Transparency aTransparency)
{
#ifndef MOZ_TREE_CAIRO
// Directly use the Cairo draw target to render the widget if using system Cairo everywhere.
BorrowedCairoContext borrow(aDrawTarget);
if (borrow.mCairo) {
if (aSnapped) {
cairo_identity_matrix(borrow.mCairo);
}
if (aDrawOrigin != Point(0, 0)) {
cairo_translate(borrow.mCairo, aDrawOrigin.x, aDrawOrigin.y);
}
if (aScaleFactor != 1) {
cairo_scale(borrow.mCairo, aScaleFactor, aScaleFactor);
}
moz_gtk_widget_paint(aGTKWidgetType, borrow.mCairo, &aGDKRect, &aState, aFlags, aDirection);
borrow.Finish();
return;
}
#endif
// A direct Cairo draw target is not available, so we need to create a temporary one.
bool needClip = !aSnapped || aContext->HasComplexClip();
#if defined(MOZ_X11) && defined(CAIRO_HAS_XLIB_SURFACE)
if (!needClip) {
// If using a Cairo xlib surface, then try to reuse it.
BorrowedXlibDrawable borrow(aDrawTarget);
if (borrow.GetDrawable()) {
nsIntSize size = aDrawTarget->GetSize();
cairo_surface_t* surf = nullptr;
// Check if the surface is using XRender.
#ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE
if (borrow.GetXRenderFormat()) {
surf = cairo_xlib_surface_create_with_xrender_format(
borrow.GetDisplay(), borrow.GetDrawable(), borrow.GetScreen(),
borrow.GetXRenderFormat(), size.width, size.height);
} else {
#else
if (! borrow.GetXRenderFormat()) {
#endif
surf = cairo_xlib_surface_create(
borrow.GetDisplay(), borrow.GetDrawable(), borrow.GetVisual(),
size.width, size.height);
}
if (!NS_WARN_IF(!surf)) {
cairo_t* cr = cairo_create(surf);
if (!NS_WARN_IF(!cr)) {
cairo_new_path(cr);
cairo_rectangle(cr, aDrawOrigin.x, aDrawOrigin.y, aDrawSize.width, aDrawSize.height);
cairo_clip(cr);
if (aDrawOrigin != Point(0, 0)) {
cairo_translate(cr, aDrawOrigin.x, aDrawOrigin.y);
}
if (aScaleFactor != 1) {
cairo_scale(cr, aScaleFactor, aScaleFactor);
}
moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
cairo_destroy(cr);
}
cairo_surface_destroy(surf);
}
borrow.Finish();
return;
}
}
#endif
// Check if the widget requires complex masking that must be composited.
// Try to directly write to the draw target's pixels if possible.
uint8_t* data;
nsIntSize size;
int32_t stride;
SurfaceFormat format;
if (!needClip && aDrawTarget->LockBits(&data, &size, &stride, &format)) {
// Create a Cairo image surface context the device rectangle.
cairo_surface_t* surf =
cairo_image_surface_create_for_data(
data + int32_t(aDrawOrigin.y) * stride + int32_t(aDrawOrigin.x) * BytesPerPixel(format),
GfxFormatToCairoFormat(format), aDrawSize.width, aDrawSize.height, stride);
if (!NS_WARN_IF(!surf)) {
cairo_t* cr = cairo_create(surf);
if (!NS_WARN_IF(!cr)) {
if (aScaleFactor != 1) {
cairo_scale(cr, aScaleFactor, aScaleFactor);
}
moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
cairo_destroy(cr);
}
cairo_surface_destroy(surf);
}
aDrawTarget->ReleaseBits(data);
} else {
// If the widget has any transparency, make sure to choose an alpha format.
format = aTransparency != nsITheme::eOpaque ? SurfaceFormat::B8G8R8A8 : aDrawTarget->GetFormat();
// Create a temporary data surface to render the widget into.
RefPtr<DataSourceSurface> dataSurface =
Factory::CreateDataSourceSurface(aDrawSize, format, aTransparency != nsITheme::eOpaque);
DataSourceSurface::MappedSurface map;
if (!NS_WARN_IF(!(dataSurface && dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)))) {
// Create a Cairo image surface wrapping the data surface.
cairo_surface_t* surf =
cairo_image_surface_create_for_data(map.mData, GfxFormatToCairoFormat(format),
aDrawSize.width, aDrawSize.height, map.mStride);
cairo_t* cr = nullptr;
if (!NS_WARN_IF(!surf)) {
cr = cairo_create(surf);
if (!NS_WARN_IF(!cr)) {
if (aScaleFactor != 1) {
cairo_scale(cr, aScaleFactor, aScaleFactor);
}
moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
}
}
// Unmap the surface before using it as a source
dataSurface->Unmap();
if (cr) {
if (needClip || aTransparency != nsITheme::eOpaque) {
// The widget either needs to be masked or has transparency, so use the slower drawing path.
aDrawTarget->DrawSurface(dataSurface,
Rect(aDrawOrigin, Size(aDrawSize)),
Rect(0, 0, aDrawSize.width, aDrawSize.height));
} else {
// The widget is a simple opaque rectangle, so just copy it out.
aDrawTarget->CopySurface(dataSurface,
IntRect(0, 0, aDrawSize.width, aDrawSize.height),
TruncatedToInt(aDrawOrigin));
}
cairo_destroy(cr);
}
if (surf) {
cairo_surface_destroy(surf);
}
}
}
}
#endif
bool
@ -796,10 +960,6 @@ nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext,
const nsRect& aRect,
const nsRect& aDirtyRect)
{
#if (MOZ_WIDGET_GTK != 2)
DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
#endif
GtkWidgetState state;
GtkThemeWidgetType gtkWidgetType;
GtkTextDirection direction = GetTextDirection(aFrame);
@ -819,8 +979,8 @@ nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext,
// to provide crisper and faster drawing.
// Don't snap if it's a non-unit scale factor. We're going to have to take
// slow paths then in any case.
bool snapXY = ctx->UserToDevicePixelSnapped(rect);
if (snapXY) {
bool snapped = ctx->UserToDevicePixelSnapped(rect);
if (snapped) {
// Leave rect in device coords but make dirtyRect consistent.
dirtyRect = ctx->UserToDevice(dirtyRect);
}
@ -849,23 +1009,6 @@ nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext,
|| !drawingRect.IntersectRect(overflowRect, drawingRect))
return NS_OK;
// gdk rectangles are wrt the drawing rect.
GdkRectangle gdk_rect = {-drawingRect.x/scaleFactor,
-drawingRect.y/scaleFactor,
widgetRect.width/scaleFactor,
widgetRect.height/scaleFactor};
// translate everything so (0,0) is the top left of the drawingRect
gfxContextAutoSaveRestore autoSR(ctx);
gfxMatrix tm;
if (!snapXY) { // else rects are in device coords
tm = ctx->CurrentMatrix();
}
tm.Translate(rect.TopLeft() + gfxPoint(drawingRect.x, drawingRect.y));
tm.Scale(scaleFactor, scaleFactor); // Draw in GDK coords
ctx->SetMatrix(tm);
NS_ASSERTION(!IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType),
"Trying to render an unsafe widget!");
@ -875,7 +1018,27 @@ nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext,
gdk_error_trap_push ();
}
Transparency transparency = GetWidgetTransparency(aFrame, aWidgetType);
// gdk rectangles are wrt the drawing rect.
GdkRectangle gdk_rect = {-drawingRect.x/scaleFactor,
-drawingRect.y/scaleFactor,
widgetRect.width/scaleFactor,
widgetRect.height/scaleFactor};
// translate everything so (0,0) is the top left of the drawingRect
gfxPoint origin = rect.TopLeft() + drawingRect.TopLeft();
#if (MOZ_WIDGET_GTK == 2)
gfxContextAutoSaveRestore autoSR(ctx);
gfxMatrix matrix;
if (!snapped) { // else rects are in device coords
matrix = ctx->CurrentMatrix();
}
matrix.Translate(origin);
matrix.Scale(scaleFactor, scaleFactor); // Draw in GDK coords
ctx->SetMatrix(matrix);
// The gdk_clip is just advisory here, meaning "you don't
// need to draw outside this rect if you don't feel like it!"
GdkRectangle gdk_clip = {0, 0, drawingRect.width, drawingRect.height};
@ -887,7 +1050,7 @@ nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext,
// clip rect we provide, so we cannot advertise support for clipping within
// the widget bounds.
uint32_t rendererFlags = 0;
if (GetWidgetTransparency(aFrame, aWidgetType) == eOpaque) {
if (transparency == eOpaque) {
rendererFlags |= gfxGdkNativeRenderer::DRAW_IS_OPAQUE;
}
@ -897,11 +1060,10 @@ nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext,
renderer.Draw(ctx, drawingRect.Size(), rendererFlags, colormap);
#else
cairo_t *cairo_ctx =
(cairo_t*)aDrawTarget.GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT);
MOZ_ASSERT(cairo_ctx);
moz_gtk_widget_paint(gtkWidgetType, cairo_ctx, &gdk_rect,
&state, flags, direction);
DrawThemeWithCairo(ctx, aContext->GetDrawTarget(),
state, gtkWidgetType, flags, direction, scaleFactor,
snapped, ToPoint(origin), drawingRect.Size(),
gdk_rect, transparency);
#endif
if (!safeState) {

View File

@ -12,6 +12,7 @@
#endif
#include <gtk/gtk.h>
#include <dlfcn.h>
#include "gfxPlatformGtk.h"
static uint32_t sScreenId = 0;

View File

@ -2050,71 +2050,52 @@ gdk_window_flash(GdkWindow * aGdkWindow,
#endif // DEBUG
#endif
struct ExposeRegion
{
nsIntRegion mRegion;
#if (MOZ_WIDGET_GTK == 2)
GdkRectangle *mRects;
GdkRectangle *mRectsEnd;
static bool
ExtractExposeRegion(nsIntRegion& aRegion, GdkEventExpose* aEvent)
{
GdkRectangle* rects;
gint nrects;
gdk_region_get_rectangles(aEvent->region, &rects, &nrects);
ExposeRegion() : mRects(nullptr)
{
}
~ExposeRegion()
{
g_free(mRects);
}
bool Init(GdkEventExpose *aEvent)
{
gint nrects;
gdk_region_get_rectangles(aEvent->region, &mRects, &nrects);
if (nrects > MAX_RECTS_IN_REGION) {
// Just use the bounding box
rects[0] = aEvent->area;
nrects = 1;
}
if (nrects > MAX_RECTS_IN_REGION) {
// Just use the bounding box
mRects[0] = aEvent->area;
nrects = 1;
}
for (GdkRectangle* r = rects; r < rects + nrects; r++) {
aRegion.Or(aRegion, nsIntRect(r->x, r->y, r->width, r->height));
LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
}
mRectsEnd = mRects + nrects;
for (GdkRectangle *r = mRects; r < mRectsEnd; r++) {
mRegion.Or(mRegion, nsIntRect(r->x, r->y, r->width, r->height));
LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
}
return true;
}
g_free(rects);
return true;
}
#else
# ifdef cairo_copy_clip_rectangle_list
# error "Looks like we're including Mozilla's cairo instead of system cairo"
# endif
cairo_rectangle_list_t *mRects;
static bool
ExtractExposeRegion(nsIntRegion& aRegion, cairo_t* cr)
{
cairo_rectangle_list_t* rects = cairo_copy_clip_rectangle_list(cr);
if (rects->status != CAIRO_STATUS_SUCCESS) {
NS_WARNING("Failed to obtain cairo rectangle list.");
return false;
}
ExposeRegion() : mRects(nullptr)
{
}
~ExposeRegion()
{
cairo_rectangle_list_destroy(mRects);
}
bool Init(cairo_t* cr)
{
mRects = cairo_copy_clip_rectangle_list(cr);
if (mRects->status != CAIRO_STATUS_SUCCESS) {
NS_WARNING("Failed to obtain cairo rectangle list.");
return false;
}
for (int i = 0; i < rects->num_rectangles; i++) {
const cairo_rectangle_t& r = rects->rectangles[i];
aRegion.Or(aRegion, nsIntRect(r.x, r.y, r.width, r.height));
LOGDRAW(("\t%d %d %d %d\n", r.x, r.y, r.width, r.height));
}
for (int i = 0; i < mRects->num_rectangles; i++) {
const cairo_rectangle_t& r = mRects->rectangles[i];
mRegion.Or(mRegion, nsIntRect(r.x, r.y, r.width, r.height));
LOGDRAW(("\t%d %d %d %d\n", r.x, r.y, r.width, r.height));
}
return true;
}
cairo_rectangle_list_destroy(rects);
return true;
}
#endif
};
#if (MOZ_WIDGET_GTK == 2)
gboolean
@ -2137,17 +2118,17 @@ nsWindow::OnExposeEvent(cairo_t *cr)
if (!listener)
return FALSE;
ExposeRegion exposeRegion;
nsIntRegion exposeRegion;
#if (MOZ_WIDGET_GTK == 2)
if (!exposeRegion.Init(aEvent)) {
if (!ExtractExposeRegion(exposeRegion, aEvent)) {
#else
if (!exposeRegion.Init(cr)) {
if (!ExtractExposeRegion(exposeRegion, cr)) {
#endif
return FALSE;
}
gint scale = GdkScaleFactor();
nsIntRegion& region = exposeRegion.mRegion;
nsIntRegion region = exposeRegion;
region.ScaleRoundOut(scale, scale);
ClientLayerManager *clientLayers =
@ -2240,33 +2221,11 @@ nsWindow::OnExposeEvent(cairo_t *cr)
return TRUE;
}
gfxASurface* surf;
#if (MOZ_WIDGET_GTK == 2)
surf = GetThebesSurface();
#else
surf = GetThebesSurface(cr);
#endif
nsRefPtr<gfxContext> ctx;
if (gfxPlatform::GetPlatform()->
SupportsAzureContentForType(BackendType::CAIRO)) {
IntSize intSize(surf->GetSize().width, surf->GetSize().height);
RefPtr<DrawTarget> dt =
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, intSize);
ctx = new gfxContext(dt);
} else if (gfxPlatform::GetPlatform()->
SupportsAzureContentForType(BackendType::SKIA) &&
surf->GetType() == gfxSurfaceType::Image) {
gfxImageSurface* imgSurf = static_cast<gfxImageSurface*>(surf);
SurfaceFormat format = ImageFormatToSurfaceFormat(imgSurf->Format());
IntSize intSize(surf->GetSize().width, surf->GetSize().height);
RefPtr<DrawTarget> dt =
gfxPlatform::GetPlatform()->CreateDrawTargetForData(
imgSurf->Data(), intSize, imgSurf->Stride(), format);
ctx = new gfxContext(dt);
} else {
MOZ_CRASH("Unexpected content type");
RefPtr<DrawTarget> dt = StartRemoteDrawing();
if(!dt) {
return FALSE;
}
nsRefPtr<gfxContext> ctx = new gfxContext(dt);
#ifdef MOZ_X11
nsIntRect boundsRect; // for shaped only
@ -2341,11 +2300,7 @@ nsWindow::OnExposeEvent(cairo_t *cr)
}
# ifdef MOZ_HAVE_SHMIMAGE
if (mShmImage && MOZ_LIKELY(!mIsDestroyed)) {
#if (MOZ_WIDGET_GTK == 2)
mShmImage->Put(mGdkWindow, exposeRegion.mRects, exposeRegion.mRectsEnd);
#else
mShmImage->Put(mGdkWindow, exposeRegion.mRects);
#endif
mShmImage->Put(mGdkWindow, exposeRegion);
}
# endif // MOZ_HAVE_SHMIMAGE
#endif // MOZ_X11
@ -6262,24 +6217,49 @@ nsWindow::StartRemoteDrawing()
return nullptr;
}
IntSize size(surf->GetSize().width, surf->GetSize().height);
nsIntSize size = surf->GetSize();
if (size.width <= 0 || size.height <= 0) {
return nullptr;
}
return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
gfxPlatform *platform = gfxPlatform::GetPlatform();
if (platform->SupportsAzureContentForType(BackendType::CAIRO) ||
surf->GetType() == gfxSurfaceType::Xlib) {
return platform->CreateDrawTargetForSurface(surf, size);
} else if (platform->SupportsAzureContentForType(BackendType::SKIA) &&
surf->GetType() == gfxSurfaceType::Image) {
gfxImageSurface* imgSurf = static_cast<gfxImageSurface*>(surf);
SurfaceFormat format = ImageFormatToSurfaceFormat(imgSurf->Format());
return platform->CreateDrawTargetForData(
imgSurf->Data(), size, imgSurf->Stride(), format);
} else {
return nullptr;
}
}
void
nsWindow::EndRemoteDrawingInRegion(DrawTarget* aDrawTarget, nsIntRegion& aInvalidRegion)
{
#ifdef MOZ_X11
# ifdef MOZ_HAVE_SHMIMAGE
if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel || mIsDestroyed ||
!mShmImage)
return;
gint scale = GdkScaleFactor();
if (scale != 1) {
aInvalidRegion.ScaleInverseRoundOut(scale, scale);
}
mShmImage->Put(mGdkWindow, aInvalidRegion);
# endif // MOZ_HAVE_SHMIMAGE
#endif // MOZ_X11
}
// return the gfxASurface for rendering to this widget
gfxASurface*
nsWindow::GetThebesSurface()
#if (MOZ_WIDGET_GTK == 3)
{
return GetThebesSurface(nullptr);
}
gfxASurface*
nsWindow::GetThebesSurface(cairo_t *cr)
#endif
{
if (!mGdkWindow)
return nullptr;

View File

@ -194,7 +194,10 @@ public:
guint aTime,
gpointer aData);
mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() override;
virtual mozilla::TemporaryRef<mozilla::gfx::DrawTarget>
StartRemoteDrawing() override;
virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget,
nsIntRegion& aInvalidRegion) override;
private:
void UpdateAlpha(gfxPattern* aPattern, nsIntRect aBoundsRect);
@ -476,9 +479,6 @@ private:
LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
bool* aAllowRetaining = nullptr) override;
#if (MOZ_WIDGET_GTK == 3)
gfxASurface* GetThebesSurface(cairo_t *cr);
#endif
void CleanLayerManagerRecursive();

View File

@ -1656,6 +1656,9 @@ class nsIWidget : public nsISupports {
* after each composition.
*/
virtual void EndRemoteDrawing() = 0;
virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget, nsIntRegion& aInvalidRegion) {
EndRemoteDrawing();
}
/**
* Clean up any resources used by Start/EndRemoteDrawing.

View File

@ -121,7 +121,7 @@ nsShmImage::AsSurface()
#if (MOZ_WIDGET_GTK == 2)
void
nsShmImage::Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd)
nsShmImage::Put(GdkWindow* aWindow, const nsIntRegion& aRegion)
{
GdkDrawable* gd;
gint dx, dy;
@ -131,7 +131,8 @@ nsShmImage::Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd)
Drawable d = GDK_DRAWABLE_XID(gd);
GC gc = XCreateGC(dpy, d, 0, nullptr);
for (GdkRectangle* r = aRects; r < aEnd; r++) {
nsIntRegionRectIterator iter(aRegion);
for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
XShmPutImage(dpy, d, gc, mImage,
r->x, r->y,
r->x - dx, r->y - dy,
@ -151,20 +152,19 @@ nsShmImage::Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd)
#elif (MOZ_WIDGET_GTK == 3)
void
nsShmImage::Put(GdkWindow* aWindow, cairo_rectangle_list_t* aRects)
nsShmImage::Put(GdkWindow* aWindow, const nsIntRegion& aRegion)
{
Display* dpy = gdk_x11_get_default_xdisplay();
Drawable d = GDK_WINDOW_XID(aWindow);
int dx = 0, dy = 0;
GC gc = XCreateGC(dpy, d, 0, nullptr);
cairo_rectangle_t r;
for (int i = 0; i < aRects->num_rectangles; i++) {
r = aRects->rectangles[i];
nsIntRegionRectIterator iter(aRegion);
for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
XShmPutImage(dpy, d, gc, mImage,
r.x, r.y,
r.x - dx, r.y - dy,
r.width, r.height,
r->x, r->y,
r->x - dx, r->y - dy,
r->width, r->height,
False);
}

View File

@ -63,10 +63,8 @@ private:
public:
already_AddRefed<gfxASurface> AsSurface();
#if (MOZ_WIDGET_GTK == 2)
void Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd);
#elif (MOZ_WIDGET_GTK == 3)
void Put(GdkWindow* aWindow, cairo_rectangle_list_t* aRects);
#ifdef MOZ_WIDGET_GTK
void Put(GdkWindow* aWindow, const nsIntRegion& aRegion);
#elif defined(MOZ_WIDGET_QT)
void Put(QWindow* aWindow, QRect& aRect);
#endif