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