Bug 890156 - patch 1 - Add nsIWidget::GetDesktopToDeviceScale() method. r=emk
authorJonathan Kew <jkew@mozilla.com>
Fri, 04 Dec 2015 16:58:05 +0000
changeset 279788 cc09fb02f2c9191098ff2ab9ba97ed57162e806b
parent 279787 f4b5097c00c6373b07ec3140a1c0741732beaeda
child 279789 20c8f6d967569c5f878621c6ee15cbc1f3c51017
push id19299
push userryanvm@gmail.com
push dateThu, 14 Jan 2016 01:28:35 +0000
treeherderb2g-inbound@3c473ad89a25 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemk
bugs890156
milestone46.0a1
Bug 890156 - patch 1 - Add nsIWidget::GetDesktopToDeviceScale() method. r=emk
widget/cocoa/nsChildView.h
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/nsIWidget.h
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -385,16 +385,20 @@ public:
   // Returns the "backing scale factor" of the view's window, which is the
   // ratio of pixels in the window's backing store to Cocoa points. Prior to
   // HiDPI support in OS X 10.7, this was always 1.0, but in HiDPI mode it
   // will be 2.0 (and might potentially other values as screen resolutions
   // evolve). This gives the relationship between what Gecko calls "device
   // pixels" and the Cocoa "points" coordinate system.
   CGFloat                 BackingScaleFactor() const;
 
+  mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() final {
+    return mozilla::DesktopToLayoutDeviceScale(BackingScaleFactor());
+  }
+
   // Call if the window's backing scale factor changes - i.e., it is moved
   // between HiDPI and non-HiDPI screens
   void                    BackingScaleFactorChanged();
 
   virtual double          GetDefaultScaleInternal() override;
 
   virtual int32_t         RoundsWidgetCoordinatesTo() override;
 
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -319,16 +319,20 @@ public:
     NS_IMETHOD              SetCursor(nsCursor aCursor) override;
     NS_IMETHOD              SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY) override;
 
     CGFloat                 BackingScaleFactor();
     void                    BackingScaleFactorChanged();
     virtual double          GetDefaultScaleInternal() override;
     virtual int32_t         RoundsWidgetCoordinatesTo() override;
 
