1 /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /* the features that media queries can test */
8 #include "nsMediaFeatures.h"
10 #include "nsCSSKeywords.h"
11 #include "nsStyleConsts.h"
12 #include "nsPresContext.h"
13 #include "nsCSSValue.h"
15 #include "mozilla/LookAndFeel.h"
17 #include "nsCSSRuleProcessor.h"
18 #include "nsDeviceContext.h"
19 #include "nsIDocument.h"
21 using namespace mozilla
;
23 static const nsCSSProps::KTableValue kOrientationKeywords
[] = {
24 eCSSKeyword_portrait
, NS_STYLE_ORIENTATION_PORTRAIT
,
25 eCSSKeyword_landscape
, NS_STYLE_ORIENTATION_LANDSCAPE
,
26 eCSSKeyword_UNKNOWN
, -1
29 static const nsCSSProps::KTableValue kScanKeywords
[] = {
30 eCSSKeyword_progressive
, NS_STYLE_SCAN_PROGRESSIVE
,
31 eCSSKeyword_interlace
, NS_STYLE_SCAN_INTERLACE
,
32 eCSSKeyword_UNKNOWN
, -1
36 struct WindowsThemeName
{
37 LookAndFeel::WindowsTheme id
;
41 // Windows theme identities used in the -moz-windows-theme media query.
42 const WindowsThemeName themeStrings
[] = {
43 { LookAndFeel::eWindowsTheme_Aero
, L
"aero" },
44 { LookAndFeel::eWindowsTheme_AeroLite
, L
"aero-lite" },
45 { LookAndFeel::eWindowsTheme_LunaBlue
, L
"luna-blue" },
46 { LookAndFeel::eWindowsTheme_LunaOlive
, L
"luna-olive" },
47 { LookAndFeel::eWindowsTheme_LunaSilver
, L
"luna-silver" },
48 { LookAndFeel::eWindowsTheme_Royale
, L
"royale" },
49 { LookAndFeel::eWindowsTheme_Zune
, L
"zune" },
50 { LookAndFeel::eWindowsTheme_Generic
, L
"generic" }
53 struct OperatingSystemVersionInfo
{
54 LookAndFeel::OperatingSystemVersion id
;
58 // Os version identities used in the -moz-os-version media query.
59 const OperatingSystemVersionInfo osVersionStrings
[] = {
60 { LookAndFeel::eOperatingSystemVersion_WindowsXP
, L
"windows-xp" },
61 { LookAndFeel::eOperatingSystemVersion_WindowsVista
, L
"windows-vista" },
62 { LookAndFeel::eOperatingSystemVersion_Windows7
, L
"windows-win7" },
63 { LookAndFeel::eOperatingSystemVersion_Windows8
, L
"windows-win8" },
67 // A helper for four features below
69 GetSize(nsPresContext
* aPresContext
)
72 if (aPresContext
->IsRootPaginatedDocument())
73 // We want the page size, including unprintable areas and margins.
74 size
= aPresContext
->GetPageSize();
76 size
= aPresContext
->GetVisibleArea().Size();
81 GetWidth(nsPresContext
* aPresContext
, const nsMediaFeature
*,
84 nsSize size
= GetSize(aPresContext
);
85 float pixelWidth
= aPresContext
->AppUnitsToFloatCSSPixels(size
.width
);
86 aResult
.SetFloatValue(pixelWidth
, eCSSUnit_Pixel
);
91 GetHeight(nsPresContext
* aPresContext
, const nsMediaFeature
*,
94 nsSize size
= GetSize(aPresContext
);
95 float pixelHeight
= aPresContext
->AppUnitsToFloatCSSPixels(size
.height
);
96 aResult
.SetFloatValue(pixelHeight
, eCSSUnit_Pixel
);
100 inline static nsDeviceContext
*
101 GetDeviceContextFor(nsPresContext
* aPresContext
)
103 // It would be nice to call
104 // nsLayoutUtils::GetDeviceContextForScreenInfo here, except for two
105 // things: (1) it can flush, and flushing is bad here, and (2) it
106 // doesn't really get us consistency in multi-monitor situations
108 return aPresContext
->DeviceContext();
111 // A helper for three features below.
113 GetDeviceSize(nsPresContext
* aPresContext
)
117 if (aPresContext
->IsDeviceSizePageSize()) {
118 size
= GetSize(aPresContext
);
119 } else if (aPresContext
->IsRootPaginatedDocument()) {
120 // We want the page size, including unprintable areas and margins.
121 // XXX The spec actually says we want the "page sheet size", but
122 // how is that different?
123 size
= aPresContext
->GetPageSize();
125 GetDeviceContextFor(aPresContext
)->
126 GetDeviceSurfaceDimensions(size
.width
, size
.height
);
132 GetDeviceWidth(nsPresContext
* aPresContext
, const nsMediaFeature
*,
135 nsSize size
= GetDeviceSize(aPresContext
);
136 float pixelWidth
= aPresContext
->AppUnitsToFloatCSSPixels(size
.width
);
137 aResult
.SetFloatValue(pixelWidth
, eCSSUnit_Pixel
);
142 GetDeviceHeight(nsPresContext
* aPresContext
, const nsMediaFeature
*,
145 nsSize size
= GetDeviceSize(aPresContext
);
146 float pixelHeight
= aPresContext
->AppUnitsToFloatCSSPixels(size
.height
);
147 aResult
.SetFloatValue(pixelHeight
, eCSSUnit_Pixel
);
152 GetOrientation(nsPresContext
* aPresContext
, const nsMediaFeature
*,
155 nsSize size
= GetSize(aPresContext
);
157 if (size
.width
> size
.height
) {
158 orientation
= NS_STYLE_ORIENTATION_LANDSCAPE
;
160 // Per spec, square viewports should be 'portrait'
161 orientation
= NS_STYLE_ORIENTATION_PORTRAIT
;
164 aResult
.SetIntValue(orientation
, eCSSUnit_Enumerated
);
169 GetDeviceOrientation(nsPresContext
* aPresContext
, const nsMediaFeature
*,
172 nsSize size
= GetDeviceSize(aPresContext
);
174 if (size
.width
> size
.height
) {
175 orientation
= NS_STYLE_ORIENTATION_LANDSCAPE
;
177 // Per spec, square viewports should be 'portrait'
178 orientation
= NS_STYLE_ORIENTATION_PORTRAIT
;
181 aResult
.SetIntValue(orientation
, eCSSUnit_Enumerated
);
186 GetIsResourceDocument(nsPresContext
* aPresContext
, const nsMediaFeature
*,
189 nsIDocument
* doc
= aPresContext
->Document();
190 aResult
.SetIntValue(doc
&& doc
->IsResourceDoc() ? 1 : 0, eCSSUnit_Integer
);
194 // Helper for two features below
196 MakeArray(const nsSize
& aSize
, nsCSSValue
& aResult
)
198 nsRefPtr
<nsCSSValue::Array
> a
= nsCSSValue::Array::Create(2);
200 a
->Item(0).SetIntValue(aSize
.width
, eCSSUnit_Integer
);
201 a
->Item(1).SetIntValue(aSize
.height
, eCSSUnit_Integer
);
203 aResult
.SetArrayValue(a
, eCSSUnit_Array
);
208 GetAspectRatio(nsPresContext
* aPresContext
, const nsMediaFeature
*,
211 return MakeArray(GetSize(aPresContext
), aResult
);
215 GetDeviceAspectRatio(nsPresContext
* aPresContext
, const nsMediaFeature
*,
218 return MakeArray(GetDeviceSize(aPresContext
), aResult
);
222 GetColor(nsPresContext
* aPresContext
, const nsMediaFeature
*,
225 // FIXME: This implementation is bogus. nsDeviceContext
226 // doesn't provide reliable information (should be fixed in bug
228 // FIXME: On a monochrome device, return 0!
229 nsDeviceContext
*dx
= GetDeviceContextFor(aPresContext
);
232 // The spec says to use bits *per color component*, so divide by 3,
233 // and round down, since the spec says to use the smallest when the
234 // color components differ.
236 aResult
.SetIntValue(int32_t(depth
), eCSSUnit_Integer
);
241 GetColorIndex(nsPresContext
* aPresContext
, const nsMediaFeature
*,
244 // We should return zero if the device does not use a color lookup
245 // table. Stuart says that our handling of displays with 8-bit
246 // color is bad enough that we never change the lookup table to
247 // match what we're trying to display, so perhaps we should always
248 // return zero. Given that there isn't any better information
249 // exposed, we don't have much other choice.
250 aResult
.SetIntValue(0, eCSSUnit_Integer
);
255 GetMonochrome(nsPresContext
* aPresContext
, const nsMediaFeature
*,
258 // For color devices we should return 0.
259 // FIXME: On a monochrome device, return the actual color depth, not
261 aResult
.SetIntValue(0, eCSSUnit_Integer
);
266 GetResolution(nsPresContext
* aPresContext
, const nsMediaFeature
*,
269 // Resolution measures device pixels per CSS (inch/cm/pixel). We
270 // return it in device pixels per CSS inches.
271 float dpi
= float(nsPresContext::AppUnitsPerCSSInch()) /
272 float(aPresContext
->AppUnitsPerDevPixel());
273 aResult
.SetFloatValue(dpi
, eCSSUnit_Inch
);
278 GetScan(nsPresContext
* aPresContext
, const nsMediaFeature
*,
281 // Since Gecko doesn't support the 'tv' media type, the 'scan'
282 // feature is never present.
288 GetGrid(nsPresContext
* aPresContext
, const nsMediaFeature
*,
291 // Gecko doesn't support grid devices (e.g., ttys), so the 'grid'
292 // feature is always 0.
293 aResult
.SetIntValue(0, eCSSUnit_Integer
);
298 GetDevicePixelRatio(nsPresContext
* aPresContext
, const nsMediaFeature
*,
301 float ratio
= aPresContext
->CSSPixelsToDevPixels(1.0f
);
302 aResult
.SetFloatValue(ratio
, eCSSUnit_Number
);
307 GetSystemMetric(nsPresContext
* aPresContext
, const nsMediaFeature
* aFeature
,
310 NS_ABORT_IF_FALSE(aFeature
->mValueType
== nsMediaFeature::eBoolInteger
,
312 nsIAtom
*metricAtom
= *aFeature
->mData
.mMetric
;
313 bool hasMetric
= nsCSSRuleProcessor::HasSystemMetric(metricAtom
);
314 aResult
.SetIntValue(hasMetric
? 1 : 0, eCSSUnit_Integer
);
319 GetWindowsTheme(nsPresContext
* aPresContext
, const nsMediaFeature
* aFeature
,
324 uint8_t windowsThemeId
=
325 nsCSSRuleProcessor::GetWindowsThemeIdentifier();
327 // Classic mode should fail to match.
328 if (windowsThemeId
== LookAndFeel::eWindowsTheme_Classic
)
331 // Look up the appropriate theme string
332 for (size_t i
= 0; i
< ArrayLength(themeStrings
); ++i
) {
333 if (windowsThemeId
== themeStrings
[i
].id
) {
334 aResult
.SetStringValue(nsDependentString(themeStrings
[i
].name
),
344 GetOperatinSystemVersion(nsPresContext
* aPresContext
, const nsMediaFeature
* aFeature
,
349 int32_t metricResult
;
351 LookAndFeel::GetInt(LookAndFeel::eIntID_OperatingSystemVersionIdentifier
,
353 for (size_t i
= 0; i
< ArrayLength(osVersionStrings
); ++i
) {
354 if (metricResult
== osVersionStrings
[i
].id
) {
355 aResult
.SetStringValue(nsDependentString(osVersionStrings
[i
].name
),
366 GetIsGlyph(nsPresContext
* aPresContext
, const nsMediaFeature
* aFeature
,
369 aResult
.SetIntValue(aPresContext
->IsGlyph() ? 1 : 0, eCSSUnit_Integer
);
374 * Adding new media features requires (1) adding the new feature to this
375 * array, with appropriate entries (and potentially any new code needed
376 * to support new types in these entries and (2) ensuring that either
377 * nsPresContext::MediaFeatureValuesChanged or
378 * nsPresContext::PostMediaFeatureValuesChangedEvent is called when the
379 * value that would be returned by the entry's mGetter changes.
382 /* static */ const nsMediaFeature
383 nsMediaFeatures::features
[] = {
386 nsMediaFeature::eMinMaxAllowed
,
387 nsMediaFeature::eLength
,
393 nsMediaFeature::eMinMaxAllowed
,
394 nsMediaFeature::eLength
,
399 &nsGkAtoms::deviceWidth
,
400 nsMediaFeature::eMinMaxAllowed
,
401 nsMediaFeature::eLength
,
406 &nsGkAtoms::deviceHeight
,
407 nsMediaFeature::eMinMaxAllowed
,
408 nsMediaFeature::eLength
,
413 &nsGkAtoms::orientation
,
414 nsMediaFeature::eMinMaxNotAllowed
,
415 nsMediaFeature::eEnumerated
,
416 { kOrientationKeywords
},
420 &nsGkAtoms::aspectRatio
,
421 nsMediaFeature::eMinMaxAllowed
,
422 nsMediaFeature::eIntRatio
,
427 &nsGkAtoms::deviceAspectRatio
,
428 nsMediaFeature::eMinMaxAllowed
,
429 nsMediaFeature::eIntRatio
,
435 nsMediaFeature::eMinMaxAllowed
,
436 nsMediaFeature::eInteger
,
441 &nsGkAtoms::colorIndex
,
442 nsMediaFeature::eMinMaxAllowed
,
443 nsMediaFeature::eInteger
,
448 &nsGkAtoms::monochrome
,
449 nsMediaFeature::eMinMaxAllowed
,
450 nsMediaFeature::eInteger
,
455 &nsGkAtoms::resolution
,
456 nsMediaFeature::eMinMaxAllowed
,
457 nsMediaFeature::eResolution
,
463 nsMediaFeature::eMinMaxNotAllowed
,
464 nsMediaFeature::eEnumerated
,
470 nsMediaFeature::eMinMaxNotAllowed
,
471 nsMediaFeature::eBoolInteger
,
476 // Mozilla extensions
478 &nsGkAtoms::_moz_device_pixel_ratio
,
479 nsMediaFeature::eMinMaxAllowed
,
480 nsMediaFeature::eFloat
,
485 &nsGkAtoms::_moz_device_orientation
,
486 nsMediaFeature::eMinMaxNotAllowed
,
487 nsMediaFeature::eEnumerated
,
488 { kOrientationKeywords
},
492 &nsGkAtoms::_moz_is_resource_document
,
493 nsMediaFeature::eMinMaxNotAllowed
,
494 nsMediaFeature::eBoolInteger
,
496 GetIsResourceDocument
499 &nsGkAtoms::_moz_color_picker_available
,
500 nsMediaFeature::eMinMaxNotAllowed
,
501 nsMediaFeature::eBoolInteger
,
502 { &nsGkAtoms::color_picker_available
},
506 &nsGkAtoms::_moz_scrollbar_start_backward
,
507 nsMediaFeature::eMinMaxNotAllowed
,
508 nsMediaFeature::eBoolInteger
,
509 { &nsGkAtoms::scrollbar_start_backward
},
513 &nsGkAtoms::_moz_scrollbar_start_forward
,
514 nsMediaFeature::eMinMaxNotAllowed
,
515 nsMediaFeature::eBoolInteger
,
516 { &nsGkAtoms::scrollbar_start_forward
},
520 &nsGkAtoms::_moz_scrollbar_end_backward
,
521 nsMediaFeature::eMinMaxNotAllowed
,
522 nsMediaFeature::eBoolInteger
,
523 { &nsGkAtoms::scrollbar_end_backward
},
527 &nsGkAtoms::_moz_scrollbar_end_forward
,
528 nsMediaFeature::eMinMaxNotAllowed
,
529 nsMediaFeature::eBoolInteger
,
530 { &nsGkAtoms::scrollbar_end_forward
},
534 &nsGkAtoms::_moz_scrollbar_thumb_proportional
,
535 nsMediaFeature::eMinMaxNotAllowed
,
536 nsMediaFeature::eBoolInteger
,
537 { &nsGkAtoms::scrollbar_thumb_proportional
},
541 &nsGkAtoms::_moz_images_in_menus
,
542 nsMediaFeature::eMinMaxNotAllowed
,
543 nsMediaFeature::eBoolInteger
,
544 { &nsGkAtoms::images_in_menus
},
548 &nsGkAtoms::_moz_images_in_buttons
,
549 nsMediaFeature::eMinMaxNotAllowed
,
550 nsMediaFeature::eBoolInteger
,
551 { &nsGkAtoms::images_in_buttons
},
555 &nsGkAtoms::_moz_overlay_scrollbars
,
556 nsMediaFeature::eMinMaxNotAllowed
,
557 nsMediaFeature::eBoolInteger
,
558 { &nsGkAtoms::overlay_scrollbars
},
562 &nsGkAtoms::_moz_windows_default_theme
,
563 nsMediaFeature::eMinMaxNotAllowed
,
564 nsMediaFeature::eBoolInteger
,
565 { &nsGkAtoms::windows_default_theme
},
569 &nsGkAtoms::_moz_mac_graphite_theme
,
570 nsMediaFeature::eMinMaxNotAllowed
,
571 nsMediaFeature::eBoolInteger
,
572 { &nsGkAtoms::mac_graphite_theme
},
576 &nsGkAtoms::_moz_mac_lion_theme
,
577 nsMediaFeature::eMinMaxNotAllowed
,
578 nsMediaFeature::eBoolInteger
,
579 { &nsGkAtoms::mac_lion_theme
},
583 &nsGkAtoms::_moz_mac_yosemite_theme
,
584 nsMediaFeature::eMinMaxNotAllowed
,
585 nsMediaFeature::eBoolInteger
,
586 { &nsGkAtoms::mac_yosemite_theme
},
590 &nsGkAtoms::_moz_windows_compositor
,
591 nsMediaFeature::eMinMaxNotAllowed
,
592 nsMediaFeature::eBoolInteger
,
593 { &nsGkAtoms::windows_compositor
},
597 &nsGkAtoms::_moz_windows_classic
,
598 nsMediaFeature::eMinMaxNotAllowed
,
599 nsMediaFeature::eBoolInteger
,
600 { &nsGkAtoms::windows_classic
},
604 &nsGkAtoms::_moz_windows_glass
,
605 nsMediaFeature::eMinMaxNotAllowed
,
606 nsMediaFeature::eBoolInteger
,
607 { &nsGkAtoms::windows_glass
},
611 &nsGkAtoms::_moz_touch_enabled
,
612 nsMediaFeature::eMinMaxNotAllowed
,
613 nsMediaFeature::eBoolInteger
,
614 { &nsGkAtoms::touch_enabled
},
618 &nsGkAtoms::_moz_menubar_drag
,
619 nsMediaFeature::eMinMaxNotAllowed
,
620 nsMediaFeature::eBoolInteger
,
621 { &nsGkAtoms::menubar_drag
},
625 &nsGkAtoms::_moz_windows_theme
,
626 nsMediaFeature::eMinMaxNotAllowed
,
627 nsMediaFeature::eIdent
,
632 &nsGkAtoms::_moz_os_version
,
633 nsMediaFeature::eMinMaxNotAllowed
,
634 nsMediaFeature::eIdent
,
636 GetOperatinSystemVersion
640 &nsGkAtoms::_moz_swipe_animation_enabled
,
641 nsMediaFeature::eMinMaxNotAllowed
,
642 nsMediaFeature::eBoolInteger
,
643 { &nsGkAtoms::swipe_animation_enabled
},
648 &nsGkAtoms::_moz_physical_home_button
,
649 nsMediaFeature::eMinMaxNotAllowed
,
650 nsMediaFeature::eBoolInteger
,
651 { &nsGkAtoms::physical_home_button
},
655 // Internal -moz-is-glyph media feature: applies only inside SVG glyphs.
656 // Internal because it is really only useful in the user agent anyway
657 // and therefore not worth standardizing.
659 &nsGkAtoms::_moz_is_glyph
,
660 nsMediaFeature::eMinMaxNotAllowed
,
661 nsMediaFeature::eBoolInteger
,
665 // Null-mName terminator:
668 nsMediaFeature::eMinMaxAllowed
,
669 nsMediaFeature::eInteger
,