[firefox] Gtk3 - added patch for HiDPI support (mozbz#975919)

Martin Stransky stransky at fedoraproject.org
Mon Jan 19 17:32:34 UTC 2015


commit c498dd1344ac4ea6fb0e7c7f789c396db5e57121
Author: Martin Stransky <stransky at redhat.com>
Date:   Mon Jan 19 18:32:52 2015 +0100

    Gtk3 - added patch for HiDPI support (mozbz#975919)

 firefox.spec                    |    9 +-
 mozilla-975919-gtk3-hidpi.patch |  798 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 805 insertions(+), 2 deletions(-)
---
diff --git a/firefox.spec b/firefox.spec
index ca3a52a..4f2595b 100644
--- a/firefox.spec
+++ b/firefox.spec
@@ -107,7 +107,7 @@
 Summary:        Mozilla Firefox Web browser
 Name:           firefox
 Version:        35.0
-Release:        4%{?pre_tag}%{?dist}
+Release:        5%{?pre_tag}%{?dist}
 URL:            http://www.mozilla.org/projects/firefox/
 License:        MPLv1.1 or GPLv2+ or LGPLv2+
 Group:          Applications/Internet
@@ -156,6 +156,7 @@ Patch409:        mozilla-1073117-entry-button-size.patch
 Patch410:        mozilla-1073117-button-focus.patch
 Patch411:        mozilla-1073117-focus-sizes.patch
 Patch412:        mozilla-1073117-no-gap-tab.patch
+Patch413:        mozilla-975919-gtk3-hidpi.patch
 
 %if %{official_branding}
 # Required by Mozilla Corporation
@@ -314,6 +315,7 @@ cd %{tarballdir}
 %patch410 -p1 -b .1073117-button-focus
 %patch411 -p1 -b .1073117-focus-sizes
 %patch412 -p1 -b .1073117-no-gap-tab
+%patch413 -p1 -b .975919-gtk3-hidpi
 %endif
 
 %if %{official_branding}
@@ -767,9 +769,12 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
 #---------------------------------------------------------------------
 
 %changelog
+* Mon Jan 19 2015 Martin Stransky <stransky at redhat.com> - 35.0-5
+- Enable release build config
+- Gtk3 - added patch for HiDPI support (mozbz#975919)
+
 * Mon Jan 19 2015 Martin Stransky <stransky at redhat.com> - 35.0-4
 - Gtk3 - fixed tabs rendering
-- Enable release build config
 
 * Wed Jan 14 2015 Martin Stransky <stransky at redhat.com> - 35.0-3
 - Gtk3 - replaced obsoleted focus properties
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 at 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();
+ };
+ 


More information about the scm-commits mailing list