Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsScreen.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 "nsContentUtils.h"
8
#include "nsScreen.h"
9
#include "nsIDocument.h"
10
#include "nsIDocShell.h"
11
#include "nsIDocument.h"
12
#include "nsPresContext.h"
13
#include "nsCOMPtr.h"
14
#include "nsIDocShellTreeItem.h"
15
#include "nsLayoutUtils.h"
16
#include "nsJSUtils.h"
17
#include "nsDeviceContext.h"
18
19
using namespace mozilla;
20
using namespace mozilla::dom;
21
22
/* static */ already_AddRefed<nsScreen>
23
nsScreen::Create(nsPIDOMWindowInner* aWindow)
24
0
{
25
0
  MOZ_ASSERT(aWindow);
26
0
27
0
  if (!aWindow->GetDocShell()) {
28
0
    return nullptr;
29
0
  }
30
0
31
0
  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
32
0
  NS_ENSURE_TRUE(sgo, nullptr);
33
0
34
0
  RefPtr<nsScreen> screen = new nsScreen(aWindow);
35
0
  return screen.forget();
36
0
}
37
38
nsScreen::nsScreen(nsPIDOMWindowInner* aWindow)
39
  : DOMEventTargetHelper(aWindow)
40
  , mScreenOrientation(new ScreenOrientation(aWindow, this))
41
0
{
42
0
}
43
44
nsScreen::~nsScreen()
45
0
{
46
0
}
47
48
49
// QueryInterface implementation for nsScreen
50
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScreen)
51
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
52
53
NS_IMPL_ADDREF_INHERITED(nsScreen, DOMEventTargetHelper)
54
NS_IMPL_RELEASE_INHERITED(nsScreen, DOMEventTargetHelper)
55
56
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsScreen,
57
                                   DOMEventTargetHelper,
58
                                   mScreenOrientation)
59
60
int32_t
61
nsScreen::GetPixelDepth(ErrorResult& aRv)
62
0
{
63
0
  // Return 24 to prevent fingerprinting.
64
0
  if (ShouldResistFingerprinting()) {
65
0
    return 24;
66
0
  }
67
0
68
0
  nsDeviceContext* context = GetDeviceContext();
69
0
70
0
  if (!context) {
71
0
    aRv.Throw(NS_ERROR_FAILURE);
72
0
    return -1;
73
0
  }
74
0
75
0
  uint32_t depth;
76
0
  context->GetDepth(depth);
77
0
  return depth;
78
0
}
79
80
nsPIDOMWindowOuter*
81
nsScreen::GetOuter() const
82
0
{
83
0
  if (nsPIDOMWindowInner* inner = GetOwner()) {
84
0
    return inner->GetOuterWindow();
85
0
  }
86
0
87
0
  return nullptr;
88
0
}
89
90
nsDeviceContext*
91
nsScreen::GetDeviceContext()
92
0
{
93
0
  return nsLayoutUtils::GetDeviceContextForScreenInfo(GetOuter());
94
0
}
95
96
nsresult
97
nsScreen::GetRect(nsRect& aRect)
98
0
{
99
0
  // Return window inner rect to prevent fingerprinting.
100
0
  if (ShouldResistFingerprinting()) {
101
0
    return GetWindowInnerRect(aRect);
102
0
  }
103
0
104
0
  nsDeviceContext *context = GetDeviceContext();
105
0
106
0
  if (!context) {
107
0
    return NS_ERROR_FAILURE;
108
0
  }
109
0
110
0
  context->GetRect(aRect);
111
0
  LayoutDevicePoint screenTopLeftDev =
112
0
    LayoutDevicePixel::FromAppUnits(aRect.TopLeft(),
113
0
                                    context->AppUnitsPerDevPixel());
114
0
  DesktopPoint screenTopLeftDesk =
115
0
    screenTopLeftDev / context->GetDesktopToDeviceScale();
116
0
117
0
  aRect.x = NSToIntRound(screenTopLeftDesk.x);
118
0
  aRect.y = NSToIntRound(screenTopLeftDesk.y);
119
0
120
0
  aRect.SetHeight(nsPresContext::AppUnitsToIntCSSPixels(aRect.Height()));
121
0
  aRect.SetWidth(nsPresContext::AppUnitsToIntCSSPixels(aRect.Width()));
122
0
123
0
  return NS_OK;
124
0
}
125
126
nsresult
127
nsScreen::GetAvailRect(nsRect& aRect)
128
0
{
129
0
  // Return window inner rect to prevent fingerprinting.
130
0
  if (ShouldResistFingerprinting()) {
131
0
    return GetWindowInnerRect(aRect);
132
0
  }
133
0
134
0
  nsDeviceContext *context = GetDeviceContext();
135
0
136
0
  if (!context) {
137
0
    return NS_ERROR_FAILURE;
138
0
  }
139
0
140
0
  nsRect r;
141
0
  context->GetRect(r);
142
0
  LayoutDevicePoint screenTopLeftDev =
143
0
    LayoutDevicePixel::FromAppUnits(r.TopLeft(),
144
0
                                    context->AppUnitsPerDevPixel());
145
0
  DesktopPoint screenTopLeftDesk =
146
0
    screenTopLeftDev / context->GetDesktopToDeviceScale();
147
0
148
0
  context->GetClientRect(aRect);
149
0
150
0
  aRect.x = NSToIntRound(screenTopLeftDesk.x) +
151
0
            nsPresContext::AppUnitsToIntCSSPixels(aRect.x - r.x);
152
0
  aRect.y = NSToIntRound(screenTopLeftDesk.y) +
153
0
            nsPresContext::AppUnitsToIntCSSPixels(aRect.y - r.y);
154
0
155
0
  aRect.SetHeight(nsPresContext::AppUnitsToIntCSSPixels(aRect.Height()));
156
0
  aRect.SetWidth(nsPresContext::AppUnitsToIntCSSPixels(aRect.Width()));
157
0
158
0
  return NS_OK;
159
0
}
160
161
mozilla::dom::ScreenOrientation*
162
nsScreen::Orientation() const
163
0
{
164
0
  return mScreenOrientation;
165
0
}
166
167
void
168
nsScreen::GetMozOrientation(nsString& aOrientation,
169
                            CallerType aCallerType) const
