diff -up firefox-40.0/mozilla-release/gfx/2d/BorrowedContext.h.1127752 firefox-40.0/mozilla-release/gfx/2d/BorrowedContext.h --- firefox-40.0/mozilla-release/gfx/2d/BorrowedContext.h.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/2d/BorrowedContext.h 2015-08-26 14:07:24.666087911 +0200 @@ -8,6 +8,11 @@ #include "2D.h" +#ifdef MOZ_X11 +#include +#include +#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. diff -up firefox-40.0/mozilla-release/gfx/2d/DrawTargetCairo.cpp.1127752 firefox-40.0/mozilla-release/gfx/2d/DrawTargetCairo.cpp --- firefox-40.0/mozilla-release/gfx/2d/DrawTargetCairo.cpp.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/2d/DrawTargetCairo.cpp 2015-08-26 14:07:24.666087911 +0200 @@ -1714,5 +1714,50 @@ BorrowedCairoContext::ReturnCairoContext 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(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 + } } diff -up firefox-40.0/mozilla-release/gfx/2d/DrawTargetCairo.h.1127752 firefox-40.0/mozilla-release/gfx/2d/DrawTargetCairo.h --- firefox-40.0/mozilla-release/gfx/2d/DrawTargetCairo.h.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/2d/DrawTargetCairo.h 2015-08-26 14:07:24.666087911 +0200 @@ -54,6 +54,7 @@ class DrawTargetCairo final : public Dra public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetCairo, override) friend class BorrowedCairoContext; + friend class BorrowedXlibDrawable; DrawTargetCairo(); virtual ~DrawTargetCairo(); diff -up firefox-40.0/mozilla-release/gfx/2d/DrawTargetSkia.cpp.1127752 firefox-40.0/mozilla-release/gfx/2d/DrawTargetSkia.cpp --- firefox-40.0/mozilla-release/gfx/2d/DrawTargetSkia.cpp.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/2d/DrawTargetSkia.cpp 2015-08-26 14:07:24.667087889 +0200 @@ -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(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::CreateSourceSurfaceFromN cairo_surface_t* surf = static_cast(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 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; diff -up firefox-40.0/mozilla-release/gfx/2d/DrawTargetSkia.h.1127752 firefox-40.0/mozilla-release/gfx/2d/DrawTargetSkia.h --- firefox-40.0/mozilla-release/gfx/2d/DrawTargetSkia.h.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/2d/DrawTargetSkia.h 2015-08-26 14:07:24.667087889 +0200 @@ -36,6 +36,9 @@ public: virtual BackendType GetBackendType() const override { return BackendType::SKIA; } virtual TemporaryRef 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, diff -up firefox-40.0/mozilla-release/gfx/2d/moz.build.1127752 firefox-40.0/mozilla-release/gfx/2d/moz.build --- firefox-40.0/mozilla-release/gfx/2d/moz.build.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/2d/moz.build 2015-08-26 14:07:24.667087889 +0200 @@ -79,6 +79,7 @@ if CONFIG['MOZ_ENABLE_SKIA']: 'image_operations.cpp', # Uses _USE_MATH_DEFINES ] EXPORTS.mozilla.gfx += [ + 'HelpersCairo.h', 'HelpersSkia.h', ] diff -up firefox-40.0/mozilla-release/gfx/layers/basic/BasicCompositor.cpp.1127752 firefox-40.0/mozilla-release/gfx/layers/basic/BasicCompositor.cpp --- firefox-40.0/mozilla-release/gfx/layers/basic/BasicCompositor.cpp.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/layers/basic/BasicCompositor.cpp 2015-08-26 14:07:24.667087889 +0200 @@ -523,7 +523,7 @@ BasicCompositor::BeginFrame(const nsIntR RefPtr target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR); if (!target) { if (!mTarget) { - mWidget->EndRemoteDrawing(); + mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); } return; } @@ -585,7 +585,7 @@ BasicCompositor::EndFrame() IntPoint(r->x - offset.x, r->y - offset.y)); } if (!mTarget) { - mWidget->EndRemoteDrawing(); + mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); } mDrawTarget = nullptr; diff -up firefox-40.0/mozilla-release/gfx/src/nsRegion.h.1127752 firefox-40.0/mozilla-release/gfx/src/nsRegion.h --- firefox-40.0/mozilla-release/gfx/src/nsRegion.h.1127752 2015-08-07 17:54:05.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/src/nsRegion.h 2015-08-26 14:07:24.667087889 +0200 @@ -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); diff -up firefox-40.0/mozilla-release/gfx/thebes/gfxContext.cpp.1127752 firefox-40.0/mozilla-release/gfx/thebes/gfxContext.cpp --- firefox-40.0/mozilla-release/gfx/thebes/gfxContext.cpp.1127752 2015-08-07 17:54:05.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/thebes/gfxContext.cpp 2015-08-26 14:07:24.668087868 +0200 @@ -619,6 +619,23 @@ gfxContext::GetClipExtents() } 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; diff -up firefox-40.0/mozilla-release/gfx/thebes/gfxContext.h.1127752 firefox-40.0/mozilla-release/gfx/thebes/gfxContext.h --- firefox-40.0/mozilla-release/gfx/thebes/gfxContext.h.1127752 2015-08-07 17:54:05.000000000 +0200 +++ firefox-40.0/mozilla-release/gfx/thebes/gfxContext.h 2015-08-26 14:07:24.668087868 +0200 @@ -446,6 +446,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 * fully contained by the current clip. diff -up firefox-40.0/mozilla-release/widget/gtk/nsNativeThemeGTK.cpp.1127752 firefox-40.0/mozilla-release/widget/gtk/nsNativeThemeGTK.cpp --- firefox-40.0/mozilla-release/widget/gtk/nsNativeThemeGTK.cpp.1127752 2015-08-26 14:07:24.657088105 +0200 +++ firefox-40.0/mozilla-release/widget/gtk/nsNativeThemeGTK.cpp 2015-08-26 14:07:24.669087846 +0200 @@ -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 #include @@ -706,6 +718,158 @@ ThemeRenderer::DrawWithGDK(GdkDrawable * 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 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 @@ -800,10 +964,6 @@ nsNativeThemeGTK::DrawWidgetBackground(n const nsRect& aRect, const nsRect& aDirtyRect) { -#if (MOZ_WIDGET_GTK != 2) - DrawTarget& aDrawTarget = *aContext->GetDrawTarget(); -#endif - GtkWidgetState state; GtkThemeWidgetType gtkWidgetType; GtkTextDirection direction = GetTextDirection(aFrame); @@ -823,8 +983,8 @@ nsNativeThemeGTK::DrawWidgetBackground(n // 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); } @@ -853,23 +1013,6 @@ nsNativeThemeGTK::DrawWidgetBackground(n || !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!"); @@ -879,7 +1022,27 @@ nsNativeThemeGTK::DrawWidgetBackground(n 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}; @@ -891,7 +1054,7 @@ nsNativeThemeGTK::DrawWidgetBackground(n // 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; } @@ -901,11 +1064,10 @@ nsNativeThemeGTK::DrawWidgetBackground(n 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) { diff -up firefox-40.0/mozilla-release/widget/gtk/nsScreenGtk.cpp.1127752 firefox-40.0/mozilla-release/widget/gtk/nsScreenGtk.cpp --- firefox-40.0/mozilla-release/widget/gtk/nsScreenGtk.cpp.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/widget/gtk/nsScreenGtk.cpp 2015-08-26 14:07:24.669087846 +0200 @@ -12,6 +12,7 @@ #endif #include #include +#include "gfxPlatformGtk.h" static uint32_t sScreenId = 0; diff -up firefox-40.0/mozilla-release/widget/gtk/nsWindow.cpp.1127752 firefox-40.0/mozilla-release/widget/gtk/nsWindow.cpp --- firefox-40.0/mozilla-release/widget/gtk/nsWindow.cpp.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/widget/gtk/nsWindow.cpp 2015-08-26 14:07:24.670087825 +0200 @@ -2050,71 +2050,52 @@ gdk_window_flash(GdkWindow * aGdkWind #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; - } +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; + } - mRectsEnd = mRects + nrects; + 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)); + } - 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 ctx; - if (gfxPlatform::GetPlatform()-> - SupportsAzureContentForType(BackendType::CAIRO)) { - IntSize intSize(surf->GetSize().width, surf->GetSize().height); - RefPtr 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(surf); - SurfaceFormat format = ImageFormatToSurfaceFormat(imgSurf->Format()); - IntSize intSize(surf->GetSize().width, surf->GetSize().height); - RefPtr dt = - gfxPlatform::GetPlatform()->CreateDrawTargetForData( - imgSurf->Data(), intSize, imgSurf->Stride(), format); - ctx = new gfxContext(dt); - } else { - MOZ_CRASH("Unexpected content type"); + RefPtr dt = StartRemoteDrawing(); + if(!dt) { + return FALSE; } + nsRefPtr 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(surf); + SurfaceFormat format = ImageFormatToSurfaceFormat(imgSurf->Format()); + return platform->CreateDrawTargetForData( + imgSurf->Data(), size, imgSurf->Stride(), format); + } else { + return nullptr; + } } -// return the gfxASurface for rendering to this widget -gfxASurface* -nsWindow::GetThebesSurface() -#if (MOZ_WIDGET_GTK == 3) +void +nsWindow::EndRemoteDrawingInRegion(DrawTarget* aDrawTarget, nsIntRegion& aInvalidRegion) { - return GetThebesSurface(nullptr); +#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(cairo_t *cr) -#endif +nsWindow::GetThebesSurface() { if (!mGdkWindow) return nullptr; diff -up firefox-40.0/mozilla-release/widget/gtk/nsWindow.h.1127752 firefox-40.0/mozilla-release/widget/gtk/nsWindow.h --- firefox-40.0/mozilla-release/widget/gtk/nsWindow.h.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/widget/gtk/nsWindow.h 2015-08-26 14:07:24.671087803 +0200 @@ -194,7 +194,10 @@ public: guint aTime, gpointer aData); - mozilla::TemporaryRef StartRemoteDrawing() override; + virtual mozilla::TemporaryRef + StartRemoteDrawing() override; + virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget, + nsIntRegion& aInvalidRegion) override; private: void UpdateAlpha(gfxPattern* aPattern, nsIntRect aBoundsRect); @@ -467,9 +470,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(); diff -up firefox-40.0/mozilla-release/widget/nsIWidget.h.1127752 firefox-40.0/mozilla-release/widget/nsIWidget.h --- firefox-40.0/mozilla-release/widget/nsIWidget.h.1127752 2015-08-26 14:07:24.671087803 +0200 +++ firefox-40.0/mozilla-release/widget/nsIWidget.h 2015-08-26 14:07:59.529337002 +0200 @@ -1657,6 +1657,9 @@ class nsIWidget : public nsISupports { * after each composition. */ virtual void EndRemoteDrawing() = 0; + virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget, nsIntRegion& aInvalidRegion) { + EndRemoteDrawing(); + } /** * A hook for the widget to prepare a Compositor, during the latter's initialization. diff -up firefox-40.0/mozilla-release/widget/nsShmImage.cpp.1127752 firefox-40.0/mozilla-release/widget/nsShmImage.cpp --- firefox-40.0/mozilla-release/widget/nsShmImage.cpp.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/widget/nsShmImage.cpp 2015-08-26 14:07:24.672087781 +0200 @@ -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, GdkR 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, GdkR #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); } diff -up firefox-40.0/mozilla-release/widget/nsShmImage.h.1127752 firefox-40.0/mozilla-release/widget/nsShmImage.h --- firefox-40.0/mozilla-release/widget/nsShmImage.h.1127752 2015-08-07 17:54:22.000000000 +0200 +++ firefox-40.0/mozilla-release/widget/nsShmImage.h 2015-08-26 14:07:24.672087781 +0200 @@ -63,10 +63,8 @@ private: public: already_AddRefed 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