Bug 1350643 - Part 2: Add nsIScreen::GetDPI. draft
authorSamael Wang <freesamael@gmail.com>
Fri, 12 May 2017 18:02:49 +0800
changeset 583512 9bf75f8f201402c1f1423e1491761899f35f8cd6
parent 583511 df91939ad189c8a1c1aeb1779481c94366bd6e65
child 583513 099b8ee2847cb29d36396f0341eaf6f71eac964c
push id60419
push userbmo:sawang@mozilla.com
push dateWed, 24 May 2017 06:09:38 +0000
bugs1350643
milestone55.0a1
Bug 1350643 - Part 2: Add nsIScreen::GetDPI. MozReview-Commit-ID: 2tuC4cnowwa
dom/ipc/DOMTypes.ipdlh
widget/Screen.cpp
widget/Screen.h
widget/ScreenManager.cpp
widget/cocoa/ScreenHelperCocoa.mm
widget/gtk/ScreenHelperGTK.cpp
widget/nsBaseScreen.cpp
widget/nsBaseScreen.h
widget/nsIScreen.idl
widget/windows/ScreenHelperWin.cpp
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -198,12 +198,13 @@ struct ScreenDetails {
   LayoutDeviceIntRect rect;
   DesktopIntRect rectDisplayPix;
   LayoutDeviceIntRect availRect;
   DesktopIntRect availRectDisplayPix;
   int32_t pixelDepth;
   int32_t colorDepth;
   DesktopToLayoutDeviceScale contentsScaleFactor;
   CSSToLayoutDeviceScale defaultCSSScaleFactor;
+  float dpi;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/widget/Screen.cpp
+++ b/widget/Screen.cpp
@@ -11,58 +11,62 @@
 namespace mozilla {
 namespace widget {
 
 NS_IMPL_ISUPPORTS(Screen, nsIScreen)
 
 Screen::Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
                uint32_t aPixelDepth, uint32_t aColorDepth,
                DesktopToLayoutDeviceScale aContentsScale,
-               CSSToLayoutDeviceScale aDefaultCssScale)
+               CSSToLayoutDeviceScale aDefaultCssScale,
+               float aDPI)
   : mRect(aRect)
   , mAvailRect(aAvailRect)
   , mRectDisplayPix(RoundedToInt(aRect / aContentsScale))
   , mAvailRectDisplayPix(RoundedToInt(aAvailRect / aContentsScale))
   , mPixelDepth(aPixelDepth)
   , mColorDepth(aColorDepth)
   , mContentsScale(aContentsScale)
   , mDefaultCssScale(aDefaultCssScale)
+  , mDPI(aDPI)
 {
 }
 
 Screen::Screen(const mozilla::dom::ScreenDetails& aScreen)
   : mRect(aScreen.rect())
   , mAvailRect(aScreen.availRect())
   , mRectDisplayPix(aScreen.rectDisplayPix())
   , mAvailRectDisplayPix(aScreen.availRectDisplayPix())
   , mPixelDepth(aScreen.pixelDepth())
   , mColorDepth(aScreen.colorDepth())
   , mContentsScale(aScreen.contentsScaleFactor())
   , mDefaultCssScale(aScreen.defaultCSSScaleFactor())
+  , mDPI(aScreen.dpi())
 {
 }
 
 Screen::Screen(const Screen& aOther)
   : mRect(aOther.mRect)
   , mAvailRect(aOther.mAvailRect)
   , mRectDisplayPix(aOther.mRectDisplayPix)
   , mAvailRectDisplayPix(aOther.mAvailRectDisplayPix)
   , mPixelDepth(aOther.mPixelDepth)
   , mColorDepth(aOther.mColorDepth)
   , mContentsScale(aOther.mContentsScale)
   , mDefaultCssScale(aOther.mDefaultCssScale)
+  , mDPI(aOther.mDPI)
 {
 }
 
 mozilla::dom::ScreenDetails
 Screen::ToScreenDetails()
 {
   return mozilla::dom::ScreenDetails(
     mRect, mRectDisplayPix, mAvailRect, mAvailRectDisplayPix,
-    mPixelDepth, mColorDepth, mContentsScale, mDefaultCssScale);
+    mPixelDepth, mColorDepth, mContentsScale, mDefaultCssScale, mDPI);
 }
 
 NS_IMETHODIMP
 Screen::GetRect(int32_t* aOutLeft,
                 int32_t* aOutTop,
                 int32_t* aOutWidth,
                 int32_t* aOutHeight)
 {
@@ -140,10 +144,17 @@ Screen::GetDefaultCSSScaleFactor(double 
   if (scale > 0.0) {
     *aOutScale = scale;
   } else {
     *aOutScale = mDefaultCssScale.scale;
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+Screen::GetDpi(float* aDPI)
+{
+  *aDPI = mDPI;
+  return NS_OK;
+}
+
 } // namespace widget
 } // namespace mozilla
--- a/widget/Screen.h
+++ b/widget/Screen.h
@@ -24,32 +24,34 @@ class Screen final : public nsIScreen
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISCREEN
 
   Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
          uint32_t aPixelDepth, uint32_t aColorDepth,
          DesktopToLayoutDeviceScale aContentsScale,
-         CSSToLayoutDeviceScale aDefaultCssScale);
+         CSSToLayoutDeviceScale aDefaultCssScale,
+         float dpi);
   explicit Screen(const mozilla::dom::ScreenDetails& aScreenDetails);
   Screen(const Screen& aOther);
 
   mozilla::dom::ScreenDetails ToScreenDetails();
 
 private:
   virtual ~Screen() {}
 
   LayoutDeviceIntRect mRect;
   LayoutDeviceIntRect mAvailRect;
   DesktopIntRect mRectDisplayPix;
   DesktopIntRect mAvailRectDisplayPix;
   uint32_t mPixelDepth;
   uint32_t mColorDepth;
   DesktopToLayoutDeviceScale mContentsScale;
   CSSToLayoutDeviceScale mDefaultCssScale;
