Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/nsMediaFeatures.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
/* the features that media queries can test */
8
9
#include "nsMediaFeatures.h"
10
#include "nsGkAtoms.h"
11
#include "nsCSSKeywords.h"
12
#include "nsStyleConsts.h"
13
#include "nsPresContext.h"
14
#include "nsCSSProps.h"
15
#include "nsCSSValue.h"
16
#include "mozilla/LookAndFeel.h"
17
#include "nsDeviceContext.h"
18
#include "nsIBaseWindow.h"
19
#include "nsIDocShell.h"
20
#include "nsIDocument.h"
21
#include "nsIWidget.h"
22
#include "nsContentUtils.h"
23
#include "mozilla/StyleSheet.h"
24
#include "mozilla/StyleSheetInlines.h"
25
26
using namespace mozilla;
27
28
static nsTArray<RefPtr<nsAtom>>* sSystemMetrics = nullptr;
29
30
#ifdef XP_WIN
31
struct OperatingSystemVersionInfo {
32
  LookAndFeel::OperatingSystemVersion mId;
33
  nsStaticAtom** mName;
34
};
35
36
// Os version identities used in the -moz-os-version media query.
37
const OperatingSystemVersionInfo kOsVersionStrings[] = {
38
  { LookAndFeel::eOperatingSystemVersion_Windows7,  &nsGkAtoms::windows_win7 },
39
  { LookAndFeel::eOperatingSystemVersion_Windows8,  &nsGkAtoms::windows_win8 },
40
  { LookAndFeel::eOperatingSystemVersion_Windows10, &nsGkAtoms::windows_win10 }
41
};
42
#endif
43
44
// A helper for four features below
45
static nsSize
46
GetSize(nsIDocument* aDocument)
47
0
{
48
0
  nsPresContext* pc = aDocument->GetPresContext();
49
0
50
0
  // Per spec, return a 0x0 viewport if we're not being rendered. See:
51
0
  //
52
0
  //  * https://github.com/w3c/csswg-drafts/issues/571
53
0
  //  * https://github.com/whatwg/html/issues/1813
54
0
  //
55
0
  if (!pc) {
56
0
    return { };
57
0
  }
58
0
59
0
  if (pc->IsRootPaginatedDocument()) {
60
0
    // We want the page size, including unprintable areas and margins.
61
0
    //
62
0
    // FIXME(emilio, bug 1414600): Not quite!
63
0
    return pc->GetPageSize();
64
0
  }
65
0
66
0
  return pc->GetVisibleArea().Size();
67
0
}
68
69
static bool
70
IsDeviceSizePageSize(nsIDocument* aDocument)
71
0
{
72
0
  nsIDocShell* docShell = aDocument->GetDocShell();
73
0
  if (!docShell) {
74
0
    return false;
75
0
  }
76
0
  return docShell->GetDeviceSizeIsPageSize();
77
0
}
78
79
// A helper for three features below.
80
static nsSize
81
GetDeviceSize(nsIDocument* aDocument)
82
0
{
83
0
  if (nsContentUtils::ShouldResistFingerprinting(aDocument) ||
84
0
      IsDeviceSizePageSize(aDocument)) {
85
0
    return GetSize(aDocument);
86
0
  }
87
0
88
0
  nsPresContext* pc = aDocument->GetPresContext();
89
0
  // NOTE(emilio): We should probably figure out how to return an appropriate
90
0
  // device size here, though in a multi-screen world that makes no sense
91
0
  // really.
92
0
  if (!pc) {
93
0
    return { };
94
0
  }
95
0
96
0
  if (pc->IsRootPaginatedDocument()) {
97
0
    // We want the page size, including unprintable areas and margins.
98
0
    // XXX The spec actually says we want the "page sheet size", but
99
0
    // how is that different?
100
0
    return pc->GetPageSize();
101
0
  }
102
0
103
0
  nsSize size;
104
0
  pc->DeviceContext()->GetDeviceSurfaceDimensions(size.width, size.height);
105
0
  return size;
106
0
}
107
108
bool
109
Gecko_MediaFeatures_IsResourceDocument(nsIDocument* aDocument)
110
0
{
111
0
  return aDocument->IsResourceDoc();
112
0
}
113
114
static nsDeviceContext*
115
GetDeviceContextFor(nsIDocument* aDocument)
116
0
{
117
0
  nsPresContext* pc = aDocument->GetPresContext();
118
0
  if (!pc) {
119
0
    return nullptr;
120
0
  }
121
0
122
0
  // It would be nice to call nsLayoutUtils::GetDeviceContextForScreenInfo here,
123
0
  // except for two things:  (1) it can flush, and flushing is bad here, and (2)
124
0
  // it doesn't really get us consistency in multi-monitor situations *anyway*.
125
0
  return pc->DeviceContext();
126
0
}
127
128
void
129
Gecko_MediaFeatures_GetDeviceSize(nsIDocument* aDocument,
130
                                  nscoord* aWidth,
131
                                  nscoord* aHeight)
