Bug 1194751 - Part 4. Add ScreenManager and Screen classes. r?mconley,jimm,karlt draft
authorKan-Ru Chen <kanru@kanru.info>
Tue, 14 Mar 2017 18:44:54 +0800
changeset 551527 96a8407046ed436da88719438eb52f964f24671e
parent 551526 d7fff28c9fb444589fa353f511707ac56ed82cf3
child 551528 54d15aa4e182397e3fe607bb1bc5ee5993c1d4f9
push id51072
push userkchen@mozilla.com
push dateSun, 26 Mar 2017 23:21:39 +0000
reviewersmconley, jimm, karlt
bugs1194751
milestone55.0a1
Bug 1194751 - Part 4. Add ScreenManager and Screen classes. r?mconley,jimm,karlt 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',
 ]