+  float mDPI;
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif
 
--- a/widget/ScreenManager.cpp
+++ b/widget/ScreenManager.cpp
@@ -124,17 +124,18 @@ ScreenManager::ScreenForRect(int32_t aX,
                              nsIScreen** aOutScreen)
 {
   if (mScreenList.IsEmpty()) {
     MOZ_LOG(sScreenLog, LogLevel::Warning,
             ("No screen available. This can happen in xpcshell."));
     RefPtr<Screen> ret = new Screen(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
                                     0, 0,
                                     DesktopToLayoutDeviceScale(),
-                                    CSSToLayoutDeviceScale());
+                                    CSSToLayoutDeviceScale(),
+                                    96 /* dpi */);
     ret.forget(aOutScreen);
     return NS_OK;
   }
 
   // Optimize for the common case. If the number of screens is only
   // one then just return the primary screen.
   if (mScreenList.Length() == 1) {
     return GetPrimaryScreen(aOutScreen);
@@ -173,17 +174,18 @@ NS_IMETHODIMP
 ScreenManager::GetPrimaryScreen(nsIScreen** aPrimaryScreen)
 {
   if (mScreenList.IsEmpty()) {
     MOZ_LOG(sScreenLog, LogLevel::Warning,
             ("No screen available. This can happen in xpcshell."));
     RefPtr<Screen> ret = new Screen(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
                                     0, 0,
                                     DesktopToLayoutDeviceScale(),
-                                    CSSToLayoutDeviceScale());
+                                    CSSToLayoutDeviceScale(),
+                                    96 /* dpi */);
     ret.forget(aPrimaryScreen);
     return NS_OK;
   }
 
   RefPtr<Screen> ret = mScreenList[0];
   ret.forget(aPrimaryScreen);
   return NS_OK;
 }