170
0
{
171
0
  switch (mScreenOrientation->DeviceType(aCallerType)) {
172
0
  case OrientationType::Portrait_primary:
173
0
    aOrientation.AssignLiteral("portrait-primary");
174
0
    break;
175
0
  case OrientationType::Portrait_secondary:
176
0
    aOrientation.AssignLiteral("portrait-secondary");
177
0
    break;
178
0
  case OrientationType::Landscape_primary:
179
0
    aOrientation.AssignLiteral("landscape-primary");
180
0
    break;
181
0
  case OrientationType::Landscape_secondary:
182
0
    aOrientation.AssignLiteral("landscape-secondary");
183
0
    break;
184
0
  default:
185
0
    MOZ_CRASH("Unacceptable screen orientation type.");
186
0
  }
187
0
}
188
189
static void
190
UpdateDocShellOrientationLock(nsPIDOMWindowInner* aWindow,
191
                              hal::ScreenOrientation aOrientation)
192
0
{
193
0
  if (!aWindow) {
194
0
    return;
195
0
  }
196
0
197
0
  nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
198
0
  if (!docShell) {
199
0
    return;
200
0
  }
201
0
202
0
  nsCOMPtr<nsIDocShellTreeItem> root;
203
0
  docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
204
0
  nsCOMPtr<nsIDocShell> rootShell(do_QueryInterface(root));
205
0
  if (!rootShell) {
206
0
    return;
207
0
  }
208
0
209
0
  rootShell->SetOrientationLock(aOrientation);
210
0
}
211
212
bool
213
nsScreen::MozLockOrientation(const nsAString& aOrientation, ErrorResult& aRv)
214
0
{
215
0
  nsString orientation(aOrientation);
216
0
  Sequence<nsString> orientations;
217
0
  if (!orientations.AppendElement(orientation, fallible)) {
218
0
    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
219
0
    return false;
220
0
  }
221
0
  return MozLockOrientation(orientations, aRv);
222
0
}
223
224
bool
225
nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
226
                             ErrorResult& aRv)
