summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Stransky <stransky@anakreon.cz>2015-08-26 14:22:17 +0200
committerMartin Stransky <stransky@anakreon.cz>2015-08-26 14:22:17 +0200
commit571fefe2c8f741b92c865e9122af56f6258b3fc1 (patch)
tree7e2e4d95923c7b15cafabf5cd3231b2b85b9c4df
parentChangelog fix (diff)
downloadlibrewolf-fedora-ff-571fefe2c8f741b92c865e9122af56f6258b3fc1.tar.gz
librewolf-fedora-ff-571fefe2c8f741b92c865e9122af56f6258b3fc1.tar.bz2
librewolf-fedora-ff-571fefe2c8f741b92c865e9122af56f6258b3fc1.zip
Added a fix for mozbz#1127752 (rhbz#1256875) - Gtk3&OMTC crashes
-rw-r--r--firefox.spec7
-rw-r--r--mozilla-1127752.patch941
2 files changed, 947 insertions, 1 deletions
diff --git a/firefox.spec b/firefox.spec
index 043acda..3c11b18 100644
--- a/firefox.spec
+++ b/firefox.spec
@@ -91,7 +91,7 @@
Summary: Mozilla Firefox Web browser
Name: firefox
Version: 40.0
-Release: 9%{?pre_tag}%{?dist}
+Release: 10%{?pre_tag}%{?dist}
URL: http://www.mozilla.org/projects/firefox/
License: MPLv1.1 or GPLv2+ or LGPLv2+
Group: Applications/Internet
@@ -138,6 +138,7 @@ Patch422: mozilla-1169232.patch
Patch423: mozilla-1129873-apppicker.patch
Patch424: mozilla-entry-padding.patch
Patch425: mozilla-1192243.patch
+Patch426: mozilla-1127752.patch
# Fix Skia Neon stuff on AArch64
Patch500: aarch64-fix-skia.patch
@@ -285,6 +286,7 @@ cd %{tarballdir}
%patch423 -p1 -b .1129873-apppicker
%patch424 -p2 -b .entry-padding
%patch425 -p1 -b .1192243
+%patch426 -p2 -b .1127752
%endif
%patch500 -p1
@@ -777,6 +779,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
#---------------------------------------------------------------------
%changelog
+* Wed Aug 26 2015 Martin Stransky <stransky@redhat.com> - 40.0-10
+- Added a fix for mozbz#1127752 (rhbz#1256875) - Gtk3&OMTC crashes
+
* Tue Aug 25 2015 Martin Stransky <stransky@redhat.com> - 40.0-9
- Enabled hardened builds
diff --git a/mozilla-1127752.patch b/mozilla-1127752.patch
new file mode 100644
index 0000000..e188a70
--- /dev/null
+++ b/mozilla-1127752.patch
@@ -0,0 +1,941 @@
+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 <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.
+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<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
++
+ }
+ }
+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<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::CreateSourceSurfaceFromN
+ 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;
+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<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,
+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<CompositingRenderTarget> 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 <algorithm>
+ #include <dlfcn.h>
+
+@@ -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<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
+@@ -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 <gtk/gtk.h>
+ #include <dlfcn.h>
++#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<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;
++ }
+ }
+
+-// 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<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);
+@@ -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<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
bgstack15