lewp_css/domain/at_rules/media/
media_expression.rs

1// This file is part of css. It is subject to the license terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/css/master/COPYRIGHT. No part of predicator, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
2// Copyright © 2017 The developers of css. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/css/master/COPYRIGHT.
3
4use {
5    crate::{parsers::{Parse, ParserContext}, CustomParseError, domain::units::{Unit,LengthUnit}},
6    super::{MediaExpressionKind::{self, *}, Ratio, MediaResolution, MediaGrid, ColorBitDepth, MediaOrientation, MediaScan, MediaUpdate, MediaOverflowBlock, MediaOverflowInline, MediaColorGamut, MediaPointer, MediaHover, MediaTransform3D, Device, MediaColorIndex, MonochromeBitDepth, ColorScheme, ReducedMotion},
7    super::Range::*,
8    cssparser::{ParseError, Parser, ToCss},
9    std::fmt,
10};
11
12/// A single expression as per <http://dev.w3.org/csswg/mediaqueries-3/#media1>
13#[derive(Clone, Debug, PartialEq)]
14pub struct MediaExpression(pub MediaExpressionKind);
15
16impl ToCss for MediaExpression
17{
18	fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result
19	{
20		#[inline(always)]
21		fn write<W: fmt::Write, T: ToCss>(dest: &mut W, name: &str, value: &T) -> fmt::Result
22		{
23			dest.write_char('(')?;
24			dest.write_str(name)?;
25			dest.write_char(':')?;
26			value.to_css(dest)?;
27			dest.write_char(')')
28		}
29		
30		match self.0
31		{
32			Width(AtLeast(ref value)) => write(dest, "min-width", value),
33			
34			Width(AtMost(ref value)) => write(dest, "max-width", value),
35			
36			Width(Exact(ref value)) => write(dest, "width", value),
37			
38			Height(AtLeast(ref value)) => write(dest, "min-height", value),
39			
40			Height(AtMost(ref value)) => write(dest, "max-height", value),
41			
42			Height(Exact(ref value)) => write(dest, "height", value),
43			
44			AspectRatio(AtLeast(ref value)) => write(dest, "min-aspect-ratio", value),
45			
46			AspectRatio(AtMost(ref value)) => write(dest, "max-aspect-ratio", value),
47			
48			AspectRatio(Exact(ref value)) => write(dest, "aspect-ratio", value),
49			
50			Orientation(ref value) => write(dest, "orientation", value),
51			
52			Resolution(AtLeast(ref value)) => write(dest, "min-resolution", value),
53			
54			Resolution(AtMost(ref value)) => write(dest, "max-resolution", value),
55			
56			Resolution(Exact(ref value)) => write(dest, "resolution", value),
57			
58			Scan(ref value) => write(dest, "scan", value),
59			
60			Grid(ref value) => write(dest, "grid", value),
61			
62			Update(ref value) => write(dest, "update", value),
63			
64			OverflowBlock(ref value) => write(dest, "overflow-block", value),
65			
66			OverflowInline(ref value) => write(dest, "overflow-inline", value),
67			
68			Color(AtLeast(ref value)) => write(dest, "min-color", value),
69			
70			Color(AtMost(ref value)) => write(dest, "max-color", value),
71			
72			Color(Exact(ref value)) => write(dest, "color", value),
73			
74			ColorIndex(AtLeast(ref value)) => write(dest, "min-color-index", value),
75			
76			ColorIndex(AtMost(ref value)) => write(dest, "max-color-index", value),
77			
78			ColorIndex(Exact(ref value)) => write(dest, "color-index", value),
79			
80			Monochrome(AtLeast(ref value)) => write(dest, "min-monochrome", value),
81			
82			Monochrome(AtMost(ref value)) => write(dest, "max-monochrome", value),
83			
84			Monochrome(Exact(ref value)) => write(dest, "monochrome", value),
85			
86			ColorGamut(ref value) => write(dest, "color-gamut", value),
87			
88			Pointer(ref value) => write(dest, "pointer", value),
89			
90			Hover(ref value) => write(dest, "hover", value),
91			
92			AnyPointer(ref value) => write(dest, "any-pointer", value),
93			
94			AnyHover(ref value) => write(dest, "any-hover", value),
95			
96			Transform3D(ref value) => write(dest, "-webkit-transform-3d", value),
97			
98			PrefersColorScheme(ref value) => write(dest, "prefers-color-scheme", value),
99			
100			PrefersReducedMotion(ref value) => write(dest, "prefers-reduced-motion", value),
101		}
102	}
103}
104
105impl MediaExpression
106{
107	pub(crate) fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, CustomParseError<'i>>>
108	{
109		input.expect_parenthesis_block()?;
110		input.parse_nested_block(|input|
111		{
112			let name = input.expect_ident_cloned()?;
113			input.expect_colon()?;
114			
115			Ok
116			(
117				MediaExpression
118				(
119					match_ignore_ascii_case!
120					{
121						&name,
122						
123						"min-width" => Width(AtLeast(LengthUnit::parse_one_outside_calc_function(context, input)?)),
124						
125						"max-width" => Width(AtMost(LengthUnit::parse_one_outside_calc_function(context, input)?)),
126						
127						"width" => Width(Exact(LengthUnit::parse_one_outside_calc_function(context, input)?)),
128						
129						"min-height" => Height(AtLeast(LengthUnit::parse_one_outside_calc_function(context, input)?)),
130						
131						"max-height" => Height(AtMost(LengthUnit::parse_one_outside_calc_function(context, input)?)),
132						
133						"height" => Height(Exact(LengthUnit::parse_one_outside_calc_function(context, input)?)),
134						
135						"min-aspect-ratio" => AspectRatio(AtLeast(Ratio::parse(context, input)?)),
136						
137						"max-aspect-ratio" => AspectRatio(AtMost(Ratio::parse(context, input)?)),
138						
139						"aspect-ratio" => AspectRatio(Exact(Ratio::parse(context, input)?)),
140						
141						"orientation" => Orientation(MediaOrientation::parse(input)?),
142						
143						"min-resolution" => Resolution(AtLeast(MediaResolution::parse(context, input)?)),
144						
145						"max-resolution" => Resolution(AtLeast(MediaResolution::parse(context, input)?)),
146						
147						"resolution" => Resolution(Exact(MediaResolution::parse(context, input)?)),
148						
149						"-webkit-min-device-pixel-ratio" => Resolution(AtLeast(MediaResolution::parseWebKit(input)?)),
150						
151						"-webkit-max-device-pixel-ratio" => Resolution(AtMost(MediaResolution::parseWebKit(input)?)),
152						
153						"-webkit-device-pixel-ratio" => Resolution(Exact(MediaResolution::parseWebKit(input)?)),
154						
155						"scan" => Scan(MediaScan::parse(input)?),
156						
157						"grid" => Grid(MediaGrid::parse(context, input)?),
158						
159						"update" => Update(MediaUpdate::parse(input)?),
160						
161						"overflow-block" => OverflowBlock(MediaOverflowBlock::parse(input)?),
162						
163						"overflow-inline" => OverflowInline(MediaOverflowInline::parse(input)?),
164						
165						"min-color" => Color(AtLeast(ColorBitDepth::parse(context, input)?)),
166						
167						"max-color" => Color(AtMost(ColorBitDepth::parse(context, input)?)),
168						
169						"color" => Color(Exact(ColorBitDepth::parse(context, input)?)),
170						
171						"min-color-index" => ColorIndex(AtLeast(MediaColorIndex::parse(context, input)?)),
172						
173						"max-color-index" => ColorIndex(AtMost(MediaColorIndex::parse(context, input)?)),
174						
175						"color-index" => ColorIndex(Exact(MediaColorIndex::parse(context, input)?)),
176						
177						"min-monochrome" => Monochrome(AtLeast(MonochromeBitDepth::parse(context, input)?)),
178						
179						"max-monochrome" => Monochrome(AtMost(MonochromeBitDepth::parse(context, input)?)),
180						
181						"monochrome" => Monochrome(Exact(MonochromeBitDepth::parse(context, input)?)),
182						
183						"color-gamut" => ColorGamut(MediaColorGamut::parse(input)?),
184						
185						"pointer" => Pointer(MediaPointer::parse(input)?),
186						
187						"hover" => Hover(MediaHover::parse(input)?),
188						
189						"any-pointer" => AnyPointer(MediaPointer::parse(input)?),
190						
191						"any-hover" => AnyHover(MediaHover::parse(input)?),
192						
193						"-webkit-transform-3d" => Transform3D(MediaTransform3D::parse(context, input)?),
194						
195						"prefers-color-scheme" => PrefersColorScheme(ColorScheme::parse(input)?),
196						
197						"prefers-reduced-motion" => PrefersReducedMotion(ReducedMotion::parse(input)?),
198						
199						"min-device-width" | "max-device-width" | "device-width" | "min-device-height" | "max-device-height" | "device-height" | "min-device-aspect-ratio" | "max-device-aspect-ratio" | "device-aspect-ratio" => return Err(ParseError::from(CustomParseError::DeprecatedMediaQueryExpression(name.clone()))),
200						
201						_ => return Err(ParseError::from(CustomParseError::UnsupportedMediaQueryExpression(name.clone())))
202					}
203				)
204			)
205		})
206	}
207	
208	/// Evaluate this expression and return whether it matches the current device.
209	pub fn matches<D: Device>(&self, device: &D) -> bool
210	{
211		use self::MediaExpressionKind::*;
212		
213		match self.0
214		{
215			Width(ref range) => device.viewportWidthMatches(range),
216			
217			Height(ref range) => device.viewportHeightMatches(range),
218			
219			AspectRatio(ref range) => device.viewportAspectRatioMatches(range),
220			
221			Orientation(orientation) => device.orientationMatches(orientation),
222			
223			Resolution(ref range) => device.viewportResolutionMatches(range),
224			
225			Scan(ref scan) => device.scanMatches(scan),
226			
227			Grid(ref grid) => device.gridMatches(grid),
228			
229			Update(ref update) => device.updateMatches(update),
230			
231			OverflowBlock(ref overflowBlock) => device.overflowBlockMatches(overflowBlock),
232			
233			OverflowInline(ref overflowInline) => device.overflowInlineMatches(overflowInline),
234			
235			Color(ref range) => device.colorBitDepthMatches(range),
236			
237			ColorIndex(ref range) => device.colorIndexMatches(range),
238			
239			Monochrome(ref range) => device.monochromeBitDepthMatches(range),
240			
241			ColorGamut(ref colorGamut) => device.colorGamutMatches(colorGamut),
242			
243			Pointer(ref pointer) => device.pointerMatches(pointer),
244			
245			Hover(ref hover) => device.hoverMatches(hover),
246			
247			AnyPointer(ref pointer) => device.anyPointerMatches(pointer),
248			
249			AnyHover(ref hover) => device.anyHoverMatches(hover),
250			
251			Transform3D(ref transform3D) => device.transform3DMatches(transform3D),
252			
253			PrefersColorScheme(ref prefers_color_scheme) => device.prefers_color_scheme(prefers_color_scheme),
254			
255			PrefersReducedMotion(ref prefers_reduced_motion) => device.prefers_reduced_motion(prefers_reduced_motion),
256		}
257	}
258}