From 571fefe2c8f741b92c865e9122af56f6258b3fc1 Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Wed, 26 Aug 2015 14:22:17 +0200 Subject: Added a fix for mozbz#1127752 (rhbz#1256875) - Gtk3&OMTC crashes --- firefox.spec | 7 +- mozilla-1127752.patch | 941 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 947 insertions(+), 1 deletion(-) create mode 100644 mozilla-1127752.patch 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 - 40.0-10 +- Added a fix for mozbz#1127752 (rhbz#1256875) - Gtk3&OMTC crashes + * Tue Aug 25 2015 Martin Stransky - 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 ++#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 -- cgit