--- a/widget/cocoa/ScreenHelperCocoa.mm
+++ b/widget/cocoa/ScreenHelperCocoa.mm
@@ -89,24 +89,32 @@ MakeScreen(NSScreen* aScreen)
   NSRect frame = [aScreen frame];
   LayoutDeviceIntRect rect =
     nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale);
   frame = [aScreen visibleFrame];
   LayoutDeviceIntRect availRect =
     nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale);
   NSWindowDepth depth = [aScreen depth];
   uint32_t pixelDepth = NSBitsPerPixelFromDepth(depth);
-
-  MOZ_LOG(sScreenLog, LogLevel::Debug, ("New screen [%d %d %d %d %d %f]",
+  CGDirectDisplayID displayID =
+    [[[aScreen deviceDescription] objectForKey:@"NSScreenNumber"] intValue];
+  float dpi = 96.0f;
+  CGFloat heightMM = ::CGDisplayScreenSize(displayID).height;
+  if (heightMM > 0) {
+    dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
+  }
+  MOZ_LOG(sScreenLog, LogLevel::Debug, ("New screen [%d %d %d %d %d %f %f]",
                                         rect.x, rect.y, rect.width, rect.height,
-                                        pixelDepth, contentsScaleFactor.scale));
+                                        pixelDepth, contentsScaleFactor.scale,
+                                        dpi));
 
   RefPtr<Screen> screen = new Screen(rect, availRect,
                                      pixelDepth, pixelDepth,
-                                     contentsScaleFactor, defaultCssScaleFactor);
+                                     contentsScaleFactor, defaultCssScaleFactor,
+                                     dpi);
   return screen.forget();
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nullptr);
 }
 
 void
 ScreenHelperCocoa::RefreshScreens()
 {
--- a/widget/gtk/ScreenHelperGTK.cpp
+++ b/widget/gtk/ScreenHelperGTK.cpp
@@ -137,30 +137,41 @@ MakeScreen(GdkScreen* aScreen, gint aMon
   LayoutDeviceIntRect rect(monitor.x * gdkScaleFactor,
                            monitor.y * gdkScaleFactor,
                            monitor.width * gdkScaleFactor,
                            monitor.height * gdkScaleFactor);
   LayoutDeviceIntRect availRect(workarea.x * gdkScaleFactor,
                                 workarea.y * gdkScaleFactor,
                                 workarea.width * gdkScaleFactor,
                                 workarea.height * gdkScaleFactor);
+
   GdkVisual * visual = gdk_screen_get_system_visual(aScreen);
   uint32_t pixelDepth = gdk_visual_get_depth(visual);
+
   DesktopToLayoutDeviceScale contentsScale(gdkScaleFactor);
   CSSToLayoutDeviceScale defaultCssScale(
     gdkScaleFactor * gfxPlatformGtk::GetFontScaleFactor());
 
+  // XXX: I once kept getting -1 until reboot when writing this, so we'd better
+  // have a default value for fallback.
+  float dpi = 96.0f;
+  gint heightMM = gdk_screen_get_monitor_height_mm(aScreen, aMonitorNum);
+  if (heightMM > 0) {
+    dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
+  }
+
   MOZ_LOG(sScreenLog, LogLevel::Debug,
-           ("New screen [%d %d %d %d (%d %d %d %d) %d %f]",
+           ("New screen [%d %d %d %d (%d %d %d %d) %d %f %f]",
             rect.x, rect.y, rect.width, rect.height,
             availRect.x, availRect.y, availRect.width, availRect.height,
-            pixelDepth, defaultCssScale.scale));
+            pixelDepth, defaultCssScale.scale, dpi));
   RefPtr<Screen> screen = new Screen(rect, availRect,
                                      pixelDepth, pixelDepth,
-                                     contentsScale, defaultCssScale);
+                                     contentsScale, defaultCssScale,
+                                     dpi);
   return screen.forget();
 }
 
 void
 ScreenHelperGTK::RefreshScreens()
 {
   MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing screens"));
   AutoTArray<RefPtr<Screen>, 4> screenList;
--- a/widget/nsBaseScreen.cpp
+++ b/widget/nsBaseScreen.cpp
@@ -39,8 +39,15 @@ nsBaseScreen::GetContentsScaleFactor(dou
 }
 
 NS_IMETHODIMP
 nsBaseScreen::GetDefaultCSSScaleFactor(double* aScaleFactor)
 {
   *aScaleFactor = 1.0;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsBaseScreen::GetDpi(float* aDPI)
+{
+  *aDPI = 96;
+  return NS_OK;
+}
--- a/widget/nsBaseScreen.h
+++ b/widget/nsBaseScreen.h
@@ -27,13 +27,15 @@ public:
                                int32_t *outWidth, int32_t *outHeight) override;
   NS_IMETHOD GetAvailRectDisplayPix(int32_t *outLeft,  int32_t *outTop,
                                     int32_t *outWidth, int32_t *outHeight) override;
 
   NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor) override;
 
   NS_IMETHOD GetDefaultCSSScaleFactor(double* aScaleFactor) override;
 
