author | Lee Salzman <lsalzman@mozilla.com> |
Fri, 01 May 2015 14:08:04 -0400 | |
changeset 243628 | 8538bc4d2cbd90499cbd17dd12b608b5025acbf6 |
parent 243627 | e0faf96523b2322f52c94edf2f01298c93656725 |
child 243629 | 1663d6ff4ae055c4517ac636e26b0b2e566fcf3d |
push id | 28744 |
push user | kwierso@gmail.com |
push date | Wed, 13 May 2015 18:12:16 +0000 |
treeherder | mozilla-central@324c3423deaf [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jrmuizel |
bugs | 1127752 |
milestone | 41.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
|
--- a/gfx/2d/BorrowedContext.h +++ b/gfx/2d/BorrowedContext.h @@ -3,16 +3,21 @@ * 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/. */ #ifndef _MOZILLA_GFX_BORROWED_CONTEXT_H #define _MOZILLA_GFX_BORROWED_CONTEXT_H #include "2D.h" +#ifdef MOZ_X11 +#include <X11/extensions/Xrender.h> +#include <X11/Xlib.h> +#endif + struct _cairo; typedef struct _cairo cairo_t; namespace mozilla { namespace gfx { /* This is a helper class that let's you borrow a cairo_t from a @@ -64,16 +69,79 @@ public: cairo_t *mCairo; private: static cairo_t* BorrowCairoContextFromDrawTarget(DrawTarget *aDT); static void ReturnCairoContextToDrawTarget(DrawTarget *aDT, cairo_t *aCairo); 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. * * Callers should check the cg member after constructing the object * to see if it succeeded. The DrawTarget should not be used while * the context is borrowed. */ class BorrowedCGContext
--- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -1709,10 +1709,55 @@ BorrowedCairoContext::ReturnCairoContext return; } DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(aDT); cairo_restore(aCairo); 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 + } }
--- a/gfx/2d/DrawTargetCairo.h +++ b/gfx/2d/DrawTargetCairo.h @@ -49,16 +49,17 @@ class GradientStopsCairo : public Gradie ExtendMode mExtendMode; }; class DrawTargetCairo final : public DrawTarget { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetCairo, override) friend class BorrowedCairoContext; + friend class BorrowedXlibDrawable; DrawTargetCairo(); virtual ~DrawTargetCairo(); virtual DrawTargetType GetType() const override; virtual BackendType GetBackendType() const override { return BackendType::CAIRO; } virtual TemporaryRef<SourceSurface> Snapshot() override; virtual IntSize GetSize() override;
--- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -143,16 +143,45 @@ DrawTargetSkia::Snapshot() mSnapshot = snapshot; if (!snapshot->InitFromCanvas(mCanvas.get(), mFormat, this)) return nullptr; } 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) { switch (aPattern.GetType()) { case PatternType::COLOR: { Color color = static_cast<const ColorPattern&>(aPattern).mColor; aPaint.setColor(ColorToSkColor(color, aAlpha)); @@ -683,20 +712,20 @@ DrawTargetSkia::CreateSourceSurfaceFromN if (aSurface.mSize.width <= 0 || aSurface.mSize.height <= 0) { gfxWarning() << "Can't create a SourceSurface without a valid size"; return nullptr; } 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; #endif } return nullptr; }
--- a/gfx/2d/DrawTargetSkia.h +++ b/gfx/2d/DrawTargetSkia.h @@ -31,16 +31,19 @@ public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetSkia, override) DrawTargetSkia(); virtual ~DrawTargetSkia(); virtual DrawTargetType GetType() const override; 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, const Rect &aSource, const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), const DrawOptions &aOptions = DrawOptions()) override; virtual void DrawFilter(FilterNode *aNode, const Rect &aSourceRect,
--- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -74,16 +74,17 @@ if CONFIG['MOZ_ENABLE_SKIA']: 'DrawTargetSkia.cpp', 'PathSkia.cpp', 'SourceSurfaceSkia.cpp', ] SOURCES += [ 'image_operations.cpp', # Uses _USE_MATH_DEFINES ] EXPORTS.mozilla.gfx += [ + 'HelpersCairo.h', 'HelpersSkia.h', ] # Are we targeting x86 or x64? If so, build SSE2 files. if CONFIG['INTEL_ARCHITECTURE']: SOURCES += [ 'BlurSSE2.cpp', 'FilterProcessingSSE2.cpp',
--- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -512,17 +512,17 @@ BasicCompositor::BeginFrame(const nsIntR return; } // Setup an intermediate render target to buffer all compositing. We will // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame() RefPtr<CompositingRenderTarget> target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR); if (!target) { if (!mTarget) { - mWidget->EndRemoteDrawing(); + mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); } return; } SetRenderTarget(target); // We only allocate a surface sized to the invalidated region, so we need to // translate future coordinates. mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-invalidRect.x, @@ -574,17 +574,17 @@ BasicCompositor::EndFrame() // pixels. nsIntRegionRectIterator iter(mInvalidRegion); for (const IntRect *r = iter.Next(); r; r = iter.Next()) { dest->CopySurface(source, IntRect(r->x - mInvalidRect.x, r->y - mInvalidRect.y, r->width, r->height), IntPoint(r->x - offset.x, r->y - offset.y)); } if (!mTarget) { - mWidget->EndRemoteDrawing(); + mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); } mDrawTarget = nullptr; mRenderTarget = nullptr; } } }
--- a/gfx/src/nsRegion.h +++ b/gfx/src/nsRegion.h @@ -710,16 +710,22 @@ public: } Derived& ScaleRoundOut (float aXScale, float aYScale) { mImpl.ScaleRoundOut(aXScale, aYScale); return This(); } + Derived& ScaleInverseRoundOut (float aXScale, float aYScale) + { + mImpl.ScaleInverseRoundOut(aXScale, aYScale); + return This(); + } + Derived& Transform (const gfx3DMatrix &aTransform) { mImpl.Transform(aTransform); return This(); } /** * Make sure the region has at most aMaxRects by adding area to it
--- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -614,16 +614,33 @@ gfxContext::GetClipExtents() Matrix mat = mTransform; mat.Invert(); rect = mat.TransformBounds(rect); 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) { unsigned int lastReset = 0; for (int i = mStateStack.Length() - 2; i > 0; i--) { if (mStateStack[i].clipWasReset) { lastReset = i; break; }
--- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -441,16 +441,21 @@ public: /** * This will return the current bounds of the clip region in user * space. */ 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 * fully contained by the current clip. */ bool ClipContainsRect(const gfxRect& aRect); /** * Groups
--- a/widget/gtk/nsNativeThemeGTK.cpp +++ b/widget/gtk/nsNativeThemeGTK.cpp @@ -28,16 +28,28 @@ #include "mozilla/Services.h" #include <gdk/gdkprivate.h> #include <gtk/gtk.h> #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> using namespace mozilla; using namespace mozilla::gfx; NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeGTK, nsNativeTheme, nsITheme, nsIObserver) @@ -697,16 +709,168 @@ ThemeRenderer::DrawWithGDK(GdkDrawable * gdk_rectangle_intersect(&gdk_clip, &surfaceRect, &gdk_clip); NS_ASSERTION(numClipRects == 0, "We don't support clipping!!!"); moz_gtk_widget_paint(mGTKWidgetType, drawable, &gdk_rect, &gdk_clip, &mState, mFlags, mDirection); 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 nsNativeThemeGTK::GetExtraSizeForWidget(nsIFrame* aFrame, uint8_t aWidgetType, nsIntMargin* aExtra) { *aExtra = nsIntMargin(0,0,0,0); // Allow an extra one pixel above and below the thumb for certain @@ -791,20 +955,16 @@ nsNativeThemeGTK::GetExtraSizeForWidget( NS_IMETHODIMP nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, const nsRect& aRect, const nsRect& aDirtyRect) { -#if (MOZ_WIDGET_GTK != 2) - DrawTarget& aDrawTarget = *aContext->GetDrawTarget(); -#endif - GtkWidgetState state; GtkThemeWidgetType gtkWidgetType; GtkTextDirection direction = GetTextDirection(aFrame); gint flags; if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, &state, &flags)) return NS_OK; @@ -814,18 +974,18 @@ nsNativeThemeGTK::DrawWidgetBackground(n gfxRect rect = presContext->AppUnitsToGfxUnits(aRect); gfxRect dirtyRect = presContext->AppUnitsToGfxUnits(aDirtyRect); gint scaleFactor = nsScreenGtk::GetGtkMonitorScaleFactor(); // Align to device pixels where sensible // 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); } // Translate the dirty rect so that it is wrt the widget top-left. dirtyRect.MoveBy(-rect.TopLeft()); // Round out the dirty rect to gdk pixels to ensure that gtk draws // enough pixels for interpolation to device pixels. @@ -844,69 +1004,71 @@ nsNativeThemeGTK::DrawWidgetBackground(n nsIntRect drawingRect(int32_t(dirtyRect.X()), int32_t(dirtyRect.Y()), int32_t(dirtyRect.Width()), int32_t(dirtyRect.Height())); if (widgetRect.IsEmpty() || !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!"); bool safeState = IsWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state); if (!safeState) { gLastGdkError = 0; 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}; ThemeRenderer renderer(state, gtkWidgetType, flags, direction, gdk_rect, gdk_clip); // Some themes (e.g. Clearlooks) just don't clip properly to any // 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; } // GtkStyles (used by the widget drawing backend) are created for a // particular colormap/visual. GdkColormap* colormap = moz_gtk_widget_get_colormap(); 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) { gdk_flush(); gLastGdkError = gdk_error_trap_pop (); if (gLastGdkError) { #ifdef DEBUG
--- a/widget/gtk/nsScreenGtk.cpp +++ b/widget/gtk/nsScreenGtk.cpp @@ -7,16 +7,17 @@ #include <gdk/gdk.h> #ifdef MOZ_X11 #include <gdk/gdkx.h> #include <X11/Xatom.h> #endif #include <gtk/gtk.h> #include <dlfcn.h> +#include "gfxPlatformGtk.h" static uint32_t sScreenId = 0; nsScreenGtk :: nsScreenGtk ( ) : mScreenNum(0), mRect(0, 0, 0, 0), mAvailRect(0, 0, 0, 0),
--- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -2045,81 +2045,62 @@ gdk_window_flash(GdkWindow * aGdkWind gdk_gc_destroy(gc); gdk_region_offset(aRegion, -x, -y); } #endif /* MOZ_X11 */ #endif // DEBUG #endif -struct ExposeRegion -{ - nsIntRegion mRegion; - #if (MOZ_WIDGET_GTK == 2) - GdkRectangle *mRects; - GdkRectangle *mRectsEnd; - - 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 - mRects[0] = aEvent->area; - nrects = 1; - } - - 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; - } +static bool +ExtractExposeRegion(nsIntRegion& aRegion, GdkEventExpose* aEvent) +{ + GdkRectangle* rects; + gint nrects; + gdk_region_get_rectangles(aEvent->region, &rects, &nrects); + + if (nrects > MAX_RECTS_IN_REGION) { + // Just use the bounding box + rects[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)); + } + + 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; - - 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 < 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; - } +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; + } + + 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)); + } + + cairo_rectangle_list_destroy(rects); + return true; +} #endif -}; #if (MOZ_WIDGET_GTK == 2) gboolean nsWindow::OnExposeEvent(GdkEventExpose *aEvent) #else gboolean nsWindow::OnExposeEvent(cairo_t *cr) #endif @@ -2132,27 +2113,27 @@ nsWindow::OnExposeEvent(cairo_t *cr) if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel) return FALSE; nsIWidgetListener *listener = mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener; 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 = (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) ? static_cast<ClientLayerManager*>(GetLayerManager()) : nullptr; if (clientLayers && mCompositorParent) { @@ -2235,43 +2216,21 @@ nsWindow::OnExposeEvent(cairo_t *cr) // If this widget uses OMTC... if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) { listener->PaintWindow(this, region); listener->DidPaintWindow(); 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 ctx->NewPath(); if (shaped) { // Collapse update area to the bounding box. This is so we only have to // call UpdateTranslucentWindowAlpha once. After we have dropped @@ -2336,21 +2295,17 @@ nsWindow::OnExposeEvent(cairo_t *cr) ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetPattern(pattern); ctx->Paint(); } } } # 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 listener->DidPaintWindow(); // Synchronously flush any new dirty areas #if (MOZ_WIDGET_GTK == 2) @@ -6257,34 +6212,59 @@ nsWindow::GetSurfaceForGdkDrawable(GdkDr TemporaryRef<DrawTarget> nsWindow::StartRemoteDrawing() { gfxASurface *surf = GetThebesSurface(); if (!surf) { 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; #ifdef MOZ_X11 gint width, height; #if (MOZ_WIDGET_GTK == 2)
--- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -189,17 +189,20 @@ public: GdkDragContext *aDragContext, gint aX, gint aY, GtkSelectionData*aSelectionData, guint aInfo, 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); void NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint); @@ -471,19 +474,16 @@ private: void DispatchMissedButtonReleases(GdkEventCrossing *aGdkEvent); // nsBaseWidget virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr, 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(); /** * |mIMModule| takes all IME related stuff. * * This is owned by the top-level nsWindow or the topmost child * nsWindow embedded in a non-Gecko widget.
--- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -1651,16 +1651,19 @@ class nsIWidget : public nsISupports { /** * Ensure that what was painted into the DrawTarget returned from * StartRemoteDrawing reaches the screen. * * Called by BasicCompositor on the compositor thread for OMTC drawing * 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. * * Called by BasicCompositor on the compositor thread for OMTC drawing * when the compositor is destroyed. */ virtual void CleanupRemoteDrawing() = 0;
--- a/widget/nsShmImage.cpp +++ b/widget/nsShmImage.cpp @@ -116,27 +116,28 @@ nsShmImage::AsSurface() mSize, mImage->bytes_per_line, mFormat) ).forget(); } #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; gdk_window_get_internal_paint_info(aWindow, &gd, &dx, &dy); Display* dpy = gdk_x11_get_default_xdisplay(); 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, r->width, r->height, False); } XFreeGC(dpy, gc); @@ -146,30 +147,29 @@ nsShmImage::Put(GdkWindow* aWindow, GdkR // synchronization mechanism; other options are possible. If this // XSync is shown to hurt responsiveness, we need to explore the // other options. XSync(dpy, False); } #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); } XFreeGC(dpy, gc); // FIXME/bug 597336: we need to ensure that the shm image isn't // scribbled over before all its pending XShmPutImage()s complete. // However, XSync() is an unnecessarily heavyweight
--- a/widget/nsShmImage.h +++ b/widget/nsShmImage.h @@ -58,20 +58,18 @@ private: } XDestroyImage(mImage); } } 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 gfxIntSize Size() const { return mSize; } private: nsShmImage()