summaryrefslogtreecommitdiff
path: root/mozilla-975919-gtk3-hidpi.patch
diff options
context:
space:
mode:
Diffstat (limited to 'mozilla-975919-gtk3-hidpi.patch')
-rw-r--r--mozilla-975919-gtk3-hidpi.patch798
1 files changed, 798 insertions, 0 deletions
diff --git a/mozilla-975919-gtk3-hidpi.patch b/mozilla-975919-gtk3-hidpi.patch
new file mode 100644
index 0000000..283b7ac
--- /dev/null
+++ b/mozilla-975919-gtk3-hidpi.patch
@@ -0,0 +1,798 @@
+# HG changeset patch
+# Parent 7b33ee7fd162d784f382250d3fa811e86a1b7348
+# User Andrew Comminos <andrew@morlunk.com>
+Bug 975919 - Added support for HiDPI on GTK 3.10+
+
+diff --git a/widget/gtk/nsGtkUtils.h b/widget/gtk/nsGtkUtils.h
+--- a/widget/gtk/nsGtkUtils.h
++++ b/widget/gtk/nsGtkUtils.h
+@@ -4,16 +4,17 @@
+ /* 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 nsGtkUtils_h__
+ #define nsGtkUtils_h__
+
+ #include <glib.h>
++#include <dlfcn.h>
+
+ // Some gobject functions expect functions for gpointer arguments.
+ // gpointer is void* but C++ doesn't like casting functions to void*.
+ template<class T> static inline gpointer
+ FuncToGpointer(T aFunction)
+ {
+ return reinterpret_cast<gpointer>
+ (reinterpret_cast<uintptr_t>
+diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp
+--- a/widget/gtk/nsLookAndFeel.cpp
++++ b/widget/gtk/nsLookAndFeel.cpp
+@@ -728,16 +728,27 @@ GetSystemFontInfo(GtkWidget *aWidget,
+
+ // |size| is now either pixels or pango-points (not Mozilla-points!)
+
+ if (!pango_font_description_get_size_is_absolute(desc)) {
+ // |size| is in pango-points, so convert to pixels.
+ size *= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT;
+ }
+
++ // Scale fonts up on HiDPI displays.
++ // This would be done automatically with cairo, but we manually manage
++ // the display scale for platform consistency.
++ static gint (*GdkScreenGetMonitorScaleFactorPtr)(GdkScreen*,gint) =
++ (gint (*)(GdkScreen*,gint)) dlsym(RTLD_DEFAULT,
++ "gdk_screen_get_monitor_scale_factor");
++ if (GdkScreenGetMonitorScaleFactorPtr) {
++ GdkScreen *screen = gdk_screen_get_default();
++ size *= (*GdkScreenGetMonitorScaleFactorPtr)(screen, 0);
++ }
++
+ // |size| is now pixels
+
+ aFontStyle->size = size;
+
+ pango_font_description_free(desc);
+ }
+
+ static void
+diff --git a/widget/gtk/nsScreenGtk.cpp b/widget/gtk/nsScreenGtk.cpp
+--- a/widget/gtk/nsScreenGtk.cpp
++++ b/widget/gtk/nsScreenGtk.cpp
+@@ -6,20 +6,20 @@
+ #include "nsScreenGtk.h"
+
+ #include <gdk/gdk.h>
+ #ifdef MOZ_X11
+ #include <gdk/gdkx.h>
+ #include <X11/Xatom.h>
+ #endif
+ #include <gtk/gtk.h>
++#include <dlfcn.h>
+
+ static uint32_t sScreenId = 0;
+
+-
+ nsScreenGtk :: nsScreenGtk ( )
+ : mScreenNum(0),
+ mRect(0, 0, 0, 0),
+ mAvailRect(0, 0, 0, 0),
+ mId(++sScreenId)
+ {
+ }
+
+@@ -35,37 +35,68 @@ nsScreenGtk :: GetId(uint32_t *aId)
+ *aId = mId;
+ return NS_OK;
+ } // GetId
+
+
+ NS_IMETHODIMP
+ nsScreenGtk :: GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
+ {
++ double scale;
++ GetContentsScaleFactor(&scale);
++
++ *outLeft = NSToIntRound(mRect.x * scale);
++ *outTop = NSToIntRound(mRect.y * scale);
++ *outWidth = NSToIntRound(mRect.width * scale);
++ *outHeight = NSToIntRound(mRect.height * scale);
++
++ return NS_OK;
++
++} // GetRect
++
++
++NS_IMETHODIMP
++nsScreenGtk :: GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
++{
++ double scale;
++ GetContentsScaleFactor(&scale);
++
++ *outLeft = NSToIntRound(mAvailRect.x * scale);
++ *outTop = NSToIntRound(mAvailRect.y * scale);
++ *outWidth = NSToIntRound(mAvailRect.width * scale);
++ *outHeight = NSToIntRound(mAvailRect.height * scale);
++
++ return NS_OK;
++
++} // GetAvailRect
++
++NS_IMETHODIMP
++nsScreenGtk :: GetRectDisplayPix(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
++{
+ *outLeft = mRect.x;
+ *outTop = mRect.y;
+ *outWidth = mRect.width;
+ *outHeight = mRect.height;
+
+ return NS_OK;
+
+-} // GetRect
++} // GetRectDisplayPix
+
+
+ NS_IMETHODIMP
+-nsScreenGtk :: GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
++nsScreenGtk :: GetAvailRectDisplayPix(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
+ {
+ *outLeft = mAvailRect.x;
+ *outTop = mAvailRect.y;
+ *outWidth = mAvailRect.width;
+ *outHeight = mAvailRect.height;
+
+ return NS_OK;
+
+-} // GetAvailRect
++} // GetAvailRectDisplayPix
+
+
+ NS_IMETHODIMP
+ nsScreenGtk :: GetPixelDepth(int32_t *aPixelDepth)
+ {
+ GdkVisual * visual = gdk_screen_get_system_visual(gdk_screen_get_default());
+ *aPixelDepth = gdk_visual_get_depth(visual);
+
+@@ -77,16 +108,33 @@ nsScreenGtk :: GetPixelDepth(int32_t *aP
+ NS_IMETHODIMP
+ nsScreenGtk :: GetColorDepth(int32_t *aColorDepth)
+ {
+ return GetPixelDepth ( aColorDepth );
+
+ } // GetColorDepth
+
+
++NS_IMETHODIMP
++nsScreenGtk :: GetContentsScaleFactor(double* aContentsScaleFactor)
++{
++ static gint (*GdkScreenGetMonitorScaleFactorPtr)(GdkScreen*,gint) =
++ (gint (*)(GdkScreen*,gint)) dlsym(RTLD_DEFAULT,
++ "gdk_screen_get_monitor_scale_factor");
++ if (GdkScreenGetMonitorScaleFactorPtr) {
++ GdkScreen *screen = gdk_screen_get_default();
++ *aContentsScaleFactor = (*GdkScreenGetMonitorScaleFactorPtr)
++ (screen, mScreenNum);
++ } else {
++ *aContentsScaleFactor = 1;
++ }
++ return NS_OK;
++}
++
++
+ void
+ nsScreenGtk :: Init (GdkWindow *aRootWindow)
+ {
+ // We listen for configure events on the root window to pick up
+ // changes to this rect. We could listen for "size_changed" signals
+ // on the default screen to do this, except that doesn't work with
+ // versions of GDK predating the GdkScreen object. See bug 256646.
+ mAvailRect = mRect = nsIntRect(0, 0, gdk_screen_width(), gdk_screen_height());
+diff --git a/widget/gtk/nsScreenGtk.h b/widget/gtk/nsScreenGtk.h
+--- a/widget/gtk/nsScreenGtk.h
++++ b/widget/gtk/nsScreenGtk.h
+@@ -28,18 +28,21 @@ class nsScreenGtk : public nsBaseScreen
+ {
+ public:
+ nsScreenGtk();
+ ~nsScreenGtk();
+
+ NS_IMETHOD GetId(uint32_t* aId);
+ NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
+ NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
++ NS_IMETHOD GetRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
++ NS_IMETHOD GetAvailRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
+ NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth);
+ NS_IMETHOD GetColorDepth(int32_t* aColorDepth);
++ NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor);
+
+ void Init(GdkWindow *aRootWindow);
+ #ifdef MOZ_X11
+ void Init(XineramaScreenInfo *aScreenInfo);
+ #endif /* MOZ_X11 */
+
+ private:
+ uint32_t mScreenNum;
+diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
+--- a/widget/gtk/nsWindow.cpp
++++ b/widget/gtk/nsWindow.cpp
+@@ -466,16 +466,19 @@ nsWindow::DispatchResized(int32_t aWidth
+
+ nsresult
+ nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
+ {
+ #ifdef DEBUG
+ debug_DumpEvent(stdout, aEvent->widget, aEvent,
+ nsAutoCString("something"), 0);
+ #endif
++ // Translate the mouse event into device pixels.
++ aEvent->refPoint.x = GdkCoordToDevicePixels(aEvent->refPoint.x);
++ aEvent->refPoint.y = GdkCoordToDevicePixels(aEvent->refPoint.y);
+
+ aStatus = nsEventStatus_eIgnore;
+ nsIWidgetListener* listener =
+ mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
+ if (listener) {
+ aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
+ }
+
+@@ -724,16 +727,22 @@ nsWindow::GetDPI()
+ double heightInches = DisplayHeightMM(dpy, defaultScreen)/MM_PER_INCH_FLOAT;
+ if (heightInches < 0.25) {
+ // Something's broken, but we'd better not crash.
+ return 96.0f;
+ }
+ return float(DisplayHeight(dpy, defaultScreen)/heightInches);
+ }
+
++double
++nsWindow::GetDefaultScaleInternal()
++{
++ return GdkScaleFactor();
++}
++
+ NS_IMETHODIMP
+ nsWindow::SetParent(nsIWidget *aNewParent)
+ {
+ if (mContainer || !mGdkWindow) {
+ NS_NOTREACHED("nsWindow::SetParent called illegally");
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+@@ -822,18 +831,19 @@ nsWindow::ReparentNativeWidgetInternal(n
+ SetWidgetForHierarchy(mGdkWindow, aOldContainer, aNewContainer);
+
+ if (aOldContainer == gInvisibleContainer) {
+ CheckDestroyInvisibleContainer();
+ }
+ }
+
+ if (!mIsTopLevel) {
+- gdk_window_reparent(mGdkWindow, aNewParentWindow, mBounds.x,
+- mBounds.y);
++ gdk_window_reparent(mGdkWindow, aNewParentWindow,
++ DevicePixelsToGdkCoordRoundDown(mBounds.x),
++ DevicePixelsToGdkCoordRoundDown(mBounds.y));
+ }
+ }
+
+ nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
+ bool parentHasMappedToplevel =
+ newParent && newParent->mHasMappedToplevel;
+ if (mHasMappedToplevel != parentHasMappedToplevel) {
+ SetHasMappedToplevel(parentHasMappedToplevel);
+@@ -858,52 +868,56 @@ nsWindow::IsVisible() const
+ {
+ return mIsShown;
+ }
+
+ NS_IMETHODIMP
+ nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
+ {
+ if (mIsTopLevel && mShell) {
+- int32_t screenWidth = gdk_screen_width();
+- int32_t screenHeight = gdk_screen_height();
++ int width = GdkCoordToDevicePixels(gdk_screen_width());
++ int height = GdkCoordToDevicePixels(gdk_screen_height());
+ if (aAllowSlop) {
+ if (*aX < (kWindowPositionSlop - mBounds.width))
+ *aX = kWindowPositionSlop - mBounds.width;
+- if (*aX > (screenWidth - kWindowPositionSlop))
+- *aX = screenWidth - kWindowPositionSlop;
++ if (*aX > (width - kWindowPositionSlop))
++ *aX = width - kWindowPositionSlop;
+ if (*aY < (kWindowPositionSlop - mBounds.height))
+ *aY = kWindowPositionSlop - mBounds.height;
+- if (*aY > (screenHeight - kWindowPositionSlop))
+- *aY = screenHeight - kWindowPositionSlop;
++ if (*aY > (height - kWindowPositionSlop))
++ *aY = height - kWindowPositionSlop;
+ } else {
+ if (*aX < 0)
+ *aX = 0;
+- if (*aX > (screenWidth - mBounds.width))
+- *aX = screenWidth - mBounds.width;
++ if (*aX > (width - mBounds.width))
++ *aX = width - mBounds.width;
+ if (*aY < 0)
+ *aY = 0;
+- if (*aY > (screenHeight - mBounds.height))
+- *aY = screenHeight - mBounds.height;
++ if (*aY > (height - mBounds.height))
++ *aY = height - mBounds.height;
+ }
+ }
+ return NS_OK;
+ }
+
+ void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
+ {
+ mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize);
+ mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize);
+
+ if (mShell) {
+ GdkGeometry geometry;
+- geometry.min_width = mSizeConstraints.mMinSize.width;
+- geometry.min_height = mSizeConstraints.mMinSize.height;
+- geometry.max_width = mSizeConstraints.mMaxSize.width;
+- geometry.max_height = mSizeConstraints.mMaxSize.height;
++ geometry.min_width = DevicePixelsToGdkCoordRoundUp(
++ mSizeConstraints.mMinSize.width);
++ geometry.min_height = DevicePixelsToGdkCoordRoundUp(
++ mSizeConstraints.mMinSize.height);
++ geometry.max_width = DevicePixelsToGdkCoordRoundUp(
++ mSizeConstraints.mMaxSize.width);
++ geometry.max_height = DevicePixelsToGdkCoordRoundUp(
++ mSizeConstraints.mMaxSize.height);
+
+ uint32_t hints = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
+ gtk_window_set_geometry_hints(GTK_WINDOW(mShell), nullptr,
+ &geometry, GdkWindowHints(hints));
+ }
+ }
+
+ NS_IMETHODIMP
+@@ -1156,21 +1170,23 @@ nsWindow::Move(double aX, double aY)
+ mBounds.x = x;
+ mBounds.y = y;
+
+ if (!mCreated)
+ return NS_OK;
+
+ mNeedsMove = false;
+
++ GdkPoint point = DevicePixelsToGdkPointRoundDown(nsIntPoint(x, y));
++
+ if (mIsTopLevel) {
+- gtk_window_move(GTK_WINDOW(mShell), x, y);
++ gtk_window_move(GTK_WINDOW(mShell), point.x, point.y);
+ }
+ else if (mGdkWindow) {
+- gdk_window_move(mGdkWindow, x, y);
++ gdk_window_move(mGdkWindow, point.x, point.y);
+ }
+
+ NotifyRollupGeometryChange();
+ return NS_OK;
+ }
+
+ NS_IMETHODIMP
+ nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
+@@ -1427,17 +1443,17 @@ nsWindow::SetFocus(bool aRaise)
+
+ NS_IMETHODIMP
+ nsWindow::GetScreenBounds(nsIntRect &aRect)
+ {
+ if (mIsTopLevel && mContainer) {
+ // use the point including window decorations
+ gint x, y;
+ gdk_window_get_root_origin(gtk_widget_get_window(GTK_WIDGET(mContainer)), &x, &y);
+- aRect.MoveTo(x, y);
++ aRect.MoveTo(GdkPointToDevicePixels({ x, y }));
+ }
+ else {
+ aRect.MoveTo(WidgetToScreenOffset());
+ }
+ // mBounds.Size() is the window bounds, not the window-manager frame
+ // bounds (bug 581863). gdk_window_get_frame_extents would give the
+ // frame bounds, but mBounds.Size() is returned here for consistency
+ // with Resize.
+@@ -1597,27 +1613,22 @@ nsWindow::SetCursor(imgIContainer* aCurs
+ }
+
+ NS_IMETHODIMP
+ nsWindow::Invalidate(const nsIntRect &aRect)
+ {
+ if (!mGdkWindow)
+ return NS_OK;
+
+- GdkRectangle rect;
+- rect.x = aRect.x;
+- rect.y = aRect.y;
+- rect.width = aRect.width;
+- rect.height = aRect.height;
++ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(aRect);
++ gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
+
+ LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
+ rect.x, rect.y, rect.width, rect.height));
+
+- gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
+-
+ return NS_OK;
+ }
+
+ void*
+ nsWindow::GetNativeData(uint32_t aDataType)
+ {
+ switch (aDataType) {
+ case NS_NATIVE_WINDOW:
+@@ -1745,17 +1756,17 @@ nsIntPoint
+ nsWindow::WidgetToScreenOffset()
+ {
+ gint x = 0, y = 0;
+
+ if (mGdkWindow) {
+ gdk_window_get_origin(mGdkWindow, &x, &y);
+ }
+
+- return nsIntPoint(x, y);
++ return GdkPointToDevicePixels({ x, y });
+ }
+
+ NS_IMETHODIMP
+ nsWindow::EnableDragDrop(bool aEnable)
+ {
+ return NS_OK;
+ }
+
+@@ -2037,17 +2048,19 @@ nsWindow::OnExposeEvent(cairo_t *cr)
+ #if (MOZ_WIDGET_GTK == 2)
+ if (!exposeRegion.Init(aEvent)) {
+ #else
+ if (!exposeRegion.Init(cr)) {
+ #endif
+ return FALSE;
+ }
+
+- nsIntRegion &region = exposeRegion.mRegion;
++ gint scale = GdkScaleFactor();
++ nsIntRegion& region = exposeRegion.mRegion;
++ region.ScaleRoundOut(scale, scale);
+
+ ClientLayerManager *clientLayers =
+ (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT)
+ ? static_cast<ClientLayerManager*>(GetLayerManager())
+ : nullptr;
+
+ if (clientLayers && mCompositorParent) {
+ // We need to paint to the screen even if nothing changed, since if we
+@@ -2377,31 +2390,34 @@ nsWindow::OnContainerUnrealize()
+
+ void
+ nsWindow::OnSizeAllocate(GtkAllocation *aAllocation)
+ {
+ LOG(("size_allocate [%p] %d %d %d %d\n",
+ (void *)this, aAllocation->x, aAllocation->y,
+ aAllocation->width, aAllocation->height));
+
+- nsIntSize size(aAllocation->width, aAllocation->height);
++ nsIntSize size = GdkRectToDevicePixels(*aAllocation).Size();
++
+ if (mBounds.Size() == size)
+ return;
+
++ nsIntRect rect;
++
+ // Invalidate the new part of the window now for the pending paint to
+ // minimize background flashes (GDK does not do this for external resizes
+ // of toplevels.)
+ if (mBounds.width < size.width) {
+- GdkRectangle rect =
+- { mBounds.width, 0, size.width - mBounds.width, size.height };
++ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
++ { mBounds.width, 0, size.width - mBounds.width, size.height });
+ gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
+ }
+ if (mBounds.height < size.height) {
+- GdkRectangle rect =
+- { 0, mBounds.height, size.width, size.height - mBounds.height };
++ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
++ { 0, mBounds.height, size.width, size.height - mBounds.height });
+ gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
+ }
+
+ mBounds.SizeTo(size);
+
+ if (!mGdkWindow)
+ return;
+
+@@ -3843,67 +3859,75 @@ nsWindow::SetWindowClass(const nsAString
+ nsMemory::Free(res_name);
+
+ return NS_OK;
+ }
+
+ void
+ nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint)
+ {
++ gint width = DevicePixelsToGdkCoordRoundUp(aWidth);
++ gint height = DevicePixelsToGdkCoordRoundUp(aHeight);
++
+ LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
+- aWidth, aHeight));
++ width, height));
+
+ // clear our resize flag
+ mNeedsResize = false;
+
+ if (mIsTopLevel) {
+- gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
++ gtk_window_resize(GTK_WINDOW(mShell), width, height);
+ }
+ else if (mContainer) {
+ GtkWidget *widget = GTK_WIDGET(mContainer);
+ GtkAllocation allocation, prev_allocation;
+ gtk_widget_get_allocation(widget, &prev_allocation);
+ allocation.x = prev_allocation.x;
+ allocation.y = prev_allocation.y;
+- allocation.width = aWidth;
+- allocation.height = aHeight;
++ allocation.width = width;
++ allocation.height = height;
+ gtk_widget_size_allocate(widget, &allocation);
+ }
+ else if (mGdkWindow) {
+- gdk_window_resize(mGdkWindow, aWidth, aHeight);
++ gdk_window_resize(mGdkWindow, width, height);
+ }
+ }
+
+ void
+ nsWindow::NativeResize(int32_t aX, int32_t aY,
+ int32_t aWidth, int32_t aHeight,
+ bool aRepaint)
+ {
++ gint width = DevicePixelsToGdkCoordRoundUp(aWidth);
++ gint height = DevicePixelsToGdkCoordRoundUp(aHeight);
++ gint x = DevicePixelsToGdkCoordRoundDown(aX);
++ gint y = DevicePixelsToGdkCoordRoundDown(aY);
++
+ mNeedsResize = false;
+ mNeedsMove = false;
+
+ LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
+- aX, aY, aWidth, aHeight));
++ x, y, width, height));
+
+ if (mIsTopLevel) {
+- // aX and aY give the position of the window manager frame top-left.
+- gtk_window_move(GTK_WINDOW(mShell), aX, aY);
++ // x and y give the position of the window manager frame top-left.
++ gtk_window_move(GTK_WINDOW(mShell), x, y);
+ // This sets the client window size.
+- gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
++ gtk_window_resize(GTK_WINDOW(mShell), width, height);
+ }
+ else if (mContainer) {
+ GtkAllocation allocation;
+- allocation.x = aX;
+- allocation.y = aY;
+- allocation.width = aWidth;
+- allocation.height = aHeight;
++ allocation.x = x;
++ allocation.y = y;
++ allocation.width = width;
++ allocation.height = height;
+ gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
+ }
+ else if (mGdkWindow) {
+- gdk_window_move_resize(mGdkWindow, aX, aY, aWidth, aHeight);
++ gdk_window_move_resize(mGdkWindow, x, y, width, height);
+ }
+ }
+
+ void
+ nsWindow::NativeShow(bool aAction)
+ {
+ if (aAction) {
+ // unset our flag now that our window has been shown
+@@ -6178,18 +6202,18 @@ nsWindow::GetThebesSurface(cairo_t *cr)
+ #if (MOZ_WIDGET_GTK == 2)
+ gdk_drawable_get_size(GDK_DRAWABLE(mGdkWindow), &width, &height);
+ #else
+ width = gdk_window_get_width(mGdkWindow);
+ height = gdk_window_get_height(mGdkWindow);
+ #endif
+
+ // Owen Taylor says this is the right thing to do!
+- width = std::min(32767, width);
+- height = std::min(32767, height);
++ width = std::min(32767, (int)std::ceil(GdkCoordToDevicePixels(width)));
++ height = std::min(32767, (int)std::ceil(GdkCoordToDevicePixels(height)));
+ gfxIntSize size(width, height);
+
+ GdkVisual *gdkVisual = gdk_window_get_visual(mGdkWindow);
+ Visual* visual = gdk_x11_visual_get_xvisual(gdkVisual);
+
+ # ifdef MOZ_HAVE_SHMIMAGE
+ bool usingShm = false;
+ if (nsShmImage::UseShm()) {
+@@ -6204,18 +6228,27 @@ nsWindow::GetThebesSurface(cairo_t *cr)
+ }
+ if (!usingShm)
+ # endif // MOZ_HAVE_SHMIMAGE
+ {
+ #if (MOZ_WIDGET_GTK == 3)
+ #if MOZ_TREE_CAIRO
+ #error "cairo-gtk3 target must be built with --enable-system-cairo"
+ #else
++ // Available as of Cairo 1.14
++ static void (*CairoSurfaceSetDeviceScalePtr) (cairo_surface_t*,double,double) =
++ (void (*)(cairo_surface_t*,double,double)) dlsym(RTLD_DEFAULT,
++ "cairo_surface_set_device_scale");
++
+ if (cr) {
+ cairo_surface_t *surf = cairo_get_target(cr);
++ if (GdkScaleFactor() > 1) {
++ // Disable auto-scaling on HiDPI devices, let mozilla manage it.
++ (*CairoSurfaceSetDeviceScalePtr)(surf, 1, 1);
++ }
+ if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
+ NS_NOTREACHED("Missing cairo target?");
+ return nullptr;
+ }
+ mThebesSurface = gfxASurface::Wrap(surf);
+ } else
+ #endif
+ #endif // (MOZ_WIDGET_GTK == 3)
+@@ -6286,16 +6319,18 @@ nsWindow::BeginMoveDrag(WidgetMouseEvent
+
+ GdkWindow *gdk_window;
+ gint button, screenX, screenY;
+ if (!GetDragInfo(aEvent, &gdk_window, &button, &screenX, &screenY)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // tell the window manager to start the move
++ screenX = DevicePixelsToGdkCoordRoundDown(screenX);
++ screenY = DevicePixelsToGdkCoordRoundDown(screenY);
+ gdk_window_begin_move_drag(gdk_window, button, screenX, screenY,
+ aEvent->time);
+
+ return NS_OK;
+ }
+
+ NS_IMETHODIMP
+ nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent,
+@@ -6377,16 +6412,80 @@ nsWindow::ClearCachedResources()
+ for (GList* list = children; list; list = list->next) {
+ nsWindow* window = get_window_for_gdk_window(GDK_WINDOW(list->data));
+ if (window) {
+ window->ClearCachedResources();
+ }
+ }
+ }
+
++gint
++nsWindow::GdkScaleFactor()
++{
++#if (MOZ_WIDGET_GTK >= 3)
++ // Available as of GTK 3.10+
++ static gint (*GdkWindowGetScaleFactorPtr) (GdkWindow*) =
++ (gint (*)(GdkWindow*)) dlsym(RTLD_DEFAULT,
++ "gdk_window_get_scale_factor");
++ if (GdkWindowGetScaleFactorPtr)
++ return (*GdkWindowGetScaleFactorPtr)(mGdkWindow);
++#endif
++ return 1;
++}
++
++
++gint
++nsWindow::DevicePixelsToGdkCoordRoundUp(int pixels) {
++ return NSToIntCeil(float(pixels)/float(GdkScaleFactor()));
++}
++
++gint
++nsWindow::DevicePixelsToGdkCoordRoundDown(int pixels) {
++ return NSToIntFloor(float(pixels)/float(GdkScaleFactor()));
++}
++
++GdkPoint
++nsWindow::DevicePixelsToGdkPointRoundDown(nsIntPoint point) {
++ float scale = GdkScaleFactor();
++ return { NSToIntFloor(float(point.x)/scale),
++ NSToIntFloor(float(point.y)/scale) };
++}
++
++GdkRectangle
++nsWindow::DevicePixelsToGdkRectRoundOut(nsIntRect rect) {
++ gint scale = GdkScaleFactor();
++ nsIntRect scaledRect = rect;
++ scaledRect.ScaleInverseRoundOut(scale);
++ return { scaledRect.x,
++ scaledRect.y,
++ scaledRect.width,
++ scaledRect.height };
++}
++
++int
++nsWindow::GdkCoordToDevicePixels(gint coords) {
++ return coords * GdkScaleFactor();
++}
++
++nsIntPoint
++nsWindow::GdkPointToDevicePixels(GdkPoint point) {
++ gint scale = GdkScaleFactor();
++ return nsIntPoint(point.x * scale,
++ point.y * scale);
++}
++
++nsIntRect
++nsWindow::GdkRectToDevicePixels(GdkRectangle rect) {
++ gint scale = GdkScaleFactor();
++ return nsIntRect(rect.x * scale,
++ rect.y * scale,
++ rect.width * scale,
++ rect.height * scale);
++}
++
+ nsresult
+ nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
+ uint32_t aNativeMessage,
+ uint32_t aModifierFlags)
+ {
+ if (!mGdkWindow) {
+ return NS_OK;
+ }
+diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
+--- a/widget/gtk/nsWindow.h
++++ b/widget/gtk/nsWindow.h
+@@ -92,16 +92,17 @@ public:
+ NS_IMETHOD Create(nsIWidget *aParent,
+ nsNativeWidget aNativeParent,
+ const nsIntRect &aRect,
+ nsDeviceContext *aContext,
+ nsWidgetInitData *aInitData);
+ NS_IMETHOD Destroy(void);
+ virtual nsIWidget *GetParent();
+ virtual float GetDPI();
++ virtual double GetDefaultScaleInternal();
+ virtual nsresult SetParent(nsIWidget* aNewParent);
+ NS_IMETHOD SetModal(bool aModal);
+ virtual bool IsVisible() const;
+ NS_IMETHOD ConstrainPosition(bool aAllowSlop,
+ int32_t *aX,
+ int32_t *aY);
+ virtual void SetSizeConstraints(const SizeConstraints& aConstraints);
+ NS_IMETHOD Move(double aX,
+@@ -468,16 +469,30 @@ private:
+ * 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
+ * ancestor widget's instance. So, one set of IM contexts is created for
+ * all windows in a hierarchy. If the children are released after the top
+ * level window is released, the children still have a valid pointer,
+ * however, IME doesn't work at that time.
+ */
+ nsRefPtr<nsGtkIMModule> mIMModule;
++
++ // HiDPI scale conversion
++ gint GdkScaleFactor();
++
++ // To GDK
++ gint DevicePixelsToGdkCoordRoundUp(int pixels);
++ gint DevicePixelsToGdkCoordRoundDown(int pixels);
++ GdkPoint DevicePixelsToGdkPointRoundDown(nsIntPoint point);
++ GdkRectangle DevicePixelsToGdkRectRoundOut(nsIntRect rect);
++
++ // From GDK
++ int GdkCoordToDevicePixels(gint coords);
++ nsIntPoint GdkPointToDevicePixels(GdkPoint point);
++ nsIntRect GdkRectToDevicePixels(GdkRectangle rect);
+ };
+
+ class nsChildWindow : public nsWindow {
+ public:
+ nsChildWindow();
+ ~nsChildWindow();
+ };
+
bgstack15