1use crate::derives::*;
8use crate::parser::ParserContext;
9use crate::values::computed::{self, CSSPixelLength, Ratio, Resolution};
10use crate::Atom;
11use cssparser::Parser;
12use selectors::kleene_value::KleeneValue;
13use std::fmt;
14use style_traits::ParseError;
15
16pub type KeywordDiscriminant = u8;
18
19type QueryFeatureGetter<T> = fn(device: &computed::Context) -> T;
20
21pub type KeywordSerializer = fn(KeywordDiscriminant) -> String;
26
27pub type KeywordParser = for<'a, 'i, 't> fn(
29 context: &'a ParserContext,
30 input: &'a mut Parser<'i, 't>,
31) -> Result<KeywordDiscriminant, ParseError<'i>>;
32
33#[allow(missing_docs)]
37pub enum Evaluator {
38 Length(QueryFeatureGetter<CSSPixelLength>),
39 OptionalLength(QueryFeatureGetter<Option<CSSPixelLength>>),
40 Integer(QueryFeatureGetter<i32>),
41 Float(QueryFeatureGetter<f32>),
42 BoolInteger(QueryFeatureGetter<bool>),
43 NumberRatio(QueryFeatureGetter<Ratio>),
45 OptionalNumberRatio(QueryFeatureGetter<Option<Ratio>>),
46 Resolution(QueryFeatureGetter<Resolution>),
48 Enumerated {
50 parser: KeywordParser,
52 serializer: KeywordSerializer,
57 evaluator: fn(&computed::Context, Option<KeywordDiscriminant>) -> KleeneValue,
60 },
61}
62
63macro_rules! keyword_evaluator {
69 ($actual_evaluator:ident, $keyword_type:ty) => {{
70 fn __parse<'i, 't>(
71 context: &$crate::parser::ParserContext,
72 input: &mut $crate::cssparser::Parser<'i, 't>,
73 ) -> Result<$crate::queries::feature::KeywordDiscriminant, ::style_traits::ParseError<'i>>
74 {
75 let kw = <$keyword_type as $crate::parser::Parse>::parse(context, input)?;
76 Ok(kw as $crate::queries::feature::KeywordDiscriminant)
77 }
78
79 fn __serialize(kw: $crate::queries::feature::KeywordDiscriminant) -> String {
80 let value: $keyword_type = ::num_traits::cast::FromPrimitive::from_u8(kw).unwrap();
83 <$keyword_type as ::style_traits::ToCss>::to_css_string(&value)
84 }
85
86 fn __evaluate(
87 context: &$crate::values::computed::Context,
88 value: Option<$crate::queries::feature::KeywordDiscriminant>,
89 ) -> selectors::kleene_value::KleeneValue {
90 let value: Option<$keyword_type> =
93 value.map(|kw| ::num_traits::cast::FromPrimitive::from_u8(kw).unwrap());
94 selectors::kleene_value::KleeneValue::from($actual_evaluator(context, value))
95 }
96
97 $crate::queries::feature::Evaluator::Enumerated {
98 parser: __parse,
99 serializer: __serialize,
100 evaluator: __evaluate,
101 }
102 }};
103}
104
105#[derive(Clone, Copy, Debug, ToShmem)]
108pub struct FeatureFlags(u8);
109bitflags! {
110 impl FeatureFlags : u8 {
111 const CHROME_AND_UA_ONLY = 1 << 0;
113 const WEBKIT_PREFIX = 1 << 1;
115 const CONTAINER_REQUIRES_INLINE_AXIS = 1 << 2;
117 const CONTAINER_REQUIRES_BLOCK_AXIS = 1 << 3;
119 const CONTAINER_REQUIRES_WIDTH_AXIS = 1 << 4;
121 const CONTAINER_REQUIRES_HEIGHT_AXIS = 1 << 5;
123 const VIEWPORT_DEPENDENT = 1 << 6;
125 const STYLE = 1 << 7;
127 }
128}
129
130impl FeatureFlags {
131 pub fn parsing_requirements(self) -> Self {
133 self.intersection(Self::CHROME_AND_UA_ONLY | Self::WEBKIT_PREFIX)
134 }
135
136 pub fn all_container_axes() -> Self {
138 Self::CONTAINER_REQUIRES_INLINE_AXIS
139 | Self::CONTAINER_REQUIRES_BLOCK_AXIS
140 | Self::CONTAINER_REQUIRES_WIDTH_AXIS
141 | Self::CONTAINER_REQUIRES_HEIGHT_AXIS
142 }
143
144 pub fn container_axes(self) -> Self {
146 self.intersection(Self::all_container_axes())
147 }
148}
149
150#[derive(Clone, Copy, Debug, Eq, PartialEq)]
152#[allow(missing_docs)]
153pub enum AllowsRanges {
154 Yes,
155 No,
156}
157
158pub struct QueryFeatureDescription {
160 pub name: Atom,
162 pub allows_ranges: AllowsRanges,
164 pub evaluator: Evaluator,
167 pub flags: FeatureFlags,
169}
170
171impl QueryFeatureDescription {
172 #[inline]
174 pub fn allows_ranges(&self) -> bool {
175 self.allows_ranges == AllowsRanges::Yes
176 }
177}
178
179macro_rules! feature {
181 ($name:expr, $allows_ranges:expr, $evaluator:expr, $flags:expr,) => {
182 $crate::queries::feature::QueryFeatureDescription {
183 name: $name,
184 allows_ranges: $allows_ranges,
185 evaluator: $evaluator,
186 flags: $flags,
187 }
188 };
189}
190
191impl fmt::Debug for QueryFeatureDescription {
192 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193 f.debug_struct("QueryFeatureDescription")
194 .field("name", &self.name)
195 .field("allows_ranges", &self.allows_ranges)
196 .field("flags", &self.flags)
197 .finish()
198 }
199}