+    mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() final {
+      return mozilla::DesktopToLayoutDeviceScale(BackingScaleFactor());
+    }
+
     NS_IMETHOD              SetTitle(const nsAString& aTitle) override;
 
     NS_IMETHOD Invalidate(const LayoutDeviceIntRect& aRect) override;
     virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
     virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nullptr) override;
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -286,34 +286,35 @@ nsresult nsCocoaWindow::Create(nsIWidget
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mWindowType == eWindowType_popup) {
     if (aInitData->mMouseTransparent) {
       [mWindow setIgnoresMouseEvents:YES];
     }
     // now we can convert newBounds to device pixels for the window we created,
     // as the child view expects a rect expressed in the dev pix of its parent
-    DesktopToLayoutDeviceScale scale(BackingScaleFactor());
-    return CreatePopupContentView(RoundedToInt(newBounds * scale));
+    LayoutDeviceIntRect devRect =
+      RoundedToInt(newBounds * GetDesktopToDeviceScale());
+    return CreatePopupContentView(devRect);
   }
 
   mIsAnimationSuppressed = aInitData->mIsAnimationSuppressed;
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 nsresult nsCocoaWindow::Create(nsIWidget* aParent,
                                nsNativeWidget aNativeParent,
                                const LayoutDeviceIntRect& aRect,
                                nsWidgetInitData* aInitData)
 {
-  DesktopToLayoutDeviceScale scale(GetDefaultScaleInternal());
-  DesktopIntRect desktopRect = RoundedToInt(aRect / scale);
+  DesktopIntRect desktopRect =
+    RoundedToInt(aRect / GetDesktopToDeviceScale());
   return Create(aParent, aNativeParent, desktopRect, aInitData);
 }
 
 static unsigned int WindowMaskForBorderStyle(nsBorderStyle aBorderStyle)
 {
   bool allOrDefault = (aBorderStyle == eBorderStyle_all ||
                          aBorderStyle == eBorderStyle_default);
 
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -826,34 +826,39 @@ nsBaseWidget::PerformFullscreenTransitio
 //
 //-------------------------------------------------------------------------
 NS_IMETHODIMP nsBaseWidget::MakeFullScreen(bool aFullScreen, nsIScreen* aScreen)
 {
   HideWindowChrome(aFullScreen);
 
   if (aFullScreen) {
     if (!mOriginalBounds) {
-      mOriginalBounds = new CSSIntRect();
+      mOriginalBounds = new LayoutDeviceIntRect();
     }
-    *mOriginalBounds = GetScaledScreenBounds();
+    GetScreenBounds(*mOriginalBounds);
 
     // Move to top-left corner of screen and size to the screen dimensions
     nsCOMPtr<nsIScreen> screen = aScreen;
     if (!screen) {
       screen = GetWidgetScreen();
     }
     if (screen) {
       int32_t left, top, width, height;
       if (NS_SUCCEEDED(screen->GetRectDisplayPix(&left, &top, &width, &height))) {
         Resize(left, top, width, height, true);
       }
     }
   } else if (mOriginalBounds) {
-    Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
-           mOriginalBounds->height, true);
+    if (BoundsUseDesktopPixels()) {
+      DesktopRect deskRect = *mOriginalBounds / GetDesktopToDeviceScale();
+      Resize(deskRect.x, deskRect.y, deskRect.width, deskRect.height, true);
+    } else {
+      Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
+             mOriginalBounds->height, true);
+    }
   }
 
   return NS_OK;
 }
 
 nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
     nsBaseWidget* aWidget, gfxContext* aTarget,
     BufferMode aDoubleBuffering, ScreenRotation aRotation)
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -181,16 +181,21 @@ public:
   // applies its GetDefaultScale() value to them before using them as mBounds
   // etc (which are always stored in device pixels).
   // Note that APIs that -get- the widget's position/size/bounds, rather than
   // -setting- them (i.e. moving or resizing the widget) will always return
   // values in the widget's device pixels.
   bool                    BoundsUseDesktopPixels() const {
     return mWindowType <= eWindowType_popup;
   }
+  // Default implementation, to be overridden by platforms where desktop coords
+  // are virtualized and may not correspond to device pixels on the screen.
+  mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override {
+    return mozilla::DesktopToLayoutDeviceScale(1.0);
+  }
   NS_IMETHOD              MoveClient(double aX, double aY) override;
   NS_IMETHOD              ResizeClient(double aWidth, double aHeight, bool aRepaint) override;
   NS_IMETHOD              ResizeClient(double aX, double aY, double aWidth, double aHeight, bool aRepaint) override;
   NS_IMETHOD              GetBounds(LayoutDeviceIntRect& aRect) override;
   NS_IMETHOD              GetClientBounds(LayoutDeviceIntRect& aRect) override;
   NS_IMETHOD              GetScreenBounds(LayoutDeviceIntRect& aRect) override;
   NS_IMETHOD              GetRestoredBounds(LayoutDeviceIntRect& aRect) override;
   NS_IMETHOD              GetNonClientMargins(LayoutDeviceIntMargin& aMargins) override;
@@ -509,17 +514,17 @@ protected:
   RefPtr<APZCTreeManager> mAPZC;
   RefPtr<APZEventState> mAPZEventState;
   SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback;
   RefPtr<WidgetShutdownObserver> mShutdownObserver;
   RefPtr<TextEventDispatcher> mTextEventDispatcher;
   nsCursor          mCursor;
   nsBorderStyle     mBorderStyle;
   nsIntRect         mBounds;
