Bug 1579327 [wpt PR 18888] - Make canShare() and files support tests tentative, a...
[gecko.git] / widget / ScreenManager.cpp
blobbeb5d5b5e4878e6ccf79bfd88b52de65c11c7a3c
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/. */
7 #include "ScreenManager.h"
9 #include "mozilla/ClearOnShutdown.h"
10 #include "mozilla/dom/ContentParent.h"
11 #include "mozilla/dom/DOMTypes.h"
12 #include "mozilla/Logging.h"
13 #include "mozilla/StaticPtr.h"
15 static mozilla::LazyLogModule sScreenLog("WidgetScreen");
17 namespace mozilla {
18 namespace widget {
20 NS_IMPL_ISUPPORTS(ScreenManager, nsIScreenManager)
22 ScreenManager::ScreenManager() {}
24 ScreenManager::~ScreenManager() {}
26 static StaticRefPtr<ScreenManager> sSingleton;
28 ScreenManager& ScreenManager::GetSingleton() {
29 if (!sSingleton) {
30 sSingleton = new ScreenManager();
31 ClearOnShutdown(&sSingleton);
33 return *sSingleton;
36 already_AddRefed<ScreenManager> ScreenManager::GetAddRefedSingleton() {
37 RefPtr<ScreenManager> sm = &GetSingleton();
38 return sm.forget();
41 void ScreenManager::SetHelper(UniquePtr<Helper> aHelper) {
42 mHelper = std::move(aHelper);
45 void ScreenManager::Refresh(nsTArray<RefPtr<Screen>>&& aScreens) {
46 MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refresh screens"));
48 mScreenList = std::move(aScreens);
50 CopyScreensToAllRemotesIfIsParent();
53 void ScreenManager::Refresh(nsTArray<mozilla::dom::ScreenDetails>&& aScreens) {
54 MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refresh screens from IPC"));
56 mScreenList.Clear();
57 for (auto& screen : aScreens) {
58 mScreenList.AppendElement(new Screen(screen));
61 CopyScreensToAllRemotesIfIsParent();
64 template <class Range>
65 void ScreenManager::CopyScreensToRemoteRange(Range aRemoteRange) {
66 AutoTArray<dom::ScreenDetails, 4> screens;
67 for (auto& screen : mScreenList) {
68 screens.AppendElement(screen->ToScreenDetails());
70 for (auto cp : aRemoteRange) {
71 MOZ_LOG(sScreenLog, LogLevel::Debug,
72 ("Send screens to [Pid %d]", cp->Pid()));
73 if (!cp->SendRefreshScreens(screens)) {
74 MOZ_LOG(sScreenLog, LogLevel::Error,
75 ("SendRefreshScreens to [Pid %d] failed", cp->Pid()));
80 void ScreenManager::CopyScreensToRemote(dom::ContentParent* aContentParent) {
81 MOZ_ASSERT(aContentParent);
82 MOZ_ASSERT(XRE_IsParentProcess());
84 auto range = {aContentParent};
85 CopyScreensToRemoteRange(range);
88 void ScreenManager::CopyScreensToAllRemotesIfIsParent() {
89 if (XRE_IsContentProcess()) {
90 return;
93 MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing all ContentParents"));
95 CopyScreensToRemoteRange(
96 dom::ContentParent::AllProcesses(dom::ContentParent::eLive));
99 // Returns the screen that contains the rectangle. If the rect overlaps
100 // multiple screens, it picks the screen with the greatest area of intersection.
102 // The coordinates are in desktop pixels.
104 NS_IMETHODIMP
105 ScreenManager::ScreenForRect(int32_t aX, int32_t aY, int32_t aWidth,
106 int32_t aHeight, nsIScreen** aOutScreen) {
107 if (mScreenList.IsEmpty()) {
108 MOZ_LOG(sScreenLog, LogLevel::Warning,
109 ("No screen available. This can happen in xpcshell."));
110 RefPtr<Screen> ret = new Screen(
111 LayoutDeviceIntRect(), LayoutDeviceIntRect(), 0, 0,
112 DesktopToLayoutDeviceScale(), CSSToLayoutDeviceScale(), 96 /* dpi */);
113 ret.forget(aOutScreen);
114 return NS_OK;
117 // Optimize for the common case. If the number of screens is only
118 // one then just return the primary screen.
119 if (mScreenList.Length() == 1) {
120 return GetPrimaryScreen(aOutScreen);
123 // which screen should we return?
124 Screen* which = mScreenList[0].get();
126 // walk the list of screens and find the one that has the most
127 // surface area.
128 uint32_t area = 0;
129 DesktopIntRect windowRect(aX, aY, aWidth, aHeight);
130 for (auto& screen : mScreenList) {
131 int32_t x, y, width, height;
132 x = y = width = height = 0;
133 screen->GetRectDisplayPix(&x, &y, &width, &height);
134 // calculate the surface area
135 DesktopIntRect screenRect(x, y, width, height);
136 screenRect.IntersectRect(screenRect, windowRect);
137 uint32_t tempArea = screenRect.Area();
138 if (tempArea > area) {
139 which = screen.get();
140 area = tempArea;
144 // If the rect intersects one or more screen,
145 // return the screen that has the largest intersection.
146 if (area > 0) {
147 RefPtr<Screen> ret = which;
148 ret.forget(aOutScreen);
149 return NS_OK;
152 // If the rect does not intersect a screen, find
153 // a screen that is nearest to the rect.
154 uint32_t distance = UINT32_MAX;
155 for (auto& screen : mScreenList) {
156 int32_t x, y, width, height;
157 x = y = width = height = 0;
158 screen->GetRectDisplayPix(&x, &y, &width, &height);
160 uint32_t distanceX = 0;
161 if (aX > (x + width)) {
162 distanceX = aX - (x + width);
163 } else if ((aX + aWidth) < x) {
164 distanceX = x - (aX + aWidth);
167 uint32_t distanceY = 0;
168 if (aY > (y + height)) {
169 distanceY = aY - (y + height);
170 } else if ((aY + aHeight) < y) {
171 distanceY = y - (aY + aHeight);
174 uint32_t tempDistance = distanceX * distanceX + distanceY * distanceY;
175 if (tempDistance < distance) {
176 which = screen.get();
177 distance = tempDistance;
178 if (distance == 0) {
179 break;
184 RefPtr<Screen> ret = which;
185 ret.forget(aOutScreen);
186 return NS_OK;
189 // The screen with the menubar/taskbar. This shouldn't be needed very
190 // often.
192 NS_IMETHODIMP
193 ScreenManager::GetPrimaryScreen(nsIScreen** aPrimaryScreen) {
194 if (mScreenList.IsEmpty()) {
195 MOZ_LOG(sScreenLog, LogLevel::Warning,
196 ("No screen available. This can happen in xpcshell."));
197 RefPtr<Screen> ret = new Screen(
198 LayoutDeviceIntRect(), LayoutDeviceIntRect(), 0, 0,
199 DesktopToLayoutDeviceScale(), CSSToLayoutDeviceScale(), 96 /* dpi */);
200 ret.forget(aPrimaryScreen);
201 return NS_OK;
204 RefPtr<Screen> ret = mScreenList[0];
205 ret.forget(aPrimaryScreen);
206 return NS_OK;
209 } // namespace widget
210 } // namespace mozilla