зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1127752 - fixes for using Skia and OMTC with GTK3. r=jrmuizel
This commit is contained in:
Родитель
bb77c3fc69
Коммит
e38cad0b37
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -79,6 +79,7 @@ if CONFIG['MOZ_ENABLE_SKIA']:
|
|||
'image_operations.cpp', # Uses _USE_MATH_DEFINES
|
||||
]
|
||||
EXPORTS.mozilla.gfx += [
|
||||
'HelpersCairo.h',
|
||||
'HelpersSkia.h',
|
||||
]
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#endif
|
||||
#include <gtk/gtk.h>
|
||||
#include <dlfcn.h>
|
||||
#include "gfxPlatformGtk.h"
|
||||
|
||||
static uint32_t sScreenId = 0;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче