From 9d679c9b205b9de9f8213131432848f54213ecf1 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Thu, 31 May 2018 18:22:48 +1000 Subject: [PATCH 01/14] style: Ignore case in media feature names inside media query expressions. Media feature names are converted to lower case before being processed, making them effectively case-insensitive. Prefixes ("min-", etc.) and values are already treated in a case-insensitive manner. Bug: 1464091 Reviewed-by: heycam MozReview-Commit-ID: JUeeEQEMIi4 --- components/style/gecko/media_queries.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 554606bb9db..833db60a037 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -23,7 +23,7 @@ use properties::ComputedValues; use servo_arc::Arc; use std::fmt::{self, Write}; use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}; -use str::starts_with_ignore_ascii_case; +use str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase}; use string_cache::Atom; use style_traits::{CSSPixel, CssWriter, DevicePixel}; use style_traits::{ParseError, StyleParseErrorKind, ToCss}; @@ -596,7 +596,7 @@ impl Expression { Range::Equal }; - let atom = Atom::from(feature_name); + let atom = Atom::from(string_as_ascii_lowercase(feature_name)); match find_feature(|f| atom.as_ptr() == unsafe { *f.mName as *mut _ }) { Some(f) => Ok((f, range)), None => Err(()), From 238314e606b0403a6d9a9c1fdc6587a9d6614b7a Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Wed, 13 Jun 2018 06:42:14 +0900 Subject: [PATCH 02/14] style: Double f64::EPSILON for calculation error. It's possible that both this_weight and other_weght have calculation errors which are approximately equal to f64::EPSILON. Bug: 1468294 Reviewed-by: birtles MozReview-Commit-ID: 8OddG9rI3qd --- .../style/properties/helpers/animated_properties.mako.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index d935726eb48..de0e48c782d 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -1739,7 +1739,9 @@ impl Animate for Quaternion { let (this_weight, other_weight) = procedure.weights(); debug_assert!( - (this_weight + other_weight - 1.0f64).abs() <= f64::EPSILON || + // Doule EPSILON since both this_weight and other_weght have calculation errors + // which are approximately equal to EPSILON. + (this_weight + other_weight - 1.0f64).abs() <= f64::EPSILON * 2.0 || other_weight == 1.0f64 || other_weight == 0.0f64, "animate should only be used for interpolating or accumulating transforms" ); From 74189514fd2aaf02b966bd9c7f849114682ea479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 5 Jun 2018 17:16:51 +0200 Subject: [PATCH 03/14] style: Merge ServoDocumentRule and CSSMozDocumentRule. Bug: 1451289 Reviewed-by: emilio MozReview-Commit-ID: BkMMXBWdsfz --- components/style/gecko/arc_types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index 3ef3d07da13..7351cbfeac4 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -9,12 +9,12 @@ #![allow(non_snake_case, missing_docs)] use gecko_bindings::bindings::RawServoCounterStyleRule; -use gecko_bindings::bindings::RawServoDocumentRule; use gecko_bindings::bindings::RawServoFontFeatureValuesRule; use gecko_bindings::bindings::RawServoImportRule; use gecko_bindings::bindings::RawServoKeyframe; use gecko_bindings::bindings::RawServoKeyframesRule; use gecko_bindings::bindings::RawServoMediaRule; +use gecko_bindings::bindings::RawServoMozDocumentRule; use gecko_bindings::bindings::RawServoNamespaceRule; use gecko_bindings::bindings::RawServoPageRule; use gecko_bindings::bindings::RawServoRuleNode; @@ -98,7 +98,7 @@ impl_arc_ffi!(Locked => RawServoPageRule impl_arc_ffi!(Locked => RawServoSupportsRule [Servo_SupportsRule_AddRef, Servo_SupportsRule_Release]); -impl_arc_ffi!(Locked => RawServoDocumentRule +impl_arc_ffi!(Locked => RawServoMozDocumentRule [Servo_DocumentRule_AddRef, Servo_DocumentRule_Release]); impl_arc_ffi!(Locked => RawServoFontFeatureValuesRule From 4d255392f7a08d16a90ef1caa084e46e980b61fe Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Thu, 7 Jun 2018 15:55:26 +1000 Subject: [PATCH 04/14] style: Change nscolor to StyleComplexColor in nsStyleGradientStop. Bug: 1467379 Reviewed-by: xidorn MozReview-Commit-ID: D9KQcv9uQ4S --- components/style/gecko/conversions.rs | 7 +++---- components/style/values/computed/image.rs | 9 ++++----- components/style/values/specified/image.rs | 20 +++++++------------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index bbc2776daa9..14fee693a03 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -9,7 +9,7 @@ #![allow(unsafe_code)] use app_units::Au; -use gecko::values::{convert_rgba_to_nscolor, GeckoStyleCoordConvertible}; +use gecko::values::GeckoStyleCoordConvertible; use gecko_bindings::bindings; use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue}; use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage}; @@ -358,7 +358,7 @@ impl nsStyleImage { match *item { GradientItem::ColorStop(ref stop) => { - gecko_stop.mColor = convert_rgba_to_nscolor(&stop.color); + gecko_stop.mColor = stop.color.into(); gecko_stop.mIsInterpolationHint = false; coord.set(stop.position); }, @@ -433,7 +433,6 @@ impl nsStyleImage { } unsafe fn get_gradient(self: &nsStyleImage) -> Box { - use gecko::values::convert_nscolor_to_rgba; use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER; use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; @@ -601,7 +600,7 @@ impl nsStyleImage { ) } else { GradientItem::ColorStop(ColorStop { - color: convert_nscolor_to_rgba(stop.mColor), + color: stop.mColor.into(), position: LengthOrPercentage::from_gecko_style_coord(&stop.mLocation), }) } diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index 6976182a6f4..91e55c39910 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -7,12 +7,11 @@ //! //! [image]: https://drafts.csswg.org/css-images/#image-values -use cssparser::RGBA; use std::f32::consts::PI; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; use values::{Either, None_}; -use values::computed::{Angle, Context}; +use values::computed::{Angle, Color, Context}; use values::computed::{Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue}; #[cfg(feature = "gecko")] use values::computed::Percentage; @@ -32,7 +31,7 @@ pub type Image = generic::Image; /// Computed values for a CSS gradient. /// pub type Gradient = - generic::Gradient; + generic::Gradient; /// A computed gradient kind. pub type GradientKind = @@ -58,10 +57,10 @@ pub enum LineDirection { pub type EndingShape = generic::EndingShape; /// A computed gradient item. -pub type GradientItem = generic::GradientItem; +pub type GradientItem = generic::GradientItem; /// A computed color stop. -pub type ColorStop = generic::ColorStop; +pub type ColorStop = generic::ColorStop; /// Computed values for `-moz-image-rect(...)`. pub type MozImageRect = generic::MozImageRect; diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index 2390292253b..64d24573f4a 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -26,7 +26,7 @@ use values::generics::image::{self as generic, Circle, CompatMode, Ellipse, Shap use values::generics::image::PaintWorklet; use values::generics::position::Position as GenericPosition; use values::specified::{Angle, Color, Length, LengthOrPercentage}; -use values::specified::{Number, NumberOrPercentage, Percentage, RGBAColor}; +use values::specified::{Number, NumberOrPercentage, Percentage}; use values::specified::position::{LegacyPosition, Position, PositionComponent, Side, X, Y}; use values::specified::url::SpecifiedImageUrl; @@ -41,19 +41,13 @@ pub type Image = generic::Image; /// #[cfg(not(feature = "gecko"))] pub type Gradient = - generic::Gradient; + generic::Gradient; /// Specified values for a CSS gradient. /// #[cfg(feature = "gecko")] -pub type Gradient = generic::Gradient< - LineDirection, - Length, - LengthOrPercentage, - GradientPosition, - RGBAColor, - Angle, ->; +pub type Gradient = + generic::Gradient; impl SpecifiedValueInfo for Gradient { const SUPPORTED_TYPES: u8 = CssType::GRADIENT; @@ -121,10 +115,10 @@ pub enum GradientPosition { pub type EndingShape = generic::EndingShape; /// A specified gradient item. -pub type GradientItem = generic::GradientItem; +pub type GradientItem = generic::GradientItem; /// A computed color stop. -pub type ColorStop = generic::ColorStop; +pub type ColorStop = generic::ColorStop; /// Specified values for `moz-image-rect` /// -moz-image-rect(, top, right, bottom, left); @@ -957,7 +951,7 @@ impl Parse for ColorStop { input: &mut Parser<'i, 't>, ) -> Result> { Ok(ColorStop { - color: RGBAColor::parse(context, input)?, + color: Color::parse(context, input)?, position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(), }) } From 9ca081c53246d9eb52cdf5914fbeb3644f988e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 14 Jun 2018 13:00:18 -0700 Subject: [PATCH 05/14] style: Unify some #[derive]s between Servo and Gecko. Bug: 1468846 Reviewed-by: xidorn MozReview-Commit-ID: FqoNCuLcdm7 --- components/style/gecko/media_queries.rs | 6 +++--- components/style/media_queries.rs | 16 ++++++---------- components/style/values/specified/resolution.rs | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 833db60a037..9dbfb5c8cb9 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -229,7 +229,7 @@ impl Device { } /// The kind of matching that should be performed on a media feature value. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] pub enum Range { /// At least the specified value. Min, @@ -241,7 +241,7 @@ pub enum Range { /// A expression for gecko contains a reference to the media feature, the value /// the media query contained, and the range to evaluate. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, MallocSizeOf)] pub struct Expression { feature: &'static nsMediaFeature, value: Option, @@ -294,7 +294,7 @@ impl PartialEq for Expression { /// If the first, this would need to store the relevant values. /// /// See: https://github.com/w3c/csswg-drafts/issues/1968 -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq)] pub enum MediaExpressionValue { /// A length. Length(Length), diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs index 5742e794c3f..11cf6c85dc7 100644 --- a/components/style/media_queries.rs +++ b/components/style/media_queries.rs @@ -24,9 +24,8 @@ pub use servo::media_queries::{Device, Expression}; pub use gecko::media_queries::{Device, Expression}; /// A type that encapsulates a media query list. -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] #[css(comma)] -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, ToCss)] pub struct MediaList { /// The list of media queries. #[css(iterable)] @@ -43,8 +42,7 @@ impl MediaList { } /// -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -#[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] pub enum Qualifier { /// Hide a media query from legacy UAs: /// @@ -57,8 +55,7 @@ pub enum Qualifier { /// A [media query][mq]. /// /// [mq]: https://drafts.csswg.org/mediaqueries/ -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive(Clone, Debug, MallocSizeOf, PartialEq)] pub struct MediaQuery { /// The qualifier for this query. pub qualifier: Option, @@ -123,8 +120,7 @@ impl ToCss for MediaQuery { } /// -#[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] pub enum MediaQueryType { /// A media type that matches every device. All, @@ -152,8 +148,7 @@ impl MediaQueryType { } /// -#[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] pub struct MediaType(pub CustomIdent); impl MediaType { @@ -180,6 +175,7 @@ impl MediaType { } } } + impl MediaQuery { /// Parse a media query given css input. /// diff --git a/components/style/values/specified/resolution.rs b/components/style/values/specified/resolution.rs index 52da8eaea34..2965b65821a 100644 --- a/components/style/values/specified/resolution.rs +++ b/components/style/values/specified/resolution.rs @@ -12,7 +12,7 @@ use style_traits::{ParseError, StyleParseErrorKind}; use values::CSSFloat; /// A specified resolution. -#[derive(Clone, Debug, PartialEq, ToCss)] +#[derive(Clone, Debug, PartialEq, MallocSizeOf, ToCss)] pub enum Resolution { /// Dots per inch. #[css(dimension)] From ddf386b02b79326e694bcddd2a865d60831d2ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 14 Jun 2018 13:03:59 -0700 Subject: [PATCH 06/14] style: Move media_queries module to be a directory. Bug: 1468846 Reviewed-by: xidorn MozReview-Commit-ID: 7H93L6f0bAl --- components/style/{media_queries.rs => media_queries/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename components/style/{media_queries.rs => media_queries/mod.rs} (100%) diff --git a/components/style/media_queries.rs b/components/style/media_queries/mod.rs similarity index 100% rename from components/style/media_queries.rs rename to components/style/media_queries/mod.rs From c7b36fb43fecaebd46cd9483da556a9170183547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 14 Jun 2018 13:22:07 -0700 Subject: [PATCH 07/14] style: Move MediaList to its own module. And move the parsing from a free function to MediaList::parse. Bug: 1468846 Reviewed-by: xidorn MozReview-Commit-ID: 75ES6I2EEOE --- components/style/media_queries/media_list.rs | 143 +++++++++++++++++++ components/style/media_queries/mod.rs | 142 +----------------- components/style/stylesheets/rule_parser.rs | 16 ++- 3 files changed, 159 insertions(+), 142 deletions(-) create mode 100644 components/style/media_queries/media_list.rs diff --git a/components/style/media_queries/media_list.rs b/components/style/media_queries/media_list.rs new file mode 100644 index 00000000000..89926815d6c --- /dev/null +++ b/components/style/media_queries/media_list.rs @@ -0,0 +1,143 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! A media query list: +//! +//! https://drafts.csswg.org/mediaqueries/#typedef-media-query-list + +use cssparser::{Delimiter, Parser}; +use cssparser::{ParserInput, Token}; +use context::QuirksMode; +use error_reporting::{ContextualParseError, ParseErrorReporter}; +use parser::{ParserContext, ParserErrorContext}; +use super::{Device, MediaQuery, Qualifier}; + +/// A type that encapsulates a media query list. +#[css(comma)] +#[derive(Clone, Debug, MallocSizeOf, ToCss)] +pub struct MediaList { + /// The list of media queries. + #[css(iterable)] + pub media_queries: Vec, +} + +impl MediaList { + /// Parse a media query list from CSS. + /// + /// Always returns a media query list. If any invalid media query is + /// found, the media query list is only filled with the equivalent of + /// "not all", see: + /// + /// + pub fn parse( + context: &ParserContext, + input: &mut Parser, + error_reporter: &R, + ) -> MediaList + where + R: ParseErrorReporter, + { + if input.is_exhausted() { + return Self::empty(); + } + + let mut media_queries = vec![]; + loop { + let start_position = input.position(); + match input.parse_until_before(Delimiter::Comma, |i| MediaQuery::parse(context, i)) { + Ok(mq) => { + media_queries.push(mq); + }, + Err(err) => { + media_queries.push(MediaQuery::never_matching()); + let location = err.location; + let error = + ContextualParseError::InvalidMediaRule(input.slice_from(start_position), err); + let error_context = ParserErrorContext { error_reporter }; + context.log_css_error(&error_context, location, error); + }, + } + + match input.next() { + Ok(&Token::Comma) => {}, + Ok(_) => unreachable!(), + Err(_) => break, + } + } + + MediaList { media_queries } + } + + /// Create an empty MediaList. + pub fn empty() -> Self { + MediaList { + media_queries: vec![], + } + } + + /// Evaluate a whole `MediaList` against `Device`. + pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> bool { + // Check if it is an empty media query list or any queries match (OR condition) + // https://drafts.csswg.org/mediaqueries-4/#mq-list + self.media_queries.is_empty() || self.media_queries.iter().any(|mq| { + let media_match = mq.media_type.matches(device.media_type()); + + // Check if all conditions match (AND condition) + let query_match = media_match && + mq.expressions + .iter() + .all(|expression| expression.matches(&device, quirks_mode)); + + // Apply the logical NOT qualifier to the result + match mq.qualifier { + Some(Qualifier::Not) => !query_match, + _ => query_match, + } + }) + } + + /// Whether this `MediaList` contains no media queries. + pub fn is_empty(&self) -> bool { + self.media_queries.is_empty() + } + + /// Append a new media query item to the media list. + /// + /// + /// Returns true if added, false if fail to parse the medium string. + pub fn append_medium(&mut self, context: &ParserContext, new_medium: &str) -> bool { + let mut input = ParserInput::new(new_medium); + let mut parser = Parser::new(&mut input); + let new_query = match MediaQuery::parse(&context, &mut parser) { + Ok(query) => query, + Err(_) => { + return false; + }, + }; + // This algorithm doesn't actually matches the current spec, + // but it matches the behavior of Gecko and Edge. + // See https://github.com/w3c/csswg-drafts/issues/697 + self.media_queries.retain(|query| query != &new_query); + self.media_queries.push(new_query); + true + } + + /// Delete a media query from the media list. + /// + /// + /// Returns true if found and deleted, false otherwise. + pub fn delete_medium(&mut self, context: &ParserContext, old_medium: &str) -> bool { + let mut input = ParserInput::new(old_medium); + let mut parser = Parser::new(&mut input); + let old_query = match MediaQuery::parse(context, &mut parser) { + Ok(query) => query, + Err(_) => { + return false; + }, + }; + let old_len = self.media_queries.len(); + self.media_queries.retain(|query| query != &old_query); + old_len != self.media_queries.len() + } +} diff --git a/components/style/media_queries/mod.rs b/components/style/media_queries/mod.rs index 11cf6c85dc7..e1db6ca40cd 100644 --- a/components/style/media_queries/mod.rs +++ b/components/style/media_queries/mod.rs @@ -7,40 +7,22 @@ //! [mq]: https://drafts.csswg.org/mediaqueries/ use Atom; -use context::QuirksMode; -use cssparser::{Delimiter, Parser}; -use cssparser::{ParserInput, Token}; -use error_reporting::{ContextualParseError, ParseErrorReporter}; -use parser::{ParserContext, ParserErrorContext}; +use cssparser::Parser; +use parser::ParserContext; use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; use str::string_as_ascii_lowercase; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use values::CustomIdent; +mod media_list; + +pub use self::media_list::MediaList; #[cfg(feature = "servo")] pub use servo::media_queries::{Device, Expression}; #[cfg(feature = "gecko")] pub use gecko::media_queries::{Device, Expression}; -/// A type that encapsulates a media query list. -#[css(comma)] -#[derive(Clone, Debug, MallocSizeOf, ToCss)] -pub struct MediaList { - /// The list of media queries. - #[css(iterable)] - pub media_queries: Vec, -} - -impl MediaList { - /// Create an empty MediaList. - pub fn empty() -> Self { - MediaList { - media_queries: vec![], - } - } -} - /// #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] pub enum Qualifier { @@ -233,117 +215,3 @@ impl MediaQuery { } } } - -/// Parse a media query list from CSS. -/// -/// Always returns a media query list. If any invalid media query is found, the -/// media query list is only filled with the equivalent of "not all", see: -/// -/// -pub fn parse_media_query_list( - context: &ParserContext, - input: &mut Parser, - error_reporter: &R, -) -> MediaList -where - R: ParseErrorReporter, -{ - if input.is_exhausted() { - return MediaList::empty(); - } - - let mut media_queries = vec![]; - loop { - let start_position = input.position(); - match input.parse_until_before(Delimiter::Comma, |i| MediaQuery::parse(context, i)) { - Ok(mq) => { - media_queries.push(mq); - }, - Err(err) => { - media_queries.push(MediaQuery::never_matching()); - let location = err.location; - let error = - ContextualParseError::InvalidMediaRule(input.slice_from(start_position), err); - let error_context = ParserErrorContext { error_reporter }; - context.log_css_error(&error_context, location, error); - }, - } - - match input.next() { - Ok(&Token::Comma) => {}, - Ok(_) => unreachable!(), - Err(_) => break, - } - } - - MediaList { - media_queries: media_queries, - } -} - -impl MediaList { - /// Evaluate a whole `MediaList` against `Device`. - pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> bool { - // Check if it is an empty media query list or any queries match (OR condition) - // https://drafts.csswg.org/mediaqueries-4/#mq-list - self.media_queries.is_empty() || self.media_queries.iter().any(|mq| { - let media_match = mq.media_type.matches(device.media_type()); - - // Check if all conditions match (AND condition) - let query_match = media_match && - mq.expressions - .iter() - .all(|expression| expression.matches(&device, quirks_mode)); - - // Apply the logical NOT qualifier to the result - match mq.qualifier { - Some(Qualifier::Not) => !query_match, - _ => query_match, - } - }) - } - - /// Whether this `MediaList` contains no media queries. - pub fn is_empty(&self) -> bool { - self.media_queries.is_empty() - } - - /// Append a new media query item to the media list. - /// - /// - /// Returns true if added, false if fail to parse the medium string. - pub fn append_medium(&mut self, context: &ParserContext, new_medium: &str) -> bool { - let mut input = ParserInput::new(new_medium); - let mut parser = Parser::new(&mut input); - let new_query = match MediaQuery::parse(&context, &mut parser) { - Ok(query) => query, - Err(_) => { - return false; - }, - }; - // This algorithm doesn't actually matches the current spec, - // but it matches the behavior of Gecko and Edge. - // See https://github.com/w3c/csswg-drafts/issues/697 - self.media_queries.retain(|query| query != &new_query); - self.media_queries.push(new_query); - true - } - - /// Delete a media query from the media list. - /// - /// - /// Returns true if found and deleted, false otherwise. - pub fn delete_medium(&mut self, context: &ParserContext, old_medium: &str) -> bool { - let mut input = ParserInput::new(old_medium); - let mut parser = Parser::new(&mut input); - let old_query = match MediaQuery::parse(context, &mut parser) { - Ok(query) => query, - Err(_) => { - return false; - }, - }; - let old_len = self.media_queries.len(); - self.media_queries.retain(|query| query != &old_query); - old_len != self.media_queries.len() - } -} diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index a446068faac..259130dd89b 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -10,7 +10,7 @@ use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListP use cssparser::{BasicParseError, BasicParseErrorKind, CowRcStr, SourceLocation}; use error_reporting::{ContextualParseError, ParseErrorReporter}; use font_face::parse_font_face_block; -use media_queries::{parse_media_query_list, MediaList}; +use media_queries::MediaList; use parser::{Parse, ParserContext, ParserErrorContext}; use properties::parse_property_declaration_list; use selector_parser::{SelectorImpl, SelectorParser}; @@ -197,8 +197,11 @@ impl<'a, 'i, R: ParseErrorReporter> AtRuleParser<'i> for TopLevelRuleParser<'a, let url_string = input.expect_url_or_string()?.as_ref().to_owned(); let url = CssUrl::parse_from_string(url_string, &self.context); - let media = parse_media_query_list(&self.context, input, - self.error_context.error_reporter); + let media = MediaList::parse( + &self.context, + input, + self.error_context.error_reporter, + ); let media = Arc::new(self.shared_lock.wrap(media)); let prelude = AtRuleNonBlockPrelude::Import(url, media, location); @@ -380,8 +383,11 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a match_ignore_ascii_case! { &*name, "media" => { - let media_queries = parse_media_query_list(self.context, input, - self.error_context.error_reporter); + let media_queries = MediaList::parse( + self.context, + input, + self.error_context.error_reporter, + ); let arc = Arc::new(self.shared_lock.wrap(media_queries)); Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Media(arc, location))) }, From 67d8bfb7202e3857f1c168b12b3ceb292ed4f24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 14 Jun 2018 13:38:47 -0700 Subject: [PATCH 08/14] style: Introduce Qualifier::parse. Bug: 1468846 Reviewed-by: xidorn MozReview-Commit-ID: 4IOJpaS9ijI --- components/style/media_queries/mod.rs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/components/style/media_queries/mod.rs b/components/style/media_queries/mod.rs index e1db6ca40cd..eeb6b95000b 100644 --- a/components/style/media_queries/mod.rs +++ b/components/style/media_queries/mod.rs @@ -24,7 +24,7 @@ pub use servo::media_queries::{Device, Expression}; pub use gecko::media_queries::{Device, Expression}; /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)] pub enum Qualifier { /// Hide a media query from legacy UAs: /// @@ -168,20 +168,7 @@ impl MediaQuery { ) -> Result> { let mut expressions = vec![]; - let qualifier = if input - .try(|input| input.expect_ident_matching("only")) - .is_ok() - { - Some(Qualifier::Only) - } else if input - .try(|input| input.expect_ident_matching("not")) - .is_ok() - { - Some(Qualifier::Not) - } else { - None - }; - + let qualifier = input.try(Qualifier::parse).ok(); let media_type = match input.try(|i| i.expect_ident_cloned()) { Ok(ident) => MediaQueryType::parse(&*ident).map_err(|()| { input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) From ba5be8d0ebaae17c246f055a52ef5264e549bc00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 14 Jun 2018 13:54:07 -0700 Subject: [PATCH 09/14] style: Move MediaQuery and friends to its own module. Bug: 1468846 Reviewed-by: xidorn MozReview-Commit-ID: 3FRMnIHFwR3 --- components/style/media_queries/media_query.rs | 197 ++++++++++++++++++ components/style/media_queries/mod.rs | 192 +---------------- 2 files changed, 200 insertions(+), 189 deletions(-) create mode 100644 components/style/media_queries/media_query.rs diff --git a/components/style/media_queries/media_query.rs b/components/style/media_queries/media_query.rs new file mode 100644 index 00000000000..fa7b387cf3d --- /dev/null +++ b/components/style/media_queries/media_query.rs @@ -0,0 +1,197 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! A media query: +//! +//! https://drafts.csswg.org/mediaqueries/#typedef-media-query + +use Atom; +use cssparser::Parser; +use parser::ParserContext; +use selectors::parser::SelectorParseErrorKind; +use std::fmt::{self, Write}; +use str::string_as_ascii_lowercase; +use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use values::CustomIdent; + +use super::Expression; + +/// +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)] +pub enum Qualifier { + /// Hide a media query from legacy UAs: + /// + Only, + /// Negate a media query: + /// + Not, +} + +/// +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] +pub struct MediaType(pub CustomIdent); + +impl MediaType { + /// The `screen` media type. + pub fn screen() -> Self { + MediaType(CustomIdent(atom!("screen"))) + } + + /// The `print` media type. + pub fn print() -> Self { + MediaType(CustomIdent(atom!("print"))) + } + + fn parse(name: &str) -> Result { + // From https://drafts.csswg.org/mediaqueries/#mq-syntax: + // + // The production does not include the keywords not, or, and, and only. + // + // Here we also perform the to-ascii-lowercase part of the serialization + // algorithm: https://drafts.csswg.org/cssom/#serializing-media-queries + match_ignore_ascii_case! { name, + "not" | "or" | "and" | "only" => Err(()), + _ => Ok(MediaType(CustomIdent(Atom::from(string_as_ascii_lowercase(name))))), + } + } +} + +/// A [media query][mq]. +/// +/// [mq]: https://drafts.csswg.org/mediaqueries/ +#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +pub struct MediaQuery { + /// The qualifier for this query. + pub qualifier: Option, + /// The media type for this query, that can be known, unknown, or "all". + pub media_type: MediaQueryType, + /// The set of expressions that this media query contains. + pub expressions: Vec, +} + +impl ToCss for MediaQuery { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + if let Some(qual) = self.qualifier { + qual.to_css(dest)?; + dest.write_char(' ')?; + } + + match self.media_type { + MediaQueryType::All => { + // We need to print "all" if there's a qualifier, or there's + // just an empty list of expressions. + // + // Otherwise, we'd serialize media queries like "(min-width: + // 40px)" in "all (min-width: 40px)", which is unexpected. + if self.qualifier.is_some() || self.expressions.is_empty() { + dest.write_str("all")?; + } + }, + MediaQueryType::Concrete(MediaType(ref desc)) => desc.to_css(dest)?, + } + + if self.expressions.is_empty() { + return Ok(()); + } + + if self.media_type != MediaQueryType::All || self.qualifier.is_some() { + dest.write_str(" and ")?; + } + + self.expressions[0].to_css(dest)?; + + for expr in self.expressions.iter().skip(1) { + dest.write_str(" and ")?; + expr.to_css(dest)?; + } + Ok(()) + } +} + +impl MediaQuery { + /// Return a media query that never matches, used for when we fail to parse + /// a given media query. + pub fn never_matching() -> Self { + Self { + qualifier: Some(Qualifier::Not), + media_type: MediaQueryType::All, + expressions: vec![], + } + } + + /// Parse a media query given css input. + /// + /// Returns an error if any of the expressions is unknown. + pub fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let mut expressions = vec![]; + + let qualifier = input.try(Qualifier::parse).ok(); + let media_type = match input.try(|i| i.expect_ident_cloned()) { + Ok(ident) => MediaQueryType::parse(&*ident).map_err(|()| { + input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) + })?, + Err(_) => { + // Media type is only optional if qualifier is not specified. + if qualifier.is_some() { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + // Without a media type, require at least one expression. + expressions.push(Expression::parse(context, input)?); + + MediaQueryType::All + }, + }; + + // Parse any subsequent expressions + loop { + if input + .try(|input| input.expect_ident_matching("and")) + .is_err() + { + return Ok(MediaQuery { + qualifier, + media_type, + expressions, + }); + } + expressions.push(Expression::parse(context, input)?) + } + } +} + +/// +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] +pub enum MediaQueryType { + /// A media type that matches every device. + All, + /// A specific media type. + Concrete(MediaType), +} + +impl MediaQueryType { + fn parse(ident: &str) -> Result { + match_ignore_ascii_case! { ident, + "all" => return Ok(MediaQueryType::All), + _ => (), + }; + + // If parseable, accept this type as a concrete type. + MediaType::parse(ident).map(MediaQueryType::Concrete) + } + + /// Returns whether this media query type matches a MediaType. + pub fn matches(&self, other: MediaType) -> bool { + match *self { + MediaQueryType::All => true, + MediaQueryType::Concrete(ref known_type) => *known_type == other, + } + } +} diff --git a/components/style/media_queries/mod.rs b/components/style/media_queries/mod.rs index eeb6b95000b..8da14fc67e5 100644 --- a/components/style/media_queries/mod.rs +++ b/components/style/media_queries/mod.rs @@ -6,199 +6,13 @@ //! //! [mq]: https://drafts.csswg.org/mediaqueries/ -use Atom; -use cssparser::Parser; -use parser::ParserContext; -use selectors::parser::SelectorParseErrorKind; -use std::fmt::{self, Write}; -use str::string_as_ascii_lowercase; -use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; -use values::CustomIdent; - mod media_list; +mod media_query; pub use self::media_list::MediaList; +pub use self::media_query::{MediaQuery, MediaQueryType, MediaType, Qualifier}; + #[cfg(feature = "servo")] pub use servo::media_queries::{Device, Expression}; #[cfg(feature = "gecko")] pub use gecko::media_queries::{Device, Expression}; - -/// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)] -pub enum Qualifier { - /// Hide a media query from legacy UAs: - /// - Only, - /// Negate a media query: - /// - Not, -} - -/// A [media query][mq]. -/// -/// [mq]: https://drafts.csswg.org/mediaqueries/ -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] -pub struct MediaQuery { - /// The qualifier for this query. - pub qualifier: Option, - /// The media type for this query, that can be known, unknown, or "all". - pub media_type: MediaQueryType, - /// The set of expressions that this media query contains. - pub expressions: Vec, -} - -impl MediaQuery { - /// Return a media query that never matches, used for when we fail to parse - /// a given media query. - fn never_matching() -> Self { - Self { - qualifier: Some(Qualifier::Not), - media_type: MediaQueryType::All, - expressions: vec![], - } - } -} - -impl ToCss for MediaQuery { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - if let Some(qual) = self.qualifier { - qual.to_css(dest)?; - dest.write_char(' ')?; - } - - match self.media_type { - MediaQueryType::All => { - // We need to print "all" if there's a qualifier, or there's - // just an empty list of expressions. - // - // Otherwise, we'd serialize media queries like "(min-width: - // 40px)" in "all (min-width: 40px)", which is unexpected. - if self.qualifier.is_some() || self.expressions.is_empty() { - dest.write_str("all")?; - } - }, - MediaQueryType::Concrete(MediaType(ref desc)) => desc.to_css(dest)?, - } - - if self.expressions.is_empty() { - return Ok(()); - } - - if self.media_type != MediaQueryType::All || self.qualifier.is_some() { - dest.write_str(" and ")?; - } - - self.expressions[0].to_css(dest)?; - - for expr in self.expressions.iter().skip(1) { - dest.write_str(" and ")?; - expr.to_css(dest)?; - } - Ok(()) - } -} - -/// -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] -pub enum MediaQueryType { - /// A media type that matches every device. - All, - /// A specific media type. - Concrete(MediaType), -} - -impl MediaQueryType { - fn parse(ident: &str) -> Result { - match_ignore_ascii_case! { ident, - "all" => return Ok(MediaQueryType::All), - _ => (), - }; - - // If parseable, accept this type as a concrete type. - MediaType::parse(ident).map(MediaQueryType::Concrete) - } - - fn matches(&self, other: MediaType) -> bool { - match *self { - MediaQueryType::All => true, - MediaQueryType::Concrete(ref known_type) => *known_type == other, - } - } -} - -/// -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] -pub struct MediaType(pub CustomIdent); - -impl MediaType { - /// The `screen` media type. - pub fn screen() -> Self { - MediaType(CustomIdent(atom!("screen"))) - } - - /// The `print` media type. - pub fn print() -> Self { - MediaType(CustomIdent(atom!("print"))) - } - - fn parse(name: &str) -> Result { - // From https://drafts.csswg.org/mediaqueries/#mq-syntax: - // - // The production does not include the keywords not, or, and, and only. - // - // Here we also perform the to-ascii-lowercase part of the serialization - // algorithm: https://drafts.csswg.org/cssom/#serializing-media-queries - match_ignore_ascii_case! { name, - "not" | "or" | "and" | "only" => Err(()), - _ => Ok(MediaType(CustomIdent(Atom::from(string_as_ascii_lowercase(name))))), - } - } -} - -impl MediaQuery { - /// Parse a media query given css input. - /// - /// Returns an error if any of the expressions is unknown. - pub fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let mut expressions = vec![]; - - let qualifier = input.try(Qualifier::parse).ok(); - let media_type = match input.try(|i| i.expect_ident_cloned()) { - Ok(ident) => MediaQueryType::parse(&*ident).map_err(|()| { - input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) - })?, - Err(_) => { - // Media type is only optional if qualifier is not specified. - if qualifier.is_some() { - return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); - } - - // Without a media type, require at least one expression. - expressions.push(Expression::parse(context, input)?); - - MediaQueryType::All - }, - }; - - // Parse any subsequent expressions - loop { - if input - .try(|input| input.expect_ident_matching("and")) - .is_err() - { - return Ok(MediaQuery { - qualifier, - media_type, - expressions, - }); - } - expressions.push(Expression::parse(context, input)?) - } - } -} From 7230102ebac2eb26027530145c76a221abcd0a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 14 Jun 2018 14:35:10 -0700 Subject: [PATCH 10/14] style: Minor indentation cleanup. MozReview-Commit-ID: 7MAVnsjXx63 --- components/style/gecko/media_queries.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 9dbfb5c8cb9..1c34762f286 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -118,8 +118,7 @@ impl Device { /// Set the font size of the root element (for rem) pub fn set_root_font_size(&self, size: Au) { - self.root_font_size - .store(size.0 as isize, Ordering::Relaxed) + self.root_font_size.store(size.0 as isize, Ordering::Relaxed) } /// Sets the body text color for the "inherit color from body" quirk. From 63981e962a528cca34456797528b816f68f174e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 16 Jun 2018 03:21:41 -0700 Subject: [PATCH 11/14] style: Relax a bit an invalid assertion. We may end up looking at a non-flushed AuthorStyles object when looking at whether attribute changes and such may affect style. Check the styles are clean to preserve the assertion, since if that happens before the first flush, we may not have updated the quirks_mode field (and that's fine). Bug: 1468640 MozReview-Commit-ID: FgVpiTf4qMr --- components/style/gecko/wrapper.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 5475be1e3fc..0ce4a45d175 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -178,11 +178,13 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> { as *const bindings::RawServoAuthorStyles) }; + let author_styles = AuthorStyles::::from_ffi(author_styles); debug_assert!( author_styles.quirks_mode == self.as_node().owner_doc().quirks_mode() || - author_styles.stylesheets.is_empty() + author_styles.stylesheets.is_empty() || + author_styles.stylesheets.dirty() ); &author_styles.data From 1face496a28e89f62e468a2ddeadc22391209294 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Fri, 25 May 2018 10:44:17 -0700 Subject: [PATCH 12/14] style: -webkit-appearance alias for -moz-appearance (behind a pref). Bug: 1429713 Reviewed-by: emilio --- components/style/properties/longhand/box.mako.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 898f7391de0..aea51fed766 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -626,6 +626,7 @@ ${helpers.single_keyword("-moz-appearance", gecko_ffi_name="mAppearance", gecko_constant_prefix="ThemeWidgetType_NS_THEME", products="gecko", + alias="-webkit-appearance:layout.css.webkit-appearance.enabled", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)", animation_value_type="discrete")} From d9d9fed7d5214fe25f786f37233a23a7e0af449e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 18 Jun 2018 19:13:40 +0200 Subject: [PATCH 13/14] style: Fix tidy. --- components/style/media_queries/media_list.rs | 2 +- components/style/media_queries/media_query.rs | 5 ++--- components/style/values/specified/resolution.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/components/style/media_queries/media_list.rs b/components/style/media_queries/media_list.rs index 89926815d6c..5243174e07f 100644 --- a/components/style/media_queries/media_list.rs +++ b/components/style/media_queries/media_list.rs @@ -6,9 +6,9 @@ //! //! https://drafts.csswg.org/mediaqueries/#typedef-media-query-list +use context::QuirksMode; use cssparser::{Delimiter, Parser}; use cssparser::{ParserInput, Token}; -use context::QuirksMode; use error_reporting::{ContextualParseError, ParseErrorReporter}; use parser::{ParserContext, ParserErrorContext}; use super::{Device, MediaQuery, Qualifier}; diff --git a/components/style/media_queries/media_query.rs b/components/style/media_queries/media_query.rs index fa7b387cf3d..10fa84bd61a 100644 --- a/components/style/media_queries/media_query.rs +++ b/components/style/media_queries/media_query.rs @@ -13,12 +13,11 @@ use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; use str::string_as_ascii_lowercase; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use super::Expression; use values::CustomIdent; -use super::Expression; - /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] pub enum Qualifier { /// Hide a media query from legacy UAs: /// diff --git a/components/style/values/specified/resolution.rs b/components/style/values/specified/resolution.rs index 2965b65821a..77a269c251b 100644 --- a/components/style/values/specified/resolution.rs +++ b/components/style/values/specified/resolution.rs @@ -12,7 +12,7 @@ use style_traits::{ParseError, StyleParseErrorKind}; use values::CSSFloat; /// A specified resolution. -#[derive(Clone, Debug, PartialEq, MallocSizeOf, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] pub enum Resolution { /// Dots per inch. #[css(dimension)] From 083857a4b0b0e52f7086998d67955727389d6d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 18 Jun 2018 19:32:59 +0200 Subject: [PATCH 14/14] Fix Servo build. --- components/layout/display_list/background.rs | 21 +++++++++++++------- components/layout/display_list/builder.rs | 4 ++++ components/script/dom/cssmediarule.rs | 9 ++++++--- components/script/dom/htmllinkelement.rs | 21 ++++++++++++++------ components/script/dom/htmlstyleelement.rs | 10 ++++++---- components/script/dom/medialist.rs | 9 ++++++--- components/script/dom/window.rs | 7 +++++-- 7 files changed, 56 insertions(+), 25 deletions(-) diff --git a/components/layout/display_list/background.rs b/components/layout/display_list/background.rs index 145c069cb85..4036c2efd2c 100644 --- a/components/layout/display_list/background.rs +++ b/components/layout/display_list/background.rs @@ -20,6 +20,7 @@ use style::computed_values::background_attachment::single_value::T as Background use style::computed_values::background_clip::single_value::T as BackgroundClip; use style::computed_values::background_origin::single_value::T as BackgroundOrigin; use style::computed_values::border_image_outset::T as BorderImageOutset; +use style::properties::ComputedValues; use style::properties::style_structs::{self, Background}; use style::values::Either; use style::values::computed::{Angle, GradientItem, BackgroundSize as ComputedBackgroundSize}; @@ -429,7 +430,11 @@ fn convert_ellipse_size_keyword( } } -fn convert_gradient_stops(gradient_items: &[GradientItem], total_length: Au) -> Vec { +fn convert_gradient_stops( + style: &ComputedValues, + gradient_items: &[GradientItem], + total_length: Au, +) -> Vec { // Determine the position of each stop per CSS-IMAGES § 3.4. // Only keep the color stops, discard the color interpolation hints. @@ -497,8 +502,8 @@ fn convert_gradient_stops(gradient_items: &[GradientItem], total_length: Au) -> .unwrap(); let end_offset = position_to_offset(end_stop.position.unwrap(), total_length); stop_run = Some(StopRun { - start_offset: start_offset, - end_offset: end_offset, + start_offset, + end_offset, start_index: i - 1, stop_count: end_index, }) @@ -518,7 +523,7 @@ fn convert_gradient_stops(gradient_items: &[GradientItem], total_length: Au) -> assert!(offset.is_finite()); stops.push(GradientStop { offset: offset, - color: stop.color.to_layout(), + color: style.resolve_color(stop.color).to_layout(), }) } stops @@ -533,6 +538,7 @@ fn as_gradient_extend_mode(repeating: bool) -> ExtendMode { } pub fn convert_linear_gradient( + style: &ComputedValues, size: Size2D, stops: &[GradientItem], direction: LineDirection, @@ -581,19 +587,20 @@ pub fn convert_linear_gradient( // This is the length of the gradient line. let length = Au::from_f32_px((delta.x.to_f32_px() * 2.0).hypot(delta.y.to_f32_px() * 2.0)); - let stops = convert_gradient_stops(stops, length); + let stops = convert_gradient_stops(style, stops, length); let center = Point2D::new(size.width / 2, size.height / 2); Gradient { start_point: (center - delta).to_layout(), end_point: (center + delta).to_layout(), - stops: stops, + stops, extend_mode: as_gradient_extend_mode(repeating), } } pub fn convert_radial_gradient( + style: &ComputedValues, size: Size2D, stops: &[GradientItem], shape: EndingShape, @@ -620,7 +627,7 @@ pub fn convert_radial_gradient( }, }; - let stops = convert_gradient_stops(stops, radius.width); + let stops = convert_gradient_stops(style, stops, radius.width); RadialGradient { center: center.to_layout(), diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index b5c252cc64e..16a1fc85770 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -1116,6 +1116,7 @@ impl FragmentDisplayListBuilding for Fragment { let display_item = match gradient.kind { GradientKind::Linear(angle_or_corner) => { let gradient = convert_linear_gradient( + style, placement.tile_size, &gradient.items[..], angle_or_corner, @@ -1130,6 +1131,7 @@ impl FragmentDisplayListBuilding for Fragment { }, GradientKind::Radial(shape, center, _angle) => { let gradient = convert_radial_gradient( + style, placement.tile_size, &gradient.items[..], shape, @@ -1298,6 +1300,7 @@ impl FragmentDisplayListBuilding for Fragment { Either::Second(Image::Gradient(ref gradient)) => Some(match gradient.kind { GradientKind::Linear(angle_or_corner) => BorderDetails::Gradient(GradientBorder { gradient: convert_linear_gradient( + style, bounds.size, &gradient.items[..], angle_or_corner, @@ -1308,6 +1311,7 @@ impl FragmentDisplayListBuilding for Fragment { GradientKind::Radial(shape, center, _angle) => { BorderDetails::RadialGradient(RadialGradientBorder { gradient: convert_radial_gradient( + style, bounds.size, &gradient.items[..], shape, diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index 11f05d125a8..0ecdf71a314 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -16,7 +16,7 @@ use dom::medialist::MediaList; use dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; -use style::media_queries::parse_media_query_list; +use style::media_queries::MediaList as StyleMediaList; use style::parser::ParserContext; use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::{CssRuleType, MediaRule}; @@ -79,8 +79,11 @@ impl CSSMediaRule { ParsingMode::DEFAULT, quirks_mode); - let new_medialist = parse_media_query_list(&context, &mut input, - window.css_error_reporter()); + let new_medialist = StyleMediaList::parse( + &context, + &mut input, + window.css_error_reporter(), + ); let mut guard = self.cssconditionrule.shared_lock().write(); // Clone an Arc because we can’t borrow `guard` twice at the same time. diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index f55a795ba0d..ab84906d223 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -29,7 +29,7 @@ use std::borrow::ToOwned; use std::cell::Cell; use std::default::Default; use style::attr::AttrValue; -use style::media_queries::parse_media_query_list; +use style::media_queries::MediaList; use style::parser::ParserContext as CssParserContext; use style::str::HTML_SPACE_CHARACTERS; use style::stylesheets::{CssRuleType, Stylesheet}; @@ -277,12 +277,21 @@ impl HTMLLinkElement { let mut input = ParserInput::new(&mq_str); let mut css_parser = CssParser::new(&mut input); let doc_url = document.url(); - let context = CssParserContext::new_for_cssom(&doc_url, Some(CssRuleType::Media), - ParsingMode::DEFAULT, - document.quirks_mode()); + // FIXME(emilio): This looks somewhat fishy, since we use the context + // only to parse the media query list, CssRuleType::Media doesn't make + // much sense. + let context = CssParserContext::new_for_cssom( + &doc_url, + Some(CssRuleType::Media), + ParsingMode::DEFAULT, + document.quirks_mode(), + ); let window = document.window(); - let media = parse_media_query_list(&context, &mut css_parser, - window.css_error_reporter()); + let media = MediaList::parse( + &context, + &mut css_parser, + window.css_error_reporter(), + ); let im_attribute = element.get_attribute(&ns!(), &local_name!("integrity")); let integrity_val = im_attribute.r().map(|a| a.value()); diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 6a6bc416d2d..6778af92218 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -21,7 +21,7 @@ use html5ever::{LocalName, Prefix}; use net_traits::ReferrerPolicy; use servo_arc::Arc; use std::cell::Cell; -use style::media_queries::parse_media_query_list; +use style::media_queries::MediaList; use style::parser::ParserContext as CssParserContext; use style::stylesheets::{CssRuleType, Stylesheet, Origin}; use style_traits::ParsingMode; @@ -91,9 +91,11 @@ impl HTMLStyleElement { let shared_lock = node.owner_doc().style_shared_lock().clone(); let mut input = ParserInput::new(&mq_str); let css_error_reporter = window.css_error_reporter(); - let mq = Arc::new(shared_lock.wrap(parse_media_query_list(&context, - &mut CssParser::new(&mut input), - css_error_reporter))); + let mq = Arc::new(shared_lock.wrap(MediaList::parse( + &context, + &mut CssParser::new(&mut input), + css_error_reporter), + )); let loader = StylesheetLoader::for_element(self.upcast()); let sheet = Stylesheet::from_str(&data, window.get_url(), Origin::Author, mq, diff --git a/components/script/dom/medialist.rs b/components/script/dom/medialist.rs index 449c3c19ea6..2f5b33c1016 100644 --- a/components/script/dom/medialist.rs +++ b/components/script/dom/medialist.rs @@ -13,8 +13,8 @@ use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; -use style::media_queries::{MediaQuery, parse_media_query_list}; use style::media_queries::MediaList as StyleMediaList; +use style::media_queries::MediaQuery; use style::parser::ParserContext; use style::shared_lock::{SharedRwLock, Locked}; use style::stylesheets::CssRuleType; @@ -80,8 +80,11 @@ impl MediaListMethods for MediaList { let context = ParserContext::new_for_cssom(&url, Some(CssRuleType::Media), ParsingMode::DEFAULT, quirks_mode); - *media_queries = parse_media_query_list(&context, &mut parser, - window.css_error_reporter()); + *media_queries = StyleMediaList::parse( + &context, + &mut parser, + window.css_error_reporter(), + ); } // https://drafts.csswg.org/cssom/#dom-medialist-length diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 2db7609bec4..0f259dd2ea7 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1020,8 +1020,11 @@ impl WindowMethods for Window { let context = CssParserContext::new_for_cssom(&url, Some(CssRuleType::Media), ParsingMode::DEFAULT, quirks_mode); - let media_query_list = media_queries::parse_media_query_list(&context, &mut parser, - self.css_error_reporter()); + let media_query_list = media_queries::MediaList::parse( + &context, + &mut parser, + self.css_error_reporter(), + ); let document = self.Document(); let mql = MediaQueryList::new(&document, media_query_list); self.media_query_lists.push(&*mql);