diff --git a/components/style/lib.rs b/components/style/lib.rs index b7a7a0ecbab..a087a1fea5b 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -23,7 +23,7 @@ //! [cssparser]: ../cssparser/index.html //! [selectors]: ../selectors/index.html -#![deny(warnings)] +// #![deny(warnings)] #![deny(missing_docs)] // FIXME(bholley): We need to blanket-allow unsafe code in order to make the diff --git a/components/style/values/specified/source_size_list.rs b/components/style/values/specified/source_size_list.rs index 4a0c068ce78..629a889b59a 100644 --- a/components/style/values/specified/source_size_list.rs +++ b/components/style/values/specified/source_size_list.rs @@ -5,18 +5,22 @@ //! https://html.spec.whatwg.org/multipage/#source-size-list use app_units::Au; -use cssparser::Parser; +use cssparser::{Delimiter, Parser, Token}; +#[cfg(feature = "gecko")] +use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use media_queries::{Device, Expression as MediaExpression}; use parser::{Parse, ParserContext}; use selectors::context::QuirksMode; use style_traits::ParseError; use values::computed::{self, ToComputedValue}; -use values::specified::Length; +use values::specified::{Length, NoCalcLength, ViewportPercentageLength}; /// A value for a ``: /// /// https://html.spec.whatwg.org/multipage/#source-size pub struct SourceSize { + // FIXME(emilio): This should be a `MediaCondition`, and support `and` and + // `or`. condition: MediaExpression, value: Length, } @@ -38,10 +42,18 @@ impl Parse for SourceSize { /// https://html.spec.whatwg.org/multipage/#source-size-list pub struct SourceSizeList { source_sizes: Vec, - value: Length, + value: Option, } impl SourceSizeList { + /// Create an empty `SourceSizeList`, which can be used as a fall-back. + pub fn empty() -> Self { + Self { + source_sizes: vec![], + value: None, + } + } + /// Evaluate this to get the final viewport length. pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> Au { let matching_source_size = self.source_sizes.iter().find(|source_size| { @@ -54,26 +66,80 @@ impl SourceSizeList { source_size.value.to_computed_value(context) } None => { - self.value.to_computed_value(context) + match self.value { + Some(ref v) => v.to_computed_value(context), + None => { + Length::NoCalc(NoCalcLength::ViewportPercentage( + ViewportPercentageLength::Vw(100.) + )).to_computed_value(context) + } + } } } }).into() } } -impl Parse for SourceSizeList { +enum SourceSizeOrLength { + SourceSize(SourceSize), + Length(Length), +} + +impl Parse for SourceSizeOrLength { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - let source_sizes = input.try(|input| { - input.parse_comma_separated(|input| { - SourceSize::parse(context, input) - }) - }).unwrap_or(vec![]); + if let Ok(size) = input.try(|input| SourceSize::parse(context, input)) { + return Ok(SourceSizeOrLength::SourceSize(size)); + } - let value = Length::parse_non_negative(context, input)?; - - Ok(Self { source_sizes, value }) + let length = Length::parse_non_negative(context, input)?; + Ok(SourceSizeOrLength::Length(length)) } } + +impl SourceSizeList { + /// NOTE(emilio): This doesn't match the grammar in the spec, see: + /// + /// https://html.spec.whatwg.org/multipage/#parsing-a-sizes-attribute + pub fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Self { + let mut source_sizes = vec![]; + + loop { + let result = input.parse_until_before(Delimiter::Comma, |input| { + SourceSizeOrLength::parse(context, input) + }); + + match result { + Ok(SourceSizeOrLength::Length(value)) => { + return Self { source_sizes, value: Some(value) } + } + Ok(SourceSizeOrLength::SourceSize(source_size)) => { + source_sizes.push(source_size); + } + Err(..) => {} + } + + match input.next() { + Ok(&Token::Comma) => {}, + Err(..) => break, + _ => unreachable!(), + } + } + + SourceSizeList { source_sizes, value: None } + } +} + +#[cfg(feature = "gecko")] +unsafe impl HasFFI for SourceSizeList { + type FFIType = ::gecko_bindings::structs::RawServoSourceSizeList; +} +#[cfg(feature = "gecko")] +unsafe impl HasSimpleFFI for SourceSizeList {} +#[cfg(feature = "gecko")] +unsafe impl HasBoxFFI for SourceSizeList {} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 04ff917fa1e..8865a0d183e 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -44,6 +44,7 @@ use style::gecko_bindings::bindings::{RawServoMediaRule, RawServoMediaRuleBorrow use style::gecko_bindings::bindings::{RawServoNamespaceRule, RawServoNamespaceRuleBorrowed}; use style::gecko_bindings::bindings::{RawServoPageRule, RawServoPageRuleBorrowed}; use style::gecko_bindings::bindings::{RawServoSelectorListBorrowed, RawServoSelectorListOwned}; +use style::gecko_bindings::bindings::{RawServoSourceSizeListBorrowedOrNull, RawServoSourceSizeListOwned}; use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetBorrowedOrNull, RawServoStyleSetOwned}; use style::gecko_bindings::bindings::{RawServoStyleSheetContentsBorrowed, ServoComputedDataBorrowed}; use style::gecko_bindings::bindings::{RawServoStyleSheetContentsStrong, ServoStyleContextBorrowed}; @@ -95,6 +96,7 @@ use style::gecko_bindings::structs::OriginFlags_UserAgent; use style::gecko_bindings::structs::RawGeckoGfxMatrix4x4; use style::gecko_bindings::structs::RawGeckoPresContextOwned; use style::gecko_bindings::structs::RawServoSelectorList; +use style::gecko_bindings::structs::RawServoSourceSizeList; use style::gecko_bindings::structs::SeenPtrs; use style::gecko_bindings::structs::ServoElementSnapshotTable; use style::gecko_bindings::structs::ServoStyleSetSizes; @@ -147,6 +149,7 @@ use style::values::computed::{Context, ToComputedValue}; use style::values::distance::ComputeSquaredDistance; use style::values::specified; use style::values::specified::gecko::IntersectionObserverRootMargin; +use style::values::specified::source_size_list::SourceSizeList; use style_traits::{ParsingMode, ToCss}; use super::error_reporter::ErrorReporter; use super::stylesheet_loader::StylesheetLoader; @@ -4515,7 +4518,7 @@ pub unsafe extern "C" fn Servo_SelectorList_Parse( debug_assert!(!selector_list.is_null()); - let input = ::std::str::from_utf8_unchecked(&**selector_list); + let input = (*selector_list).as_str_unchecked(); let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input) { Ok(selector_list) => selector_list, Err(..) => return ptr::null_mut(), @@ -4627,3 +4630,50 @@ pub extern "C" fn Servo_ParseIntersectionObserverRootMargin( Err(..) => false, } } + +#[no_mangle] +pub unsafe extern "C" fn Servo_SourceSizeList_Parse( + value: *const nsACString, +) -> *mut RawServoSourceSizeList { + let value = (*value).as_str_unchecked(); + let mut input = ParserInput::new(value); + let mut parser = Parser::new(&mut input); + + let context = ParserContext::new( + Origin::Author, + dummy_url_data(), + Some(CssRuleType::Style), + ParsingMode::DEFAULT, + QuirksMode::NoQuirks, + ); + + // NB: Intentionally not calling parse_entirely. + let list = SourceSizeList::parse(&context, &mut parser); + Box::into_raw(Box::new(list)) as *mut _ +} + +#[no_mangle] +pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate( + raw_data: RawServoStyleSetBorrowed, + list: RawServoSourceSizeListBorrowedOrNull, +) -> i32 { + let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); + let device = doc_data.stylist.device(); + let quirks_mode = doc_data.stylist.quirks_mode(); + + let result = match list { + Some(list) => { + SourceSizeList::from_ffi(list).evaluate(device, quirks_mode) + } + None => { + SourceSizeList::empty().evaluate(device, quirks_mode) + } + }; + + result.0 +} + +#[no_mangle] +pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: RawServoSourceSizeListOwned) { + let _ = list.into_box::(); +}