new file mode 100644
--- /dev/null
+++ b/widget/WindowSurface.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MOZILLA_WIDGET_WINDOW_SURFACE_H
+#define _MOZILLA_WIDGET_WINDOW_SURFACE_H
+
+#include "mozilla/gfx/2D.h"
+#include "Units.h"
+
+namespace mozilla {
+namespace widget {
+
+// A class for drawing to double-buffered windows.
+class WindowSurface {
+public:
+ virtual ~WindowSurface() {}
+
+ // Locks a region of the window for drawing, returning a draw target
+ // capturing the bounds of the provided region.
+ // Implementations must permit invocation from any thread.
+ virtual already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) = 0;
+
+ // Swaps the provided invalid region from the back buffer to the window.
+ // Implementations must permit invocation from any thread.
+ virtual void Commit(const LayoutDeviceIntRegion& aInvalidRegion) = 0;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // _MOZILLA_WIDGET_WINDOW_SURFACE_H
new file mode 100644
--- /dev/null
+++ b/widget/WindowSurfaceX11SHM.cpp
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WindowSurfaceX11SHM.h"
+
+namespace mozilla {
+namespace widget {
+
+WindowSurfaceX11SHM::WindowSurfaceX11SHM(Display* aDisplay, Drawable aWindow,
+ Visual* aVisual, unsigned int aDepth)
+{
+ mFrontImage = new nsShmImage(aDisplay, aWindow, aVisual, aDepth);
+ mBackImage = new nsShmImage(aDisplay, aWindow, aVisual, aDepth);
+}
+
+already_AddRefed<gfx::DrawTarget>
+WindowSurfaceX11SHM::Lock(const LayoutDeviceIntRegion& aRegion)
+{
+ mBackImage.swap(mFrontImage);
+ return mBackImage->CreateDrawTarget(aRegion);
+}
+
+void
+WindowSurfaceX11SHM::Commit(const LayoutDeviceIntRegion& aInvalidRegion)
+{
+ mBackImage->Put(aInvalidRegion);
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/WindowSurfaceX11SHM.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MOZILLA_WIDGET_WINDOW_SURFACE_X11_SHM_H
+#define _MOZILLA_WIDGET_WINDOW_SURFACE_X11_SHM_H
+
+#ifdef MOZ_X11
+
+#include "mozilla/widget/WindowSurface.h"
+#include "nsShmImage.h"
+
+namespace mozilla {
+namespace widget {
+
+class WindowSurfaceX11SHM : public WindowSurface {
+public:
+ WindowSurfaceX11SHM(Display* aDisplay, Drawable aWindow, Visual* aVisual,
+ unsigned int aDepth);
+
+ already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) override;
+ void Commit(const LayoutDeviceIntRegion& aInvalidRegion) override;
+
+private:
+ RefPtr<nsShmImage> mFrontImage;
+ RefPtr<nsShmImage> mBackImage;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_X11
+#endif // _MOZILLA_WIDGET_WINDOW_SURFACE_X11_SHM_H
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WindowSurfaceX11.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WindowSurfaceX11.h"
+#include "gfxPlatform.h"
+
+namespace mozilla {
+namespace widget {
+
+WindowSurfaceX11::WindowSurfaceX11(Display* aDisplay,
+ Window aWindow,
+ Visual* aVisual,
+ unsigned int aDepth)
+ : mDisplay(aDisplay)
+ , mWindow(aWindow)
+ , mVisual(aVisual)
+ , mDepth(aDepth)
+ , mFormat(GetVisualFormat(aVisual, aDepth))
+ , mGC(None)
+{
+ MOZ_ASSERT(mFormat != gfx::SurfaceFormat::UNKNOWN,
+ "Could not find SurfaceFormat for visual!");
+}
+
+WindowSurfaceX11::~WindowSurfaceX11()
+{
+ if (mGC != None)
+ XFreeGC(mDisplay, mGC);
+}
+
+void
+WindowSurfaceX11::Commit(const LayoutDeviceIntRegion& aInvalidRegion)
+{
+ AutoTArray<XRectangle, 32> xrects;
+ xrects.SetCapacity(aInvalidRegion.GetNumRects());
+
+ for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
+ const mozilla::LayoutDeviceIntRect &r = iter.Get();
+ XRectangle xrect = { (short)r.x, (short)r.y, (unsigned short)r.width, (unsigned short)r.height };
+ xrects.AppendElement(xrect);
+ }
+
+ if (!mGC) {
+ mGC = XCreateGC(mDisplay, mWindow, 0, nullptr);
+ if (!mGC) {
+ NS_WARNING("Couldn't create X11 graphics context for window!");
+ return;
+ }
+ }
+
+ XSetClipRectangles(mDisplay, mGC, 0, 0, xrects.Elements(), xrects.Length(), YXBanded);
+ CommitToDrawable(mWindow, mGC, aInvalidRegion);
+}
+
+/* static */
+gfx::SurfaceFormat
+WindowSurfaceX11::GetVisualFormat(const Visual* aVisual, unsigned int aDepth)
+{
+ switch (aDepth) {
+ case 32:
+ if (aVisual->red_mask == 0xff0000 &&
+ aVisual->green_mask == 0xff00 &&
+ aVisual->blue_mask == 0xff) {
+ return gfx::SurfaceFormat::B8G8R8A8;
+ }
+ break;
+ case 24:
+ // Only support the BGRX layout, and report it as BGRA to the compositor.
+ // The alpha channel will be discarded when we put the image.
+ // Cairo/pixman lacks some fast paths for compositing BGRX onto BGRA, so
+ // just report it as BGRX directly in that case.
+ if (aVisual->red_mask == 0xff0000 &&
+ aVisual->green_mask == 0xff00 &&
+ aVisual->blue_mask == 0xff) {
+ gfx::BackendType backend = gfxPlatform::GetPlatform()->GetDefaultContentBackend();
+ return backend == gfx::BackendType::CAIRO ? gfx::SurfaceFormat::B8G8R8X8
+ : gfx::SurfaceFormat::B8G8R8A8;
+ }
+ break;
+ case 16:
+ if (aVisual->red_mask == 0xf800 &&
+ aVisual->green_mask == 0x07e0 &&
+ aVisual->blue_mask == 0x1f) {
+ return gfx::SurfaceFormat::R5G6B5_UINT16;
+ }
+ break;
+ }
+
+ return gfx::SurfaceFormat::UNKNOWN;
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WindowSurfaceX11.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_X11_H
+#define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_X11_H
+
+#ifdef MOZ_X11
+
+#include "mozilla/widget/WindowSurface.h"
+#include "mozilla/gfx/Types.h"
+
+#include <X11/Xlib.h>
+
+namespace mozilla {
+namespace widget {
+
+class WindowSurfaceX11 : public WindowSurface {
+public:
+ WindowSurfaceX11(Display* aDisplay, Window aWindow, Visual* aVisual,
+ unsigned int aDepth);
+ ~WindowSurfaceX11();
+
+ void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
+
+ virtual already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) = 0;
+
+ // Draws the buffered image onto aDest using the given GC.
+ // The GC provided has been clipped to aInvalidRegion.
+ virtual void CommitToDrawable(Drawable aDest, GC aGC,
+ const LayoutDeviceIntRegion& aInvalidRegion) = 0;
+
+protected:
+ static gfx::SurfaceFormat GetVisualFormat(const Visual* aVisual, unsigned int aDepth);
+
+ Display* const mDisplay;
+ const Window mWindow;
+ Visual* const mVisual;
+ const unsigned int mDepth;
+ const gfx::SurfaceFormat mFormat;
+
+ GC mGC;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_X11
+#endif // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_X11_H
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WindowSurfaceX11Image.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WindowSurfaceX11Image.h"
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Tools.h"
+#include "gfxPlatform.h"
+
+namespace mozilla {
+namespace widget {
+
+WindowSurfaceX11Image::WindowSurfaceX11Image(Display* aDisplay,
+ Window aWindow,
+ Visual* aVisual,
+ unsigned int aDepth)
+ : WindowSurfaceX11(aDisplay, aWindow, aVisual, aDepth)
+ , mImage(nullptr)
+{
+}
+
+WindowSurfaceX11Image::~WindowSurfaceX11Image()
+{
+ if (mImage)
+ XDestroyImage(mImage);
+}
+
+already_AddRefed<gfx::DrawTarget>
+WindowSurfaceX11Image::Lock(const LayoutDeviceIntRegion& aRegion)
+{
+ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
+ gfx::IntSize size(bounds.XMost(), bounds.YMost());
+
+ if (!mImage || mImage->width < size.width || mImage->height < size.height) {
+ if (mImage)
+ XDestroyImage(mImage);
+
+ int stride = gfx::GetAlignedStride<16>(gfx::BytesPerPixel(mFormat) * size.width);
+ char* data = static_cast<char*>(malloc(stride * size.height));
+ if (!data)
+ return nullptr;
+
+ mImage = XCreateImage(mDisplay, mVisual, mDepth, ZPixmap, 0,
+ data, size.width, size.height,
+ 8 * gfx::BytesPerPixel(mFormat), stride);
+ }
+
+ if (!mImage)
+ return nullptr;
+
+ unsigned char* data = (unsigned char*) mImage->data;
+ return gfxPlatform::GetPlatform()->CreateDrawTargetForData(data,
+ size,
+ mImage->bytes_per_line,
+ mFormat);
+}
+
+void
+WindowSurfaceX11Image::CommitToDrawable(Drawable aDest, GC aGC,
+ const LayoutDeviceIntRegion& aInvalidRegion)
+{
+ MOZ_ASSERT(mImage, "Attempted to commit invalid surface!");
+
+ gfx::IntRect bounds = aInvalidRegion.GetBounds().ToUnknownRect();
+ gfx::IntSize size(bounds.XMost(), bounds.YMost());
+ XPutImage(mDisplay, aDest, aGC, mImage, bounds.x, bounds.y,
+ bounds.x, bounds.y, size.width, size.height);
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WindowSurfaceX11Image.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_X11_IMAGE_H
+#define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_X11_IMAGE_H
+
+#ifdef MOZ_X11
+
+#include "WindowSurfaceX11.h"
+
+namespace mozilla {
+namespace widget {
+
+class WindowSurfaceX11Image : public WindowSurfaceX11 {
+public:
+ WindowSurfaceX11Image(Display* aDisplay, Window aWindow, Visual* aVisual,
+ unsigned int aDepth);
+ ~WindowSurfaceX11Image();
+
+ already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) override;
+ void CommitToDrawable(Drawable aDest, GC aGC,
+ const LayoutDeviceIntRegion& aInvalidRegion) override;
+
+private:
+ XImage* mImage;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_X11
+#endif // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_X11_IMAGE_H
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WindowSurfaceXRender.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WindowSurfaceXRender.h"
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Types.h"
+#include "gfxPlatform.h"
+
+namespace mozilla {
+namespace widget {
+
+WindowSurfaceXRender::WindowSurfaceXRender(Display* aDisplay,
+ Window aWindow,
+ Visual* aVisual,
+ unsigned int aDepth)
+ : WindowSurfaceX11(aDisplay, aWindow, aVisual, aDepth)
+ , mXlibSurface(nullptr)
+{
+}
+
+already_AddRefed<gfx::DrawTarget>
+WindowSurfaceXRender::Lock(const LayoutDeviceIntRegion& aRegion)
+{
+ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
+ gfx::IntSize size(bounds.XMost(), bounds.YMost());
+ if (!mXlibSurface || mXlibSurface->CairoStatus() != 0 ||
+ mXlibSurface->GetSize().width < size.width ||
+ mXlibSurface->GetSize().height < size.height)
+ {
+ mXlibSurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(mDisplay),
+ mVisual,
+ size,
+ mWindow);
+ }
+
+ if (mXlibSurface && mXlibSurface->CairoStatus() == 0) {
+ return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mXlibSurface.get(), size);
+ }
+ return nullptr;
+}
+
+void
+WindowSurfaceXRender::CommitToDrawable(Drawable aDest, GC aGC,
+ const LayoutDeviceIntRegion& aInvalidRegion)
+{
+ MOZ_ASSERT(mXlibSurface && mXlibSurface->CairoStatus() == 0,
+ "Attempted to commit invalid surface!");
+ gfx::IntRect bounds = aInvalidRegion.GetBounds().ToUnknownRect();
+ gfx::IntSize size(bounds.XMost(), bounds.YMost());
+ XCopyArea(mDisplay, mXlibSurface->XDrawable(), aDest, aGC, bounds.x, bounds.y,
+ size.width, size.height, bounds.x, bounds.y);
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WindowSurfaceXRender.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_XRENDER_H
+#define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_XRENDER_H
+
+#ifdef MOZ_X11
+
+#include "WindowSurfaceX11.h"
+#include "gfxXlibSurface.h"
+
+namespace mozilla {
+namespace widget {
+
+class WindowSurfaceXRender : public WindowSurfaceX11 {
+public:
+ WindowSurfaceXRender(Display* aDisplay, Window aWindow, Visual* aVisual,
+ unsigned int aDepth);
+
+ already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) override;
+ void CommitToDrawable(Drawable aDest, GC aGC,
+ const LayoutDeviceIntRegion& aInvalidRegion) override;
+
+private:
+ RefPtr<gfxXlibSurface> mXlibSurface;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_X11
+#endif // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_XRENDER_H
--- a/widget/gtk/moz.build
+++ b/widget/gtk/moz.build
@@ -58,16 +58,19 @@ if CONFIG['NS_PRINTING']:
'nsPrintSettingsGTK.cpp',
'nsPSPrinters.cpp',
]
if CONFIG['MOZ_X11']:
UNIFIED_SOURCES += [
'nsClipboard.cpp',
'nsDragService.cpp',
+ 'WindowSurfaceX11.cpp',
+ 'WindowSurfaceX11Image.cpp',
+ 'WindowSurfaceXRender.cpp',
]
if CONFIG['ACCESSIBILITY']:
UNIFIED_SOURCES += [
'maiRedundantObjectFactory.c',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2':
--- a/widget/gtk/nsDeviceContextSpecG.cpp
+++ b/widget/gtk/nsDeviceContextSpecG.cpp
@@ -20,16 +20,17 @@
#include "nsPSPrinters.h"
#include "nsPaperPS.h" /* Paper size list */
#include "nsPrintSettingsGTK.h"
#include "nsIFileStreams.h"
#include "nsIFile.h"
#include "nsTArray.h"
+#include "nsThreadUtils.h"
#include "mozilla/Preferences.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
using namespace mozilla;
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -112,18 +112,21 @@ using namespace mozilla::widget;
#include "Layers.h"
#include "GLContextProvider.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/HelpersCairo.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#ifdef MOZ_X11
#include "gfxXlibSurface.h"
-#endif
-
+#include "WindowSurfaceX11Image.h"
+#include "WindowSurfaceX11SHM.h"
+#include "WindowSurfaceXRender.h"
+#endif // MOZ_X11
+
#include "nsShmImage.h"
#include "nsIDOMWheelEvent.h"
#include "NativeKeyBindings.h"
#include <dlfcn.h>
@@ -471,18 +474,16 @@ nsWindow::nsWindow()
mTransparencyBitmap = nullptr;
mTransparencyBitmapWidth = 0;
mTransparencyBitmapHeight = 0;
#if GTK_CHECK_VERSION(3,4,0)
mLastScrollEventTime = GDK_CURRENT_TIME;
#endif
-
- mFallbackSurface = nullptr;
mPendingConfigures = 0;
}
nsWindow::~nsWindow()
{
LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
delete[] mTransparencyBitmap;
@@ -795,21 +796,16 @@ nsWindow::Destroy(void)
}
#ifdef ACCESSIBILITY
if (mRootAccessible) {
mRootAccessible = nullptr;
}
#endif
- if (mFallbackSurface) {
- cairo_surface_destroy(mFallbackSurface);
- mFallbackSurface = nullptr;
- }
-
// Save until last because OnDestroy() may cause us to be deleted.
OnDestroy();
return NS_OK;
}
nsIWidget *
nsWindow::GetParent(void)
@@ -6552,143 +6548,46 @@ nsWindow::GetDrawTargetForGdkDrawable(Gd
return nullptr;
}
return dt.forget();
}
#endif
already_AddRefed<DrawTarget>
-nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion, BufferMode* aBufferMode)
-{
- if (!mGdkWindow || aRegion.IsEmpty()) {
+nsWindow::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode)
+{
+ if (aInvalidRegion.IsEmpty())
return nullptr;
+
+ if (!mWindowSurface) {
+ mWindowSurface = CreateWindowSurface();
+ if (!mWindowSurface)
+ return nullptr;
}
- RefPtr<DrawTarget> dt;
-
+ *aBufferMode = BufferMode::BUFFER_NONE;
+ RefPtr<DrawTarget> dt = nullptr;
+ if (!(dt = mWindowSurface->Lock(aInvalidRegion))) {
#ifdef MOZ_X11
- bool useXRender = false;
-#ifdef MOZ_WIDGET_GTK
- useXRender = gfxPlatformGtk::GetPlatform()->UseXRender();
-#endif
-
- if (useXRender) {
- LayoutDeviceIntRect bounds = aRegion.GetBounds();
- LayoutDeviceIntSize size(bounds.XMost(), bounds.YMost());
- RefPtr<gfxXlibSurface> surf = new gfxXlibSurface(mXDisplay, mXWindow, mXVisual, size.ToUnknownSize());
- if (!surf->CairoStatus()) {
- dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf.get(), surf->GetSize());
- *aBufferMode = BufferMode::BUFFERED;
- }
- }
-
-# ifdef MOZ_HAVE_SHMIMAGE
- if (!dt && mIsX11Display && nsShmImage::UseShm()) {
- mBackShmImage.swap(mFrontShmImage);
- if (!mBackShmImage) {
- mBackShmImage = new nsShmImage(mXDisplay, mXWindow, mXVisual, mXDepth);
- }
- dt = mBackShmImage->CreateDrawTarget(aRegion);
- *aBufferMode = BufferMode::BUFFER_NONE;
- if (!dt) {
- mBackShmImage = nullptr;
- }
- }
-# endif // MOZ_HAVE_SHMIMAGE
+ if (mIsX11Display) {
+ gfxWarningOnce() << "Failed to lock WindowSurface, falling back to XPutImage backend.";
+ mWindowSurface = MakeUnique<WindowSurfaceX11Image>(mXDisplay, mXWindow, mXVisual, mXDepth);
+ }
#endif // MOZ_X11
-
- // If MIT-SHM and XRender are unavailable, buffer to an image surface.
- if (!dt) {
- IntRect bounds = aRegion.GetBounds().ToUnknownRect();
- IntSize size(bounds.XMost(), bounds.YMost());
-
- // Recreate the fallback surface if there is unsufficient space to render.
- if (!mFallbackSurface ||
- cairo_image_surface_get_width(mFallbackSurface) < size.width ||
- cairo_image_surface_get_height(mFallbackSurface) < size.height)
- {
- if (mFallbackSurface)
- cairo_surface_destroy(mFallbackSurface);
-
- GdkScreen* screen = gdk_screen_get_default();
- bool argb = gdk_window_get_visual(mGdkWindow) ==
- gdk_screen_get_rgba_visual(screen);
- cairo_format_t cairo_format = argb ? CAIRO_FORMAT_ARGB32
- : CAIRO_FORMAT_RGB24;
- mFallbackSurface = cairo_image_surface_create(cairo_format,
- bounds.XMost(),
- bounds.YMost());
-
- // Set the appropriate device scale so that our surface can be used
- // as a source without transforming to the GDK window's scale.
- static auto sCairoSurfaceSetDeviceScale =
- (void (*)(cairo_surface_t*, double, double))
- dlsym(RTLD_DEFAULT, "cairo_surface_set_device_scale");
- if (sCairoSurfaceSetDeviceScale) {
- gint scale = GdkScaleFactor();
- sCairoSurfaceSetDeviceScale(mFallbackSurface, scale, scale);
- }
-
- cairo_surface_flush(mFallbackSurface);
- }
-
- SurfaceFormat format = CairoFormatToGfxFormat(
- cairo_image_surface_get_format(mFallbackSurface));
- dt = gfxPlatform::GetPlatform()->CreateDrawTargetForData(
- cairo_image_surface_get_data(mFallbackSurface)
- + bounds.x * BytesPerPixel(format)
- + bounds.y * cairo_image_surface_get_stride(mFallbackSurface),
- bounds.Size(),
- cairo_image_surface_get_stride(mFallbackSurface),
- format);
- *aBufferMode = BufferMode::BUFFER_NONE;
}
-
return dt.forget();
}
-already_AddRefed<DrawTarget>
-nsWindow::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode)
-{
- return GetDrawTarget(aInvalidRegion, aBufferMode);
-}
-
void
nsWindow::EndRemoteDrawingInRegion(DrawTarget* aDrawTarget,
LayoutDeviceIntRegion& aInvalidRegion)
{
-#ifdef MOZ_X11
-# ifdef MOZ_HAVE_SHMIMAGE
- if (!mGdkWindow) {
- return;
- }
-
- if (mBackShmImage) {
- mBackShmImage->Put(aInvalidRegion);
- }
-# endif // MOZ_HAVE_SHMIMAGE
-#endif // MOZ_X11
-
- if (mFallbackSurface) {
- cairo_t* cr = gdk_cairo_create(mGdkWindow);
- cairo_surface_mark_dirty(mFallbackSurface);
- cairo_set_source_surface(cr, mFallbackSurface, 0, 0);
-
- for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
- // Transform our path into the window's coordinate system.
- const IntRectTyped<LayoutDevicePixel> & r = iter.Get();
- cairo_rectangle(cr, DevicePixelsToGdkCoordRoundDown(r.x),
- DevicePixelsToGdkCoordRoundDown(r.y),
- DevicePixelsToGdkCoordRoundUp(r.width),
- DevicePixelsToGdkCoordRoundUp(r.height));
- }
- cairo_fill(cr);
- cairo_destroy(cr);
- }
+ if (mWindowSurface)
+ mWindowSurface->Commit(aInvalidRegion);
}
// Code shared begin BeginMoveDrag and BeginResizeDrag
bool
nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent,
GdkWindow** aWindow, gint* aButton,
gint* aRootX, gint* aRootY)
{
@@ -7114,8 +7013,44 @@ nsWindow::SynthesizeNativeTouchPoint(uin
}
#endif
int32_t
nsWindow::RoundsWidgetCoordinatesTo()
{
return GdkScaleFactor();
}
+
+UniquePtr<WindowSurface>
+nsWindow::CreateWindowSurface()
+{
+ if (!mGdkWindow)
+ return nullptr;
+
+ // TODO: Add path for Wayland. We can't use gdk_cairo_create as it's not
+ // threadsafe.
+ if (!mIsX11Display)
+ return nullptr;
+
+#ifdef MOZ_X11
+ // Blit to the window with the following priority:
+ // 1. XRender (iff XRender is enabled)
+ // 2. MIT-SHM
+ // 3. XPutImage
+
+#ifdef MOZ_WIDGET_GTK
+ if (gfxPlatformGtk::GetPlatform()->UseXRender()) {
+ LOGDRAW(("Drawing to nsWindow %p using XRender\n", (void*)this));
+ return MakeUnique<WindowSurfaceXRender>(mXDisplay, mXWindow, mXVisual, mXDepth);
+ }
+#endif // MOZ_WIDGET_GTK
+
+#ifdef MOZ_HAVE_SHMIMAGE
+ if (nsShmImage::UseShm()) {
+ LOGDRAW(("Drawing to nsWindow %p using MIT-SHM\n", (void*)this));
+ return MakeUnique<WindowSurfaceX11SHM>(mXDisplay, mXWindow, mXVisual, mXDepth);
+ }
+#endif // MOZ_HAVE_SHMIMAGE
+
+ LOGDRAW(("Drawing to nsWindow %p using XPutImage\n", (void*)this));
+ return MakeUnique<WindowSurfaceX11Image>(mXDisplay, mXWindow, mXVisual, mXDepth);
+#endif // MOZ_X11
+}
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -19,17 +19,17 @@
#include "nsBaseWidget.h"
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#ifdef MOZ_X11
#include <gdk/gdkx.h>
#endif /* MOZ_X11 */
-#include "nsShmImage.h"
+#include "mozilla/widget/WindowSurface.h"
#ifdef ACCESSIBILITY
#include "mozilla/a11y/Accessible.h"
#endif
#include "mozilla/EventForwards.h"
#include "mozilla/TouchEvents.h"
#include "IMContextWrapper.h"
@@ -312,19 +312,16 @@ public:
void ClearTransparencyBitmap();
virtual void SetTransparencyMode(nsTransparencyMode aMode) override;
virtual nsTransparencyMode GetTransparencyMode() override;
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
nsresult UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
uint8_t* aAlphas, int32_t aStride);
- already_AddRefed<mozilla::gfx::DrawTarget> GetDrawTarget(const LayoutDeviceIntRegion& aRegion,
- mozilla::layers::BufferMode* aBufferMode);
-
#if (MOZ_WIDGET_GTK == 2)
static already_AddRefed<DrawTarget> GetDrawTargetForGdkDrawable(GdkDrawable* aDrawable,
const mozilla::gfx::IntSize& aSize);
#endif
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) override;
virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
@@ -453,32 +450,25 @@ private:
#if GTK_CHECK_VERSION(3,4,0)
// This field omits duplicate scroll events caused by GNOME bug 726878.
guint32 mLastScrollEventTime;
// for touch event handling
nsRefPtrHashtable<nsPtrHashKey<GdkEventSequence>, mozilla::dom::Touch> mTouches;
#endif
+ mozilla::UniquePtr<mozilla::widget::WindowSurface> mWindowSurface;
+
#ifdef MOZ_X11
Display* mXDisplay;
Window mXWindow;
Visual* mXVisual;
int mXDepth;
#endif
-#ifdef MOZ_HAVE_SHMIMAGE
- // If we're using xshm rendering
- RefPtr<nsShmImage> mFrontShmImage;
- RefPtr<nsShmImage> mBackShmImage;
-#endif
-
- // A fallback image surface when a SHM surface is unavailable.
- cairo_surface_t* mFallbackSurface;
-
// Upper bound on pending ConfigureNotify events to be dispatched to the
// window. See bug 1225044.
int mPendingConfigures;
#ifdef ACCESSIBILITY
RefPtr<mozilla::a11y::Accessible> mRootAccessible;
/**
@@ -557,16 +547,18 @@ private:
virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
void CleanLayerManagerRecursive();
virtual int32_t RoundsWidgetCoordinatesTo() override;
+ mozilla::UniquePtr<mozilla::widget::WindowSurface> CreateWindowSurface();
+
/**
* |mIMContext| takes all IME related stuff.
*
* This is owned by the top-level nsWindow or the topmost child
* nsWindow embedded in a non-Gecko widget.
*
* The instance is created when the top level widget is created. And when
* the widget is destroyed, it's released. All child windows refer its
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -128,16 +128,17 @@ EXPORTS.mozilla += [
]
EXPORTS.mozilla.widget += [
'CompositorWidget.h',
'IMEData.h',
'InProcessCompositorWidget.h',
'PuppetBidiKeyboard.h',
'WidgetMessageUtils.h',
+ 'WindowSurface.h'
]
UNIFIED_SOURCES += [
'CompositorWidget.cpp',
'ContentCache.cpp',
'GfxDriverInfo.cpp',
'GfxInfoBase.cpp',
'GfxInfoCollector.cpp',
@@ -198,17 +199,18 @@ if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
EXPORTS.ipc = ['nsGUIEventIPC.h']
if CONFIG['MOZ_X11']:
DIRS += ['x11']
UNIFIED_SOURCES += [
'GfxInfoX11.cpp'
]
SOURCES += [
- 'nsShmImage.cpp'
+ 'nsShmImage.cpp',
+ 'WindowSurfaceX11SHM.cpp',
]
if toolkit in ('cocoa', 'windows'):
UNIFIED_SOURCES += [
'nsBaseClipboard.cpp',
]
if toolkit in {'gtk2', 'gtk3', 'cocoa', 'windows',