Bug 1698786: part 2) Change some compile-time dependent `printf`s to `MOZ_LOG` in...
[gecko.git] / layout / style / nsMediaFeatures.cpp
blob445a031b11c6e3c65ed859a03a83a21da88f1472
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 /* the features that media queries can test */
9 #include "nsMediaFeatures.h"
10 #include "nsGkAtoms.h"
11 #include "nsStyleConsts.h"
12 #include "nsPresContext.h"
13 #include "nsCSSProps.h"
14 #include "nsCSSValue.h"
15 #include "mozilla/LookAndFeel.h"
16 #include "nsDeviceContext.h"
17 #include "nsIBaseWindow.h"
18 #include "nsIDocShell.h"
19 #include "nsIPrintSettings.h"
20 #include "mozilla/dom/Document.h"
21 #include "mozilla/dom/DocumentInlines.h"
22 #include "mozilla/dom/BrowsingContextBinding.h"
23 #include "nsIWidget.h"
24 #include "nsContentUtils.h"
25 #include "mozilla/RelativeLuminanceUtils.h"
26 #include "mozilla/StaticPrefs_browser.h"
27 #include "mozilla/StyleSheet.h"
28 #include "mozilla/StyleSheetInlines.h"
29 #include "mozilla/GeckoBindings.h"
30 #include "PreferenceSheet.h"
31 #include "nsGlobalWindowOuter.h"
33 using namespace mozilla;
34 using mozilla::dom::DisplayMode;
35 using mozilla::dom::Document;
37 static nsTArray<const nsStaticAtom*>* sSystemMetrics = nullptr;
39 // A helper for four features below
40 static nsSize GetSize(const Document* aDocument) {
41 nsPresContext* pc = aDocument->GetPresContext();
43 // Per spec, return a 0x0 viewport if we're not being rendered. See:
45 // * https://github.com/w3c/csswg-drafts/issues/571
46 // * https://github.com/whatwg/html/issues/1813
48 if (!pc) {
49 return {};
52 if (pc->IsRootPaginatedDocument()) {
53 // We want the page size, including unprintable areas and margins.
55 // FIXME(emilio, bug 1414600): Not quite!
56 return pc->GetPageSize();
59 return pc->GetVisibleArea().Size();
62 // A helper for three features below.
63 static nsSize GetDeviceSize(const Document* aDocument) {
64 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
65 return GetSize(aDocument);
68 // Media queries in documents in an RDM pane should use the simulated
69 // device size.
70 Maybe<CSSIntSize> deviceSize =
71 nsGlobalWindowOuter::GetRDMDeviceSize(*aDocument);
72 if (deviceSize.isSome()) {
73 return CSSPixel::ToAppUnits(deviceSize.value());
76 nsPresContext* pc = aDocument->GetPresContext();
77 // NOTE(emilio): We should probably figure out how to return an appropriate
78 // device size here, though in a multi-screen world that makes no sense
79 // really.
80 if (!pc) {
81 return {};
84 if (pc->IsRootPaginatedDocument()) {
85 // We want the page size, including unprintable areas and margins.
86 // XXX The spec actually says we want the "page sheet size", but
87 // how is that different?
88 return pc->GetPageSize();
91 nsSize size;
92 pc->DeviceContext()->GetDeviceSurfaceDimensions(size.width, size.height);
93 return size;
96 bool Gecko_MediaFeatures_IsResourceDocument(const Document* aDocument) {
97 return aDocument->IsResourceDoc();
100 bool Gecko_MediaFeatures_ShouldAvoidNativeTheme(const Document* aDocument) {
101 return aDocument->ShouldAvoidNativeTheme();
104 static nsDeviceContext* GetDeviceContextFor(const Document* aDocument) {
105 nsPresContext* pc = aDocument->GetPresContext();
106 if (!pc) {
107 return nullptr;
110 // It would be nice to call nsLayoutUtils::GetDeviceContextForScreenInfo here,
111 // except for two things: (1) it can flush, and flushing is bad here, and (2)
112 // it doesn't really get us consistency in multi-monitor situations *anyway*.
113 return pc->DeviceContext();
116 void Gecko_MediaFeatures_GetDeviceSize(const Document* aDocument,
117 nscoord* aWidth, nscoord* aHeight) {
118 nsSize size = GetDeviceSize(aDocument);
119 *aWidth = size.width;
120 *aHeight = size.height;
123 uint32_t Gecko_MediaFeatures_GetMonochromeBitsPerPixel(
124 const Document* aDocument) {
125 // The default bits per pixel for a monochrome device. We could propagate this
126 // further to nsIPrintSettings, but Gecko doesn't actually know this value
127 // from the hardware, so it seems silly to do so.
128 static constexpr uint32_t kDefaultMonochromeBpp = 8;
130 nsPresContext* pc = aDocument->GetPresContext();
131 if (!pc) {
132 return 0;
134 nsIPrintSettings* ps = pc->GetPrintSettings();
135 if (!ps) {
136 return 0;
138 bool color = true;
139 ps->GetPrintInColor(&color);
140 return color ? 0 : kDefaultMonochromeBpp;
143 uint32_t Gecko_MediaFeatures_GetColorDepth(const Document* aDocument) {
144 if (Gecko_MediaFeatures_GetMonochromeBitsPerPixel(aDocument) != 0) {
145 // If we're a monochrome device, then the color depth is zero.
146 return 0;
149 // Use depth of 24 when resisting fingerprinting, or when we're not being
150 // rendered.
151 uint32_t depth = 24;
153 if (!nsContentUtils::ShouldResistFingerprinting(aDocument)) {
154 if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) {
155 dx->GetDepth(depth);
159 // The spec says to use bits *per color component*, so divide by 3,
160 // and round down, since the spec says to use the smallest when the
161 // color components differ.
162 return depth / 3;
165 float Gecko_MediaFeatures_GetResolution(const Document* aDocument) {
166 // We're returning resolution in terms of device pixels per css pixel, since
167 // that is the preferred unit for media queries of resolution. This avoids
168 // introducing precision error from conversion to and from less-used
169 // physical units like inches.
170 nsPresContext* pc = aDocument->GetPresContext();
171 if (!pc) {
172 return 1.;
175 if (pc->GetOverrideDPPX() > 0.) {
176 return pc->GetOverrideDPPX();
179 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
180 return pc->DeviceContext()->GetFullZoom();
182 // Get the actual device pixel ratio, which also takes zoom into account.
183 return float(AppUnitsPerCSSPixel()) /
184 pc->DeviceContext()->AppUnitsPerDevPixel();
187 static const Document* TopDocument(const Document* aDocument) {
188 const Document* current = aDocument;
189 while (const Document* parent = current->GetInProcessParentDocument()) {
190 current = parent;
192 return current;
195 StyleDisplayMode Gecko_MediaFeatures_GetDisplayMode(const Document* aDocument) {
196 const Document* rootDocument = TopDocument(aDocument);
198 nsCOMPtr<nsISupports> container = rootDocument->GetContainer();
199 if (nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container)) {
200 nsCOMPtr<nsIWidget> mainWidget;
201 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
202 if (mainWidget && mainWidget->SizeMode() == nsSizeMode_Fullscreen) {
203 return StyleDisplayMode::Fullscreen;
207 static_assert(static_cast<int32_t>(DisplayMode::Browser) ==
208 static_cast<int32_t>(StyleDisplayMode::Browser) &&
209 static_cast<int32_t>(DisplayMode::Minimal_ui) ==
210 static_cast<int32_t>(StyleDisplayMode::MinimalUi) &&
211 static_cast<int32_t>(DisplayMode::Standalone) ==
212 static_cast<int32_t>(StyleDisplayMode::Standalone) &&
213 static_cast<int32_t>(DisplayMode::Fullscreen) ==
214 static_cast<int32_t>(StyleDisplayMode::Fullscreen),
215 "DisplayMode must mach nsStyleConsts.h");
217 dom::BrowsingContext* browsingContext = aDocument->GetBrowsingContext();
218 if (!browsingContext) {
219 return StyleDisplayMode::Browser;
221 return static_cast<StyleDisplayMode>(browsingContext->DisplayMode());
224 bool Gecko_MediaFeatures_HasSystemMetric(const Document* aDocument,
225 nsAtom* aMetric,
226 bool aIsAccessibleFromContent) {
227 if (aIsAccessibleFromContent &&
228 nsContentUtils::ShouldResistFingerprinting(aDocument)) {
229 return false;
232 nsMediaFeatures::InitSystemMetrics();
233 return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
236 nsAtom* Gecko_MediaFeatures_GetOperatingSystemVersion(
237 const Document* aDocument) {
238 using OperatingSystemVersion = LookAndFeel::OperatingSystemVersion;
240 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
241 return nullptr;
244 int32_t metricResult;
245 if (NS_FAILED(LookAndFeel::GetInt(
246 LookAndFeel::IntID::OperatingSystemVersionIdentifier,
247 &metricResult))) {
248 return nullptr;
251 switch (OperatingSystemVersion(metricResult)) {
252 case OperatingSystemVersion::Windows7:
253 return nsGkAtoms::windows_win7;
254 case OperatingSystemVersion::Windows8:
255 return nsGkAtoms::windows_win8;
256 case OperatingSystemVersion::Windows10:
257 return nsGkAtoms::windows_win10;
258 default:
259 return nullptr;
263 bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) {
264 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
265 return false;
267 return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
270 StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme(
271 const Document* aDocument) {
272 return aDocument->PrefersColorScheme();
275 StylePrefersContrast Gecko_MediaFeatures_PrefersContrast(
276 const Document* aDocument) {
277 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
278 return StylePrefersContrast::NoPreference;
280 // Neither Linux, Windows, nor Mac have a way to indicate that low contrast is
281 // preferred so we use the presence of an accessibility theme as a signal.
282 if (!!LookAndFeel::GetInt(LookAndFeel::IntID::UseAccessibilityTheme, 0)) {
283 return StylePrefersContrast::More;
285 return StylePrefersContrast::NoPreference;
288 static PointerCapabilities GetPointerCapabilities(const Document* aDocument,
289 LookAndFeel::IntID aID) {
290 MOZ_ASSERT(aID == LookAndFeel::IntID::PrimaryPointerCapabilities ||
291 aID == LookAndFeel::IntID::AllPointerCapabilities);
292 MOZ_ASSERT(aDocument);
294 if (dom::BrowsingContext* bc = aDocument->GetBrowsingContext()) {
295 // The touch-events-override happens only for the Responsive Design Mode so
296 // that we don't need to care about ResistFingerprinting.
297 if (bc->TouchEventsOverride() == dom::TouchEventsOverride::Enabled) {
298 return PointerCapabilities::Coarse;
302 // The default value for Desktop is mouse-type pointer, and for Android
303 // a coarse pointer.
304 const PointerCapabilities kDefaultCapabilities =
305 #ifdef ANDROID
306 PointerCapabilities::Coarse;
307 #else
308 PointerCapabilities::Fine | PointerCapabilities::Hover;
309 #endif
311 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
312 return kDefaultCapabilities;
315 int32_t intValue;
316 nsresult rv = LookAndFeel::GetInt(aID, &intValue);
317 if (NS_FAILED(rv)) {
318 return kDefaultCapabilities;
321 return static_cast<PointerCapabilities>(intValue);
324 PointerCapabilities Gecko_MediaFeatures_PrimaryPointerCapabilities(
325 const Document* aDocument) {
326 return GetPointerCapabilities(aDocument,
327 LookAndFeel::IntID::PrimaryPointerCapabilities);
330 PointerCapabilities Gecko_MediaFeatures_AllPointerCapabilities(
331 const Document* aDocument) {
332 return GetPointerCapabilities(aDocument,
333 LookAndFeel::IntID::AllPointerCapabilities);
336 /* static */
337 void nsMediaFeatures::InitSystemMetrics() {
338 if (sSystemMetrics) return;
340 MOZ_ASSERT(NS_IsMainThread());
342 sSystemMetrics = new nsTArray<const nsStaticAtom*>;
344 /***************************************************************************
345 * ANY METRICS ADDED HERE SHOULD ALSO BE ADDED AS MEDIA QUERIES BELOW *
346 ***************************************************************************/
348 int32_t metricResult =
349 LookAndFeel::GetInt(LookAndFeel::IntID::ScrollArrowStyle);
350 if (metricResult & LookAndFeel::eScrollArrow_StartBackward) {
351 sSystemMetrics->AppendElement(
352 (nsStaticAtom*)nsGkAtoms::_moz_scrollbar_start_backward);
354 if (metricResult & LookAndFeel::eScrollArrow_StartForward) {
355 sSystemMetrics->AppendElement(
356 (nsStaticAtom*)nsGkAtoms::_moz_scrollbar_start_forward);
358 if (metricResult & LookAndFeel::eScrollArrow_EndBackward) {
359 sSystemMetrics->AppendElement(
360 (nsStaticAtom*)nsGkAtoms::_moz_scrollbar_end_backward);
362 if (metricResult & LookAndFeel::eScrollArrow_EndForward) {
363 sSystemMetrics->AppendElement(
364 (nsStaticAtom*)nsGkAtoms::_moz_scrollbar_end_forward);
367 metricResult = LookAndFeel::GetInt(LookAndFeel::IntID::ScrollSliderStyle);
368 if (metricResult != LookAndFeel::eScrollThumbStyle_Normal) {
369 sSystemMetrics->AppendElement(
370 (nsStaticAtom*)nsGkAtoms::_moz_scrollbar_thumb_proportional);
373 metricResult = LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars);
374 if (metricResult) {
375 sSystemMetrics->AppendElement(
376 (nsStaticAtom*)nsGkAtoms::_moz_overlay_scrollbars);
379 metricResult = LookAndFeel::GetInt(LookAndFeel::IntID::MenuBarDrag);
380 if (metricResult) {
381 sSystemMetrics->AppendElement((nsStaticAtom*)nsGkAtoms::_moz_menubar_drag);
384 nsresult rv = LookAndFeel::GetInt(LookAndFeel::IntID::WindowsDefaultTheme,
385 &metricResult);
386 if (NS_SUCCEEDED(rv) && metricResult) {
387 sSystemMetrics->AppendElement(
388 (nsStaticAtom*)nsGkAtoms::_moz_windows_default_theme);
391 rv = LookAndFeel::GetInt(LookAndFeel::IntID::MacGraphiteTheme, &metricResult);
392 if (NS_SUCCEEDED(rv) && metricResult) {
393 sSystemMetrics->AppendElement(
394 (nsStaticAtom*)nsGkAtoms::_moz_mac_graphite_theme);
397 rv = LookAndFeel::GetInt(LookAndFeel::IntID::MacBigSurTheme, &metricResult);
398 if (NS_SUCCEEDED(rv) && metricResult) {
399 sSystemMetrics->AppendElement(
400 (nsStaticAtom*)nsGkAtoms::_moz_mac_big_sur_theme);
403 rv = LookAndFeel::GetInt(LookAndFeel::IntID::WindowsAccentColorInTitlebar,
404 &metricResult);
405 if (NS_SUCCEEDED(rv) && metricResult) {
406 sSystemMetrics->AppendElement(
407 (nsStaticAtom*)nsGkAtoms::_moz_windows_accent_color_in_titlebar);
410 rv = LookAndFeel::GetInt(LookAndFeel::IntID::DWMCompositor, &metricResult);
411 if (NS_SUCCEEDED(rv) && metricResult) {
412 sSystemMetrics->AppendElement(
413 (nsStaticAtom*)nsGkAtoms::_moz_windows_compositor);
416 rv = LookAndFeel::GetInt(LookAndFeel::IntID::WindowsGlass, &metricResult);
417 if (NS_SUCCEEDED(rv) && metricResult) {
418 sSystemMetrics->AppendElement((nsStaticAtom*)nsGkAtoms::_moz_windows_glass);
421 rv = LookAndFeel::GetInt(LookAndFeel::IntID::WindowsClassic, &metricResult);
422 if (NS_SUCCEEDED(rv) && metricResult) {
423 sSystemMetrics->AppendElement(
424 (nsStaticAtom*)nsGkAtoms::_moz_windows_classic);
427 rv = LookAndFeel::GetInt(LookAndFeel::IntID::SwipeAnimationEnabled,
428 &metricResult);
429 if (NS_SUCCEEDED(rv) && metricResult) {
430 sSystemMetrics->AppendElement(
431 (nsStaticAtom*)nsGkAtoms::_moz_swipe_animation_enabled);
434 rv = LookAndFeel::GetInt(LookAndFeel::IntID::GTKCSDAvailable, &metricResult);
435 if (NS_SUCCEEDED(rv) && metricResult) {
436 sSystemMetrics->AppendElement(
437 (nsStaticAtom*)nsGkAtoms::_moz_gtk_csd_available);
440 rv = LookAndFeel::GetInt(LookAndFeel::IntID::GTKCSDHideTitlebarByDefault,
441 &metricResult);
442 if (NS_SUCCEEDED(rv) && metricResult) {
443 sSystemMetrics->AppendElement(
444 (nsStaticAtom*)nsGkAtoms::_moz_gtk_csd_hide_titlebar_by_default);
447 rv = LookAndFeel::GetInt(LookAndFeel::IntID::GTKCSDTransparentBackground,
448 &metricResult);
449 if (NS_SUCCEEDED(rv) && metricResult) {
450 sSystemMetrics->AppendElement(
451 (nsStaticAtom*)nsGkAtoms::_moz_gtk_csd_transparent_background);
454 rv = LookAndFeel::GetInt(LookAndFeel::IntID::GTKCSDMinimizeButton,
455 &metricResult);
456 if (NS_SUCCEEDED(rv) && metricResult) {
457 sSystemMetrics->AppendElement(
458 (nsStaticAtom*)nsGkAtoms::_moz_gtk_csd_minimize_button);
461 rv = LookAndFeel::GetInt(LookAndFeel::IntID::GTKCSDMaximizeButton,
462 &metricResult);
463 if (NS_SUCCEEDED(rv) && metricResult) {
464 sSystemMetrics->AppendElement(
465 (nsStaticAtom*)nsGkAtoms::_moz_gtk_csd_maximize_button);
468 rv =
469 LookAndFeel::GetInt(LookAndFeel::IntID::GTKCSDCloseButton, &metricResult);
470 if (NS_SUCCEEDED(rv) && metricResult) {
471 sSystemMetrics->AppendElement(
472 (nsStaticAtom*)nsGkAtoms::_moz_gtk_csd_close_button);
475 rv = LookAndFeel::GetInt(LookAndFeel::IntID::GTKCSDReversedPlacement,
476 &metricResult);
477 if (NS_SUCCEEDED(rv) && metricResult) {
478 sSystemMetrics->AppendElement(
479 (nsStaticAtom*)nsGkAtoms::_moz_gtk_csd_reversed_placement);
482 rv = LookAndFeel::GetInt(LookAndFeel::IntID::SystemUsesDarkTheme,
483 &metricResult);
484 if (NS_SUCCEEDED(rv) && metricResult) {
485 sSystemMetrics->AppendElement(
486 (nsStaticAtom*)nsGkAtoms::_moz_system_dark_theme);
490 /* static */
491 void nsMediaFeatures::FreeSystemMetrics() {
492 delete sSystemMetrics;
493 sSystemMetrics = nullptr;
496 /* static */
497 void nsMediaFeatures::Shutdown() { FreeSystemMetrics(); }