-  CSSIntRect*       mOriginalBounds;
+  LayoutDeviceIntRect* mOriginalBounds;
   // When this pointer is null, the widget is not clipped
   mozilla::UniquePtr<LayoutDeviceIntRect[]> mClipRects;
   uint32_t          mClipRectCount;
   nsSizeMode        mSizeMode;
   nsPopupLevel      mPopupLevel;
   nsPopupType       mPopupType;
   SizeConstraints   mSizeConstraints;
 
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -424,20 +424,18 @@ class nsIWidget : public nsISupports {
      * mapping is not straightforward or the native platform needs to use the
      * desktop pixel values directly.
      */
     NS_IMETHOD Create(nsIWidget* aParent,
                       nsNativeWidget aNativeParent,
                       const DesktopIntRect& aRect,
                       nsWidgetInitData* aInitData = nullptr)
     {
-        // GetDefaultScaleInternal() here is a placeholder, to be replaced by
-        // GetDesktopToDeviceScale in a later patch
-        mozilla::DesktopToLayoutDeviceScale scale(GetDefaultScaleInternal());
-        LayoutDeviceIntRect devPixRect = RoundedToInt(aRect * scale);
+        LayoutDeviceIntRect devPixRect =
+          RoundedToInt(aRect * GetDesktopToDeviceScale());
         return Create(aParent, aNativeParent, devPixRect, aInitData);
     }
 
     /**
      * Allocate, initialize, and return a widget that is a child of
      * |this|.  The returned widget (if nonnull) has gone through the
      * equivalent of CreateInstance(widgetCID) + Create(...).
      *
@@ -542,16 +540,23 @@ class nsIWidget : public nsISupports {
 
     /**
      * Return the physical DPI of the screen containing the window ...
      * the number of device pixels per inch.
      */
     virtual float GetDPI() = 0;
 
     /**
+     * Return the scaling factor between device pixels and the platform-
+     * dependent "desktop pixels" used to manage window positions on a
+     * potentially multi-screen, mixed-resolution desktop.
+     */
+    virtual mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() = 0;
+
+    /**
      * Returns the CompositorVsyncDispatcher associated with this widget
      */
     virtual CompositorVsyncDispatcher* GetCompositorVsyncDispatcher() = 0;
 
     /**
      * Return the default scale factor for the window. This is the
      * default number of device pixels per CSS pixel to use. This should
      * depend on OS/platform settings such as the Mac's "UI scale factor"
@@ -853,17 +858,17 @@ class nsIWidget : public nsISupports {
      * relative to its parent widget.
      *
      * @param aRect   On return it holds the  x, y, width and height of
      *                this widget.
      */
     NS_IMETHOD GetBounds(LayoutDeviceIntRect& aRect) = 0;
 
     /**
-     * Get this widget's outside dimensions in global coordinates. This
+     * Get this widget's outside dimensions in device coordinates. This
      * includes any title bar on the window.
      *
      * @param aRect   On return it holds the  x, y, width and height of
      *                this widget.
      */
     NS_IMETHOD GetScreenBounds(LayoutDeviceIntRect& aRect) = 0;
 
     /**
@@ -873,28 +878,28 @@ class nsIWidget : public nsISupports {
      * This method will fail if the size mode is not nsSizeMode_Normal and
      * the platform doesn't have the ability.
      * This method will always succeed if the current size mode is
      * nsSizeMode_Normal.
      *
      * @param aRect   On return it holds the  x, y, width and height of
      *                this widget.
      */
-    NS_IMETHOD GetRestoredBounds(mozilla::LayoutDeviceIntRect& aRect) = 0;
+    NS_IMETHOD GetRestoredBounds(LayoutDeviceIntRect& aRect) = 0;
 
     /**
      * Get this widget's client area bounds, if the window has a 3D border
      * appearance this returns the area inside the border. The position is the
      * position of the client area relative to the client area of the parent
      * widget (for root widgets and popup widgets it is in screen coordinates).
      *
      * @param aRect   On return it holds the  x. y, width and height of
      *                the client area of this widget.
      */
-    NS_IMETHOD GetClientBounds(mozilla::LayoutDeviceIntRect& aRect) = 0;
+    NS_IMETHOD GetClientBounds(LayoutDeviceIntRect& aRect) = 0;
 
     /**
      * Get the non-client area dimensions of the window.
      */
     NS_IMETHOD GetNonClientMargins(LayoutDeviceIntMargin& aMargins) = 0;
 
     /**
      * Sets the non-client area dimensions of the window. Pass -1 to restore