132
0
{
133
0
  nsSize size = GetDeviceSize(aDocument);
134
0
  *aWidth = size.width;
135
0
  *aHeight = size.height;
136
0
}
137
138
uint32_t
139
Gecko_MediaFeatures_GetColorDepth(nsIDocument* aDocument)
140
0
{
141
0
  // Use depth of 24 when resisting fingerprinting, or when we're not being
142
0
  // rendered.
143
0
  uint32_t depth = 24;
144
0
145
0
  if (!nsContentUtils::ShouldResistFingerprinting(aDocument)) {
146
0
    if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) {
147
0
      // FIXME: On a monochrome device, return 0!
148
0
      dx->GetDepth(depth);
149
0
    }
150
0
  }
151
0
152
0
  // The spec says to use bits *per color component*, so divide by 3,
153
0
  // and round down, since the spec says to use the smallest when the
154
0
  // color components differ.
155
0
  return depth / 3;
156
0
}
157
158
float
159
Gecko_MediaFeatures_GetResolution(nsIDocument* aDocument)
160
0
{
161
0
  // We're returning resolution in terms of device pixels per css pixel, since
162
0
  // that is the preferred unit for media queries of resolution. This avoids
163
0
  // introducing precision error from conversion to and from less-used
164
0
  // physical units like inches.
165
0
  nsPresContext* pc = aDocument->GetPresContext();
166
0
  if (!pc) {
167
0
    return 1.;
168
0
  }
169
0
170
0
  if (pc->GetOverrideDPPX() > 0.) {
171
0
    return pc->GetOverrideDPPX();
172
0
  }
173
0
174
0
  if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
175
0
    return pc->DeviceContext()->GetFullZoom();
176
0
  }
177
0
  // Get the actual device pixel ratio, which also takes zoom into account.
178
0
  return float(AppUnitsPerCSSPixel()) / pc->DeviceContext()->AppUnitsPerDevPixel();
179
0
}
180
181
static nsIDocument*
182
TopDocument(nsIDocument* aDocument)
183
0
{
184
0
  nsIDocument* current = aDocument;
185
0
  while (nsIDocument* parent = current->GetParentDocument()) {
186
0
    current = parent;
187
0
  }
188
0
  return current;
189
0
}
190
191
StyleDisplayMode
192
Gecko_MediaFeatures_GetDisplayMode(nsIDocument* aDocument)
193
0
{
194
0
  nsIDocument* rootDocument = TopDocument(aDocument);
195
0
196
0
  nsCOMPtr<nsISupports> container = rootDocument->GetContainer();
197
0
  if (nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container)) {
198
0
    nsCOMPtr<nsIWidget> mainWidget;
199
0
    baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
200
0
    if (mainWidget && mainWidget->SizeMode() == nsSizeMode_Fullscreen) {
201
0
      return StyleDisplayMode::Fullscreen;
202
0
    }
203
0
  }
204
0
205
0
  static_assert(nsIDocShell::DISPLAY_MODE_BROWSER == static_cast<int32_t>(StyleDisplayMode::Browser) &&
206
0
                nsIDocShell::DISPLAY_MODE_MINIMAL_UI == static_cast<int32_t>(StyleDisplayMode::MinimalUi) &&
207
0
                nsIDocShell::DISPLAY_MODE_STANDALONE == static_cast<int32_t>(StyleDisplayMode::Standalone) &&
208
0
                nsIDocShell::DISPLAY_MODE_FULLSCREEN == static_cast<int32_t>(StyleDisplayMode::Fullscreen),
209
0
                "nsIDocShell display modes must mach nsStyleConsts.h");
