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