+  NS_IMETHOD GetDpi(float* aDPI) override;
+
 protected:
   virtual ~nsBaseScreen();
 };
 
 #endif // nsBaseScreen_h
--- a/widget/nsIScreen.idl
+++ b/widget/nsIScreen.idl
@@ -52,9 +52,14 @@ interface nsIScreen : nsISupports
   readonly attribute double contentsScaleFactor;
 
   /**
    * The default number of device pixels per unscaled CSS pixel for this
    * screen. This is probably what contentsScaleFactor originally meant
    * to be, prior to confusion between CSS pixels and desktop pixel units.
    */
   readonly attribute double defaultCSSScaleFactor;
+
+  /**
+   * The DPI of the screen.
+   */
+  readonly attribute float dpi;
 };
--- a/widget/windows/ScreenHelperWin.cpp
+++ b/widget/windows/ScreenHelperWin.cpp
@@ -43,22 +43,29 @@ CollectMonitors(HMONITOR aMon, HDC hDCSc
                                 info.rcWork.bottom - info.rcWork.top);
   uint32_t pixelDepth = ::GetDeviceCaps(hDCScreen, BITSPIXEL);
   if (pixelDepth == 32) {
     // If a device uses 32 bits per pixel, it's still only using 8 bits
     // per color component, which is what our callers want to know.
     // (Some devices report 32 and some devices report 24.)
     pixelDepth = 24;
   }
-  MOZ_LOG(sScreenLog, LogLevel::Debug, ("New screen [%d %d %d %d %d %f]",
+  float dpi = 96.0f;
+  int heightMM = ::GetDeviceCaps(hDCScreen, VERTSIZE);
+  if (heightMM > 0) {
+    dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
+  }
+  MOZ_LOG(sScreenLog, LogLevel::Debug, ("New screen [%d %d %d %d %d %f %f]",
                                         rect.x, rect.y, rect.width, rect.height,
-                                        pixelDepth, defaultCssScaleFactor.scale));
+                                        pixelDepth, defaultCssScaleFactor.scale,
+                                        dpi));
   auto screen = new Screen(rect, availRect,
                            pixelDepth, pixelDepth,
-                           contentsScaleFactor, defaultCssScaleFactor);
+                           contentsScaleFactor, defaultCssScaleFactor,
+                           dpi);
   if (info.dwFlags & MONITORINFOF_PRIMARY) {
     // The primary monitor must be the first element of the screen list.
     screens->InsertElementAt(0, Move(screen));
   } else {
     screens->AppendElement(Move(screen));
   }
   return TRUE;
 }