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 "nsCSSValue.h"
15 #ifdef XP_WIN
16 #include "mozilla/LookAndFeel.h"
17 #endif
18 #ifdef MOZ_OLD_STYLE
19 #include "nsCSSRuleProcessor.h"
20 #endif
21 #include "nsDeviceContext.h"
22 #include "nsIBaseWindow.h"
23 #include "nsIDocShell.h"
24 #include "nsIDocument.h"
25 #include "nsIWidget.h"
26 #include "nsContentUtils.h"
27 #include "mozilla/StyleSheet.h"
28 #include "mozilla/StyleSheetInlines.h"
29
30 using namespace mozilla;
31
32 static nsTArray<RefPtr<nsAtom>>* sSystemMetrics = nullptr;
33
34 #ifdef XP_WIN
35 // Cached theme identifier for the moz-windows-theme media query.
36 static uint8_t sWinThemeId = LookAndFeel::eWindowsTheme_Generic;
37 #endif
38
39 static const nsCSSProps::KTableEntry kOrientationKeywords[] = {
40 {eCSSKeyword_portrait, StyleOrientation::Portrait},
41 {eCSSKeyword_landscape, StyleOrientation::Landscape},
42 {eCSSKeyword_UNKNOWN, -1}};
43
44 static const nsCSSProps::KTableEntry kScanKeywords[] = {
45 {eCSSKeyword_progressive, StyleScan::Progressive},
46 {eCSSKeyword_interlace, StyleScan::Interlace},
47 {eCSSKeyword_UNKNOWN, -1}};
48
49 static const nsCSSProps::KTableEntry kDisplayModeKeywords[] = {
50 {eCSSKeyword_browser, StyleDisplayMode::Browser},
51 {eCSSKeyword_minimal_ui, StyleDisplayMode::MinimalUi},
52 {eCSSKeyword_standalone, StyleDisplayMode::Standalone},
53 {eCSSKeyword_fullscreen, StyleDisplayMode::Fullscreen},
54 {eCSSKeyword_UNKNOWN, -1}};
55
56 #ifdef XP_WIN
57 struct WindowsThemeName {
58 LookAndFeel::WindowsTheme mId;
59 nsStaticAtom** mName;
60 };
61
62 // Windows theme identities used in the -moz-windows-theme media query.
63 const WindowsThemeName kThemeStrings[] = {
64 {LookAndFeel::eWindowsTheme_Aero, &nsGkAtoms::aero},
65 {LookAndFeel::eWindowsTheme_AeroLite, &nsGkAtoms::aero_lite},
66 {LookAndFeel::eWindowsTheme_LunaBlue, &nsGkAtoms::luna_blue},
67 {LookAndFeel::eWindowsTheme_LunaOlive, &nsGkAtoms::luna_olive},
68 {LookAndFeel::eWindowsTheme_LunaSilver, &nsGkAtoms::luna_silver},
69 {LookAndFeel::eWindowsTheme_Royale, &nsGkAtoms::royale},
70 {LookAndFeel::eWindowsTheme_Zune, &nsGkAtoms::zune},
71 {LookAndFeel::eWindowsTheme_Generic, &nsGkAtoms::generic_}};
72
73 struct OperatingSystemVersionInfo {
74 LookAndFeel::OperatingSystemVersion mId;
75 nsStaticAtom** mName;
76 };
77
78 // Os version identities used in the -moz-os-version media query.
79 const OperatingSystemVersionInfo kOsVersionStrings[] = {
80 {LookAndFeel::eOperatingSystemVersion_Windows7, &nsGkAtoms::windows_win7},
81 {LookAndFeel::eOperatingSystemVersion_Windows8, &nsGkAtoms::windows_win8},
82 {LookAndFeel::eOperatingSystemVersion_Windows10,
83 &nsGkAtoms::windows_win10}};
84 #endif
85
86 // A helper for four features below
GetSize(nsIDocument * aDocument)87 static nsSize GetSize(nsIDocument* aDocument) {
88 nsPresContext* pc = aDocument->GetPresContext();
89
90 // Per spec, return a 0x0 viewport if we're not being rendered. See:
91 //
92 // * https://github.com/w3c/csswg-drafts/issues/571
93 // * https://github.com/whatwg/html/issues/1813
94 //
95 if (!pc) {
96 return {};
97 }
98
99 if (pc->IsRootPaginatedDocument()) {
100 // We want the page size, including unprintable areas and margins.
101 //
102 // FIXME(emilio, bug 1414600): Not quite!
103 return pc->GetPageSize();
104 }
105
106 return pc->GetVisibleArea().Size();
107 }
108
GetWidth(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)109 static void GetWidth(nsIDocument* aDocument, const nsMediaFeature*,
110 nsCSSValue& aResult) {
111 nsSize size = GetSize(aDocument);
112 aResult.SetFloatValue(CSSPixel::FromAppUnits(size.width), eCSSUnit_Pixel);
113 }
114
GetHeight(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)115 static void GetHeight(nsIDocument* aDocument, const nsMediaFeature*,
116 nsCSSValue& aResult) {
117 nsSize size = GetSize(aDocument);
118 aResult.SetFloatValue(CSSPixel::FromAppUnits(size.height), eCSSUnit_Pixel);
119 }
120
IsDeviceSizePageSize(nsIDocument * aDocument)121 static bool IsDeviceSizePageSize(nsIDocument* aDocument) {
122 nsIDocShell* docShell = aDocument->GetDocShell();
123 if (!docShell) {
124 return false;
125 }
126 return docShell->GetDeviceSizeIsPageSize();
127 }
128
129 // A helper for three features below.
GetDeviceSize(nsIDocument * aDocument)130 static nsSize GetDeviceSize(nsIDocument* aDocument) {
131 if (nsContentUtils::ShouldResistFingerprinting(aDocument) ||
132 IsDeviceSizePageSize(aDocument)) {
133 return GetSize(aDocument);
134 }
135
136 nsPresContext* pc = aDocument->GetPresContext();
137 // NOTE(emilio): We should probably figure out how to return an appropriate
138 // device size here, though in a multi-screen world that makes no sense
139 // really.
140 if (!pc) {
141 return {};
142 }
143
144 if (pc->IsRootPaginatedDocument()) {
145 // We want the page size, including unprintable areas and margins.
146 // XXX The spec actually says we want the "page sheet size", but
147 // how is that different?
148 return pc->GetPageSize();
149 }
150
151 nsSize size;
152 pc->DeviceContext()->GetDeviceSurfaceDimensions(size.width, size.height);
153 return size;
154 }
155
GetDeviceWidth(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)156 static void GetDeviceWidth(nsIDocument* aDocument, const nsMediaFeature*,
157 nsCSSValue& aResult) {
158 nsSize size = GetDeviceSize(aDocument);
159 aResult.SetFloatValue(CSSPixel::FromAppUnits(size.width), eCSSUnit_Pixel);
160 }
161
GetDeviceHeight(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)162 static void GetDeviceHeight(nsIDocument* aDocument, const nsMediaFeature*,
163 nsCSSValue& aResult) {
164 nsSize size = GetDeviceSize(aDocument);
165 aResult.SetFloatValue(CSSPixel::FromAppUnits(size.height), eCSSUnit_Pixel);
166 }
167
GetOrientation(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)168 static void GetOrientation(nsIDocument* aDocument, const nsMediaFeature*,
169 nsCSSValue& aResult) {
170 nsSize size = GetSize(aDocument);
171 // Per spec, square viewports should be 'portrait'
172 auto orientation = size.width > size.height ? StyleOrientation::Landscape
173 : StyleOrientation::Portrait;
174 aResult.SetEnumValue(orientation);
175 }
176
GetDeviceOrientation(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)177 static void GetDeviceOrientation(nsIDocument* aDocument, const nsMediaFeature*,
178 nsCSSValue& aResult) {
179 nsSize size = GetDeviceSize(aDocument);
180 // Per spec, square viewports should be 'portrait'
181 auto orientation = size.width > size.height ? StyleOrientation::Landscape
182 : StyleOrientation::Portrait;
183 aResult.SetEnumValue(orientation);
184 }
185
GetIsResourceDocument(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)186 static void GetIsResourceDocument(nsIDocument* aDocument, const nsMediaFeature*,
187 nsCSSValue& aResult) {
188 aResult.SetIntValue(aDocument->IsResourceDoc() ? 1 : 0, eCSSUnit_Integer);
189 }
190
191 // Helper for two features below
MakeArray(const nsSize & aSize,nsCSSValue & aResult)192 static void MakeArray(const nsSize& aSize, nsCSSValue& aResult) {
193 RefPtr<nsCSSValue::Array> a = nsCSSValue::Array::Create(2);
194
195 a->Item(0).SetIntValue(aSize.width, eCSSUnit_Integer);
196 a->Item(1).SetIntValue(aSize.height, eCSSUnit_Integer);
197
198 aResult.SetArrayValue(a, eCSSUnit_Array);
199 }
200
GetAspectRatio(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)201 static void GetAspectRatio(nsIDocument* aDocument, const nsMediaFeature*,
202 nsCSSValue& aResult) {
203 MakeArray(GetSize(aDocument), aResult);
204 }
205
GetDeviceAspectRatio(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)206 static void GetDeviceAspectRatio(nsIDocument* aDocument, const nsMediaFeature*,
207 nsCSSValue& aResult) {
208 MakeArray(GetDeviceSize(aDocument), aResult);
209 }
210
GetDeviceContextFor(nsIDocument * aDocument)211 static nsDeviceContext* GetDeviceContextFor(nsIDocument* aDocument) {
212 nsPresContext* pc = aDocument->GetPresContext();
213 if (!pc) {
214 return nullptr;
215 }
216
217 // It would be nice to call nsLayoutUtils::GetDeviceContextForScreenInfo here,
218 // except for two things: (1) it can flush, and flushing is bad here, and (2)
219 // it doesn't really get us consistency in multi-monitor situations *anyway*.
220 return pc->DeviceContext();
221 }
222
GetColor(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)223 static void GetColor(nsIDocument* aDocument, const nsMediaFeature*,
224 nsCSSValue& aResult) {
225 // Use depth of 24 when resisting fingerprinting, or when we're not being
226 // rendered.
227 uint32_t depth = 24;
228
229 if (!nsContentUtils::ShouldResistFingerprinting(aDocument)) {
230 if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) {
231 // FIXME: On a monochrome device, return 0!
232 dx->GetDepth(depth);
233 }
234 }
235
236 // The spec says to use bits *per color component*, so divide by 3,
237 // and round down, since the spec says to use the smallest when the
238 // color components differ.
239 depth /= 3;
240 aResult.SetIntValue(int32_t(depth), eCSSUnit_Integer);
241 }
242
GetColorIndex(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)243 static void GetColorIndex(nsIDocument* aDocument, const nsMediaFeature*,
244 nsCSSValue& aResult) {
245 // We should return zero if the device does not use a color lookup
246 // table. Stuart says that our handling of displays with 8-bit
247 // color is bad enough that we never change the lookup table to
248 // match what we're trying to display, so perhaps we should always
249 // return zero. Given that there isn't any better information
250 // exposed, we don't have much other choice.
251 aResult.SetIntValue(0, eCSSUnit_Integer);
252 }
253
GetMonochrome(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)254 static void GetMonochrome(nsIDocument* aDocument, const nsMediaFeature*,
255 nsCSSValue& aResult) {
256 // For color devices we should return 0.
257 // FIXME: On a monochrome device, return the actual color depth, not
258 // 0!
259 aResult.SetIntValue(0, eCSSUnit_Integer);
260 }
261
GetResolution(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)262 static void GetResolution(nsIDocument* aDocument, const nsMediaFeature*,
263 nsCSSValue& aResult) {
264 // We're returning resolution in terms of device pixels per css pixel, since
265 // that is the preferred unit for media queries of resolution. This avoids
266 // introducing precision error from conversion to and from less-used
267 // physical units like inches.
268
269 float dppx = 1.;
270
271 if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) {
272 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
273 dppx = dx->GetFullZoom();
274 } else {
275 // Get the actual device pixel ratio, which also takes zoom into account.
276 dppx = float(nsPresContext::AppUnitsPerCSSPixel()) /
277 dx->AppUnitsPerDevPixel();
278 }
279 }
280
281 aResult.SetFloatValue(dppx, eCSSUnit_Pixel);
282 }
283
GetScan(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)284 static void GetScan(nsIDocument* aDocument, const nsMediaFeature*,
285 nsCSSValue& aResult) {
286 // Since Gecko doesn't support the 'tv' media type, the 'scan'
287 // feature is never present.
288 aResult.Reset();
289 }
290
TopDocument(nsIDocument * aDocument)291 static nsIDocument* TopDocument(nsIDocument* aDocument) {
292 nsIDocument* current = aDocument;
293 while (nsIDocument* parent = current->GetParentDocument()) {
294 current = parent;
295 }
296 return current;
297 }
298
GetDisplayMode(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)299 static void GetDisplayMode(nsIDocument* aDocument, const nsMediaFeature*,
300 nsCSSValue& aResult) {
301 nsIDocument* rootDocument = TopDocument(aDocument);
302
303 nsCOMPtr<nsISupports> container = rootDocument->GetContainer();
304 if (nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container)) {
305 nsCOMPtr<nsIWidget> mainWidget;
306 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
307 if (mainWidget && mainWidget->SizeMode() == nsSizeMode_Fullscreen) {
308 aResult.SetEnumValue(StyleDisplayMode::Fullscreen);
309 return;
310 }
311 }
312
313 static_assert(nsIDocShell::DISPLAY_MODE_BROWSER ==
314 static_cast<int32_t>(StyleDisplayMode::Browser) &&
315 nsIDocShell::DISPLAY_MODE_MINIMAL_UI ==
316 static_cast<int32_t>(StyleDisplayMode::MinimalUi) &&
317 nsIDocShell::DISPLAY_MODE_STANDALONE ==
318 static_cast<int32_t>(StyleDisplayMode::Standalone) &&
319 nsIDocShell::DISPLAY_MODE_FULLSCREEN ==
320 static_cast<int32_t>(StyleDisplayMode::Fullscreen),
321 "nsIDocShell display modes must mach nsStyleConsts.h");
322
323 uint32_t displayMode = nsIDocShell::DISPLAY_MODE_BROWSER;
324 if (nsIDocShell* docShell = rootDocument->GetDocShell()) {
325 docShell->GetDisplayMode(&displayMode);
326 }
327
328 aResult.SetEnumValue(static_cast<StyleDisplayMode>(displayMode));
329 }
330
GetGrid(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)331 static void GetGrid(nsIDocument* aDocument, const nsMediaFeature*,
332 nsCSSValue& aResult) {
333 // Gecko doesn't support grid devices (e.g., ttys), so the 'grid'
334 // feature is always 0.
335 aResult.SetIntValue(0, eCSSUnit_Integer);
336 }
337
GetDevicePixelRatio(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)338 static void GetDevicePixelRatio(nsIDocument* aDocument, const nsMediaFeature*,
339 nsCSSValue& aResult) {
340 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
341 aResult.SetFloatValue(1.0, eCSSUnit_Number);
342 return;
343 }
344
345 nsIPresShell* presShell = aDocument->GetShell();
346 if (!presShell) {
347 aResult.SetFloatValue(1.0, eCSSUnit_Number);
348 return;
349 }
350
351 nsPresContext* pc = presShell->GetPresContext();
352 if (!pc) {
353 aResult.SetFloatValue(1.0, eCSSUnit_Number);
354 return;
355 }
356
357 float ratio = pc->CSSPixelsToDevPixels(1.0f);
358 aResult.SetFloatValue(ratio, eCSSUnit_Number);
359 }
360
GetTransform3d(nsIDocument * aDocument,const nsMediaFeature *,nsCSSValue & aResult)361 static void GetTransform3d(nsIDocument* aDocument, const nsMediaFeature*,
362 nsCSSValue& aResult) {
363 // Gecko supports 3d transforms, so this feature is always 1.
364 aResult.SetIntValue(1, eCSSUnit_Integer);
365 }
366
HasSystemMetric(nsAtom * aMetric)367 static bool HasSystemMetric(nsAtom* aMetric) {
368 nsMediaFeatures::InitSystemMetrics();
369 return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
370 }
371
372 #ifdef XP_WIN
GetWindowsThemeIdentifier()373 static uint8_t GetWindowsThemeIdentifier() {
374 nsMediaFeatures::InitSystemMetrics();
375 return sWinThemeId;
376 }
377 #endif
378
GetSystemMetric(nsIDocument * aDocument,const nsMediaFeature * aFeature,nsCSSValue & aResult)379 static void GetSystemMetric(nsIDocument* aDocument,
380 const nsMediaFeature* aFeature,
381 nsCSSValue& aResult) {
382 aResult.Reset();
383
384 const bool isAccessibleFromContentPages =
385 !(aFeature->mReqFlags & nsMediaFeature::eUserAgentAndChromeOnly);
386
387 MOZ_ASSERT(!isAccessibleFromContentPages ||
388 *aFeature->mName == nsGkAtoms::_moz_touch_enabled);
389
390 if (isAccessibleFromContentPages &&
391 nsContentUtils::ShouldResistFingerprinting(aDocument)) {
392 // If "privacy.resistFingerprinting" is enabled, then we simply don't
393 // return any system-backed media feature values. (No spoofed values
394 // returned.)
395 return;
396 }
397
398 MOZ_ASSERT(aFeature->mValueType == nsMediaFeature::eBoolInteger,
399 "unexpected type");
400
401 nsAtom* metricAtom = *aFeature->mData.mMetric;
402 bool hasMetric = HasSystemMetric(metricAtom);
403 aResult.SetIntValue(hasMetric ? 1 : 0, eCSSUnit_Integer);
404 }
405
GetWindowsTheme(nsIDocument * aDocument,const nsMediaFeature * aFeature,nsCSSValue & aResult)406 static void GetWindowsTheme(nsIDocument* aDocument,
407 const nsMediaFeature* aFeature,
408 nsCSSValue& aResult) {
409 aResult.Reset();
410
411 MOZ_ASSERT(aFeature->mReqFlags & nsMediaFeature::eUserAgentAndChromeOnly);
412 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
413 return;
414 }
415
416 #ifdef XP_WIN
417 uint8_t windowsThemeId = GetWindowsThemeIdentifier();
418
419 // Classic mode should fail to match.
420 if (windowsThemeId == LookAndFeel::eWindowsTheme_Classic) return;
421
422 // Look up the appropriate theme string
423 for (const auto& theme : kThemeStrings) {
424 if (windowsThemeId == theme.mId) {
425 aResult.SetAtomIdentValue((*theme.mName)->ToAddRefed());
426 break;
427 }
428 }
429 #endif
430 }
431
GetOperatingSystemVersion(nsIDocument * aDocument,const nsMediaFeature * aFeature,nsCSSValue & aResult)432 static void GetOperatingSystemVersion(nsIDocument* aDocument,
433 const nsMediaFeature* aFeature,
434 nsCSSValue& aResult) {
435 aResult.Reset();
436
437 MOZ_ASSERT(aFeature->mReqFlags & nsMediaFeature::eUserAgentAndChromeOnly);
438 if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
439 return;
440 }
441
442 #ifdef XP_WIN
443 int32_t metricResult;
444 if (NS_SUCCEEDED(LookAndFeel::GetInt(
445 LookAndFeel::eIntID_OperatingSystemVersionIdentifier,
446 &metricResult))) {
447 for (const auto& osVersion : kOsVersionStrings) {
448 if (metricResult == osVersion.mId) {
449 aResult.SetAtomIdentValue((*osVersion.mName)->ToAddRefed());
450 break;
451 }
452 }
453 }
454 #endif
455 }
456
GetIsGlyph(nsIDocument * aDocument,const nsMediaFeature * aFeature,nsCSSValue & aResult)457 static void GetIsGlyph(nsIDocument* aDocument, const nsMediaFeature* aFeature,
458 nsCSSValue& aResult) {
459 MOZ_ASSERT(aFeature->mReqFlags & nsMediaFeature::eUserAgentAndChromeOnly);
460 aResult.SetIntValue(aDocument->IsSVGGlyphsDocument() ? 1 : 0,
461 eCSSUnit_Integer);
462 }
463
InitSystemMetrics()464 /* static */ void nsMediaFeatures::InitSystemMetrics() {
465 if (sSystemMetrics) return;
466
467 MOZ_ASSERT(NS_IsMainThread());
468
469 sSystemMetrics = new nsTArray<RefPtr<nsAtom>>;
470
471 /***************************************************************************
472 * ANY METRICS ADDED HERE SHOULD ALSO BE ADDED AS MEDIA QUERIES BELOW *
473 ***************************************************************************/
474
475 int32_t metricResult =
476 LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollArrowStyle);
477 if (metricResult & LookAndFeel::eScrollArrow_StartBackward) {
478 sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_start_backward);
479 }
480 if (metricResult & LookAndFeel::eScrollArrow_StartForward) {
481 sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_start_forward);
482 }
483 if (metricResult & LookAndFeel::eScrollArrow_EndBackward) {
484 sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_end_backward);
485 }
486 if (metricResult & LookAndFeel::eScrollArrow_EndForward) {
487 sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_end_forward);
488 }
489
490 metricResult = LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollSliderStyle);
491 if (metricResult != LookAndFeel::eScrollThumbStyle_Normal) {
492 sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_thumb_proportional);
493 }
494
495 metricResult = LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars);
496 if (metricResult) {
497 sSystemMetrics->AppendElement(nsGkAtoms::overlay_scrollbars);
498 }
499
500 metricResult = LookAndFeel::GetInt(LookAndFeel::eIntID_MenuBarDrag);
501 if (metricResult) {
502 sSystemMetrics->AppendElement(nsGkAtoms::menubar_drag);
503 }
504
505 nsresult rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsDefaultTheme,
506 &metricResult);
507 if (NS_SUCCEEDED(rv) && metricResult) {
508 sSystemMetrics->AppendElement(nsGkAtoms::windows_default_theme);
509 }
510
511 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacGraphiteTheme, &metricResult);
512 if (NS_SUCCEEDED(rv) && metricResult) {
513 sSystemMetrics->AppendElement(nsGkAtoms::mac_graphite_theme);
514 }
515
516 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacYosemiteTheme, &metricResult);
517 if (NS_SUCCEEDED(rv) && metricResult) {
518 sSystemMetrics->AppendElement(nsGkAtoms::mac_yosemite_theme);
519 }
520
521 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsAccentColorInTitlebar,
522 &metricResult);
523 if (NS_SUCCEEDED(rv) && metricResult) {
524 sSystemMetrics->AppendElement(nsGkAtoms::windows_accent_color_in_titlebar);
525 }
526
527 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_DWMCompositor, &metricResult);
528 if (NS_SUCCEEDED(rv) && metricResult) {
529 sSystemMetrics->AppendElement(nsGkAtoms::windows_compositor);
530 }
531
532 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsGlass, &metricResult);
533 if (NS_SUCCEEDED(rv) && metricResult) {
534 sSystemMetrics->AppendElement(nsGkAtoms::windows_glass);
535 }
536
537 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsClassic, &metricResult);
538 if (NS_SUCCEEDED(rv) && metricResult) {
539 sSystemMetrics->AppendElement(nsGkAtoms::windows_classic);
540 }
541
542 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_TouchEnabled, &metricResult);
543 if (NS_SUCCEEDED(rv) && metricResult) {
544 sSystemMetrics->AppendElement(nsGkAtoms::touch_enabled);
545 }
546
547 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_SwipeAnimationEnabled,
548 &metricResult);
549 if (NS_SUCCEEDED(rv) && metricResult) {
550 sSystemMetrics->AppendElement(nsGkAtoms::swipe_animation_enabled);
551 }
552
553 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDAvailable, &metricResult);
554 if (NS_SUCCEEDED(rv) && metricResult) {
555 sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_available);
556 }
557
558 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDMinimizeButton,
559 &metricResult);
560 if (NS_SUCCEEDED(rv) && metricResult) {
561 sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_minimize_button);
562 }
563
564 rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDMaximizeButton,
565 &metricResult);
566 if (NS_SUCCEEDED(rv) && metricResult) {
567 sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_maximize_button);
568 }
569
570 rv =
571 LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDCloseButton, &metricResult);
572 if (NS_SUCCEEDED(rv) && metricResult) {
573 sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_close_button);
574 }
575
576 #ifdef XP_WIN
577 if (NS_SUCCEEDED(LookAndFeel::GetInt(
578 LookAndFeel::eIntID_WindowsThemeIdentifier, &metricResult))) {
579 sWinThemeId = metricResult;
580 switch (metricResult) {
581 case LookAndFeel::eWindowsTheme_Aero:
582 sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_aero);
583 break;
584 case LookAndFeel::eWindowsTheme_AeroLite:
585 sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_aero_lite);
586 break;
587 case LookAndFeel::eWindowsTheme_LunaBlue:
588 sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_blue);
589 break;
590 case LookAndFeel::eWindowsTheme_LunaOlive:
591 sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_olive);
592 break;
593 case LookAndFeel::eWindowsTheme_LunaSilver:
594 sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_silver);
595 break;
596 case LookAndFeel::eWindowsTheme_Royale:
597 sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_royale);
598 break;
599 case LookAndFeel::eWindowsTheme_Zune:
600 sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_zune);
601 break;
602 case LookAndFeel::eWindowsTheme_Generic:
603 sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_generic);
604 break;
605 }
606 }
607 #endif
608 }
609
FreeSystemMetrics()610 /* static */ void nsMediaFeatures::FreeSystemMetrics() {
611 delete sSystemMetrics;
612 sSystemMetrics = nullptr;
613 }
614
Shutdown()615 /* static */ void nsMediaFeatures::Shutdown() { FreeSystemMetrics(); }
616
617 /*
618 * Adding new media features requires (1) adding the new feature to this
619 * array, with appropriate entries (and potentially any new code needed
620 * to support new types in these entries and (2) ensuring that either
621 * nsPresContext::MediaFeatureValuesChanged or
622 * nsPresContext::PostMediaFeatureValuesChangedEvent is called when the
623 * value that would be returned by the entry's mGetter changes.
624 */
625
626 /* static */ const nsMediaFeature nsMediaFeatures::features[] = {
627 {&nsGkAtoms::width,
628 nsMediaFeature::eMinMaxAllowed,
629 nsMediaFeature::eLength,
630 nsMediaFeature::eNoRequirements,
631 {nullptr},
632 GetWidth},
633 {&nsGkAtoms::height,
634 nsMediaFeature::eMinMaxAllowed,
635 nsMediaFeature::eLength,
636 nsMediaFeature::eNoRequirements,
637 {nullptr},
638 GetHeight},
639 {&nsGkAtoms::deviceWidth,
640 nsMediaFeature::eMinMaxAllowed,
641 nsMediaFeature::eLength,
642 nsMediaFeature::eNoRequirements,
643 {nullptr},
644 GetDeviceWidth},
645 {&nsGkAtoms::deviceHeight,
646 nsMediaFeature::eMinMaxAllowed,
647 nsMediaFeature::eLength,
648 nsMediaFeature::eNoRequirements,
649 {nullptr},
650 GetDeviceHeight},
651 {&nsGkAtoms::orientation,
652 nsMediaFeature::eMinMaxNotAllowed,
653 nsMediaFeature::eEnumerated,
654 nsMediaFeature::eNoRequirements,
655 {kOrientationKeywords},
656 GetOrientation},
657 {&nsGkAtoms::aspectRatio,
658 nsMediaFeature::eMinMaxAllowed,
659 nsMediaFeature::eIntRatio,
660 nsMediaFeature::eNoRequirements,
661 {nullptr},
662 GetAspectRatio},
663 {&nsGkAtoms::deviceAspectRatio,
664 nsMediaFeature::eMinMaxAllowed,
665 nsMediaFeature::eIntRatio,
666 nsMediaFeature::eNoRequirements,
667 {nullptr},
668 GetDeviceAspectRatio},
669 {&nsGkAtoms::color,
670 nsMediaFeature::eMinMaxAllowed,
671 nsMediaFeature::eInteger,
672 nsMediaFeature::eNoRequirements,
673 {nullptr},
674 GetColor},
675 {&nsGkAtoms::colorIndex,
676 nsMediaFeature::eMinMaxAllowed,
677 nsMediaFeature::eInteger,
678 nsMediaFeature::eNoRequirements,
679 {nullptr},
680 GetColorIndex},
681 {&nsGkAtoms::monochrome,
682 nsMediaFeature::eMinMaxAllowed,
683 nsMediaFeature::eInteger,
684 nsMediaFeature::eNoRequirements,
685 {nullptr},
686 GetMonochrome},
687 {&nsGkAtoms::resolution,
688 nsMediaFeature::eMinMaxAllowed,
689 nsMediaFeature::eResolution,
690 nsMediaFeature::eNoRequirements,
691 {nullptr},
692 GetResolution},
693 {&nsGkAtoms::scan,
694 nsMediaFeature::eMinMaxNotAllowed,
695 nsMediaFeature::eEnumerated,
696 nsMediaFeature::eNoRequirements,
697 {kScanKeywords},
698 GetScan},
699 {&nsGkAtoms::grid,
700 nsMediaFeature::eMinMaxNotAllowed,
701 nsMediaFeature::eBoolInteger,
702 nsMediaFeature::eNoRequirements,
703 {nullptr},
704 GetGrid},
705 {&nsGkAtoms::displayMode,
706 nsMediaFeature::eMinMaxNotAllowed,
707 nsMediaFeature::eEnumerated,
708 nsMediaFeature::eNoRequirements,
709 {kDisplayModeKeywords},
710 GetDisplayMode},
711
712 // Webkit extensions that we support for de-facto web compatibility
713 // -webkit-{min|max}-device-pixel-ratio (controlled with its own pref):
714 {&nsGkAtoms::devicePixelRatio,
715 nsMediaFeature::eMinMaxAllowed,
716 nsMediaFeature::eFloat,
717 nsMediaFeature::eHasWebkitPrefix |
718 nsMediaFeature::eWebkitDevicePixelRatioPrefEnabled,
719 {nullptr},
720 GetDevicePixelRatio},
721 // -webkit-transform-3d:
722 {&nsGkAtoms::transform_3d,
723 nsMediaFeature::eMinMaxNotAllowed,
724 nsMediaFeature::eBoolInteger,
725 nsMediaFeature::eHasWebkitPrefix,
726 {nullptr},
727 GetTransform3d},
728
729 // Mozilla extensions
730 {&nsGkAtoms::_moz_device_pixel_ratio,
731 nsMediaFeature::eMinMaxAllowed,
732 nsMediaFeature::eFloat,
733 nsMediaFeature::eNoRequirements,
734 {nullptr},
735 GetDevicePixelRatio},
736 {&nsGkAtoms::_moz_device_orientation,
737 nsMediaFeature::eMinMaxNotAllowed,
738 nsMediaFeature::eEnumerated,
739 nsMediaFeature::eNoRequirements,
740 {kOrientationKeywords},
741 GetDeviceOrientation},
742 {&nsGkAtoms::_moz_is_resource_document,
743 nsMediaFeature::eMinMaxNotAllowed,
744 nsMediaFeature::eBoolInteger,
745 nsMediaFeature::eNoRequirements,
746 {nullptr},
747 GetIsResourceDocument},
748 {&nsGkAtoms::_moz_scrollbar_start_backward,
749 nsMediaFeature::eMinMaxNotAllowed,
750 nsMediaFeature::eBoolInteger,
751 nsMediaFeature::eUserAgentAndChromeOnly,
752 {&nsGkAtoms::scrollbar_start_backward},
753 GetSystemMetric},
754 {&nsGkAtoms::_moz_scrollbar_start_forward,
755 nsMediaFeature::eMinMaxNotAllowed,
756 nsMediaFeature::eBoolInteger,
757 nsMediaFeature::eUserAgentAndChromeOnly,
758 {&nsGkAtoms::scrollbar_start_forward},
759 GetSystemMetric},
760 {&nsGkAtoms::_moz_scrollbar_end_backward,
761 nsMediaFeature::eMinMaxNotAllowed,
762 nsMediaFeature::eBoolInteger,
763 nsMediaFeature::eUserAgentAndChromeOnly,
764 {&nsGkAtoms::scrollbar_end_backward},
765 GetSystemMetric},
766 {&nsGkAtoms::_moz_scrollbar_end_forward,
767 nsMediaFeature::eMinMaxNotAllowed,
768 nsMediaFeature::eBoolInteger,
769 nsMediaFeature::eUserAgentAndChromeOnly,
770 {&nsGkAtoms::scrollbar_end_forward},
771 GetSystemMetric},
772 {&nsGkAtoms::_moz_scrollbar_thumb_proportional,
773 nsMediaFeature::eMinMaxNotAllowed,
774 nsMediaFeature::eBoolInteger,
775 nsMediaFeature::eUserAgentAndChromeOnly,
776 {&nsGkAtoms::scrollbar_thumb_proportional},
777 GetSystemMetric},
778 {&nsGkAtoms::_moz_overlay_scrollbars,
779 nsMediaFeature::eMinMaxNotAllowed,
780 nsMediaFeature::eBoolInteger,
781 nsMediaFeature::eUserAgentAndChromeOnly,
782 {&nsGkAtoms::overlay_scrollbars},
783 GetSystemMetric},
784 {&nsGkAtoms::_moz_windows_default_theme,
785 nsMediaFeature::eMinMaxNotAllowed,
786 nsMediaFeature::eBoolInteger,
787 nsMediaFeature::eUserAgentAndChromeOnly,
788 {&nsGkAtoms::windows_default_theme},
789 GetSystemMetric},
790 {&nsGkAtoms::_moz_mac_graphite_theme,
791 nsMediaFeature::eMinMaxNotAllowed,
792 nsMediaFeature::eBoolInteger,
793 nsMediaFeature::eUserAgentAndChromeOnly,
794 {&nsGkAtoms::mac_graphite_theme},
795 GetSystemMetric},
796 {&nsGkAtoms::_moz_mac_yosemite_theme,
797 nsMediaFeature::eMinMaxNotAllowed,
798 nsMediaFeature::eBoolInteger,
799 nsMediaFeature::eUserAgentAndChromeOnly,
800 {&nsGkAtoms::mac_yosemite_theme},
801 GetSystemMetric},
802 {&nsGkAtoms::_moz_windows_accent_color_in_titlebar,
803 nsMediaFeature::eMinMaxNotAllowed,
804 nsMediaFeature::eBoolInteger,
805 nsMediaFeature::eUserAgentAndChromeOnly,
806 {&nsGkAtoms::windows_accent_color_in_titlebar},
807 GetSystemMetric},
808 {&nsGkAtoms::_moz_windows_compositor,
809 nsMediaFeature::eMinMaxNotAllowed,
810 nsMediaFeature::eBoolInteger,
811 nsMediaFeature::eUserAgentAndChromeOnly,
812 {&nsGkAtoms::windows_compositor},
813 GetSystemMetric},
814 {&nsGkAtoms::_moz_windows_classic,
815 nsMediaFeature::eMinMaxNotAllowed,
816 nsMediaFeature::eBoolInteger,
817 nsMediaFeature::eUserAgentAndChromeOnly,
818 {&nsGkAtoms::windows_classic},
819 GetSystemMetric},
820 {&nsGkAtoms::_moz_windows_glass,
821 nsMediaFeature::eMinMaxNotAllowed,
822 nsMediaFeature::eBoolInteger,
823 nsMediaFeature::eUserAgentAndChromeOnly,
824 {&nsGkAtoms::windows_glass},
825 GetSystemMetric},
826 {&nsGkAtoms::_moz_touch_enabled,
827 nsMediaFeature::eMinMaxNotAllowed,
828 nsMediaFeature::eBoolInteger,
829 // FIXME(emilio): Restrict (or remove?) when bug 1035774 lands.
830 nsMediaFeature::eNoRequirements,
831 {&nsGkAtoms::touch_enabled},
832 GetSystemMetric},
833 {&nsGkAtoms::_moz_menubar_drag,
834 nsMediaFeature::eMinMaxNotAllowed,
835 nsMediaFeature::eBoolInteger,
836 nsMediaFeature::eUserAgentAndChromeOnly,
837 {&nsGkAtoms::menubar_drag},
838 GetSystemMetric},
839 {&nsGkAtoms::_moz_windows_theme,
840 nsMediaFeature::eMinMaxNotAllowed,
841 nsMediaFeature::eIdent,
842 nsMediaFeature::eUserAgentAndChromeOnly,
843 {nullptr},
844 GetWindowsTheme},
845 {&nsGkAtoms::_moz_os_version,
846 nsMediaFeature::eMinMaxNotAllowed,
847 nsMediaFeature::eIdent,
848 nsMediaFeature::eUserAgentAndChromeOnly,
849 {nullptr},
850 GetOperatingSystemVersion},
851
852 {&nsGkAtoms::_moz_swipe_animation_enabled,
853 nsMediaFeature::eMinMaxNotAllowed,
854 nsMediaFeature::eBoolInteger,
855 nsMediaFeature::eUserAgentAndChromeOnly,
856 {&nsGkAtoms::swipe_animation_enabled},
857 GetSystemMetric},
858
859 {&nsGkAtoms::_moz_gtk_csd_available,
860 nsMediaFeature::eMinMaxNotAllowed,
861 nsMediaFeature::eBoolInteger,
862 nsMediaFeature::eUserAgentAndChromeOnly,
863 {&nsGkAtoms::gtk_csd_available},
864 GetSystemMetric},
865
866 {&nsGkAtoms::_moz_gtk_csd_minimize_button,
867 nsMediaFeature::eMinMaxNotAllowed,
868 nsMediaFeature::eBoolInteger,
869 nsMediaFeature::eUserAgentAndChromeOnly,
870 {&nsGkAtoms::gtk_csd_minimize_button},
871 GetSystemMetric},
872
873 {&nsGkAtoms::_moz_gtk_csd_maximize_button,
874 nsMediaFeature::eMinMaxNotAllowed,
875 nsMediaFeature::eBoolInteger,
876 nsMediaFeature::eUserAgentAndChromeOnly,
877 {&nsGkAtoms::gtk_csd_maximize_button},
878 GetSystemMetric},
879
880 {&nsGkAtoms::_moz_gtk_csd_close_button,
881 nsMediaFeature::eMinMaxNotAllowed,
882 nsMediaFeature::eBoolInteger,
883 nsMediaFeature::eUserAgentAndChromeOnly,
884 {&nsGkAtoms::gtk_csd_close_button},
885 GetSystemMetric},
886
887 // Internal -moz-is-glyph media feature: applies only inside SVG glyphs.
888 // Internal because it is really only useful in the user agent anyway
889 // and therefore not worth standardizing.
890 {&nsGkAtoms::_moz_is_glyph,
891 nsMediaFeature::eMinMaxNotAllowed,
892 nsMediaFeature::eBoolInteger,
893 nsMediaFeature::eUserAgentAndChromeOnly,
894 {nullptr},
895 GetIsGlyph},
896 // Null-mName terminator:
897 {nullptr,
898 nsMediaFeature::eMinMaxAllowed,
899 nsMediaFeature::eInteger,
900 nsMediaFeature::eNoRequirements,
901 {nullptr},
902 nullptr},
903 };
904