Coverage Report

Created: 2018-09-25 14:53

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