210
0
211
0
  uint32_t displayMode = nsIDocShell::DISPLAY_MODE_BROWSER;
212
0
  if (nsIDocShell* docShell = rootDocument->GetDocShell()) {
213
0
    docShell->GetDisplayMode(&displayMode);
214
0
  }
215
0
216
0
  return static_cast<StyleDisplayMode>(displayMode);
217
0
}
218
219
bool
220
Gecko_MediaFeatures_HasSystemMetric(nsIDocument* aDocument,
221
                                    nsAtom* aMetric,
222
                                    bool aIsAccessibleFromContent)
223
0
{
224
0
  if (aIsAccessibleFromContent &&
225
0
      nsContentUtils::ShouldResistFingerprinting(aDocument)) {
226
0
    return false;
227
0
  }
228
0
229
0
  nsMediaFeatures::InitSystemMetrics();
230
0
  return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
231
0
}
232
233
nsAtom*
234
Gecko_MediaFeatures_GetOperatingSystemVersion(nsIDocument* aDocument)
235
0
{
236
0
  if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
237
0
    return nullptr;
238
0
  }
239
0
240
#ifdef XP_WIN
241
  int32_t metricResult;
242
  if (NS_SUCCEEDED(
243
        LookAndFeel::GetInt(LookAndFeel::eIntID_OperatingSystemVersionIdentifier,
244
                            &metricResult))) {
245
    for (const auto& osVersion : kOsVersionStrings) {
246
      if (metricResult == osVersion.mId) {
247
        return *osVersion.mName;
248
      }
249
    }
250
  }
251
#endif
252
253
0
  return nullptr;
254
0
}
255
256
bool
257
Gecko_MediaFeatures_PrefersReducedMotion(nsIDocument* aDocument)
258
0
{
259
0
  if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
260
0
    return false;
261
0
  }
262
0
  return LookAndFeel::GetInt(LookAndFeel::eIntID_PrefersReducedMotion, 0) == 1;
263
0
}
264
265
static PointerCapabilities
266
GetPointerCapabilities(nsIDocument* aDocument, LookAndFeel::IntID aID)
267
0
{
268
0
  MOZ_ASSERT(aID == LookAndFeel::eIntID_PrimaryPointerCapabilities ||
269
0
             aID == LookAndFeel::eIntID_AllPointerCapabilities);
270
0
271
0
  // The default value is mouse-type pointer.
272
0
  const PointerCapabilities kDefaultCapabilities =
273
0
    PointerCapabilities::Fine | PointerCapabilities::Hover;
274
0
275
0
  if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
276
0
    return kDefaultCapabilities;
277
0
  }
278
0
279
0
  int32_t intValue;
280
0
  nsresult rv = LookAndFeel::GetInt(aID, &intValue);
281
0
  if (NS_FAILED(rv)) {
282
0
    return kDefaultCapabilities;
283
0
  }
284
0
285
0
  return static_cast<PointerCapabilities>(intValue);
286
0
}
287
288
PointerCapabilities
289
Gecko_MediaFeatures_PrimaryPointerCapabilities(nsIDocument* aDocument)
290
0
{
291
0
  return GetPointerCapabilities(aDocument,
292
0
                                LookAndFeel::eIntID_PrimaryPointerCapabilities);
293
0
}
294
295
PointerCapabilities
296
Gecko_MediaFeatures_AllPointerCapabilities(nsIDocument* aDocument)
297
0
{
298
0
  return GetPointerCapabilities(aDocument,
299
0
                                LookAndFeel::eIntID_AllPointerCapabilities);
300
0
}
301
302
/* static */ void
303
nsMediaFeatures::InitSystemMetrics()
304
0
{
305
0
  if (sSystemMetrics)
306
0
    return;
307
0
308
0
  MOZ_ASSERT(NS_IsMainThread());
309
0
310
0
  sSystemMetrics = new nsTArray<RefPtr<nsAtom>>;
311
0
312
0
  /***************************************************************************
313
0
   * ANY METRICS ADDED HERE SHOULD ALSO BE ADDED AS MEDIA QUERIES BELOW      *
314
0
   ***************************************************************************/
315
0
316
0
  int32_t metricResult =
317
0
    LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollArrowStyle);
318
0
  if (metricResult & LookAndFeel::eScrollArrow_StartBackward) {
319
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_scrollbar_start_backward);
320
0
  }
