Skip to main content

style/values/specified/
source_size_list.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! https://html.spec.whatwg.org/multipage/#source-size-list
6
7use crate::device::Device;
8use crate::dom::AttributeTracker;
9use crate::parser::{Parse, ParserContext};
10use crate::queries::{FeatureType, QueryCondition};
11use crate::stylesheets::CustomMediaEvaluator;
12use crate::values::computed::{self, ToComputedValue};
13use crate::values::specified::length::LengthUnit;
14use crate::values::specified::{Length, NoCalcLength};
15use app_units::Au;
16use cssparser::{Delimiter, Parser, Token};
17use selectors::context::QuirksMode;
18use style_traits::ParseError;
19
20/// A value for a `<source-size>`:
21///
22/// https://html.spec.whatwg.org/multipage/#source-size
23#[derive(Debug)]
24pub struct SourceSize {
25    condition: QueryCondition,
26    value: Length,
27}
28
29impl Parse for SourceSize {
30    fn parse<'i, 't>(
31        context: &ParserContext,
32        input: &mut Parser<'i, 't>,
33    ) -> Result<Self, ParseError<'i>> {
34        let condition = QueryCondition::parse(context, input, FeatureType::Media)?;
35        let value = Length::parse_non_negative(context, input)?;
36        Ok(Self { condition, value })
37    }
38}
39
40/// A value for a `<source-size-list>`:
41///
42/// https://html.spec.whatwg.org/multipage/#source-size-list
43#[derive(Debug)]
44pub struct SourceSizeList {
45    source_sizes: Vec<SourceSize>,
46    value: Option<Length>,
47}
48
49impl SourceSizeList {
50    /// Create an empty `SourceSizeList`, which can be used as a fall-back.
51    pub fn empty() -> Self {
52        Self {
53            source_sizes: vec![],
54            value: None,
55        }
56    }
57
58    /// Evaluate this <source-size-list> to get the final viewport length.
59    pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> Au {
60        computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
61            let matching_source_size = self.source_sizes.iter().find(|source_size| {
62                source_size
63                    .condition
64                    .matches(
65                        context,
66                        &mut CustomMediaEvaluator::none(),
67                        &mut AttributeTracker::new_dummy(),
68                    )
69                    .to_bool(/* unknown = */ false)
70            });
71
72            match matching_source_size {
73                Some(source_size) => source_size.value.to_computed_value(context),
74                None => match self.value {
75                    Some(ref v) => v.to_computed_value(context),
76                    None => Length::new(NoCalcLength::new(LengthUnit::Vw, 100.))
77                        .to_computed_value(context),
78                },
79            }
80        })
81        .into()
82    }
83}
84
85enum SourceSizeOrLength {
86    SourceSize(SourceSize),
87    Length(Length),
88}
89
90impl Parse for SourceSizeOrLength {
91    fn parse<'i, 't>(
92        context: &ParserContext,
93        input: &mut Parser<'i, 't>,
94    ) -> Result<Self, ParseError<'i>> {
95        if let Ok(size) = input.try_parse(|input| SourceSize::parse(context, input)) {
96            return Ok(SourceSizeOrLength::SourceSize(size));
97        }
98
99        let length = Length::parse_non_negative(context, input)?;
100        Ok(SourceSizeOrLength::Length(length))
101    }
102}
103
104impl SourceSizeList {
105    /// NOTE(emilio): This doesn't match the grammar in the spec, see:
106    ///
107    /// https://html.spec.whatwg.org/multipage/#parsing-a-sizes-attribute
108    pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Self {
109        let mut source_sizes = vec![];
110
111        loop {
112            let result = input.parse_until_before(Delimiter::Comma, |input| {
113                SourceSizeOrLength::parse(context, input)
114            });
115
116            match result {
117                Ok(SourceSizeOrLength::Length(value)) => {
118                    return Self {
119                        source_sizes,
120                        value: Some(value),
121                    };
122                },
123                Ok(SourceSizeOrLength::SourceSize(source_size)) => {
124                    source_sizes.push(source_size);
125                },
126                Err(..) => {},
127            }
128
129            match input.next() {
130                Ok(&Token::Comma) => {},
131                Err(..) => break,
132                _ => unreachable!(),
133            }
134        }
135
136        SourceSizeList {
137            source_sizes,
138            value: None,
139        }
140    }
141}