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 http://mozilla.org/MPL/2.0/. */ 4 5 //! https://html.spec.whatwg.org/multipage/#source-size-list 6 7 use app_units::Au; 8 use cssparser::{Delimiter, Parser, Token}; 9 #[cfg(feature = "gecko")] 10 use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; 11 use media_queries::{Device, Expression as MediaExpression}; 12 use parser::{Parse, ParserContext}; 13 use selectors::context::QuirksMode; 14 use style_traits::ParseError; 15 use values::computed::{self, ToComputedValue}; 16 use values::specified::{Length, NoCalcLength, ViewportPercentageLength}; 17 18 /// A value for a `<source-size>`: 19 /// 20 /// https://html.spec.whatwg.org/multipage/#source-size 21 pub struct SourceSize { 22 // FIXME(emilio): This should be a `MediaCondition`, and support `and` and 23 // `or`. 24 condition: MediaExpression, 25 value: Length, 26 } 27 28 impl Parse for SourceSize { parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>29 fn parse<'i, 't>( 30 context: &ParserContext, 31 input: &mut Parser<'i, 't>, 32 ) -> Result<Self, ParseError<'i>> { 33 let condition = MediaExpression::parse(context, input)?; 34 let value = Length::parse_non_negative(context, input)?; 35 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 pub struct SourceSizeList { 44 source_sizes: Vec<SourceSize>, 45 value: Option<Length>, 46 } 47 48 impl SourceSizeList { 49 /// Create an empty `SourceSizeList`, which can be used as a fall-back. empty() -> Self50 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. evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> Au58 pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> Au { 59 let matching_source_size = self.source_sizes.iter().find(|source_size| { 60 source_size.condition.matches(device, quirks_mode) 61 }); 62 63 computed::Context::for_media_query_evaluation(device, quirks_mode, |context| { 64 match matching_source_size { 65 Some(source_size) => { 66 source_size.value.to_computed_value(context) 67 } 68 None => { 69 match self.value { 70 Some(ref v) => v.to_computed_value(context), 71 None => { 72 Length::NoCalc(NoCalcLength::ViewportPercentage( 73 ViewportPercentageLength::Vw(100.) 74 )).to_computed_value(context) 75 } 76 } 77 } 78 } 79 }).into() 80 } 81 } 82 83 enum SourceSizeOrLength { 84 SourceSize(SourceSize), 85 Length(Length), 86 } 87 88 impl Parse for SourceSizeOrLength { parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>89 fn parse<'i, 't>( 90 context: &ParserContext, 91 input: &mut Parser<'i, 't>, 92 ) -> Result<Self, ParseError<'i>> { 93 if let Ok(size) = input.try(|input| SourceSize::parse(context, input)) { 94 return Ok(SourceSizeOrLength::SourceSize(size)); 95 } 96 97 let length = Length::parse_non_negative(context, input)?; 98 Ok(SourceSizeOrLength::Length(length)) 99 } 100 } 101 102 impl SourceSizeList { 103 /// NOTE(emilio): This doesn't match the grammar in the spec, see: 104 /// 105 /// https://html.spec.whatwg.org/multipage/#parsing-a-sizes-attribute parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Self106 pub fn parse<'i, 't>( 107 context: &ParserContext, 108 input: &mut Parser<'i, 't>, 109 ) -> 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 { source_sizes, value: Some(value) } 120 } 121 Ok(SourceSizeOrLength::SourceSize(source_size)) => { 122 source_sizes.push(source_size); 123 } 124 Err(..) => {} 125 } 126 127 match input.next() { 128 Ok(&Token::Comma) => {}, 129 Err(..) => break, 130 _ => unreachable!(), 131 } 132 } 133 134 SourceSizeList { source_sizes, value: None } 135 } 136 } 137 138 #[cfg(feature = "gecko")] 139 unsafe impl HasFFI for SourceSizeList { 140 type FFIType = ::gecko_bindings::structs::RawServoSourceSizeList; 141 } 142 #[cfg(feature = "gecko")] 143 unsafe impl HasSimpleFFI for SourceSizeList {} 144 #[cfg(feature = "gecko")] 145 unsafe impl HasBoxFFI for SourceSizeList {} 146