321
0
  if (metricResult & LookAndFeel::eScrollArrow_StartForward) {
322
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_scrollbar_start_forward);
323
0
  }
324
0
  if (metricResult & LookAndFeel::eScrollArrow_EndBackward) {
325
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_scrollbar_end_backward);
326
0
  }
327
0
  if (metricResult & LookAndFeel::eScrollArrow_EndForward) {
328
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_scrollbar_end_forward);
329
0
  }
330
0
331
0
  metricResult =
332
0
    LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollSliderStyle);
333
0
  if (metricResult != LookAndFeel::eScrollThumbStyle_Normal) {
334
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_scrollbar_thumb_proportional);
335
0
  }
336
0
337
0
  metricResult =
338
0
    LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars);
339
0
  if (metricResult) {
340
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_overlay_scrollbars);
341
0
  }
342
0
343
0
  metricResult =
344
0
    LookAndFeel::GetInt(LookAndFeel::eIntID_MenuBarDrag);
345
0
  if (metricResult) {
346
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_menubar_drag);
347
0
  }
348
0
349
0
  nsresult rv =
350
0
    LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsDefaultTheme, &metricResult);
351
0
  if (NS_SUCCEEDED(rv) && metricResult) {
352
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_windows_default_theme);
353
0
  }
354
0
355
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacGraphiteTheme, &metricResult);
356
0
  if (NS_SUCCEEDED(rv) && metricResult) {
357
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_mac_graphite_theme);
358
0
  }
359
0
360
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacYosemiteTheme, &metricResult);
361
0
  if (NS_SUCCEEDED(rv) && metricResult) {
362
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_mac_yosemite_theme);
363
0
  }
364
0
365
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsAccentColorInTitlebar, &metricResult);
366
0
  if (NS_SUCCEEDED(rv) && metricResult) {
367
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_windows_accent_color_in_titlebar);
368
0
  }
369
0
370
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_DWMCompositor, &metricResult);
371
0
  if (NS_SUCCEEDED(rv) && metricResult) {
372
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_windows_compositor);
373
0
  }
374
0
375
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsGlass, &metricResult);
376
0
  if (NS_SUCCEEDED(rv) && metricResult) {
377
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_windows_glass);
378
0
  }
379
0
380
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsClassic, &metricResult);
381
0
  if (NS_SUCCEEDED(rv) && metricResult) {
382
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_windows_classic);
383
0
  }
384
0
385
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_TouchEnabled, &metricResult);
386
0
  if (NS_SUCCEEDED(rv) && metricResult) {
387
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_touch_enabled);
388
0
  }
389
0
390
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_SwipeAnimationEnabled,
391
0
                           &metricResult);
392
0
  if (NS_SUCCEEDED(rv) && metricResult) {
393
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_swipe_animation_enabled);
394
0
  }
395
0
396
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDAvailable,
397
0
                           &metricResult);
398
0
  if (NS_SUCCEEDED(rv) && metricResult) {
399
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_gtk_csd_available);
400
0
  }
401
0
402
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDMinimizeButton,
403
0
                           &metricResult);
404
0
  if (NS_SUCCEEDED(rv) && metricResult) {
405
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_gtk_csd_minimize_button);
406
0
  }
407
0
408
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDMaximizeButton,
409
0
                           &metricResult);
410
0
  if (NS_SUCCEEDED(rv) && metricResult) {
411
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_gtk_csd_maximize_button);
412
0
  }
413
0
414
0
  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDCloseButton,
415
0
                           &metricResult);
416
0
  if (NS_SUCCEEDED(rv) && metricResult) {
417
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_gtk_csd_close_button);
418
0
  }
419
0
420
0
  metricResult =
421
0
    LookAndFeel::GetInt(LookAndFeel::eIntID_SystemUsesDarkTheme);
422
0
  if (metricResult) {
423
0
    sSystemMetrics->AppendElement(nsGkAtoms::_moz_system_dark_theme);
424
0
  }
425
0
}
426
427
/* static */ void
428
nsMediaFeatures::FreeSystemMetrics()
429
0
{
430
0
  delete sSystemMetrics;
431
0
  sSystemMetrics = nullptr;
432
0
}
433
434
/* static */ void
435
nsMediaFeatures::Shutdown()
436
0
{
437
0
  FreeSystemMetrics();
438
0
}