Auto merge of #21068 - emilio:gecko-sync, r=emilio

style: Sync changes from mozilla-central.

See each individual commit for details.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21068)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-06-18 14:02:13 -04:00 committed by GitHub
commit 615a127b99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 454 additions and 417 deletions

View file

@ -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_clip::single_value::T as BackgroundClip;
use style::computed_values::background_origin::single_value::T as BackgroundOrigin; use style::computed_values::background_origin::single_value::T as BackgroundOrigin;
use style::computed_values::border_image_outset::T as BorderImageOutset; use style::computed_values::border_image_outset::T as BorderImageOutset;
use style::properties::ComputedValues;
use style::properties::style_structs::{self, Background}; use style::properties::style_structs::{self, Background};
use style::values::Either; use style::values::Either;
use style::values::computed::{Angle, GradientItem, BackgroundSize as ComputedBackgroundSize}; 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<GradientStop> { fn convert_gradient_stops(
style: &ComputedValues,
gradient_items: &[GradientItem],
total_length: Au,
) -> Vec<GradientStop> {
// Determine the position of each stop per CSS-IMAGES § 3.4. // Determine the position of each stop per CSS-IMAGES § 3.4.
// Only keep the color stops, discard the color interpolation hints. // 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(); .unwrap();
let end_offset = position_to_offset(end_stop.position.unwrap(), total_length); let end_offset = position_to_offset(end_stop.position.unwrap(), total_length);
stop_run = Some(StopRun { stop_run = Some(StopRun {
start_offset: start_offset, start_offset,
end_offset: end_offset, end_offset,
start_index: i - 1, start_index: i - 1,
stop_count: end_index, stop_count: end_index,
}) })
@ -518,7 +523,7 @@ fn convert_gradient_stops(gradient_items: &[GradientItem], total_length: Au) ->
assert!(offset.is_finite()); assert!(offset.is_finite());
stops.push(GradientStop { stops.push(GradientStop {
offset: offset, offset: offset,
color: stop.color.to_layout(), color: style.resolve_color(stop.color).to_layout(),
}) })
} }
stops stops
@ -533,6 +538,7 @@ fn as_gradient_extend_mode(repeating: bool) -> ExtendMode {
} }
pub fn convert_linear_gradient( pub fn convert_linear_gradient(
style: &ComputedValues,
size: Size2D<Au>, size: Size2D<Au>,
stops: &[GradientItem], stops: &[GradientItem],
direction: LineDirection, direction: LineDirection,
@ -581,19 +587,20 @@ pub fn convert_linear_gradient(
// This is the length of the gradient line. // 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 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); let center = Point2D::new(size.width / 2, size.height / 2);
Gradient { Gradient {
start_point: (center - delta).to_layout(), start_point: (center - delta).to_layout(),
end_point: (center + delta).to_layout(), end_point: (center + delta).to_layout(),
stops: stops, stops,
extend_mode: as_gradient_extend_mode(repeating), extend_mode: as_gradient_extend_mode(repeating),
} }
} }
pub fn convert_radial_gradient( pub fn convert_radial_gradient(
style: &ComputedValues,
size: Size2D<Au>, size: Size2D<Au>,
stops: &[GradientItem], stops: &[GradientItem],
shape: EndingShape, 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 { RadialGradient {
center: center.to_layout(), center: center.to_layout(),

View file

@ -1116,6 +1116,7 @@ impl FragmentDisplayListBuilding for Fragment {
let display_item = match gradient.kind { let display_item = match gradient.kind {
GradientKind::Linear(angle_or_corner) => { GradientKind::Linear(angle_or_corner) => {
let gradient = convert_linear_gradient( let gradient = convert_linear_gradient(
style,
placement.tile_size, placement.tile_size,
&gradient.items[..], &gradient.items[..],
angle_or_corner, angle_or_corner,
@ -1130,6 +1131,7 @@ impl FragmentDisplayListBuilding for Fragment {
}, },
GradientKind::Radial(shape, center, _angle) => { GradientKind::Radial(shape, center, _angle) => {
let gradient = convert_radial_gradient( let gradient = convert_radial_gradient(
style,
placement.tile_size, placement.tile_size,
&gradient.items[..], &gradient.items[..],
shape, shape,
@ -1298,6 +1300,7 @@ impl FragmentDisplayListBuilding for Fragment {
Either::Second(Image::Gradient(ref gradient)) => Some(match gradient.kind { Either::Second(Image::Gradient(ref gradient)) => Some(match gradient.kind {
GradientKind::Linear(angle_or_corner) => BorderDetails::Gradient(GradientBorder { GradientKind::Linear(angle_or_corner) => BorderDetails::Gradient(GradientBorder {
gradient: convert_linear_gradient( gradient: convert_linear_gradient(
style,
bounds.size, bounds.size,
&gradient.items[..], &gradient.items[..],
angle_or_corner, angle_or_corner,
@ -1308,6 +1311,7 @@ impl FragmentDisplayListBuilding for Fragment {
GradientKind::Radial(shape, center, _angle) => { GradientKind::Radial(shape, center, _angle) => {
BorderDetails::RadialGradient(RadialGradientBorder { BorderDetails::RadialGradient(RadialGradientBorder {
gradient: convert_radial_gradient( gradient: convert_radial_gradient(
style,
bounds.size, bounds.size,
&gradient.items[..], &gradient.items[..],
shape, shape,

View file

@ -16,7 +16,7 @@ use dom::medialist::MediaList;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use servo_arc::Arc; 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::parser::ParserContext;
use style::shared_lock::{Locked, ToCssWithGuard}; use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::{CssRuleType, MediaRule}; use style::stylesheets::{CssRuleType, MediaRule};
@ -79,8 +79,11 @@ impl CSSMediaRule {
ParsingMode::DEFAULT, ParsingMode::DEFAULT,
quirks_mode); quirks_mode);
let new_medialist = parse_media_query_list(&context, &mut input, let new_medialist = StyleMediaList::parse(
window.css_error_reporter()); &context,
&mut input,
window.css_error_reporter(),
);
let mut guard = self.cssconditionrule.shared_lock().write(); let mut guard = self.cssconditionrule.shared_lock().write();
// Clone an Arc because we cant borrow `guard` twice at the same time. // Clone an Arc because we cant borrow `guard` twice at the same time.

View file

@ -29,7 +29,7 @@ use std::borrow::ToOwned;
use std::cell::Cell; use std::cell::Cell;
use std::default::Default; use std::default::Default;
use style::attr::AttrValue; 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::parser::ParserContext as CssParserContext;
use style::str::HTML_SPACE_CHARACTERS; use style::str::HTML_SPACE_CHARACTERS;
use style::stylesheets::{CssRuleType, Stylesheet}; use style::stylesheets::{CssRuleType, Stylesheet};
@ -277,12 +277,21 @@ impl HTMLLinkElement {
let mut input = ParserInput::new(&mq_str); let mut input = ParserInput::new(&mq_str);
let mut css_parser = CssParser::new(&mut input); let mut css_parser = CssParser::new(&mut input);
let doc_url = document.url(); let doc_url = document.url();
let context = CssParserContext::new_for_cssom(&doc_url, Some(CssRuleType::Media), // FIXME(emilio): This looks somewhat fishy, since we use the context
ParsingMode::DEFAULT, // only to parse the media query list, CssRuleType::Media doesn't make
document.quirks_mode()); // much sense.
let context = CssParserContext::new_for_cssom(
&doc_url,
Some(CssRuleType::Media),
ParsingMode::DEFAULT,
document.quirks_mode(),
);
let window = document.window(); let window = document.window();
let media = parse_media_query_list(&context, &mut css_parser, let media = MediaList::parse(
window.css_error_reporter()); &context,
&mut css_parser,
window.css_error_reporter(),
);
let im_attribute = element.get_attribute(&ns!(), &local_name!("integrity")); let im_attribute = element.get_attribute(&ns!(), &local_name!("integrity"));
let integrity_val = im_attribute.r().map(|a| a.value()); let integrity_val = im_attribute.r().map(|a| a.value());

View file

@ -21,7 +21,7 @@ use html5ever::{LocalName, Prefix};
use net_traits::ReferrerPolicy; use net_traits::ReferrerPolicy;
use servo_arc::Arc; use servo_arc::Arc;
use std::cell::Cell; 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::parser::ParserContext as CssParserContext;
use style::stylesheets::{CssRuleType, Stylesheet, Origin}; use style::stylesheets::{CssRuleType, Stylesheet, Origin};
use style_traits::ParsingMode; use style_traits::ParsingMode;
@ -91,9 +91,11 @@ impl HTMLStyleElement {
let shared_lock = node.owner_doc().style_shared_lock().clone(); let shared_lock = node.owner_doc().style_shared_lock().clone();
let mut input = ParserInput::new(&mq_str); let mut input = ParserInput::new(&mq_str);
let css_error_reporter = window.css_error_reporter(); let css_error_reporter = window.css_error_reporter();
let mq = Arc::new(shared_lock.wrap(parse_media_query_list(&context, let mq = Arc::new(shared_lock.wrap(MediaList::parse(
&mut CssParser::new(&mut input), &context,
css_error_reporter))); &mut CssParser::new(&mut input),
css_error_reporter),
));
let loader = StylesheetLoader::for_element(self.upcast()); let loader = StylesheetLoader::for_element(self.upcast());
let sheet = Stylesheet::from_str(&data, window.get_url(), let sheet = Stylesheet::from_str(&data, window.get_url(),
Origin::Author, mq, Origin::Author, mq,

View file

@ -13,8 +13,8 @@ use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use servo_arc::Arc; use servo_arc::Arc;
use style::media_queries::{MediaQuery, parse_media_query_list};
use style::media_queries::MediaList as StyleMediaList; use style::media_queries::MediaList as StyleMediaList;
use style::media_queries::MediaQuery;
use style::parser::ParserContext; use style::parser::ParserContext;
use style::shared_lock::{SharedRwLock, Locked}; use style::shared_lock::{SharedRwLock, Locked};
use style::stylesheets::CssRuleType; use style::stylesheets::CssRuleType;
@ -80,8 +80,11 @@ impl MediaListMethods for MediaList {
let context = ParserContext::new_for_cssom(&url, Some(CssRuleType::Media), let context = ParserContext::new_for_cssom(&url, Some(CssRuleType::Media),
ParsingMode::DEFAULT, ParsingMode::DEFAULT,
quirks_mode); quirks_mode);
*media_queries = parse_media_query_list(&context, &mut parser, *media_queries = StyleMediaList::parse(
window.css_error_reporter()); &context,
&mut parser,
window.css_error_reporter(),
);
} }
// https://drafts.csswg.org/cssom/#dom-medialist-length // https://drafts.csswg.org/cssom/#dom-medialist-length

View file

@ -1020,8 +1020,11 @@ impl WindowMethods for Window {
let context = CssParserContext::new_for_cssom(&url, Some(CssRuleType::Media), let context = CssParserContext::new_for_cssom(&url, Some(CssRuleType::Media),
ParsingMode::DEFAULT, ParsingMode::DEFAULT,
quirks_mode); quirks_mode);
let media_query_list = media_queries::parse_media_query_list(&context, &mut parser, let media_query_list = media_queries::MediaList::parse(
self.css_error_reporter()); &context,
&mut parser,
self.css_error_reporter(),
);
let document = self.Document(); let document = self.Document();
let mql = MediaQueryList::new(&document, media_query_list); let mql = MediaQueryList::new(&document, media_query_list);
self.media_query_lists.push(&*mql); self.media_query_lists.push(&*mql);

View file

@ -9,12 +9,12 @@
#![allow(non_snake_case, missing_docs)] #![allow(non_snake_case, missing_docs)]
use gecko_bindings::bindings::RawServoCounterStyleRule; use gecko_bindings::bindings::RawServoCounterStyleRule;
use gecko_bindings::bindings::RawServoDocumentRule;
use gecko_bindings::bindings::RawServoFontFeatureValuesRule; use gecko_bindings::bindings::RawServoFontFeatureValuesRule;
use gecko_bindings::bindings::RawServoImportRule; use gecko_bindings::bindings::RawServoImportRule;
use gecko_bindings::bindings::RawServoKeyframe; use gecko_bindings::bindings::RawServoKeyframe;
use gecko_bindings::bindings::RawServoKeyframesRule; use gecko_bindings::bindings::RawServoKeyframesRule;
use gecko_bindings::bindings::RawServoMediaRule; use gecko_bindings::bindings::RawServoMediaRule;
use gecko_bindings::bindings::RawServoMozDocumentRule;
use gecko_bindings::bindings::RawServoNamespaceRule; use gecko_bindings::bindings::RawServoNamespaceRule;
use gecko_bindings::bindings::RawServoPageRule; use gecko_bindings::bindings::RawServoPageRule;
use gecko_bindings::bindings::RawServoRuleNode; use gecko_bindings::bindings::RawServoRuleNode;
@ -98,7 +98,7 @@ impl_arc_ffi!(Locked<PageRule> => RawServoPageRule
impl_arc_ffi!(Locked<SupportsRule> => RawServoSupportsRule impl_arc_ffi!(Locked<SupportsRule> => RawServoSupportsRule
[Servo_SupportsRule_AddRef, Servo_SupportsRule_Release]); [Servo_SupportsRule_AddRef, Servo_SupportsRule_Release]);
impl_arc_ffi!(Locked<DocumentRule> => RawServoDocumentRule impl_arc_ffi!(Locked<DocumentRule> => RawServoMozDocumentRule
[Servo_DocumentRule_AddRef, Servo_DocumentRule_Release]); [Servo_DocumentRule_AddRef, Servo_DocumentRule_Release]);
impl_arc_ffi!(Locked<FontFeatureValuesRule> => RawServoFontFeatureValuesRule impl_arc_ffi!(Locked<FontFeatureValuesRule> => RawServoFontFeatureValuesRule

View file

@ -9,7 +9,7 @@
#![allow(unsafe_code)] #![allow(unsafe_code)]
use app_units::Au; use app_units::Au;
use gecko::values::{convert_rgba_to_nscolor, GeckoStyleCoordConvertible}; use gecko::values::GeckoStyleCoordConvertible;
use gecko_bindings::bindings; use gecko_bindings::bindings;
use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue}; use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue};
use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage}; use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage};
@ -358,7 +358,7 @@ impl nsStyleImage {
match *item { match *item {
GradientItem::ColorStop(ref stop) => { GradientItem::ColorStop(ref stop) => {
gecko_stop.mColor = convert_rgba_to_nscolor(&stop.color); gecko_stop.mColor = stop.color.into();
gecko_stop.mIsInterpolationHint = false; gecko_stop.mIsInterpolationHint = false;
coord.set(stop.position); coord.set(stop.position);
}, },
@ -433,7 +433,6 @@ impl nsStyleImage {
} }
unsafe fn get_gradient(self: &nsStyleImage) -> Box<Gradient> { unsafe fn get_gradient(self: &nsStyleImage) -> Box<Gradient> {
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_CORNER as CLOSEST_CORNER;
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE;
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER;
@ -601,7 +600,7 @@ impl nsStyleImage {
) )
} else { } else {
GradientItem::ColorStop(ColorStop { GradientItem::ColorStop(ColorStop {
color: convert_nscolor_to_rgba(stop.mColor), color: stop.mColor.into(),
position: LengthOrPercentage::from_gecko_style_coord(&stop.mLocation), position: LengthOrPercentage::from_gecko_style_coord(&stop.mLocation),
}) })
} }

View file

@ -23,7 +23,7 @@ use properties::ComputedValues;
use servo_arc::Arc; use servo_arc::Arc;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}; 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 string_cache::Atom;
use style_traits::{CSSPixel, CssWriter, DevicePixel}; use style_traits::{CSSPixel, CssWriter, DevicePixel};
use style_traits::{ParseError, StyleParseErrorKind, ToCss}; use style_traits::{ParseError, StyleParseErrorKind, ToCss};
@ -118,8 +118,7 @@ impl Device {
/// Set the font size of the root element (for rem) /// Set the font size of the root element (for rem)
pub fn set_root_font_size(&self, size: Au) { pub fn set_root_font_size(&self, size: Au) {
self.root_font_size self.root_font_size.store(size.0 as isize, Ordering::Relaxed)
.store(size.0 as isize, Ordering::Relaxed)
} }
/// Sets the body text color for the "inherit color from body" quirk. /// Sets the body text color for the "inherit color from body" quirk.
@ -229,7 +228,7 @@ impl Device {
} }
/// The kind of matching that should be performed on a media feature value. /// 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 { pub enum Range {
/// At least the specified value. /// At least the specified value.
Min, Min,
@ -241,7 +240,7 @@ pub enum Range {
/// A expression for gecko contains a reference to the media feature, the value /// A expression for gecko contains a reference to the media feature, the value
/// the media query contained, and the range to evaluate. /// the media query contained, and the range to evaluate.
#[derive(Clone, Debug)] #[derive(Clone, Debug, MallocSizeOf)]
pub struct Expression { pub struct Expression {
feature: &'static nsMediaFeature, feature: &'static nsMediaFeature,
value: Option<MediaExpressionValue>, value: Option<MediaExpressionValue>,
@ -294,7 +293,7 @@ impl PartialEq for Expression {
/// If the first, this would need to store the relevant values. /// If the first, this would need to store the relevant values.
/// ///
/// See: https://github.com/w3c/csswg-drafts/issues/1968 /// See: https://github.com/w3c/csswg-drafts/issues/1968
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
pub enum MediaExpressionValue { pub enum MediaExpressionValue {
/// A length. /// A length.
Length(Length), Length(Length),
@ -596,7 +595,7 @@ impl Expression {
Range::Equal 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 _ }) { match find_feature(|f| atom.as_ptr() == unsafe { *f.mName as *mut _ }) {
Some(f) => Ok((f, range)), Some(f) => Ok((f, range)),
None => Err(()), None => Err(()),

View file

@ -178,11 +178,13 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
as *const bindings::RawServoAuthorStyles) as *const bindings::RawServoAuthorStyles)
}; };
let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles); let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
debug_assert!( debug_assert!(
author_styles.quirks_mode == self.as_node().owner_doc().quirks_mode() || 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 &author_styles.data

View file

@ -1,353 +0,0 @@
/* 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/. */
//! [Media queries][mq].
//!
//! [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 selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write};
use str::string_as_ascii_lowercase;
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use values::CustomIdent;
#[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.
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[css(comma)]
#[derive(Clone, Debug, ToCss)]
pub struct MediaList {
/// The list of media queries.
#[css(iterable)]
pub media_queries: Vec<MediaQuery>,
}
impl MediaList {
/// Create an empty MediaList.
pub fn empty() -> Self {
MediaList {
media_queries: vec![],
}
}
}
/// <https://drafts.csswg.org/mediaqueries/#mq-prefix>
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss)]
pub enum Qualifier {
/// Hide a media query from legacy UAs:
/// <https://drafts.csswg.org/mediaqueries/#mq-only>
Only,
/// Negate a media query:
/// <https://drafts.csswg.org/mediaqueries/#mq-not>
Not,
}
/// A [media query][mq].
///
/// [mq]: https://drafts.csswg.org/mediaqueries/
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct MediaQuery {
/// The qualifier for this query.
pub qualifier: Option<Qualifier>,
/// 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<Expression>,
}
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<W>(&self, dest: &mut CssWriter<W>) -> 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(())
}
}
/// <http://dev.w3.org/csswg/mediaqueries-3/#media0>
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub enum MediaQueryType {
/// A media type that matches every device.
All,
/// A specific media type.
Concrete(MediaType),
}
impl MediaQueryType {
fn parse(ident: &str) -> Result<Self, ()> {
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,
}
}
}
/// <https://drafts.csswg.org/mediaqueries/#media-types>
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
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<Self, ()> {
// From https://drafts.csswg.org/mediaqueries/#mq-syntax:
//
// The <media-type> 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<MediaQuery, ParseError<'i>> {
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 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)?)
}
}
}
/// 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:
///
/// <https://drafts.csswg.org/mediaqueries/#error-handling>
pub fn parse_media_query_list<R>(
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.
/// <https://drafts.csswg.org/cssom/#dom-medialist-appendmedium>
///
/// 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.
/// <https://drafts.csswg.org/cssom/#dom-medialist-deletemedium>
///
/// 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()
}
}

View file

@ -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 context::QuirksMode;
use cssparser::{Delimiter, Parser};
use cssparser::{ParserInput, Token};
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<MediaQuery>,
}
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:
///
/// <https://drafts.csswg.org/mediaqueries/#error-handling>
pub fn parse<R>(
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.
/// <https://drafts.csswg.org/cssom/#dom-medialist-appendmedium>
///
/// 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.
/// <https://drafts.csswg.org/cssom/#dom-medialist-deletemedium>
///
/// 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()
}
}

View file

@ -0,0 +1,196 @@
/* 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 super::Expression;
use values::CustomIdent;
/// <https://drafts.csswg.org/mediaqueries/#mq-prefix>
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)]
pub enum Qualifier {
/// Hide a media query from legacy UAs:
/// <https://drafts.csswg.org/mediaqueries/#mq-only>
Only,
/// Negate a media query:
/// <https://drafts.csswg.org/mediaqueries/#mq-not>
Not,
}
/// <https://drafts.csswg.org/mediaqueries/#media-types>
#[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<Self, ()> {
// From https://drafts.csswg.org/mediaqueries/#mq-syntax:
//
// The <media-type> 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<Qualifier>,
/// 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<Expression>,
}
impl ToCss for MediaQuery {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> 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<MediaQuery, ParseError<'i>> {
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)?)
}
}
}
/// <http://dev.w3.org/csswg/mediaqueries-3/#media0>
#[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<Self, ()> {
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,
}
}
}

View file

@ -0,0 +1,18 @@
/* 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/. */
//! [Media queries][mq].
//!
//! [mq]: https://drafts.csswg.org/mediaqueries/
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};

View file

@ -1739,7 +1739,9 @@ impl Animate for Quaternion {
let (this_weight, other_weight) = procedure.weights(); let (this_weight, other_weight) = procedure.weights();
debug_assert!( 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, other_weight == 1.0f64 || other_weight == 0.0f64,
"animate should only be used for interpolating or accumulating transforms" "animate should only be used for interpolating or accumulating transforms"
); );

View file

@ -626,6 +626,7 @@ ${helpers.single_keyword("-moz-appearance",
gecko_ffi_name="mAppearance", gecko_ffi_name="mAppearance",
gecko_constant_prefix="ThemeWidgetType_NS_THEME", gecko_constant_prefix="ThemeWidgetType_NS_THEME",
products="gecko", products="gecko",
alias="-webkit-appearance:layout.css.webkit-appearance.enabled",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)",
animation_value_type="discrete")} animation_value_type="discrete")}

View file

@ -10,7 +10,7 @@ use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListP
use cssparser::{BasicParseError, BasicParseErrorKind, CowRcStr, SourceLocation}; use cssparser::{BasicParseError, BasicParseErrorKind, CowRcStr, SourceLocation};
use error_reporting::{ContextualParseError, ParseErrorReporter}; use error_reporting::{ContextualParseError, ParseErrorReporter};
use font_face::parse_font_face_block; 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 parser::{Parse, ParserContext, ParserErrorContext};
use properties::parse_property_declaration_list; use properties::parse_property_declaration_list;
use selector_parser::{SelectorImpl, SelectorParser}; 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_string = input.expect_url_or_string()?.as_ref().to_owned();
let url = CssUrl::parse_from_string(url_string, &self.context); let url = CssUrl::parse_from_string(url_string, &self.context);
let media = parse_media_query_list(&self.context, input, let media = MediaList::parse(
self.error_context.error_reporter); &self.context,
input,
self.error_context.error_reporter,
);
let media = Arc::new(self.shared_lock.wrap(media)); let media = Arc::new(self.shared_lock.wrap(media));
let prelude = AtRuleNonBlockPrelude::Import(url, media, location); 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, match_ignore_ascii_case! { &*name,
"media" => { "media" => {
let media_queries = parse_media_query_list(self.context, input, let media_queries = MediaList::parse(
self.error_context.error_reporter); self.context,
input,
self.error_context.error_reporter,
);
let arc = Arc::new(self.shared_lock.wrap(media_queries)); let arc = Arc::new(self.shared_lock.wrap(media_queries));
Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Media(arc, location))) Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Media(arc, location)))
}, },

View file

@ -7,12 +7,11 @@
//! //!
//! [image]: https://drafts.csswg.org/css-images/#image-values //! [image]: https://drafts.csswg.org/css-images/#image-values
use cssparser::RGBA;
use std::f32::consts::PI; use std::f32::consts::PI;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
use values::{Either, None_}; use values::{Either, None_};
use values::computed::{Angle, Context}; use values::computed::{Angle, Color, Context};
use values::computed::{Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue}; use values::computed::{Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::computed::Percentage; use values::computed::Percentage;
@ -32,7 +31,7 @@ pub type Image = generic::Image<Gradient, MozImageRect, ComputedImageUrl>;
/// Computed values for a CSS gradient. /// Computed values for a CSS gradient.
/// <https://drafts.csswg.org/css-images/#gradients> /// <https://drafts.csswg.org/css-images/#gradients>
pub type Gradient = pub type Gradient =
generic::Gradient<LineDirection, Length, LengthOrPercentage, Position, RGBA, Angle>; generic::Gradient<LineDirection, Length, LengthOrPercentage, Position, Color, Angle>;
/// A computed gradient kind. /// A computed gradient kind.
pub type GradientKind = pub type GradientKind =
@ -58,10 +57,10 @@ pub enum LineDirection {
pub type EndingShape = generic::EndingShape<Length, LengthOrPercentage>; pub type EndingShape = generic::EndingShape<Length, LengthOrPercentage>;
/// A computed gradient item. /// A computed gradient item.
pub type GradientItem = generic::GradientItem<RGBA, LengthOrPercentage>; pub type GradientItem = generic::GradientItem<Color, LengthOrPercentage>;
/// A computed color stop. /// A computed color stop.
pub type ColorStop = generic::ColorStop<RGBA, LengthOrPercentage>; pub type ColorStop = generic::ColorStop<Color, LengthOrPercentage>;
/// Computed values for `-moz-image-rect(...)`. /// Computed values for `-moz-image-rect(...)`.
pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, ComputedImageUrl>; pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, ComputedImageUrl>;

View file

@ -26,7 +26,7 @@ use values::generics::image::{self as generic, Circle, CompatMode, Ellipse, Shap
use values::generics::image::PaintWorklet; use values::generics::image::PaintWorklet;
use values::generics::position::Position as GenericPosition; use values::generics::position::Position as GenericPosition;
use values::specified::{Angle, Color, Length, LengthOrPercentage}; 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::position::{LegacyPosition, Position, PositionComponent, Side, X, Y};
use values::specified::url::SpecifiedImageUrl; use values::specified::url::SpecifiedImageUrl;
@ -41,19 +41,13 @@ pub type Image = generic::Image<Gradient, MozImageRect, SpecifiedImageUrl>;
/// <https://drafts.csswg.org/css-images/#gradients> /// <https://drafts.csswg.org/css-images/#gradients>
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
pub type Gradient = pub type Gradient =
generic::Gradient<LineDirection, Length, LengthOrPercentage, Position, RGBAColor, Angle>; generic::Gradient<LineDirection, Length, LengthOrPercentage, Position, Color, Angle>;
/// Specified values for a CSS gradient. /// Specified values for a CSS gradient.
/// <https://drafts.csswg.org/css-images/#gradients> /// <https://drafts.csswg.org/css-images/#gradients>
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub type Gradient = generic::Gradient< pub type Gradient =
LineDirection, generic::Gradient<LineDirection, Length, LengthOrPercentage, GradientPosition, Color, Angle>;
Length,
LengthOrPercentage,
GradientPosition,
RGBAColor,
Angle,
>;
impl SpecifiedValueInfo for Gradient { impl SpecifiedValueInfo for Gradient {
const SUPPORTED_TYPES: u8 = CssType::GRADIENT; const SUPPORTED_TYPES: u8 = CssType::GRADIENT;
@ -121,10 +115,10 @@ pub enum GradientPosition {
pub type EndingShape = generic::EndingShape<Length, LengthOrPercentage>; pub type EndingShape = generic::EndingShape<Length, LengthOrPercentage>;
/// A specified gradient item. /// A specified gradient item.
pub type GradientItem = generic::GradientItem<RGBAColor, LengthOrPercentage>; pub type GradientItem = generic::GradientItem<Color, LengthOrPercentage>;
/// A computed color stop. /// A computed color stop.
pub type ColorStop = generic::ColorStop<RGBAColor, LengthOrPercentage>; pub type ColorStop = generic::ColorStop<Color, LengthOrPercentage>;
/// Specified values for `moz-image-rect` /// Specified values for `moz-image-rect`
/// -moz-image-rect(<uri>, top, right, bottom, left); /// -moz-image-rect(<uri>, top, right, bottom, left);
@ -957,7 +951,7 @@ impl Parse for ColorStop {
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
Ok(ColorStop { Ok(ColorStop {
color: RGBAColor::parse(context, input)?, color: Color::parse(context, input)?,
position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(), position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(),
}) })
} }

View file

@ -12,7 +12,7 @@ use style_traits::{ParseError, StyleParseErrorKind};
use values::CSSFloat; use values::CSSFloat;
/// A specified resolution. /// A specified resolution.
#[derive(Clone, Debug, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
pub enum Resolution { pub enum Resolution {
/// Dots per inch. /// Dots per inch.
#[css(dimension)] #[css(dimension)]