227
0
{
228
0
  if (ShouldResistFingerprinting()) {
229
0
    return false;
230
0
  }
231
0
  hal::ScreenOrientation orientation = hal::eScreenOrientation_None;
232
0
233
0
  for (uint32_t i = 0; i < aOrientations.Length(); ++i) {
234
0
    const nsString& item = aOrientations[i];
235
0
236
0
    if (item.EqualsLiteral("portrait")) {
237
0
      orientation |= hal::eScreenOrientation_PortraitPrimary |
238
0
                     hal::eScreenOrientation_PortraitSecondary;
239
0
    } else if (item.EqualsLiteral("portrait-primary")) {
240
0
      orientation |= hal::eScreenOrientation_PortraitPrimary;
241
0
    } else if (item.EqualsLiteral("portrait-secondary")) {
242
0
      orientation |= hal::eScreenOrientation_PortraitSecondary;
243
0
    } else if (item.EqualsLiteral("landscape")) {
244
0
      orientation |= hal::eScreenOrientation_LandscapePrimary |
245
0
                     hal::eScreenOrientation_LandscapeSecondary;
246
0
    } else if (item.EqualsLiteral("landscape-primary")) {
247
0
      orientation |= hal::eScreenOrientation_LandscapePrimary;
248
0
    } else if (item.EqualsLiteral("landscape-secondary")) {
249
0
      orientation |= hal::eScreenOrientation_LandscapeSecondary;
250
0
    } else if (item.EqualsLiteral("default")) {
251
0
      orientation |= hal::eScreenOrientation_Default;
252
0
    } else {
253
0
      // If we don't recognize the token, we should just return 'false'
254
0
      // without throwing.
255
0
      return false;
256
0
    }
257
0
  }
258
0
259
0
  switch (mScreenOrientation->GetLockOrientationPermission(false)) {
260
0
    case ScreenOrientation::LOCK_DENIED:
261
0
      return false;
262
0
    case ScreenOrientation::LOCK_ALLOWED:
263
0
      UpdateDocShellOrientationLock(GetOwner(), orientation);
264
0
      return mScreenOrientation->LockDeviceOrientation(orientation, false, aRv);
265
0
    case ScreenOrientation::FULLSCREEN_LOCK_ALLOWED:
266
0
      UpdateDocShellOrientationLock(GetOwner(), orientation);
267
0
      return mScreenOrientation->LockDeviceOrientation(orientation, true, aRv);
268
0
  }
269
0
270
0
  // This is only for compilers that don't understand that the previous switch
271
0
  // will always return.
272
0
  MOZ_CRASH("unexpected lock orientation permission value");
273
0
}
274
275
void
276
nsScreen::MozUnlockOrientation()
277
0
{
278
0
  if (ShouldResistFingerprinting()) {
279
0
    return;
280
0
  }
281
0
  UpdateDocShellOrientationLock(GetOwner(), hal::eScreenOrientation_None);
282
0
  mScreenOrientation->UnlockDeviceOrientation();
283
0
}
284
285
bool
286
nsScreen::IsDeviceSizePageSize()
287
0
{
288
0
  if (nsPIDOMWindowInner* owner = GetOwner()) {
289
0
    nsIDocShell* docShell = owner->GetDocShell();
290
0
    if (docShell) {
291
0
      return docShell->GetDeviceSizeIsPageSize();
292
0
    }
293
0
  }
294
0
  return false;
295
0
}
296
297
/* virtual */
298
JSObject*
299
nsScreen::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
300
0
{
301
0
  return Screen_Binding::Wrap(aCx, this, aGivenProto);
302
0
}
303
304
nsresult
305
nsScreen::GetWindowInnerRect(nsRect& aRect)
306
0
{
307
0
  aRect.x = 0;
308
0
  aRect.y = 0;
309
0
  nsCOMPtr<nsPIDOMWindowInner> win = GetOwner();
310
0
  if (!win) {
311
0
    return NS_ERROR_FAILURE;
312
0
  }
313
0
  nsresult rv = win->GetInnerWidth(&aRect.width);
314
0
  NS_ENSURE_SUCCESS(rv, rv);
315
0
  return win->GetInnerHeight(&aRect.height);
316
0
}
317
318
bool nsScreen::ShouldResistFingerprinting() const
319
0
{
320
0
  bool resist = false;
321
0
  nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
322
0
  if (owner) {
323
0
    resist = nsContentUtils::ShouldResistFingerprinting(owner->GetDocShell());
324
0
  }
325
0
  return resist;
326
0
}