Bug 1194751 - Part 4. Add ScreenManager and Screen classes. r=jimm,karlt,mconley
authorKan-Ru Chen <kanru@kanru.info>
Tue, 14 Mar 2017 18:44:54 +0800
changeset 349720 b18a43068dc6d63c4f5d10d288614a4282215acc
parent 349719 ace97d197b699443091db818a2e18222a7065bb0
child 349721 4be4367d022d7b97eb90b503d6eef186cdb0309f
push id31559
push usercbook@mozilla.com
push dateMon, 27 Mar 2017 10:55:45 +0000
treeherdermozilla-central@7ac8812719a1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, karlt, mconley
bugs1194751
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1194751 - Part 4. Add ScreenManager and Screen classes. r=jimm,karlt,mconley ScreenManager takes the common parts of ScreenManagerWin, ScreenManagerGtk and ScreenManagerCocoa. It caches all screen information in the new Screen class. The cache are updated when the OS notifies there is a monitor config change; all changes will be pushed to content processes via PContent (patch part 6.) Screen is a pure data object. All platform dependent logic will be in widget specific helper classes. Each process will have a singleton ScreenManager object. Widget specific helper object is held alive by the ScreenManager when necessary, for example to receive updates from the OS. The change to to VsyncDispatcher.cpp is due to unified-build bustage. ScreenManager::ScreenForNativeWidget is not implemented because it will be removed in patch part 6. MozReview-Commit-ID: 5ezytAXSqHp *** fixup MozReview-Commit-ID: DQtq3UVZytA
widget/Screen.cpp
widget/Screen.h
widget/ScreenManager.cpp
widget/ScreenManager.h
widget/VsyncDispatcher.cpp
widget/moz.build
new file mode 100644
--- /dev/null
+++ b/widget/Screen.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* 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 "Screen.h"
+
+namespace mozilla {
+namespace widget {
+
+NS_IMPL_ISUPPORTS(Screen, nsIScreen)
+
+static uint32_t sScreenId = 0;
+
+Screen::Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
+               uint32_t aPixelDepth, uint32_t aColorDepth,
+               DesktopToLayoutDeviceScale aContentsScale,
+               CSSToLayoutDeviceScale aDefaultCssScale)
+  : mRect(aRect)
+  , mAvailRect(aAvailRect)
+  , mRectDisplayPix(RoundedToInt(aRect / aContentsScale))
+  , mAvailRectDisplayPix(RoundedToInt(aAvailRect / aContentsScale))
+  , mPixelDepth(aPixelDepth)
+  , mColorDepth(aColorDepth)
+  , mContentsScale(aContentsScale)
+  , mDefaultCssScale(aDefaultCssScale)
+  , mId(++sScreenId)
+{
+}
+
+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)
+  , mId(aOther.mId)
+{
+}
+
+NS_IMETHODIMP
+Screen::GetId(uint32_t* aOutId)
+{
+  *aOutId = mId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetRect(int32_t* aOutLeft,
+                int32_t* aOutTop,
+                int32_t* aOutWidth,
+                int32_t* aOutHeight)
+{
+  *aOutLeft = mRect.x;
+  *aOutTop = mRect.y;
+  *aOutWidth = mRect.width;
+  *aOutHeight = mRect.height;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetRectDisplayPix(int32_t* aOutLeft,
+                          int32_t* aOutTop,
+                          int32_t* aOutWidth,
+                          int32_t* aOutHeight)
+{
+  *aOutLeft = mRectDisplayPix.x;
+  *aOutTop = mRectDisplayPix.y;
+  *aOutWidth = mRectDisplayPix.width;
+  *aOutHeight = mRectDisplayPix.height;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetAvailRect(int32_t* aOutLeft,
+                     int32_t* aOutTop,
+                     int32_t* aOutWidth,
+                     int32_t* aOutHeight)
+{
+  *aOutLeft = mAvailRect.x;
+  *aOutTop = mAvailRect.y;
+  *aOutWidth = mAvailRect.width;
+  *aOutHeight = mAvailRect.height;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetAvailRectDisplayPix(int32_t* aOutLeft,
+                               int32_t* aOutTop,
+                               int32_t* aOutWidth,
+                               int32_t* aOutHeight)
+{
+  *aOutLeft = mAvailRectDisplayPix.x;
+  *aOutTop = mAvailRectDisplayPix.y;
+  *aOutWidth = mAvailRectDisplayPix.width;
+  *aOutHeight = mAvailRectDisplayPix.height;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetPixelDepth(int32_t* aPixelDepth)
+{
+  *aPixelDepth = mPixelDepth;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetColorDepth(int32_t* aColorDepth)
+{
+  *aColorDepth = mColorDepth;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetContentsScaleFactor(double *aOutScale)
+{
+  *aOutScale = mContentsScale.scale;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetDefaultCSSScaleFactor(double *aOutScale)
+{
+  *aOutScale = mDefaultCssScale.scale;
+  return NS_OK;
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/Screen.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_Screen_h
+#define mozilla_widget_Screen_h
+
+#include "nsIScreen.h"
+
+#include "Units.h"
+
+namespace mozilla {
+namespace widget {
+
+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);
+  Screen(const Screen& aOther);
+
+private:
+  virtual ~Screen() {}
+
+  LayoutDeviceIntRect mRect;
+  LayoutDeviceIntRect mAvailRect;
+  DesktopIntRect mRectDisplayPix;
+  DesktopIntRect mAvailRectDisplayPix;
+  uint32_t mPixelDepth;
+  uint32_t mColorDepth;
+  DesktopToLayoutDeviceScale mContentsScale;
+  CSSToLayoutDeviceScale mDefaultCssScale;
+  uint32_t mId;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/widget/ScreenManager.cpp
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "ScreenManager.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Logging.h"
+#include "mozilla/StaticPtr.h"
+
+static LazyLogModule sScreenLog("WidgetScreen");
+
+NS_IMPL_ISUPPORTS(ScreenManager, nsIScreenManager)
+
+namespace mozilla {
+namespace widget {
+
+ScreenManager::ScreenManager()
+{
+}
+
+ScreenManager::~ScreenManager()
+{
+}
+
+static StaticRefPtr<ScreenManager> sSingleton;
+
+ScreenManager&
+ScreenManager::GetSingleton()
+{
+  if (!sSingleton) {
+    sSingleton = new ScreenManager();
+    ClearOnShutdown(&sSingleton);
+  }
+  return *sSingleton;
+}
+
+already_AddRefed<ScreenManager>
+ScreenManager::GetAddRefedSingleton()
+{
+  RefPtr<ScreenManager> sm = &GetSingleton();
+  return sm.forget();
+}
+
+void
+ScreenManager::SetHelper(UniquePtr<Helper> aHelper)
+{
+  mHelper = Move(aHelper);
+}
+
+void
+ScreenManager::Refresh(nsTArray<RefPtr<Screen>>&& aScreens)
+{
+  mScreenList = Move(aScreens);
+}
+
+NS_IMETHODIMP
+ScreenManager::ScreenForId(uint32_t aId, nsIScreen** aOutScreen)
+{
+  *aOutScreen = nullptr;
+
+  nsresult rv;
+  for (auto& screen : mScreenList) {
+    uint32_t id;
+    rv = screen->GetId(&id);
+    if (NS_SUCCEEDED(rv) && id == aId) {
+      RefPtr<Screen> ret = screen;
+      ret.forget(aOutScreen);
+      return NS_OK;
+    }
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
+// Returns the screen that contains the rectangle. If the rect overlaps
+// multiple screens, it picks the screen with the greatest area of intersection.
+//
+// The coordinates are in desktop pixels.
+//
+NS_IMETHODIMP
+ScreenManager::ScreenForRect(int32_t aX, int32_t aY,
+                             int32_t aWidth, int32_t aHeight,
+                             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());
+    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);
+  }
+
+  // which screen should we return?
+  Screen* which = mScreenList[0].get();
+
+  // walk the list of screens and find the one that has the most
+  // surface area.
+  uint32_t area = 0;
+  DesktopIntRect windowRect(aX, aY, aWidth, aHeight);
+  for (auto& screen : mScreenList) {
+    int32_t  x, y, width, height;
+    x = y = width = height = 0;
+    screen->GetRectDisplayPix(&x, &y, &width, &height);
+    // calculate the surface area
+    DesktopIntRect screenRect(x, y, width, height);
+    screenRect.IntersectRect(screenRect, windowRect);
+    uint32_t tempArea = screenRect.width * screenRect.height;
+    if (tempArea >= area) {
+      which = screen.get();
+      area = tempArea;
+    }
+  }
+
+  RefPtr<Screen> ret = which;
+  ret.forget(aOutScreen);
+  return NS_OK;
+}
+
+// The screen with the menubar/taskbar. This shouldn't be needed very
+// often.
+//
+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());
+    ret.forget(aPrimaryScreen);
+    return NS_OK;
+  }
+
+  RefPtr<Screen> ret = mScreenList[0];
+  ret.forget(aPrimaryScreen);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScreenManager::GetSystemDefaultScale(float* aDefaultScale)
+{
+  if (mHelper) {
+    *aDefaultScale = mHelper->GetSystemDefaultScale();
+    return NS_OK;
+  }
+  *aDefaultScale = 1;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ScreenManager::ScreenForNativeWidget(void* aWidget, nsIScreen** aOutScreen)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/ScreenManager.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_ScreenManager_h
+#define mozilla_widget_ScreenManager_h
+
+#include "nsIScreenManager.h"
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/widget/Screen.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace widget {
+
+class ScreenManager final : public nsIScreenManager
+{
+public:
+  class Helper
+  {
+  public:
+    virtual float GetSystemDefaultScale() = 0;
+    virtual ~Helper() {};
+  };
+
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISCREENMANAGER
+
+  static ScreenManager& GetSingleton();
+  static already_AddRefed<ScreenManager> GetAddRefedSingleton();
+
+  void SetHelper(UniquePtr<Helper> aHelper);
+  void Refresh(nsTArray<RefPtr<Screen>>&& aScreens);
+
+private:
+  ScreenManager();
+  virtual ~ScreenManager();
+
+  AutoTArray<RefPtr<Screen>, 4> mScreenList;
+  UniquePtr<Helper> mHelper;
+};
+
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // mozilla_widget_ScreenManager_h
--- a/widget/VsyncDispatcher.cpp
+++ b/widget/VsyncDispatcher.cpp
@@ -11,16 +11,18 @@
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 
 #ifdef MOZ_GECKO_PROFILER
 #include "GeckoProfiler.h"
 #include "ProfilerMarkers.h"
 #endif
 
+using namespace mozilla::layers;
+
 namespace mozilla {
 
 CompositorVsyncDispatcher::CompositorVsyncDispatcher()
   : mCompositorObserverLock("CompositorObserverLock")
   , mDidShutdown(false)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(NS_IsMainThread());
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -125,16 +125,18 @@ EXPORTS.mozilla += [
 ]
 
 EXPORTS.mozilla.widget += [
     'CompositorWidget.h',
     'IMEData.h',
     'InProcessCompositorWidget.h',
     'nsAutoRollup.h',
     'PuppetBidiKeyboard.h',
+    'Screen.h',
+    'ScreenManager.h',
     'WidgetMessageUtils.h',
     'WindowSurface.h'
 ]
 
 UNIFIED_SOURCES += [
     'CompositorWidget.cpp',
     'ContentCache.cpp',
     'GfxDriverInfo.cpp',
@@ -157,16 +159,18 @@ UNIFIED_SOURCES += [
     'nsIWidgetListener.cpp',
     'nsPrimitiveHelpers.cpp',
     'nsPrintSettingsImpl.cpp',
     'nsScreenManagerProxy.cpp',
     'nsTransferable.cpp',
     'nsXPLookAndFeel.cpp',
     'PuppetBidiKeyboard.cpp',
     'PuppetWidget.cpp',
+    'Screen.cpp',
+    'ScreenManager.cpp',
     'ScreenProxy.cpp',
     'SharedWidgetUtils.cpp',
     'TextEventDispatcher.cpp',
     'VsyncDispatcher.cpp',
     'WidgetEventImpl.cpp',
     'WidgetUtils.cpp',
 ]