LCOV - code coverage report
Current view: top level - widget - ScreenManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 55 109 50.5 %
Date: 2017-07-14 16:53:18 Functions: 15 17 88.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "ScreenManager.h"
       8             : 
       9             : #include "mozilla/ClearOnShutdown.h"
      10             : #include "mozilla/dom/ContentParent.h"
      11             : #include "mozilla/Logging.h"
      12             : #include "mozilla/StaticPtr.h"
      13             : 
      14             : static LazyLogModule sScreenLog("WidgetScreen");
      15             : 
      16         160 : NS_IMPL_ISUPPORTS(ScreenManager, nsIScreenManager)
      17             : 
      18             : namespace mozilla {
      19             : namespace widget {
      20             : 
      21           3 : ScreenManager::ScreenManager()
      22             : {
      23           3 : }
      24             : 
      25           0 : ScreenManager::~ScreenManager()
      26             : {
      27           0 : }
      28             : 
      29           3 : static StaticRefPtr<ScreenManager> sSingleton;
      30             : 
      31             : ScreenManager&
      32           9 : ScreenManager::GetSingleton()
      33             : {
      34           9 :   if (!sSingleton) {
      35           3 :     sSingleton = new ScreenManager();
      36           3 :     ClearOnShutdown(&sSingleton);
      37             :   }
      38           9 :   return *sSingleton;
      39             : }
      40             : 
      41             : already_AddRefed<ScreenManager>
      42           3 : ScreenManager::GetAddRefedSingleton()
      43             : {
      44           6 :   RefPtr<ScreenManager> sm = &GetSingleton();
      45           6 :   return sm.forget();
      46             : }
      47             : 
      48             : void
      49           1 : ScreenManager::SetHelper(UniquePtr<Helper> aHelper)
      50             : {
      51           1 :   mHelper = Move(aHelper);
      52           1 : }
      53             : 
      54             : void
      55           1 : ScreenManager::Refresh(nsTArray<RefPtr<Screen>>&& aScreens)
      56             : {
      57           1 :   MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refresh screens"));
      58             : 
      59           1 :   mScreenList = Move(aScreens);
      60             : 
      61           1 :   CopyScreensToAllRemotesIfIsParent();
      62           1 : }
      63             : 
      64             : void
      65           2 : ScreenManager::Refresh(nsTArray<mozilla::dom::ScreenDetails>&& aScreens)
      66             : {
      67           2 :   MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refresh screens from IPC"));
      68             : 
      69           2 :   mScreenList.Clear();
      70           4 :   for (auto& screen : aScreens) {
      71           2 :     mScreenList.AppendElement(new Screen(screen));
      72             :   }
      73             : 
      74           2 :   CopyScreensToAllRemotesIfIsParent();
      75           2 : }
      76             : 
      77             : template<class Range>
      78             : void
      79           3 : ScreenManager::CopyScreensToRemoteRange(Range aRemoteRange)
      80             : {
      81           6 :   AutoTArray<ScreenDetails, 4> screens;
      82           6 :   for (auto& screen : mScreenList) {
      83           3 :     screens.AppendElement(screen->ToScreenDetails());
      84             :   }
      85           5 :   for (auto cp : aRemoteRange) {
      86           2 :     MOZ_LOG(sScreenLog, LogLevel::Debug, ("Send screens to [Pid %d]", cp->Pid()));
      87           2 :     if (!cp->SendRefreshScreens(screens)) {
      88           0 :       MOZ_LOG(sScreenLog, LogLevel::Error,
      89             :               ("SendRefreshScreens to [Pid %d] failed", cp->Pid()));
      90             :     }
      91             :   }
      92           3 : }
      93             : 
      94             : void
      95           2 : ScreenManager::CopyScreensToRemote(ContentParent* aContentParent)
      96             : {
      97           2 :   MOZ_ASSERT(aContentParent);
      98           2 :   MOZ_ASSERT(XRE_IsParentProcess());
      99             : 
     100           2 :   auto range = { aContentParent };
     101           2 :   CopyScreensToRemoteRange(range);
     102           2 : }
     103             : 
     104             : void
     105           3 : ScreenManager::CopyScreensToAllRemotesIfIsParent()
     106             : {
     107           3 :   if (XRE_IsContentProcess()) {
     108           2 :     return;
     109             :   }
     110             : 
     111           1 :   MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing all ContentParents"));
     112             : 
     113           1 :   CopyScreensToRemoteRange(ContentParent::AllProcesses(ContentParent::eLive));
     114             : }
     115             : 
     116             : // Returns the screen that contains the rectangle. If the rect overlaps
     117             : // multiple screens, it picks the screen with the greatest area of intersection.
     118             : //
     119             : // The coordinates are in desktop pixels.
     120             : //
     121             : NS_IMETHODIMP
     122          24 : ScreenManager::ScreenForRect(int32_t aX, int32_t aY,
     123             :                              int32_t aWidth, int32_t aHeight,
     124             :                              nsIScreen** aOutScreen)
     125             : {
     126          24 :   if (mScreenList.IsEmpty()) {
     127           0 :     MOZ_LOG(sScreenLog, LogLevel::Warning,
     128             :             ("No screen available. This can happen in xpcshell."));
     129           0 :     RefPtr<Screen> ret = new Screen(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
     130             :                                     0, 0,
     131           0 :                                     DesktopToLayoutDeviceScale(),
     132           0 :                                     CSSToLayoutDeviceScale());
     133           0 :     ret.forget(aOutScreen);
     134           0 :     return NS_OK;
     135             :   }
     136             : 
     137             :   // Optimize for the common case. If the number of screens is only
     138             :   // one then just return the primary screen.
     139          24 :   if (mScreenList.Length() == 1) {
     140          24 :     return GetPrimaryScreen(aOutScreen);
     141             :   }
     142             : 
     143             :   // which screen should we return?
     144           0 :   Screen* which = mScreenList[0].get();
     145             : 
     146             :   // walk the list of screens and find the one that has the most
     147             :   // surface area.
     148           0 :   uint32_t area = 0;
     149           0 :   DesktopIntRect windowRect(aX, aY, aWidth, aHeight);
     150           0 :   for (auto& screen : mScreenList) {
     151             :     int32_t  x, y, width, height;
     152           0 :     x = y = width = height = 0;
     153           0 :     screen->GetRectDisplayPix(&x, &y, &width, &height);
     154             :     // calculate the surface area
     155           0 :     DesktopIntRect screenRect(x, y, width, height);
     156           0 :     screenRect.IntersectRect(screenRect, windowRect);
     157           0 :     uint32_t tempArea = screenRect.width * screenRect.height;
     158           0 :     if (tempArea > area) {
     159           0 :       which = screen.get();
     160           0 :       area = tempArea;
     161             :     }
     162             :   }
     163             : 
     164             :   // If the rect intersects one or more screen,
     165             :   // return the screen that has the largest intersection.
     166           0 :   if (area > 0) {
     167           0 :     RefPtr<Screen> ret = which;
     168           0 :     ret.forget(aOutScreen);
     169           0 :     return NS_OK;
     170             :   }
     171             : 
     172             :   // If the rect does not intersect a screen, find
     173             :   // a screen that is nearest to the rect.
     174           0 :   uint32_t distance = UINT32_MAX;
     175           0 :   for (auto& screen : mScreenList) {
     176             :     int32_t  x, y, width, height;
     177           0 :     x = y = width = height = 0;
     178           0 :     screen->GetRectDisplayPix(&x, &y, &width, &height);
     179             : 
     180           0 :     uint32_t distanceX = 0;
     181           0 :     if (aX > (x + width)) {
     182           0 :       distanceX = aX - (x + width);
     183           0 :     } else if ((aX + aWidth) < x) {
     184           0 :       distanceX = x - (aX + aWidth);
     185             :     }
     186             : 
     187           0 :     uint32_t distanceY = 0;
     188           0 :     if (aY > (y + height)) {
     189           0 :       distanceY = aY - (y + height);
     190           0 :     } else if ((aY + aHeight) < y) {
     191           0 :       distanceY = y - (aY + aHeight);
     192             :     }
     193             : 
     194           0 :     uint32_t tempDistance = distanceX * distanceX + distanceY * distanceY;
     195           0 :     if (tempDistance < distance) {
     196           0 :       which = screen.get();
     197           0 :       distance = tempDistance;
     198           0 :       if (distance == 0) {
     199           0 :         break;
     200             :       }
     201             :     }
     202             :   }
     203             : 
     204           0 :   RefPtr<Screen> ret = which;
     205           0 :   ret.forget(aOutScreen);
     206           0 :   return NS_OK;
     207             : }
     208             : 
     209             : // The screen with the menubar/taskbar. This shouldn't be needed very
     210             : // often.
     211             : //
     212             : NS_IMETHODIMP
     213          28 : ScreenManager::GetPrimaryScreen(nsIScreen** aPrimaryScreen)
     214             : {
     215          28 :   if (mScreenList.IsEmpty()) {
     216           0 :     MOZ_LOG(sScreenLog, LogLevel::Warning,
     217             :             ("No screen available. This can happen in xpcshell."));
     218           0 :     RefPtr<Screen> ret = new Screen(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
     219             :                                     0, 0,
     220           0 :                                     DesktopToLayoutDeviceScale(),
     221           0 :                                     CSSToLayoutDeviceScale());
     222           0 :     ret.forget(aPrimaryScreen);
     223           0 :     return NS_OK;
     224             :   }
     225             : 
     226          56 :   RefPtr<Screen> ret = mScreenList[0];
     227          28 :   ret.forget(aPrimaryScreen);
     228          28 :   return NS_OK;
     229             : }
     230             : 
     231             : } // namespace widget
     232             : } // namespace mozilla

Generated by: LCOV version 1.13