diff options
48 files changed, 801 insertions, 904 deletions
diff --git a/components/layout/display_list/background.rs b/components/layout/display_list/background.rs index 19976a3bf83..7da2bff68d6 100644 --- a/components/layout/display_list/background.rs +++ b/components/layout/display_list/background.rs @@ -553,12 +553,12 @@ pub fn convert_linear_gradient( let angle = match direction { LineDirection::Angle(angle) => angle.radians(), LineDirection::Horizontal(x) => match x { - X::Left => Angle::Deg(270.).radians(), - X::Right => Angle::Deg(90.).radians(), + X::Left => Angle::from_degrees(270.).radians(), + X::Right => Angle::from_degrees(90.).radians(), }, LineDirection::Vertical(y) => match y { - Y::Top => Angle::Deg(0.).radians(), - Y::Bottom => Angle::Deg(180.).radians(), + Y::Top => Angle::from_degrees(0.).radians(), + Y::Bottom => Angle::from_degrees(180.).radians(), }, LineDirection::Corner(horizontal, vertical) => { // This the angle for one of the diagonals of the box. Our angle diff --git a/components/script/dom/css.rs b/components/script/dom/css.rs index 7a42d6b6e68..0f3c929460e 100644 --- a/components/script/dom/css.rs +++ b/components/script/dom/css.rs @@ -53,21 +53,21 @@ impl CSS { pub fn Supports_(win: &Window, condition: DOMString) -> bool { let mut input = ParserInput::new(&condition); let mut input = Parser::new(&mut input); - let cond = parse_condition_or_declaration(&mut input); - if let Ok(cond) = cond { - let url = win.Document().url(); - let context = ParserContext::new_for_cssom( - &url, - Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - None, - None, - ); - cond.eval(&context) - } else { - false - } + let cond = match parse_condition_or_declaration(&mut input) { + Ok(c) => c, + Err(..) => return false, + }; + + let url = win.Document().url(); + let context = ParserContext::new_for_cssom( + &url, + Some(CssRuleType::Style), + ParsingMode::DEFAULT, + QuirksMode::NoQuirks, + None, + None, + ); + cond.eval(&context, &Default::default()) } /// <https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet> diff --git a/components/script/dom/csssupportsrule.rs b/components/script/dom/csssupportsrule.rs index 136a742e0e7..030a6c56be9 100644 --- a/components/script/dom/csssupportsrule.rs +++ b/components/script/dom/csssupportsrule.rs @@ -81,7 +81,17 @@ impl CSSSupportsRule { None, None, ); - let enabled = cond.eval(&context); + let enabled = { + let namespaces = + self + .cssconditionrule + .parent_stylesheet() + .style_stylesheet() + .contents + .namespaces + .read(); + cond.eval(&context, &namespaces) + }; let mut guard = self.cssconditionrule.shared_lock().write(); let rule = self.supportsrule.write_with(&mut guard); rule.condition = cond; diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 8e26ff63d8a..fc4b26bb3a3 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -259,8 +259,13 @@ where Impl: SelectorImpl, { let location = input.current_source_location(); - let selector = Selector::parse(parser, input)?; - // Ensure they're actually all compound selectors. + let selector = parse_selector(parser, input)?; + + // Ensure they're actually all compound selectors without pseudo-elements. + if selector.has_pseudo_element() { + return Err(location.new_custom_error(SelectorParseErrorKind::PseudoElementInComplexSelector)); + } + if selector.iter_raw_match_order().any(|s| s.is_combinator()) { return Err(location.new_custom_error(SelectorParseErrorKind::NonCompoundSelector)); } @@ -1397,6 +1402,7 @@ where impl<Impl: SelectorImpl> Selector<Impl> { /// Parse a selector, without any pseudo-element. + #[inline] pub fn parse<'i, 't, P>( parser: &P, input: &mut CssParser<'i, 't>, @@ -1404,12 +1410,7 @@ impl<Impl: SelectorImpl> Selector<Impl> { where P: Parser<'i, Impl = Impl>, { - let selector = parse_selector(parser, input)?; - if selector.has_pseudo_element() { - let e = SelectorParseErrorKind::PseudoElementInComplexSelector; - return Err(input.new_custom_error(e)); - } - Ok(selector) + parse_selector(parser, input) } } diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 1ecc7ec6fc3..bee061fcc21 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -17,7 +17,7 @@ mod bindings { use bindgen::{Builder, CodegenConfig}; use regex::Regex; use std::cmp; - use std::collections::{HashMap, HashSet}; + use std::collections::HashSet; use std::env; use std::fs::{self, File}; use std::io::{Read, Write}; @@ -43,7 +43,7 @@ mod bindings { .expect("Failed to open config file") .read_to_string(&mut contents) .expect("Failed to read config file"); - match toml::from_str::<toml::value::Table>(&contents) { + match toml::from_str::<Table>(&contents) { Ok(result) => result, Err(e) => panic!("Failed to parse config file: {}", e), } @@ -58,22 +58,10 @@ mod bindings { }; static ref BUILD_CONFIG: Table = { // Load build-specific config overrides. - // FIXME: We should merge with CONFIG above instead of - // forcing callers to do it. let path = PathBuf::from(env::var_os("MOZ_TOPOBJDIR").unwrap()) .join("layout/style/bindgen.toml"); read_config(&path) }; - static ref TARGET_INFO: HashMap<String, String> = { - const TARGET_PREFIX: &'static str = "CARGO_CFG_TARGET_"; - let mut result = HashMap::new(); - for (k, v) in env::vars() { - if k.starts_with(TARGET_PREFIX) { - result.insert(k[TARGET_PREFIX.len()..].to_lowercase(), v); - } - } - result - }; static ref INCLUDE_RE: Regex = Regex::new(r#"#include\s*"(.+?)""#).unwrap(); static ref DISTDIR_PATH: PathBuf = { let path = PathBuf::from(env::var_os("MOZ_DIST").unwrap()); @@ -145,35 +133,6 @@ mod bindings { fn mutable_borrowed_type(self, ty: &str) -> Builder; } - fn add_clang_args(mut builder: Builder, config: &Table, matched_os: &mut bool) -> Builder { - fn add_args(mut builder: Builder, values: &[toml::Value]) -> Builder { - for item in values.iter() { - builder = builder.clang_arg(item.as_str().expect("Expect string in list")); - } - builder - } - for (k, v) in config.iter() { - if k == "args" { - builder = add_args(builder, v.as_array().unwrap().as_slice()); - continue; - } - let equal_idx = k.find('=').expect(&format!("Invalid key: {}", k)); - let (target_type, target_value) = k.split_at(equal_idx); - if TARGET_INFO[target_type] != target_value[1..] { - continue; - } - if target_type == "os" { - *matched_os = true; - } - builder = match *v { - toml::Value::Table(ref table) => add_clang_args(builder, table, matched_os), - toml::Value::Array(ref array) => add_args(builder, array), - _ => panic!("Unknown type"), - }; - } - builder - } - impl BuilderExt for Builder { fn get_initial_builder() -> Builder { use bindgen::RustTarget; @@ -207,16 +166,14 @@ mod bindings { builder = builder.clang_arg("-DDEBUG=1").clang_arg("-DJS_DEBUG=1"); } - let mut matched_os = false; - let build_config = CONFIG["build"].as_table().expect("Malformed config file"); - builder = add_clang_args(builder, build_config, &mut matched_os); let build_config = BUILD_CONFIG["build"] .as_table() .expect("Malformed config file"); - builder = add_clang_args(builder, build_config, &mut matched_os); - if !matched_os { - panic!("Unknown platform"); + let extra_bindgen_flags = build_config["args"].as_array().unwrap().as_slice(); + for item in extra_bindgen_flags.iter() { + builder = builder.clang_arg(item.as_str().expect("Expect string in list")); } + builder } fn include<T: Into<String>>(self, file: T) -> Builder { @@ -300,35 +257,57 @@ mod bindings { .expect("Unable to write output"); } - fn get_arc_types() -> Vec<String> { + fn get_types(filename: &str, macro_pat: &str) -> Vec<(String, String)> { // Read the file - let mut list_file = File::open(DISTDIR_PATH.join("include/mozilla/ServoArcTypeList.h")) - .expect("Unable to open ServoArcTypeList.h"); + let path = DISTDIR_PATH.join("include/mozilla/").join(filename); + let mut list_file = File::open(path).expect(&format!("Unable to open {}", filename)); let mut content = String::new(); list_file .read_to_string(&mut content) - .expect("Fail to read ServoArcTypeList.h"); + .expect(&format!("Failed to read {}", filename)); // Remove comments let block_comment_re = Regex::new(r#"(?s)/\*.*?\*/"#).unwrap(); + let line_comment_re = Regex::new(r#"//.*"#).unwrap(); let content = block_comment_re.replace_all(&content, ""); + let content = line_comment_re.replace_all(&content, ""); // Extract the list - let re = Regex::new(r#"^SERVO_ARC_TYPE\(\w+,\s*(\w+)\)$"#).unwrap(); + let re_string = format!(r#"^({})\(.+,\s*(\w+)\)$"#, macro_pat); + let re = Regex::new(&re_string).unwrap(); content .lines() .map(|line| line.trim()) .filter(|line| !line.is_empty()) .map(|line| { - re.captures(&line) - .expect(&format!( - "Unrecognized line in ServoArcTypeList.h: '{}'", - line - )).get(1) - .unwrap() - .as_str() - .to_string() + let captures = re + .captures(&line) + .expect(&format!("Unrecognized line in {}: '{}'", filename, line)); + let macro_name = captures.get(1).unwrap().as_str().to_string(); + let type_name = captures.get(2).unwrap().as_str().to_string(); + (macro_name, type_name) }).collect() } + fn get_borrowed_types() -> Vec<(bool, String)> { + get_types("BorrowedTypeList.h", "GECKO_BORROWED_TYPE(?:_MUT)?") + .into_iter() + .map(|(macro_name, type_name)| (macro_name.ends_with("MUT"), type_name)) + .collect() + } + + fn get_arc_types() -> Vec<String> { + get_types("ServoArcTypeList.h", "SERVO_ARC_TYPE") + .into_iter() + .map(|(_, type_name)| type_name) + .collect() + } + + fn get_boxed_types() -> Vec<String> { + get_types("ServoBoxedTypeList.h", "SERVO_BOXED_TYPE") + .into_iter() + .map(|(_, type_name)| type_name) + .collect() + } + struct BuilderWithConfig<'a> { builder: Builder, config: &'a Table, @@ -524,19 +503,6 @@ mod bindings { "&'a mut ::gecko_bindings::structs::nsTArray<{}>;"), cpp_type, rust_type)) }) - .handle_table_items("servo-owned-types", |mut builder, item| { - let name = item["name"].as_str().unwrap(); - builder = builder.blacklist_type(format!("{}Owned", name)) - .raw_line(format!("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;", name)) - .blacklist_type(format!("{}OwnedOrNull", name)) - .raw_line(format!(concat!("pub type {0}OwnedOrNull = ", - "::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;"), name)) - .mutable_borrowed_type(name); - if item["opaque"].as_bool().unwrap() { - builder = builder.zero_size_type(name, &structs_types); - } - builder - }) .handle_str_items("servo-immutable-borrow-types", |b, ty| b.borrowed_type(ty)) // Right now the only immutable borrow types are ones which we import // from the |structs| module. As such, we don't need to create an opaque @@ -544,6 +510,13 @@ mod bindings { // which _do_ need to be opaque, we'll need a separate mode. .handle_str_items("servo-borrow-types", |b, ty| b.mutable_borrowed_type(ty)) .get_builder(); + for (is_mut, ty) in get_borrowed_types().iter() { + if *is_mut { + builder = builder.mutable_borrowed_type(ty); + } else { + builder = builder.borrowed_type(ty); + } + } for ty in get_arc_types().iter() { builder = builder .blacklist_type(format!("{}Strong", ty)) @@ -553,6 +526,22 @@ mod bindings { )).borrowed_type(ty) .zero_size_type(ty, &structs_types); } + for ty in get_boxed_types().iter() { + builder = builder + .blacklist_type(format!("{}Owned", ty)) + .raw_line(format!( + "pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;", + ty + )).blacklist_type(format!("{}OwnedOrNull", ty)) + .raw_line(format!( + concat!( + "pub type {0}OwnedOrNull = ", + "::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;" + ), + ty + )).mutable_borrowed_type(ty) + .zero_size_type(ty, &structs_types); + } write_binding_file(builder, BINDINGS_FILE, &fixups); } diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index 7351cbfeac4..0a9bf4d5ccc 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -8,6 +8,7 @@ #![allow(non_snake_case, missing_docs)] +use gecko::url::CssUrlData; use gecko_bindings::bindings::RawServoCounterStyleRule; use gecko_bindings::bindings::RawServoFontFeatureValuesRule; use gecko_bindings::bindings::RawServoImportRule; @@ -22,6 +23,7 @@ use gecko_bindings::bindings::RawServoRuleNodeStrong; use gecko_bindings::bindings::RawServoSupportsRule; use gecko_bindings::bindings::ServoCssRules; use gecko_bindings::structs::RawServoAnimationValue; +use gecko_bindings::structs::RawServoCssUrlData; use gecko_bindings::structs::RawServoDeclarationBlock; use gecko_bindings::structs::RawServoFontFaceRule; use gecko_bindings::structs::RawServoMediaList; @@ -110,6 +112,9 @@ impl_arc_ffi!(Locked<FontFaceRule> => RawServoFontFaceRule impl_arc_ffi!(Locked<CounterStyleRule> => RawServoCounterStyleRule [Servo_CounterStyleRule_AddRef, Servo_CounterStyleRule_Release]); +impl_arc_ffi!(CssUrlData => RawServoCssUrlData + [Servo_CssUrlData_AddRef, Servo_CssUrlData_Release]); + // RuleNode is a Arc-like type but it does not use Arc. impl StrongRuleNode { diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 846f2113f77..10b177558fa 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -11,7 +11,7 @@ use app_units::Au; use gecko::values::GeckoStyleCoordConvertible; use gecko_bindings::bindings; -use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue}; +use gecko_bindings::structs::{self, nsStyleCoord_CalcValue}; use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage}; use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; use std::f32::consts::PI; @@ -128,35 +128,7 @@ impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto { impl From<Angle> for CoordDataValue { fn from(reference: Angle) -> Self { - match reference { - Angle::Deg(val) => CoordDataValue::Degree(val), - Angle::Grad(val) => CoordDataValue::Grad(val), - Angle::Rad(val) => CoordDataValue::Radian(val), - Angle::Turn(val) => CoordDataValue::Turn(val), - } - } -} - -impl Angle { - /// Converts Angle struct into (value, unit) pair. - pub fn to_gecko_values(&self) -> (f32, nsCSSUnit) { - match *self { - Angle::Deg(val) => (val, nsCSSUnit::eCSSUnit_Degree), - Angle::Grad(val) => (val, nsCSSUnit::eCSSUnit_Grad), - Angle::Rad(val) => (val, nsCSSUnit::eCSSUnit_Radian), - Angle::Turn(val) => (val, nsCSSUnit::eCSSUnit_Turn), - } - } - - /// Converts gecko (value, unit) pair into Angle struct - pub fn from_gecko_values(value: f32, unit: nsCSSUnit) -> Angle { - match unit { - nsCSSUnit::eCSSUnit_Degree => Angle::Deg(value), - nsCSSUnit::eCSSUnit_Grad => Angle::Grad(value), - nsCSSUnit::eCSSUnit_Radian => Angle::Rad(value), - nsCSSUnit::eCSSUnit_Turn => Angle::Turn(value), - _ => panic!("Unexpected unit for angle"), - } + CoordDataValue::Degree(reference.degrees()) } } @@ -225,13 +197,13 @@ impl nsStyleImage { match image { GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient), GenericImage::Url(ref url) => unsafe { - bindings::Gecko_SetLayerImageImageValue(self, url.0.image_value.get()); + bindings::Gecko_SetLayerImageImageValue(self, (url.0).0.url_value.get()); }, GenericImage::Rect(ref image_rect) => { unsafe { bindings::Gecko_SetLayerImageImageValue( self, - image_rect.url.0.image_value.get(), + (image_rect.url.0).0.url_value.get(), ); bindings::Gecko_InitializeImageCropRect(self); diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index d737167c28a..2ede2f5b81f 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -8,7 +8,7 @@ use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use context::QuirksMode; use dom::TElement; use gecko_bindings::bindings::{self, RawServoStyleSet}; -use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, StyleSheet as DomStyleSheet}; +use gecko_bindings::structs::{RawGeckoPresContextBorrowed, ServoStyleSetSizes, StyleSheet as DomStyleSheet}; use gecko_bindings::structs::{StyleSheetInfo, nsIDocument}; use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI}; use invalidation::media_queries::{MediaListKey, ToMediaListKey}; @@ -143,7 +143,7 @@ pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>); impl PerDocumentStyleData { /// Create a dummy `PerDocumentStyleData`. - pub fn new(pres_context: RawGeckoPresContextOwned) -> Self { + pub fn new(pres_context: RawGeckoPresContextBorrowed) -> Self { let device = Device::new(pres_context); // FIXME(emilio, tlin): How is this supposed to work with XBL? This is diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 65855b0a8a3..d95c8df7028 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -12,7 +12,7 @@ use euclid::TypedScale; use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; use gecko_bindings::bindings; use gecko_bindings::structs; -use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextOwned}; +use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextBorrowed}; use media_queries::MediaType; use properties::ComputedValues; use servo_arc::Arc; @@ -30,7 +30,7 @@ pub struct Device { /// NB: The pres context lifetime is tied to the styleset, who owns the /// stylist, and thus the `Device`, so having a raw pres context pointer /// here is fine. - pres_context: RawGeckoPresContextOwned, + pres_context: RawGeckoPresContextBorrowed, default_values: Arc<ComputedValues>, /// The font size of the root element /// This is set when computing the style of the root @@ -77,7 +77,7 @@ unsafe impl Send for Device {} impl Device { /// Trivially constructs a new `Device`. - pub fn new(pres_context: RawGeckoPresContextOwned) -> Self { + pub fn new(pres_context: RawGeckoPresContextBorrowed) -> Self { assert!(!pres_context.is_null()); Device { pres_context, diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs index 70b0e112cee..23fea10189f 100644 --- a/components/style/gecko/pseudo_element.rs +++ b/components/style/gecko/pseudo_element.rs @@ -57,15 +57,6 @@ impl PseudoElement { PseudoElementCascadeType::Lazy } - /// Whether cascading this pseudo-element makes it inherit all properties, - /// even reset ones. - /// - /// This is used in Servo for anonymous boxes, though it's likely broken. - #[inline] - pub fn inherits_all(&self) -> bool { - false - } - /// Whether the pseudo-element should inherit from the default computed /// values instead of from the parent element. /// diff --git a/components/style/gecko/regen_atoms.py b/components/style/gecko/regen_atoms.py index 097e2d6be37..36ec0f70434 100755 --- a/components/style/gecko/regen_atoms.py +++ b/components/style/gecko/regen_atoms.py @@ -35,10 +35,11 @@ class Atom: self.original_ident = ident self.value = value self.hash = hash - # The Gecko type: "nsStaticAtom", "nsICSSPseudoElement", or "nsIAnonBoxPseudo" + # The Gecko type: "nsStaticAtom", "nsCSSPseudoElementStaticAtom", or + # "nsAnonBoxPseudoStaticAtom". self.ty = ty # The type of atom: "Atom", "PseudoElement", "NonInheritingAnonBox", - # or "InheritingAnonBox" + # or "InheritingAnonBox". self.atom_type = atom_type if self.is_pseudo() or self.is_anon_box(): self.pseudo_ident = (ident.split("_", 1))[1] @@ -205,7 +206,7 @@ def write_atom_macro(atoms, file_name): def write_pseudo_elements(atoms, target_filename): pseudos = [] for atom in atoms: - if atom.type() == "nsICSSPseudoElement" or atom.type() == "nsICSSAnonBoxPseudo": + if atom.type() == "nsCSSPseudoElementStaticAtom" or atom.type() == "nsCSSAnonBoxPseudoStaticAtom": pseudos.append(atom) pseudo_definition_template = os.path.join(GECKO_DIR, "pseudo_element_definition.mako.rs") diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index 8390196c523..64ea654ba0c 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -6,18 +6,16 @@ use cssparser::Parser; use gecko_bindings::bindings; -use gecko_bindings::structs::ServoBundledURI; -use gecko_bindings::structs::mozilla::css::URLValueData; -use gecko_bindings::structs::root::{RustString, nsStyleImageRequest}; use gecko_bindings::structs::root::mozilla::CORSMode; -use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue}; +use gecko_bindings::structs::root::mozilla::css::URLValue; +use gecko_bindings::structs::root::nsStyleImageRequest; +use gecko_bindings::sugar::ownership::{HasArcFFI, FFIArcHelpers}; use gecko_bindings::sugar::refptr::RefPtr; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use nsstring::nsCString; use parser::{Parse, ParserContext}; -use servo_arc::{Arc, RawOffsetArc}; +use servo_arc::Arc; use std::fmt::{self, Write}; -use std::mem; use style_traits::{CssWriter, ParseError, ToCss}; use stylesheets::UrlExtraData; use values::computed::{Context, ToComputedValue}; @@ -25,12 +23,13 @@ use values::computed::{Context, ToComputedValue}; /// A CSS url() value for gecko. #[css(function = "url")] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)] -pub struct CssUrl { +pub struct CssUrl(pub Arc<CssUrlData>); + +/// Data shared between CssUrls. +#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)] +pub struct CssUrlData { /// The URL in unresolved string form. - /// - /// Refcounted since cloning this should be cheap and data: uris can be - /// really large. - serialization: Arc<String>, + serialization: String, /// The URL extra data. #[css(skip)] @@ -38,13 +37,12 @@ pub struct CssUrl { } impl CssUrl { - /// Try to parse a URL from a string value that is a valid CSS token for a - /// URL. + /// Parse a URL from a string value that is a valid CSS token for a URL. pub fn parse_from_string(url: String, context: &ParserContext) -> Self { - CssUrl { - serialization: Arc::new(url), + CssUrl(Arc::new(CssUrlData { + serialization: url, extra_data: context.url_data.clone(), - } + })) } /// Returns true if the URL is definitely invalid. We don't eagerly resolve @@ -54,43 +52,32 @@ impl CssUrl { false } - /// Convert from URLValueData to SpecifiedUrl. - unsafe fn from_url_value_data(url: &URLValueData) -> Self { - let arc_type = &url.mString as *const _ as *const RawOffsetArc<String>; - CssUrl { - serialization: Arc::from_raw_offset((*arc_type).clone()), - extra_data: UrlExtraData(url.mExtraData.to_safe()), - } - } - /// Returns true if this URL looks like a fragment. /// See https://drafts.csswg.org/css-values/#local-urls + #[inline] pub fn is_fragment(&self) -> bool { - self.as_str().chars().next().map_or(false, |c| c == '#') + self.0.is_fragment() } /// Return the unresolved url as string, or the empty string if it's /// invalid. + #[inline] pub fn as_str(&self) -> &str { - &*self.serialization + self.0.as_str() } +} - /// Little helper for Gecko's ffi. - pub fn as_slice_components(&self) -> (*const u8, usize) { - ( - self.serialization.as_str().as_ptr(), - self.serialization.as_str().len(), - ) +impl CssUrlData { + /// Returns true if this URL looks like a fragment. + /// See https://drafts.csswg.org/css-values/#local-urls + pub fn is_fragment(&self) -> bool { + self.as_str().chars().next().map_or(false, |c| c == '#') } - /// Create a bundled URI suitable for sending to Gecko - /// to be constructed into a css::URLValue - pub fn for_ffi(&self) -> ServoBundledURI { - let arc_offset = Arc::into_raw_offset(self.serialization.clone()); - ServoBundledURI { - mURLString: unsafe { mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset) }, - mExtraData: self.extra_data.0.get(), - } + /// Return the unresolved url as string, or the empty string if it's + /// invalid. + pub fn as_str(&self) -> &str { + &*self.serialization } } @@ -117,7 +104,7 @@ impl MallocSizeOf for CssUrl { } } -/// A specified url() value for general usage. +/// A specified non-image `url()` value. #[derive(Clone, Debug, SpecifiedValueInfo, ToCss)] pub struct SpecifiedUrl { /// The specified url value. @@ -129,72 +116,22 @@ pub struct SpecifiedUrl { } impl SpecifiedUrl { - fn from_css_url(url: CssUrl) -> Self { - let url_value = unsafe { - let ptr = bindings::Gecko_NewURLValue(url.for_ffi()); - // We do not expect Gecko_NewURLValue returns null. - debug_assert!(!ptr.is_null()); - RefPtr::from_addrefed(ptr) - }; - Self { url, url_value } - } -} - -impl PartialEq for SpecifiedUrl { - fn eq(&self, other: &Self) -> bool { - self.url.eq(&other.url) - } -} - -impl Eq for SpecifiedUrl {} - -impl Parse for SpecifiedUrl { - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result<Self, ParseError<'i>> { - CssUrl::parse(context, input).map(Self::from_css_url) - } -} - -impl MallocSizeOf for SpecifiedUrl { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - let mut n = self.url.size_of(ops); - // Although this is a RefPtr, this is the primary reference because - // SpecifiedUrl is responsible for creating the url_value. So we - // measure unconditionally here. - n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value.get()) }; - n - } -} - -/// A specified url() value for image. -/// -/// This exists so that we can construct `ImageValue` and reuse it. -#[derive(Clone, Debug, SpecifiedValueInfo, ToCss)] -pub struct SpecifiedImageUrl { - /// The specified url value. - pub url: CssUrl, - /// Gecko's ImageValue so that we can reuse it while rematching a - /// property with this specified value. - #[css(skip)] - pub image_value: RefPtr<ImageValue>, -} - -impl SpecifiedImageUrl { - /// Parse a URL from a string value. See SpecifiedUrl::parse_from_string. + /// Parse a URL from a string value. pub fn parse_from_string(url: String, context: &ParserContext) -> Self { Self::from_css_url(CssUrl::parse_from_string(url, context)) } fn from_css_url_with_cors(url: CssUrl, cors: CORSMode) -> Self { - let image_value = unsafe { - let ptr = bindings::Gecko_ImageValue_Create(url.for_ffi(), cors); - // We do not expect Gecko_ImageValue_Create returns null. + let url_value = unsafe { + let ptr = bindings::Gecko_URLValue_Create( + url.0.clone().into_strong(), + cors, + ); + // We do not expect Gecko_URLValue_Create returns null. debug_assert!(!ptr.is_null()); RefPtr::from_addrefed(ptr) }; - Self { url, image_value } + Self { url, url_value } } fn from_css_url(url: CssUrl) -> Self { @@ -206,18 +143,9 @@ impl SpecifiedImageUrl { use gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS; Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS) } - - /// Provides an alternate method for parsing that associates the URL - /// with anonymous CORS headers. - pub fn parse_with_cors_anonymous<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result<Self, ParseError<'i>> { - CssUrl::parse(context, input).map(Self::from_css_url_with_cors_anonymous) - } } -impl Parse for SpecifiedImageUrl { +impl Parse for SpecifiedUrl { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, @@ -226,21 +154,21 @@ impl Parse for SpecifiedImageUrl { } } -impl PartialEq for SpecifiedImageUrl { +impl PartialEq for SpecifiedUrl { fn eq(&self, other: &Self) -> bool { self.url.eq(&other.url) } } -impl Eq for SpecifiedImageUrl {} +impl Eq for SpecifiedUrl {} -impl MallocSizeOf for SpecifiedImageUrl { +impl MallocSizeOf for SpecifiedUrl { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { let mut n = self.url.size_of(ops); // Although this is a RefPtr, this is the primary reference because - // SpecifiedUrl is responsible for creating the image_value. So we + // SpecifiedUrl is responsible for creating the url_value. So we // measure unconditionally here. - n += unsafe { bindings::Gecko_ImageValue_SizeOfIncludingThis(self.image_value.get()) }; + n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value.get()) }; n } } @@ -259,6 +187,37 @@ impl ToComputedValue for SpecifiedUrl { } } +/// A specified image `url()` value. +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] +pub struct SpecifiedImageUrl(pub SpecifiedUrl); + +impl SpecifiedImageUrl { + /// Parse a URL from a string value that is a valid CSS token for a URL. + pub fn parse_from_string(url: String, context: &ParserContext) -> Self { + SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context)) + } + + /// Provides an alternate method for parsing that associates the URL + /// with anonymous CORS headers. + pub fn parse_with_cors_anonymous<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + CssUrl::parse(context, input) + .map(SpecifiedUrl::from_css_url_with_cors_anonymous) + .map(SpecifiedImageUrl) + } +} + +impl Parse for SpecifiedImageUrl { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + SpecifiedUrl::parse(context, input).map(SpecifiedImageUrl) + } +} + impl ToComputedValue for SpecifiedImageUrl { type ComputedValue = ComputedImageUrl; @@ -274,9 +233,9 @@ impl ToComputedValue for SpecifiedImageUrl { } fn serialize_computed_url<W>( - url_value_data: &URLValueData, + url_value: &URLValue, dest: &mut CssWriter<W>, - get_url: unsafe extern "C" fn(*const URLValueData, *mut nsCString), + get_url: unsafe extern "C" fn(*const URLValue, *mut nsCString), ) -> fmt::Result where W: Write, @@ -284,13 +243,13 @@ where dest.write_str("url(")?; unsafe { let mut string = nsCString::new(); - get_url(url_value_data, &mut string); + get_url(url_value, &mut string); string.as_str_unchecked().to_css(dest)?; } dest.write_char(')') } -/// The computed value of a CSS `url()`. +/// The computed value of a CSS non-image `url()`. /// /// The only difference between specified and computed URLs is the /// serialization. @@ -303,7 +262,7 @@ impl ToCss for ComputedUrl { W: Write, { serialize_computed_url( - &self.0.url_value._base, + &self.0.url_value, dest, bindings::Gecko_GetComputedURLSpec, ) @@ -313,12 +272,18 @@ impl ToCss for ComputedUrl { impl ComputedUrl { /// Convert from RefPtr<URLValue> to ComputedUrl. pub unsafe fn from_url_value(url_value: RefPtr<URLValue>) -> Self { - let url = CssUrl::from_url_value_data(&url_value._base); + let css_url = &*url_value.mCssUrl.mRawPtr; + let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc()); ComputedUrl(SpecifiedUrl { url, url_value }) } + + /// Get a raw pointer to the URLValue held by this ComputedUrl, for FFI. + pub fn url_value_ptr(&self) -> *mut URLValue { + self.0.url_value.get() + } } -/// The computed value of a CSS `url()` for image. +/// The computed value of a CSS image `url()`. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] pub struct ComputedImageUrl(pub SpecifiedImageUrl); @@ -328,7 +293,7 @@ impl ToCss for ComputedImageUrl { W: Write, { serialize_computed_url( - &self.0.image_value._base, + &(self.0).0.url_value, dest, bindings::Gecko_GetComputedImageURLSpec, ) @@ -338,8 +303,14 @@ impl ToCss for ComputedImageUrl { impl ComputedImageUrl { /// Convert from nsStyleImageReques to ComputedImageUrl. pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self { - let image_value = image_request.mImageValue.to_safe(); - let url = CssUrl::from_url_value_data(&image_value._base); - ComputedImageUrl(SpecifiedImageUrl { url, image_value }) + let url_value = image_request.mImageValue.to_safe(); + let css_url = &*url_value.mCssUrl.mRawPtr; + let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc()); + ComputedImageUrl(SpecifiedImageUrl(SpecifiedUrl { url, url_value })) + } + + /// Get a raw pointer to the URLValue held by this ComputedImageUrl, for FFI. + pub fn url_value_ptr(&self) -> *mut URLValue { + (self.0).0.url_value.get() } } diff --git a/components/style/gecko/values.rs b/components/style/gecko/values.rs index fed9dc161c0..4b982404809 100644 --- a/components/style/gecko/values.rs +++ b/components/style/gecko/values.rs @@ -19,7 +19,7 @@ use std::cmp::max; use values::{Auto, Either, None_, Normal}; use values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage, LengthOrPercentageOrAuto}; use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage}; -use values::computed::{MaxLength, MozLength, Percentage}; +use values::computed::{MaxLength as ComputedMaxLength, MozLength as ComputedMozLength, Percentage}; use values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber}; use values::computed::FlexBasis as ComputedFlexBasis; use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius; @@ -29,6 +29,7 @@ use values::generics::box_::Perspective; use values::generics::flex::FlexBasis; use values::generics::gecko::ScrollSnapPoint; use values::generics::grid::{TrackBreadth, TrackKeyword}; +use values::generics::length::{MaxLength, MozLength}; /// A trait that defines an interface to convert from and to `nsStyleCoord`s. pub trait GeckoStyleCoordConvertible: Sized { @@ -74,7 +75,7 @@ impl GeckoStyleCoordConvertible for ComputedFlexBasis { } fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> { - if let Some(width) = MozLength::from_gecko_style_coord(coord) { + if let Some(width) = ComputedMozLength::from_gecko_style_coord(coord) { return Some(FlexBasis::Width(width)); } @@ -325,10 +326,7 @@ impl GeckoStyleCoordConvertible for Angle { fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> { match coord.as_value() { - CoordDataValue::Degree(val) => Some(Angle::Deg(val)), - CoordDataValue::Grad(val) => Some(Angle::Grad(val)), - CoordDataValue::Radian(val) => Some(Angle::Rad(val)), - CoordDataValue::Turn(val) => Some(Angle::Turn(val)), + CoordDataValue::Degree(val) => Some(Angle::from_degrees(val)), _ => None, } } @@ -409,7 +407,7 @@ impl GeckoStyleCoordConvertible for ExtremumLength { } } -impl GeckoStyleCoordConvertible for MozLength { +impl GeckoStyleCoordConvertible for ComputedMozLength { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { match *self { MozLength::LengthOrPercentageOrAuto(ref lopoa) => lopoa.to_gecko_style_coord(coord), @@ -426,7 +424,7 @@ impl GeckoStyleCoordConvertible for MozLength { } } -impl GeckoStyleCoordConvertible for MaxLength { +impl GeckoStyleCoordConvertible for ComputedMaxLength { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { match *self { MaxLength::LengthOrPercentageOrNone(ref lopon) => lopon.to_gecko_style_coord(coord), diff --git a/components/style/gecko_bindings/sugar/ns_css_value.rs b/components/style/gecko_bindings/sugar/ns_css_value.rs index ed8892028fe..f41150712b3 100644 --- a/components/style/gecko_bindings/sugar/ns_css_value.rs +++ b/components/style/gecko_bindings/sugar/ns_css_value.rs @@ -60,7 +60,7 @@ impl nsCSSValue { pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array { debug_assert!( nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 && - self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Divided as u32 + self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Plus as u32 ); let array = *self.mValue.mArray.as_ref(); debug_assert!(!array.is_null()); @@ -198,19 +198,19 @@ impl nsCSSValue { /// Returns an `Angle` value from this `nsCSSValue`. /// - /// Panics if the unit is not `eCSSUnit_Degree` `eCSSUnit_Grad`, `eCSSUnit_Turn` - /// or `eCSSUnit_Radian`. + /// Panics if the unit is not `eCSSUnit_Degree`. + #[inline] pub fn get_angle(&self) -> Angle { - Angle::from_gecko_values(self.float_unchecked(), self.mUnit) + debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Degree); + Angle::from_degrees(self.float_unchecked()) } /// Sets Angle value to this nsCSSValue. pub fn set_angle(&mut self, angle: Angle) { debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null); - let (value, unit) = angle.to_gecko_values(); - self.mUnit = unit; + self.mUnit = nsCSSUnit::eCSSUnit_Degree; unsafe { - *self.mValue.mFloat.as_mut() = value; + *self.mValue.mFloat.as_mut() = angle.degrees(); } } diff --git a/components/style/gecko_bindings/sugar/ns_style_coord.rs b/components/style/gecko_bindings/sugar/ns_style_coord.rs index bc3b195524d..a4220f8c53c 100644 --- a/components/style/gecko_bindings/sugar/ns_style_coord.rs +++ b/components/style/gecko_bindings/sugar/ns_style_coord.rs @@ -200,12 +200,6 @@ pub enum CoordDataValue { Factor(f32), /// eStyleUnit_Degree Degree(f32), - /// eStyleUnit_Grad - Grad(f32), - /// eStyleUnit_Radian - Radian(f32), - /// eStyleUnit_Turn - Turn(f32), /// eStyleUnit_FlexFraction FlexFraction(f32), /// eStyleUnit_Coord @@ -317,18 +311,6 @@ pub unsafe trait CoordDataMut: CoordData { *unit = eStyleUnit_Degree; *union.mFloat.as_mut() = f; }, - Grad(f) => { - *unit = eStyleUnit_Grad; - *union.mFloat.as_mut() = f; - }, - Radian(f) => { - *unit = eStyleUnit_Radian; - *union.mFloat.as_mut() = f; - }, - Turn(f) => { - *unit = eStyleUnit_Turn; - *union.mFloat.as_mut() = f; - }, FlexFraction(f) => { *unit = eStyleUnit_FlexFraction; *union.mFloat.as_mut() = f; @@ -393,9 +375,6 @@ pub unsafe trait CoordData { eStyleUnit_Percent => Percent(self.get_float()), eStyleUnit_Factor => Factor(self.get_float()), eStyleUnit_Degree => Degree(self.get_float()), - eStyleUnit_Grad => Grad(self.get_float()), - eStyleUnit_Radian => Radian(self.get_float()), - eStyleUnit_Turn => Turn(self.get_float()), eStyleUnit_FlexFraction => FlexFraction(self.get_float()), eStyleUnit_Coord => Coord(self.get_integer()), eStyleUnit_Integer => Integer(self.get_integer()), @@ -413,9 +392,6 @@ pub unsafe trait CoordData { self.unit() == eStyleUnit_Percent || self.unit() == eStyleUnit_Factor || self.unit() == eStyleUnit_Degree || - self.unit() == eStyleUnit_Grad || - self.unit() == eStyleUnit_Radian || - self.unit() == eStyleUnit_Turn || self.unit() == eStyleUnit_FlexFraction ); *self.union().mFloat.as_ref() diff --git a/components/style/gecko_bindings/sugar/ns_t_array.rs b/components/style/gecko_bindings/sugar/ns_t_array.rs index bf5e168b5ef..72a7481fe96 100644 --- a/components/style/gecko_bindings/sugar/ns_t_array.rs +++ b/components/style/gecko_bindings/sugar/ns_t_array.rs @@ -82,9 +82,9 @@ impl<T> nsTArray<T> { /// Resize and set the length of the array to `len`. /// - /// unsafe because the array may contain uninitialized members. + /// unsafe because this may leave the array with uninitialized elements. /// - /// This will not call constructors, if you need that, either manually add + /// This will not call constructors. If you need that, either manually add /// bindings or run the typed `EnsureCapacity` call on the gecko side. pub unsafe fn set_len(&mut self, len: u32) { // this can leak @@ -96,6 +96,8 @@ impl<T> nsTArray<T> { /// Resizes an array containing only POD elements /// + /// unsafe because this may leave the array with uninitialized elements. + /// /// This will not leak since it only works on POD types (and thus doesn't assert) pub unsafe fn set_len_pod(&mut self, len: u32) where @@ -105,4 +107,17 @@ impl<T> nsTArray<T> { let header = self.header_mut(); header.mLength = len; } + + /// Collects the given iterator into this array. + /// + /// Not unsafe because we won't leave uninitialized elements in the array. + pub fn assign_from_iter_pod<I>(&mut self, iter: I) + where + T: Copy, + I: ExactSizeIterator + Iterator<Item = T>, + { + debug_assert!(iter.len() <= 0xFFFFFFFF); + unsafe { self.set_len_pod(iter.len() as u32); } + self.iter_mut().zip(iter).for_each(|(r, v)| *r = v); + } } diff --git a/components/style/gecko_bindings/sugar/refptr.rs b/components/style/gecko_bindings/sugar/refptr.rs index 835e77098c9..d7e7141e602 100644 --- a/components/style/gecko_bindings/sugar/refptr.rs +++ b/components/style/gecko_bindings/sugar/refptr.rs @@ -298,11 +298,6 @@ impl_threadsafe_refcount!( bindings::Gecko_ReleaseGridTemplateAreasValueArbitraryThread ); impl_threadsafe_refcount!( - structs::ImageValue, - bindings::Gecko_AddRefImageValueArbitraryThread, - bindings::Gecko_ReleaseImageValueArbitraryThread -); -impl_threadsafe_refcount!( structs::SharedFontList, bindings::Gecko_AddRefSharedFontListArbitraryThread, bindings::Gecko_ReleaseSharedFontListArbitraryThread diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 8b6298b01d2..04e65b5fa7f 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -689,7 +689,10 @@ def set_gecko_property(ffi_name, expr): } SVGPaintKind::PaintServer(url) => { unsafe { - bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.0.url_value.get()); + bindings::Gecko_nsStyleSVGPaint_SetURLValue( + paint, + url.url_value_ptr(), + ) } } SVGPaintKind::Color(color) => { @@ -1370,35 +1373,22 @@ impl Clone for ${style_struct.gecko_struct_name} { } </%def> -<%def name="impl_font_settings(ident, tag_type, value_type, gecko_value_type)"> +<%def name="impl_font_settings(ident, gecko_type, tag_type, value_type, gecko_value_type)"> <% gecko_ffi_name = to_camel_case_lower(ident) %> pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - let current_settings = &mut self.gecko.mFont.${gecko_ffi_name}; - current_settings.clear_pod(); - - unsafe { current_settings.set_len_pod(v.0.len() as u32) }; - - for (current, other) in current_settings.iter_mut().zip(v.0.iter()) { - current.mTag = other.tag.0; - current.mValue = other.value as ${gecko_value_type}; - } + let iter = v.0.iter().map(|other| structs::${gecko_type} { + mTag: other.tag.0, + mValue: other.value as ${gecko_value_type}, + }); + self.gecko.mFont.${gecko_ffi_name}.assign_from_iter_pod(iter); } pub fn copy_${ident}_from(&mut self, other: &Self) { - let current_settings = &mut self.gecko.mFont.${gecko_ffi_name}; - let other_settings = &other.gecko.mFont.${gecko_ffi_name}; - let settings_length = other_settings.len() as u32; - - current_settings.clear_pod(); - unsafe { current_settings.set_len_pod(settings_length) }; - - for (current, other) in current_settings.iter_mut().zip(other_settings.iter()) { - current.mTag = other.mTag; - current.mValue = other.mValue; - } + let iter = other.gecko.mFont.${gecko_ffi_name}.iter().map(|s| *s); + self.gecko.mFont.${gecko_ffi_name}.assign_from_iter_pod(iter); } pub fn reset_${ident}(&mut self, other: &Self) { @@ -2271,8 +2261,8 @@ fn static_assert() { // Negative numbers are invalid at parse time, but <integer> is still an // i32. - <% impl_font_settings("font_feature_settings", "FeatureTagValue", "i32", "u32") %> - <% impl_font_settings("font_variation_settings", "VariationValue", "f32", "f32") %> + <% impl_font_settings("font_feature_settings", "gfxFontFeature", "FeatureTagValue", "i32", "u32") %> + <% impl_font_settings("font_variation_settings", "gfxFontVariation", "VariationValue", "f32", "f32") %> pub fn fixup_none_generic(&mut self, device: &Device) { self.gecko.mFont.systemFont = false; @@ -3210,28 +3200,16 @@ fn static_assert() { where I: IntoIterator<Item = longhands::scroll_snap_coordinate::computed_value::single_value::T>, I::IntoIter: ExactSizeIterator { - let v = v.into_iter(); - - unsafe { self.gecko.mScrollSnapCoordinate.set_len_pod(v.len() as u32); } - for (gecko, servo) in self.gecko.mScrollSnapCoordinate - .iter_mut() - .zip(v) { - gecko.mXPosition = servo.horizontal.into(); - gecko.mYPosition = servo.vertical.into(); - } + let iter = v.into_iter().map(|c| structs::mozilla::Position { + mXPosition: c.horizontal.into(), + mYPosition: c.vertical.into(), + }); + self.gecko.mScrollSnapCoordinate.assign_from_iter_pod(iter); } pub fn copy_scroll_snap_coordinate_from(&mut self, other: &Self) { - unsafe { - self.gecko.mScrollSnapCoordinate - .set_len_pod(other.gecko.mScrollSnapCoordinate.len() as u32); - } - - for (this, that) in self.gecko.mScrollSnapCoordinate - .iter_mut() - .zip(other.gecko.mScrollSnapCoordinate.iter()) { - *this = *that; - } + let iter = other.gecko.mScrollSnapCoordinate.iter().map(|c| *c); + self.gecko.mScrollSnapCoordinate.assign_from_iter_pod(iter); } pub fn reset_scroll_snap_coordinate(&mut self, other: &Self) { @@ -4153,7 +4131,10 @@ fn static_assert() { } UrlOrNone::Url(ref url) => { unsafe { - Gecko_SetListStyleImageImageValue(&mut self.gecko, url.0.image_value.get()); + Gecko_SetListStyleImageImageValue( + &mut self.gecko, + url.url_value_ptr(), + ); } } } @@ -4989,12 +4970,12 @@ fn set_style_svg_path( Gecko_NewStyleSVGPath(shape_source); &mut shape_source.__bindgen_anon_1.mSVGPath.as_mut().mPtr.as_mut().unwrap() }; - unsafe { gecko_path.mPath.set_len(servo_path.commands().len() as u32) }; - debug_assert_eq!(gecko_path.mPath.len(), servo_path.commands().len()); - for (servo, gecko) in servo_path.commands().iter().zip(gecko_path.mPath.iter_mut()) { + + let iter = servo_path.commands().iter().map(|command| { // unsafe: cbindgen ensures the representation is the same. - *gecko = unsafe { transmute(*servo) }; - } + unsafe { transmute(*command) } + }); + gecko_path.mPath.assign_from_iter_pod(iter); // Setup fill-rule. // unsafe: cbindgen ensures the representation is the same. @@ -5358,7 +5339,7 @@ clip-path unsafe { Gecko_SetCursorImageValue( &mut self.gecko.mCursorImages[i], - v.images[i].url.0.image_value.get(), + v.images[i].url.url_value_ptr(), ); } @@ -5659,7 +5640,7 @@ clip-path unsafe { bindings::Gecko_SetContentDataImageValue( &mut self.gecko.mContents[i], - url.0.image_value.get(), + url.url_value_ptr(), ) } } diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 98a74854b8d..5259f66107d 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -9,7 +9,7 @@ from itertools import groupby %> -#[cfg(feature = "gecko")] use gecko_bindings::bindings::RawServoAnimationValueMap; +#[cfg(feature = "gecko")] use gecko_bindings::structs::RawServoAnimationValueMap; #[cfg(feature = "gecko")] use gecko_bindings::structs::RawGeckoGfxMatrix4x4; #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID; #[cfg(feature = "gecko")] use gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI}; @@ -35,7 +35,7 @@ use values::animated::effects::Filter as AnimatedFilter; use values::computed::{Angle, CalcLengthOrPercentage}; use values::computed::{ClipRect, Context}; use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto}; -use values::computed::{LengthOrPercentageOrNone, MaxLength}; +use values::computed::LengthOrPercentageOrNone; use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage}; use values::computed::length::NonNegativeLengthOrPercentage; use values::computed::ToComputedValue; @@ -893,11 +893,6 @@ impl ToAnimatedZero for LengthOrPercentageOrNone { } } -impl ToAnimatedZero for MaxLength { - #[inline] - fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } -} - impl ToAnimatedZero for FontWeight { #[inline] fn to_animated_zero(&self) -> Result<Self, ()> { diff --git a/components/style/properties/longhands/border.mako.rs b/components/style/properties/longhands/border.mako.rs index 1066dbbc619..f4b9187b88a 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -111,7 +111,7 @@ ${helpers.predefined_type( vector=False, animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER", - boxed=True, + boxed=product == "servo", )} ${helpers.predefined_type( diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index de7b613a183..164f8a7dea1 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -23,7 +23,7 @@ ${helpers.predefined_type( ${helpers.single_keyword( "text-transform", "none capitalize uppercase lowercase", - extra_gecko_values="full-width", + extra_gecko_values="full-width full-size-kana", animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", spec="https://drafts.csswg.org/css-text/#propdef-text-transform", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 5968d84bd33..330ceea7f84 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1671,53 +1671,30 @@ impl PropertyId { /// /// Returns Err(()) for unknown non-custom properties. fn parse_unchecked(property_name: &str) -> Result<Self, ()> { - // FIXME(https://github.com/rust-lang/rust/issues/33156): remove this - // enum and use PropertyId when stable Rust allows destructors in - // statics. - // - // ShorthandAlias is not used in the Servo build. - // That's why we need to allow dead_code. - #[allow(dead_code)] - pub enum StaticId { - Longhand(LonghandId), - Shorthand(ShorthandId), - LonghandAlias(LonghandId, AliasId), - ShorthandAlias(ShorthandId, AliasId), - } ascii_case_insensitive_phf_map! { - static_id -> StaticId = { + property_id -> PropertyId = { % for (kind, properties) in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]: - % for property in properties: - "${property.name}" => StaticId::${kind}(${kind}Id::${property.camel_case}), - % for alias in property.alias: - "${alias.name}" => { - StaticId::${kind}Alias(${kind}Id::${property.camel_case}, - AliasId::${alias.camel_case}) - }, - % endfor - % endfor + % for property in properties: + "${property.name}" => PropertyId::${kind}(${kind}Id::${property.camel_case}), + % for alias in property.alias: + "${alias.name}" => { + PropertyId::${kind}Alias( + ${kind}Id::${property.camel_case}, + AliasId::${alias.camel_case}, + ) + }, + % endfor + % endfor % endfor } } - Ok(match static_id(property_name) { - Some(&StaticId::Longhand(id)) => { - PropertyId::Longhand(id) - }, - Some(&StaticId::Shorthand(id)) => { - PropertyId::Shorthand(id) - }, - Some(&StaticId::LonghandAlias(id, alias)) => { - PropertyId::LonghandAlias(id, alias) - }, - Some(&StaticId::ShorthandAlias(id, alias)) => { - PropertyId::ShorthandAlias(id, alias) - }, - None => { - let name = ::custom_properties::parse_name(property_name)?; - PropertyId::Custom(::custom_properties::Name::from(name)) - }, - }) + if let Some(id) = property_id(property_name) { + return Ok(id.clone()) + } + + let name = ::custom_properties::parse_name(property_name)?; + Ok(PropertyId::Custom(::custom_properties::Name::from(name))) } /// Parses a property name, and returns an error if it's unknown or isn't @@ -3137,7 +3114,8 @@ pub enum StyleStructRef<'a, T: 'static> { } impl<'a, T: 'a> StyleStructRef<'a, T> - where T: Clone, +where + T: Clone, { /// Ensure a mutable reference of this value exists, either cloning the /// borrowed value, or returning the owned one. @@ -3153,6 +3131,22 @@ impl<'a, T: 'a> StyleStructRef<'a, T> } } + /// Whether this is pointer-equal to the struct we're going to copy the + /// value from. + /// + /// This is used to avoid allocations when people write stuff like `font: + /// inherit` or such `all: initial`. + #[inline] + pub fn ptr_eq(&self, struct_to_copy_from: &T) -> bool { + match *self { + StyleStructRef::Owned(..) => false, + StyleStructRef::Borrowed(arc) => { + &**arc as *const T == struct_to_copy_from as *const T + } + StyleStructRef::Vacated => panic!("Accessed vacated style struct") + } + } + /// Extract a unique Arc from this struct, vacating it. /// /// The vacated state is a transient one, please put the Arc back @@ -3281,15 +3275,6 @@ impl<'a> StyleBuilder<'a> { let reset_style = device.default_computed_values(); let inherited_style = parent_style.unwrap_or(reset_style); let inherited_style_ignoring_first_line = parent_style_ignoring_first_line.unwrap_or(reset_style); - // FIXME(bz): inherits_all seems like a fundamentally broken idea. I'm - // 99% sure it should give incorrect behavior for table anonymous box - // backgrounds, for example. This code doesn't attempt to make it play - // nice with inherited_style_ignoring_first_line. - let reset_style = if pseudo.map_or(false, |p| p.inherits_all()) { - inherited_style - } else { - reset_style - }; let flags = inherited_style.flags.inherited(); @@ -3388,6 +3373,10 @@ impl<'a> StyleBuilder<'a> { self.flags.insert(ComputedValueFlags::INHERITS_DISPLAY); % endif + if self.${property.style_struct.ident}.ptr_eq(inherited_struct) { + return; + } + self.${property.style_struct.ident}.mutate() .copy_${property.ident}_from( inherited_struct, @@ -3407,10 +3396,10 @@ impl<'a> StyleBuilder<'a> { self.modified_reset = true; % endif - // TODO(emilio): There's a maybe-worth it optimization here: We should - // avoid allocating a new reset struct if `reset_struct` and our struct - // is the same pointer. Would remove a bunch of stupid allocations if - // you did something like `* { all: initial }` or what not. + if self.${property.style_struct.ident}.ptr_eq(reset_struct) { + return; + } + self.${property.style_struct.ident}.mutate() .reset_${property.ident}( reset_struct, diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index 7b2c06019a4..de8257dcc4c 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -221,11 +221,6 @@ impl PseudoElement { } } - /// To be removed. - pub fn inherits_all(&self) -> bool { - false - } - /// Covert non-canonical pseudo-element to canonical one, and keep a /// canonical one as it is. pub fn canonical(&self) -> PseudoElement { diff --git a/components/style/servo/url.rs b/components/style/servo/url.rs index 91521c8a120..56213e4978e 100644 --- a/components/style/servo/url.rs +++ b/components/style/servo/url.rs @@ -23,6 +23,9 @@ use values::computed::{Context, ToComputedValue}; /// /// However, this approach is still not necessarily optimal: See /// <https://bugzilla.mozilla.org/show_bug.cgi?id=1347435#c6> +/// +/// TODO(emilio): This should be shrunk by making CssUrl a wrapper type of an +/// arc, and keep the serialization in that Arc. See gecko/url.rs for example. #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, SpecifiedValueInfo)] pub struct CssUrl { /// The original URI. This might be optional since we may insert computed diff --git a/components/style/stylesheets/font_feature_values_rule.rs b/components/style/stylesheets/font_feature_values_rule.rs index 76170151c67..f1353744f08 100644 --- a/components/style/stylesheets/font_feature_values_rule.rs +++ b/components/style/stylesheets/font_feature_values_rule.rs @@ -179,12 +179,7 @@ impl Parse for VectorValues { #[cfg(feature = "gecko")] impl ToGeckoFontFeatureValues for VectorValues { fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>) { - unsafe { - array.set_len_pod(self.0.len() as u32); - } - for (dest, value) in array.iter_mut().zip(self.0.iter()) { - *dest = *value; - } + array.assign_from_iter_pod(self.0.iter().map(|v| *v)); } } diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index 5058ad94e80..81726950665 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -277,7 +277,6 @@ impl CssRule { // nested rules are in the body state let mut rule_parser = TopLevelRuleParser { - stylesheet_origin: parent_stylesheet_contents.origin, context, shared_lock: &shared_lock, loader, diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index 683378b9b96..aa449c70e93 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -19,7 +19,7 @@ use servo_arc::Arc; use shared_lock::{Locked, SharedRwLock}; use str::starts_with_ignore_ascii_case; use style_traits::{ParseError, StyleParseErrorKind}; -use stylesheets::{CssRule, CssRuleType, CssRules, Origin, RulesMutateError, StylesheetLoader}; +use stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader}; use stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule}; use stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule}; use stylesheets::document_rule::DocumentCondition; @@ -41,8 +41,6 @@ pub struct InsertRuleContext<'a> { /// The parser for the top-level rules in a stylesheet. pub struct TopLevelRuleParser<'a> { - /// The origin of the stylesheet we're parsing. - pub stylesheet_origin: Origin, /// A reference to the lock we need to use to create rules. pub shared_lock: &'a SharedRwLock, /// A reference to a stylesheet loader if applicable, for `@import` rules. @@ -69,7 +67,6 @@ pub struct TopLevelRuleParser<'a> { impl<'b> TopLevelRuleParser<'b> { fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> { NestedRuleParser { - stylesheet_origin: self.stylesheet_origin, shared_lock: self.shared_lock, context: &self.context, namespaces: &self.namespaces, @@ -325,7 +322,6 @@ impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a> { #[derive(Clone)] // shallow, relatively cheap .clone struct NestedRuleParser<'a, 'b: 'a> { - stylesheet_origin: Origin, shared_lock: &'a SharedRwLock, context: &'a ParserContext<'b>, namespaces: &'a Namespaces, @@ -340,7 +336,6 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> { let context = ParserContext::new_with_rule_type(self.context, rule_type, self.namespaces); let nested_parser = NestedRuleParser { - stylesheet_origin: self.stylesheet_origin, shared_lock: self.shared_lock, context: &context, namespaces: self.namespaces, @@ -501,7 +496,7 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> { self.namespaces, ); - let enabled = condition.eval(&eval_context); + let enabled = condition.eval(&eval_context, self.namespaces); Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap( SupportsRule { condition, @@ -577,7 +572,7 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> { input: &mut Parser<'i, 't>, ) -> Result<Self::Prelude, ParseError<'i>> { let selector_parser = SelectorParser { - stylesheet_origin: self.stylesheet_origin, + stylesheet_origin: self.context.stylesheet_origin, namespaces: self.namespaces, url_data: Some(self.context.url_data), }; diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs index e1359cb3722..ac1d810a05b 100644 --- a/components/style/stylesheets/stylesheet.rs +++ b/components/style/stylesheets/stylesheet.rs @@ -374,7 +374,6 @@ impl Stylesheet { ); let rule_parser = TopLevelRuleParser { - stylesheet_origin: origin, shared_lock, loader: stylesheet_loader, context, diff --git a/components/style/stylesheets/supports_rule.rs b/components/style/stylesheets/supports_rule.rs index 2851d8914dd..06a7807e41d 100644 --- a/components/style/stylesheets/supports_rule.rs +++ b/components/style/stylesheets/supports_rule.rs @@ -11,7 +11,8 @@ use cssparser::parse_important; use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; use parser::ParserContext; use properties::{PropertyDeclaration, PropertyId, SourcePropertyDeclaration}; -use selectors::parser::SelectorParseErrorKind; +use selector_parser::{SelectorImpl, SelectorParser}; +use selectors::parser::{Selector, SelectorParseErrorKind}; use servo_arc::Arc; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked}; use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; @@ -19,8 +20,8 @@ use std::ffi::{CStr, CString}; use std::fmt::{self, Write}; use std::str; use str::CssStringWriter; -use style_traits::{CssWriter, ParseError, ToCss}; -use stylesheets::{CssRuleType, CssRules}; +use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use stylesheets::{CssRuleType, CssRules, Namespaces}; /// An [`@supports`][supports] rule. /// @@ -87,6 +88,8 @@ pub enum SupportsCondition { Or(Vec<SupportsCondition>), /// `property-ident: value` (value can be any tokens) Declaration(Declaration), + /// A `selector()` function. + Selector(RawSelector), /// `-moz-bool-pref("pref-name")` /// Since we need to pass it through FFI to get the pref value, /// we store it as CString directly. @@ -99,8 +102,8 @@ impl SupportsCondition { /// Parse a condition /// /// <https://drafts.csswg.org/css-conditional/#supports_condition> - pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> { - if let Ok(_) = input.try(|i| i.expect_ident_matching("not")) { + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> { + if input.try(|i| i.expect_ident_matching("not")).is_ok() { let inner = SupportsCondition::parse_in_parens(input)?; return Ok(SupportsCondition::Not(Box::new(inner))); } @@ -109,10 +112,8 @@ impl SupportsCondition { let location = input.current_source_location(); let (keyword, wrapper) = match input.next() { - Err(_) => { - // End of input - return Ok(in_parens); - }, + // End of input + Err(..) => return Ok(in_parens), Ok(&Token::Ident(ref ident)) => { match_ignore_ascii_case! { &ident, "and" => ("and", SupportsCondition::And as fn(_) -> _), @@ -132,17 +133,48 @@ impl SupportsCondition { .is_err() { // Did not find the expected keyword. - // If we found some other token, - // it will be rejected by `Parser::parse_entirely` somewhere up the stack. + // If we found some other token, it will be rejected by + // `Parser::parse_entirely` somewhere up the stack. return Ok(wrapper(conditions)); } } } + /// Parses a functional supports condition. + fn parse_functional<'i, 't>( + function: &str, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + match_ignore_ascii_case!{ function, + // Although this is an internal syntax, it is not necessary + // to check parsing context as far as we accept any + // unexpected token as future syntax, and evaluate it to + // false when not in chrome / ua sheet. + // See https://drafts.csswg.org/css-conditional-3/#general_enclosed + "-moz-bool-pref" => { + let name = { + let name = input.expect_string()?; + CString::new(name.as_bytes()) + }.map_err(|_| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?; + Ok(SupportsCondition::MozBoolPref(name)) + } + "selector" => { + let pos = input.position(); + consume_any_value(input)?; + Ok(SupportsCondition::Selector(RawSelector( + input.slice_from(pos).to_owned() + ))) + } + _ => { + Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + } + } + /// <https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens> fn parse_in_parens<'i, 't>( input: &mut Parser<'i, 't>, - ) -> Result<SupportsCondition, ParseError<'i>> { + ) -> Result<Self, ParseError<'i>> { // Whitespace is normally taken care of in `Parser::next`, // but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases. while input.try(Parser::expect_whitespace).is_ok() {} @@ -151,46 +183,45 @@ impl SupportsCondition { // FIXME: remove clone() when lifetimes are non-lexical match input.next()?.clone() { Token::ParenthesisBlock => { - let nested = input - .try(|input| input.parse_nested_block(|i| parse_condition_or_declaration(i))); + let nested = input.try(|input| { + input.parse_nested_block(parse_condition_or_declaration) + }); if nested.is_ok() { return nested; } }, Token::Function(ident) => { - // Although this is an internal syntax, it is not necessary to check - // parsing context as far as we accept any unexpected token as future - // syntax, and evaluate it to false when not in chrome / ua sheet. - // See https://drafts.csswg.org/css-conditional-3/#general_enclosed - if ident.eq_ignore_ascii_case("-moz-bool-pref") { - if let Ok(name) = input.try(|i| { - i.parse_nested_block(|i| { - i.expect_string() - .map(|s| s.to_string()) - .map_err(CssParseError::<()>::from) - }).and_then(|s| CString::new(s).map_err(|_| location.new_custom_error(()))) - }) { - return Ok(SupportsCondition::MozBoolPref(name)); - } + let nested = input.try(|input| { + input.parse_nested_block(|input| { + SupportsCondition::parse_functional(&ident, input) + }) + }); + if nested.is_ok() { + return nested; } }, t => return Err(location.new_unexpected_token_error(t)), } - input.parse_nested_block(|i| consume_any_value(i))?; + input.parse_nested_block(consume_any_value)?; Ok(SupportsCondition::FutureSyntax( input.slice_from(pos).to_owned(), )) } /// Evaluate a supports condition - pub fn eval(&self, cx: &ParserContext) -> bool { + pub fn eval( + &self, + cx: &ParserContext, + namespaces: &Namespaces, + ) -> bool { match *self { - SupportsCondition::Not(ref cond) => !cond.eval(cx), - SupportsCondition::Parenthesized(ref cond) => cond.eval(cx), - SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx)), - SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx)), + SupportsCondition::Not(ref cond) => !cond.eval(cx, namespaces), + SupportsCondition::Parenthesized(ref cond) => cond.eval(cx, namespaces), + SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx, namespaces)), + SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx, namespaces)), SupportsCondition::Declaration(ref decl) => decl.eval(cx), SupportsCondition::MozBoolPref(ref name) => eval_moz_bool_pref(name, cx), + SupportsCondition::Selector(ref selector) => selector.eval(cx, namespaces), SupportsCondition::FutureSyntax(_) => false, } } @@ -265,6 +296,11 @@ impl ToCss for SupportsCondition { decl.to_css(dest)?; dest.write_str(")") }, + SupportsCondition::Selector(ref selector) => { + dest.write_str("selector(")?; + selector.to_css(dest)?; + dest.write_str(")") + } SupportsCondition::MozBoolPref(ref name) => { dest.write_str("-moz-bool-pref(")?; let name = @@ -278,6 +314,69 @@ impl ToCss for SupportsCondition { } #[derive(Clone, Debug)] +/// A possibly-invalid CSS selector. +pub struct RawSelector(pub String); + +impl ToCss for RawSelector { + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: Write, + { + dest.write_str(&self.0) + } +} + +impl RawSelector { + /// Tries to evaluate a `selector()` function. + pub fn eval( + &self, + context: &ParserContext, + namespaces: &Namespaces, + ) -> bool { + #[cfg(feature = "gecko")] + { + if unsafe { !::gecko_bindings::structs::StaticPrefs_sVarCache_layout_css_supports_selector_enabled } { + return false; + } + } + + let mut input = ParserInput::new(&self.0); + let mut input = Parser::new(&mut input); + input.parse_entirely(|input| -> Result<(), CssParseError<()>> { + let parser = SelectorParser { + namespaces, + stylesheet_origin: context.stylesheet_origin, + url_data: Some(context.url_data), + }; + + #[allow(unused_variables)] + let selector = Selector::<SelectorImpl>::parse(&parser, input) + .map_err(|_| input.new_custom_error(()))?; + + #[cfg(feature = "gecko")] + { + use selector_parser::PseudoElement; + use selectors::parser::Component; + + let has_any_unknown_webkit_pseudo = + selector.has_pseudo_element() && + selector.iter_raw_match_order().any(|component| { + matches!( + *component, + Component::PseudoElement(PseudoElement::UnknownWebkit(..)) + ) + }); + if has_any_unknown_webkit_pseudo { + return Err(input.new_custom_error(())); + } + } + + Ok(()) + }).is_ok() + } +} + +#[derive(Clone, Debug)] /// A possibly-invalid property declaration pub struct Declaration(pub String); @@ -313,21 +412,20 @@ impl Declaration { let mut input = ParserInput::new(&self.0); let mut input = Parser::new(&mut input); - input - .parse_entirely(|input| -> Result<(), CssParseError<()>> { - let prop = input.expect_ident_cloned().unwrap(); - input.expect_colon().unwrap(); - - let id = - PropertyId::parse(&prop, context).map_err(|_| input.new_custom_error(()))?; - - let mut declarations = SourcePropertyDeclaration::new(); - input.parse_until_before(Delimiter::Bang, |input| { - PropertyDeclaration::parse_into(&mut declarations, id, &context, input) - .map_err(|_| input.new_custom_error(())) - })?; - let _ = input.try(parse_important); - Ok(()) - }).is_ok() + input.parse_entirely(|input| -> Result<(), CssParseError<()>> { + let prop = input.expect_ident_cloned().unwrap(); + input.expect_colon().unwrap(); + + let id = + PropertyId::parse(&prop, context).map_err(|_| input.new_custom_error(()))?; + + let mut declarations = SourcePropertyDeclaration::new(); + input.parse_until_before(Delimiter::Bang, |input| { + PropertyDeclaration::parse_into(&mut declarations, id, &context, input) + .map_err(|_| input.new_custom_error(())) + })?; + let _ = input.try(parse_important); + Ok(()) + }).is_ok() } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index df7a55c6f18..fe96fd78ad8 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -614,14 +614,6 @@ impl Stylist { /// Computes the style for a given "precomputed" pseudo-element, taking the /// universal rules and applying them. - /// - /// If `inherit_all` is true, then all properties are inherited from the - /// parent; otherwise, non-inherited properties are reset to their initial - /// values. The flow constructor uses this flag when constructing anonymous - /// flows. - /// - /// TODO(emilio): The type parameter could go away with a void type - /// implementing TElement. pub fn precomputed_values_for_pseudo<E>( &self, guards: &StylesheetGuards, @@ -2423,6 +2415,9 @@ impl CascadeData { if let Some(ref mut slotted_rules) = self.slotted_rules { slotted_rules.clear(); } + if let Some(ref mut host_rules) = self.host_rules { + host_rules.clear(); + } self.animations.clear(); self.extra_data.clear(); self.rules_source_order = 0; @@ -2448,6 +2443,9 @@ impl CascadeData { if let Some(ref slotted_rules) = self.slotted_rules { slotted_rules.add_size_of(ops, sizes); } + if let Some(ref host_rules) = self.host_rules { + host_rules.add_size_of(ops, sizes); + } sizes.mInvalidationMap += self.invalidation_map.size_of(ops); sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops); sizes.mOther += self.animations.size_of(ops); diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index b70ef7d6639..8944f3fc5f4 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -292,8 +292,9 @@ impl ToAnimatedValue for ComputedMaxLength { #[inline] fn from_animated_value(animated: Self::AnimatedValue) -> Self { use values::computed::{Length, LengthOrPercentageOrNone, Percentage}; + use values::generics::length::MaxLength as GenericMaxLength; match animated { - ComputedMaxLength::LengthOrPercentageOrNone(lopn) => { + GenericMaxLength::LengthOrPercentageOrNone(lopn) => { let result = match lopn { LengthOrPercentageOrNone::Length(px) => { LengthOrPercentageOrNone::Length(Length::new(px.px().max(0.))) @@ -303,7 +304,7 @@ impl ToAnimatedValue for ComputedMaxLength { }, _ => lopn, }; - ComputedMaxLength::LengthOrPercentageOrNone(result) + GenericMaxLength::LengthOrPercentageOrNone(result) }, _ => animated, } @@ -321,8 +322,9 @@ impl ToAnimatedValue for ComputedMozLength { #[inline] fn from_animated_value(animated: Self::AnimatedValue) -> Self { use values::computed::{Length, LengthOrPercentageOrAuto, Percentage}; + use values::generics::length::MozLength as GenericMozLength; match animated { - ComputedMozLength::LengthOrPercentageOrAuto(lopa) => { + GenericMozLength::LengthOrPercentageOrAuto(lopa) => { let result = match lopa { LengthOrPercentageOrAuto::Length(px) => { LengthOrPercentageOrAuto::Length(Length::new(px.px().max(0.))) @@ -332,7 +334,7 @@ impl ToAnimatedValue for ComputedMozLength { }, _ => lopa, }; - ComputedMozLength::LengthOrPercentageOrAuto(result) + GenericMozLength::LengthOrPercentageOrAuto(result) }, _ => animated, } diff --git a/components/style/values/computed/angle.rs b/components/style/values/computed/angle.rs index e162b7a2499..1c66498f7bd 100644 --- a/components/style/values/computed/angle.rs +++ b/components/style/values/computed/angle.rs @@ -7,36 +7,39 @@ use num_traits::Zero; use std::{f32, f64}; use std::f64::consts::PI; +use std::fmt::{self, Write}; use std::ops::Add; +use style_traits::{CssWriter, ToCss}; use values::CSSFloat; -use values::animated::{Animate, Procedure}; use values::distance::{ComputeSquaredDistance, SquaredDistance}; -/// A computed angle. -#[animate(fallback = "Self::animate_fallback")] +/// A computed angle in degrees. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive( - Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero, ToCss, -)] -pub enum Angle { - /// An angle with degree unit. - #[css(dimension)] - Deg(CSSFloat), - /// An angle with gradian unit. - #[css(dimension)] - Grad(CSSFloat), - /// An angle with radian unit. - #[css(dimension)] - Rad(CSSFloat), - /// An angle with turn unit. - #[css(dimension)] - Turn(CSSFloat), +#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero)] +pub struct Angle(CSSFloat); + +impl ToCss for Angle { + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: Write, + { + self.degrees().to_css(dest)?; + dest.write_str("deg") + } } +const RAD_PER_DEG: f64 = PI / 180.0; + impl Angle { /// Creates a computed `Angle` value from a radian amount. pub fn from_radians(radians: CSSFloat) -> Self { - Angle::Rad(radians) + Angle(radians / RAD_PER_DEG as f32) + } + + /// Creates a computed `Angle` value from a degrees amount. + #[inline] + pub fn from_degrees(degrees: CSSFloat) -> Self { + Angle(degrees) } /// Returns the amount of radians this angle represents. @@ -48,43 +51,18 @@ impl Angle { /// Returns the amount of radians this angle represents as a `f64`. /// /// Gecko stores angles as singles, but does this computation using doubles. - /// See nsCSSValue::GetAngleValueInRadians. + /// /// This is significant enough to mess up rounding to the nearest /// quarter-turn for 225 degrees, for example. #[inline] pub fn radians64(&self) -> f64 { - const RAD_PER_DEG: f64 = PI / 180.0; - const RAD_PER_GRAD: f64 = PI / 200.0; - const RAD_PER_TURN: f64 = PI * 2.0; - - let radians = match *self { - Angle::Deg(val) => val as f64 * RAD_PER_DEG, - Angle::Grad(val) => val as f64 * RAD_PER_GRAD, - Angle::Turn(val) => val as f64 * RAD_PER_TURN, - Angle::Rad(val) => val as f64, - }; - radians.min(f64::MAX).max(f64::MIN) + self.0 as f64 * RAD_PER_DEG } /// Return the value in degrees. - pub fn degrees(&self) -> f32 { - use std::f32::consts::PI; - self.radians() * 360. / (2. * PI) - } - - /// <https://drafts.csswg.org/css-transitions/#animtype-number> - #[inline] - fn animate_fallback(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { - Ok(Angle::from_radians( - self.radians().animate(&other.radians(), procedure)?, - )) - } -} - -impl AsRef<Angle> for Angle { #[inline] - fn as_ref(&self) -> &Self { - self + pub fn degrees(&self) -> CSSFloat { + self.0 } } @@ -93,27 +71,19 @@ impl Add for Angle { #[inline] fn add(self, rhs: Self) -> Self { - match (self, rhs) { - (Angle::Deg(x), Angle::Deg(y)) => Angle::Deg(x + y), - (Angle::Grad(x), Angle::Grad(y)) => Angle::Grad(x + y), - (Angle::Turn(x), Angle::Turn(y)) => Angle::Turn(x + y), - (Angle::Rad(x), Angle::Rad(y)) => Angle::Rad(x + y), - _ => Angle::from_radians(self.radians() + rhs.radians()), - } + Angle(self.0 + rhs.0) } } impl Zero for Angle { #[inline] fn zero() -> Self { - Angle::from_radians(0.0) + Angle(0.0) } #[inline] fn is_zero(&self) -> bool { - match *self { - Angle::Deg(val) | Angle::Grad(val) | Angle::Turn(val) | Angle::Rad(val) => val == 0., - } + self.0 == 0. } } @@ -122,7 +92,6 @@ impl ComputeSquaredDistance for Angle { fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { // Use the formula for calculating the distance between angles defined in SVG: // https://www.w3.org/TR/SVG/animate.html#complexDistances - self.radians64() - .compute_squared_distance(&other.radians64()) + self.radians64().compute_squared_distance(&other.radians64()) } } diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index 911193b0c0b..e83f4b3f6b8 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -866,7 +866,7 @@ impl ToAnimatedValue for FontStyleAngle { #[inline] fn from_animated_value(animated: Self::AnimatedValue) -> Self { - FontStyleAngle(Angle::Deg( + FontStyleAngle(Angle::from_degrees( animated .degrees() .min(specified::FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES) @@ -899,7 +899,7 @@ impl FontStyle { /// https://drafts.csswg.org/css-fonts-4/#valdef-font-style-oblique-angle #[inline] pub fn default_angle() -> FontStyleAngle { - FontStyleAngle(Angle::Deg( + FontStyleAngle(Angle::from_degrees( specified::DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES, )) } @@ -919,7 +919,7 @@ impl FontStyle { if italic { return generics::FontStyle::Italic; } - generics::FontStyle::Oblique(FontStyleAngle(Angle::Deg(angle))) + generics::FontStyle::Oblique(FontStyleAngle(Angle::from_degrees(angle))) } } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index d3bc0b5ebd0..d32ddcfafa0 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -5,9 +5,7 @@ //! `<length>` computed values, and related ones. use app_units::Au; -use logical_geometry::WritingMode; use ordered_float::NotNan; -use properties::LonghandId; use std::fmt::{self, Write}; use std::ops::{Add, Neg}; use style_traits::{CssWriter, ToCss}; @@ -17,6 +15,7 @@ use values::{specified, Auto, CSSFloat, Either, Normal}; use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::generics::NonNegative; +use values::generics::length::{MaxLength as GenericMaxLength, MozLength as GenericMozLength}; use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength}; use values::specified::length::ViewportPercentageLength; @@ -951,7 +950,8 @@ pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPerce /// block-size, and inline-size. #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum ExtremumLength { MozMaxContent, MozMinContent, @@ -959,161 +959,24 @@ pub enum ExtremumLength { MozAvailable, } -impl ExtremumLength { - /// Returns whether this size keyword can be used for the given writing-mode - /// and property. - /// - /// TODO: After these values are supported for both axes (and maybe - /// unprefixed, see bug 1322780) all this complexity can go away, and - /// everything can be derived (no need for uncacheable stuff). - fn valid_for(wm: WritingMode, longhand: LonghandId) -> bool { - // We only make sense on the inline axis. - match longhand { - // FIXME(emilio): The flex-basis thing is not quite clear... - LonghandId::FlexBasis | - LonghandId::MinWidth | - LonghandId::MaxWidth | - LonghandId::Width => !wm.is_vertical(), - - LonghandId::MinHeight | LonghandId::MaxHeight | LonghandId::Height => wm.is_vertical(), - - LonghandId::MinInlineSize | LonghandId::MaxInlineSize | LonghandId::InlineSize => true, - // The block-* properties are rejected at parse-time, so they're - // unexpected here. - _ => { - debug_assert!( - false, - "Unexpected property using ExtremumLength: {:?}", - longhand, - ); - false - }, - } - } -} - -/// A value suitable for a `min-width`, `min-height`, `width` or `height` -/// property. -/// -/// See values/specified/length.rs for more details. -#[allow(missing_docs)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToAnimatedZero, ToCss)] -pub enum MozLength { - LengthOrPercentageOrAuto(LengthOrPercentageOrAuto), - #[animation(error)] - ExtremumLength(ExtremumLength), -} +/// A computed value for `min-width`, `min-height`, `width` or `height` property. +pub type MozLength = GenericMozLength<LengthOrPercentageOrAuto>; impl MozLength { /// Returns the `auto` value. #[inline] pub fn auto() -> Self { - MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::Auto) - } -} - -impl ToComputedValue for specified::MozLength { - type ComputedValue = MozLength; - - #[inline] - fn to_computed_value(&self, context: &Context) -> MozLength { - debug_assert!( - context.for_non_inherited_property.is_some(), - "Someone added a MozLength to an inherited property? Evil!" - ); - match *self { - specified::MozLength::LengthOrPercentageOrAuto(ref lopoa) => { - MozLength::LengthOrPercentageOrAuto(lopoa.to_computed_value(context)) - }, - specified::MozLength::ExtremumLength(ext) => { - context - .rule_cache_conditions - .borrow_mut() - .set_writing_mode_dependency(context.builder.writing_mode); - if !ExtremumLength::valid_for( - context.builder.writing_mode, - context.for_non_inherited_property.unwrap(), - ) { - MozLength::auto() - } else { - MozLength::ExtremumLength(ext) - } - }, - } - } - - #[inline] - fn from_computed_value(computed: &MozLength) -> Self { - match *computed { - MozLength::LengthOrPercentageOrAuto(ref lopoa) => { - specified::MozLength::LengthOrPercentageOrAuto( - specified::LengthOrPercentageOrAuto::from_computed_value(lopoa), - ) - }, - MozLength::ExtremumLength(ext) => specified::MozLength::ExtremumLength(ext), - } + GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::Auto) } } -/// A value suitable for a `max-width` or `max-height` property. -/// See values/specified/length.rs for more details. -#[allow(missing_docs)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)] -pub enum MaxLength { - LengthOrPercentageOrNone(LengthOrPercentageOrNone), - #[animation(error)] - ExtremumLength(ExtremumLength), -} +/// A computed value for `max-width` or `min-height` property. +pub type MaxLength = GenericMaxLength<LengthOrPercentageOrNone>; impl MaxLength { /// Returns the `none` value. #[inline] pub fn none() -> Self { - MaxLength::LengthOrPercentageOrNone(LengthOrPercentageOrNone::None) - } -} - -impl ToComputedValue for specified::MaxLength { - type ComputedValue = MaxLength; - - #[inline] - fn to_computed_value(&self, context: &Context) -> MaxLength { - debug_assert!( - context.for_non_inherited_property.is_some(), - "Someone added a MaxLength to an inherited property? Evil!" - ); - match *self { - specified::MaxLength::LengthOrPercentageOrNone(ref lopon) => { - MaxLength::LengthOrPercentageOrNone(lopon.to_computed_value(context)) - }, - specified::MaxLength::ExtremumLength(ext) => { - context - .rule_cache_conditions - .borrow_mut() - .set_writing_mode_dependency(context.builder.writing_mode); - if !ExtremumLength::valid_for( - context.builder.writing_mode, - context.for_non_inherited_property.unwrap(), - ) { - MaxLength::none() - } else { - MaxLength::ExtremumLength(ext) - } - }, - } - } - - #[inline] - fn from_computed_value(computed: &MaxLength) -> Self { - match *computed { - MaxLength::LengthOrPercentageOrNone(ref lopon) => { - specified::MaxLength::LengthOrPercentageOrNone( - specified::LengthOrPercentageOrNone::from_computed_value(&lopon), - ) - }, - MaxLength::ExtremumLength(ref ext) => specified::MaxLength::ExtremumLength(ext.clone()), - } + GenericMaxLength::LengthOrPercentageOrNone(LengthOrPercentageOrNone::None) } } diff --git a/components/style/values/generics/length.rs b/components/style/values/generics/length.rs new file mode 100644 index 00000000000..99976be493e --- /dev/null +++ b/components/style/values/generics/length.rs @@ -0,0 +1,54 @@ +/* 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/. */ + +//! Generic types for CSS values related to length. + +use values::computed::ExtremumLength; + +/// A generic value for the `width`, `height`, `min-width`, or `min-height` property. +/// +/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`, +/// and cannot be `none`. +/// +/// Note that it only accepts non-negative values. +#[allow(missing_docs)] +#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + PartialEq, + SpecifiedValueInfo, + ToAnimatedZero, + ToComputedValue, + ToCss, +)] +pub enum MozLength<LengthOrPercentageOrAuto> { + LengthOrPercentageOrAuto(LengthOrPercentageOrAuto), + #[animation(error)] + ExtremumLength(ExtremumLength), +} + +/// A generic value for the `max-width` or `max-height` property. +#[allow(missing_docs)] +#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + PartialEq, + SpecifiedValueInfo, + ToAnimatedZero, + ToComputedValue, + ToCss +)] +pub enum MaxLength<LengthOrPercentageOrNone> { + LengthOrPercentageOrNone(LengthOrPercentageOrNone), + #[animation(error)] + ExtremumLength(ExtremumLength), +} diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 32ea771cf15..32e389512e4 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -27,6 +27,7 @@ pub mod font; pub mod gecko; pub mod grid; pub mod image; +pub mod length; pub mod position; pub mod rect; pub mod size; diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index cce0464d2ac..d398b40c3f1 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -10,6 +10,7 @@ use num_traits::Zero; use values::{computed, CSSFloat}; use values::computed::length::Length as ComputedLength; use values::computed::length::LengthOrPercentage as ComputedLengthOrPercentage; +use values::specified::angle::Angle as SpecifiedAngle; use values::specified::length::Length as SpecifiedLength; use values::specified::length::LengthOrPercentage as SpecifiedLengthOrPercentage; @@ -394,10 +395,30 @@ pub trait ToMatrix { fn to_3d_matrix(&self, reference_box: Option<&Rect<Au>>) -> Result<Transform3D<f64>, ()>; } +/// A little helper to deal with both specified and computed angles. +pub trait ToRadians { + /// Return the radians value as a 64-bit floating point value. + fn radians64(&self) -> f64; +} + +impl ToRadians for computed::angle::Angle { + #[inline] + fn radians64(&self) -> f64 { + computed::angle::Angle::radians64(self) + } +} + +impl ToRadians for SpecifiedAngle { + #[inline] + fn radians64(&self) -> f64 { + computed::angle::Angle::from_degrees(self.degrees()).radians64() + } +} + impl<Angle, Number, Length, Integer, LoP> ToMatrix for TransformOperation<Angle, Number, Length, Integer, LoP> where - Angle: Copy + AsRef<computed::angle::Angle>, + Angle: ToRadians + Copy, Number: Copy + Into<f32> + Into<f64>, Length: ToAbsoluteLength, LoP: ToAbsoluteLength, @@ -426,7 +447,7 @@ where let reference_height = reference_box.map(|v| v.size.height); let matrix = match *self { Rotate3D(ax, ay, az, theta) => { - let theta = TWO_PI - theta.as_ref().radians64(); + let theta = TWO_PI - theta.radians64(); let (ax, ay, az, theta) = get_normalized_vector_and_angle(ax.into(), ay.into(), az.into(), theta); Transform3D::create_rotation( @@ -437,15 +458,15 @@ where ) }, RotateX(theta) => { - let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64()); + let theta = euclid::Angle::radians(TWO_PI - theta.radians64()); Transform3D::create_rotation(1., 0., 0., theta) }, RotateY(theta) => { - let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64()); + let theta = euclid::Angle::radians(TWO_PI - theta.radians64()); Transform3D::create_rotation(0., 1., 0., theta) }, RotateZ(theta) | Rotate(theta) => { - let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64()); + let theta = euclid::Angle::radians(TWO_PI - theta.radians64()); Transform3D::create_rotation(0., 0., 1., theta) }, Perspective(ref d) => { @@ -479,16 +500,16 @@ where Transform3D::create_translation(0., 0., z.to_pixel_length(None)? as f64) }, Skew(theta_x, theta_y) => Transform3D::create_skew( - euclid::Angle::radians(theta_x.as_ref().radians64()), - euclid::Angle::radians(theta_y.map_or(0., |a| a.as_ref().radians64())), + euclid::Angle::radians(theta_x.radians64()), + euclid::Angle::radians(theta_y.map_or(0., |a| a.radians64())), ), SkewX(theta) => Transform3D::create_skew( - euclid::Angle::radians(theta.as_ref().radians64()), + euclid::Angle::radians(theta.radians64()), euclid::Angle::radians(0.), ), SkewY(theta) => Transform3D::create_skew( euclid::Angle::radians(0.), - euclid::Angle::radians(theta.as_ref().radians64()), + euclid::Angle::radians(theta.radians64()), ), Matrix3D(m) => m.into(), Matrix(m) => m.into(), diff --git a/components/style/values/specified/angle.rs b/components/style/values/specified/angle.rs index 040ea9d9a7c..b634756d89f 100644 --- a/components/style/values/specified/angle.rs +++ b/components/style/values/specified/angle.rs @@ -6,6 +6,7 @@ use cssparser::{Parser, Token}; use parser::{Parse, ParserContext}; +use std::f32::consts::PI; use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss}; use values::CSSFloat; @@ -13,15 +14,47 @@ use values::computed::{Context, ToComputedValue}; use values::computed::angle::Angle as ComputedAngle; use values::specified::calc::CalcNode; -/// A specified angle. -/// -/// Computed angles are essentially same as specified ones except for `calc()` -/// value serialization. Therefore we are storing a computed angle inside -/// to hold the actual value and its unit. +/// A specified angle dimension. +#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToCss)] +pub enum AngleDimension { + /// An angle with degree unit. + #[css(dimension)] + Deg(CSSFloat), + /// An angle with gradian unit. + #[css(dimension)] + Grad(CSSFloat), + /// An angle with radian unit. + #[css(dimension)] + Rad(CSSFloat), + /// An angle with turn unit. + #[css(dimension)] + Turn(CSSFloat), +} + +impl AngleDimension { + /// Returns the amount of degrees this angle represents. + #[inline] + fn degrees(&self) -> CSSFloat { + const DEG_PER_RAD: f32 = 180.0 / PI; + const DEG_PER_TURN: f32 = 360.0; + const DEG_PER_GRAD: f32 = 180.0 / 200.0; + + match *self { + AngleDimension::Deg(d) => d, + AngleDimension::Rad(rad) => rad * DEG_PER_RAD, + AngleDimension::Turn(turns) => turns * DEG_PER_TURN, + AngleDimension::Grad(gradians) => gradians * DEG_PER_GRAD, + } + } +} + +/// A specified Angle value, which is just the angle dimension, plus whether it +/// was specified as `calc()` or not. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)] pub struct Angle { - value: ComputedAngle, + value: AngleDimension, was_calc: bool, } @@ -41,22 +74,18 @@ impl ToCss for Angle { } } -// FIXME(emilio): Probably computed angles shouldn't preserve the unit and -// should serialize to degrees per: -// -// https://drafts.csswg.org/css-values/#compat impl ToComputedValue for Angle { type ComputedValue = ComputedAngle; #[inline] fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue { - self.value + ComputedAngle::from_degrees(self.degrees()) } #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { Angle { - value: *computed, + value: AngleDimension::Deg(computed.degrees()), was_calc: false, } } @@ -64,35 +93,18 @@ impl ToComputedValue for Angle { impl Angle { /// Creates an angle with the given value in degrees. + #[inline] pub fn from_degrees(value: CSSFloat, was_calc: bool) -> Self { Angle { - value: ComputedAngle::Deg(value), - was_calc, - } - } - - /// Creates an angle with the given value in gradians. - pub fn from_gradians(value: CSSFloat, was_calc: bool) -> Self { - Angle { - value: ComputedAngle::Grad(value), - was_calc, - } - } - - /// Creates an angle with the given value in turns. - pub fn from_turns(value: CSSFloat, was_calc: bool) -> Self { - Angle { - value: ComputedAngle::Turn(value), + value: AngleDimension::Deg(value), was_calc, } } - /// Creates an angle with the given value in radians. - pub fn from_radians(value: CSSFloat, was_calc: bool) -> Self { - Angle { - value: ComputedAngle::Rad(value), - was_calc, - } + /// Returns the value of the angle in degrees, mostly for `calc()`. + #[inline] + pub fn degrees(&self) -> CSSFloat { + self.value.degrees() } /// Whether this specified angle came from a `calc()` expression. @@ -101,39 +113,21 @@ impl Angle { self.was_calc } - /// Returns the amount of radians this angle represents. - #[inline] - pub fn radians(self) -> f32 { - self.value.radians() - } - - /// Returns the amount of degrees this angle represents. - #[inline] - pub fn degrees(self) -> f32 { - self.value.degrees() - } - /// Returns `0deg`. + #[inline] pub fn zero() -> Self { Self::from_degrees(0.0, false) } /// Returns an `Angle` parsed from a `calc()` expression. - pub fn from_calc(radians: CSSFloat) -> Self { + pub fn from_calc(degrees: CSSFloat) -> Self { Angle { - value: ComputedAngle::Rad(radians), + value: AngleDimension::Deg(degrees), was_calc: true, } } } -impl AsRef<ComputedAngle> for Angle { - #[inline] - fn as_ref(&self) -> &ComputedAngle { - &self.value - } -} - /// Whether to allow parsing an unitless zero as a valid angle. /// /// This should always be `No`, except for exceptions like: @@ -158,20 +152,26 @@ impl Parse for Angle { impl Angle { /// Parse an `<angle>` value given a value and an unit. - pub fn parse_dimension(value: CSSFloat, unit: &str, from_calc: bool) -> Result<Angle, ()> { - let angle = match_ignore_ascii_case! { unit, - "deg" => Angle::from_degrees(value, from_calc), - "grad" => Angle::from_gradians(value, from_calc), - "turn" => Angle::from_turns(value, from_calc), - "rad" => Angle::from_radians(value, from_calc), + pub fn parse_dimension( + value: CSSFloat, + unit: &str, + was_calc: bool, + ) -> Result<Angle, ()> { + let value = match_ignore_ascii_case! { unit, + "deg" => AngleDimension::Deg(value), + "grad" => AngleDimension::Grad(value), + "turn" => AngleDimension::Turn(value), + "rad" => AngleDimension::Rad(value), _ => return Err(()) }; - Ok(angle) + + Ok(Self { value, was_calc }) } /// Parse an `<angle>` allowing unitless zero to represent a zero angle. /// /// See the comment in `AllowUnitlessZeroAngle` for why. + #[inline] pub fn parse_with_unitless<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index e23ec4a745a..7e79fc892a5 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -966,20 +966,27 @@ pub enum Appearance { /// A typical dialog button. Button, /// Various arrows that go in buttons + #[parse(condition = "in_ua_or_chrome_sheet")] ButtonArrowDown, + #[parse(condition = "in_ua_or_chrome_sheet")] ButtonArrowNext, + #[parse(condition = "in_ua_or_chrome_sheet")] ButtonArrowPrevious, + #[parse(condition = "in_ua_or_chrome_sheet")] ButtonArrowUp, /// A rectangular button that contains complex content /// like images (e.g. HTML <button> elements) ButtonBevel, /// The focus outline box inside of a button. + #[parse(condition = "in_ua_or_chrome_sheet")] ButtonFocus, /// The caret of a text area Caret, /// A dual toolbar button (e.g., a Back button with a dropdown) + #[parse(condition = "in_ua_or_chrome_sheet")] Dualbutton, /// A groupbox. + #[parse(condition = "in_ua_or_chrome_sheet")] Groupbox, /// A inner-spin button. InnerSpinButton, @@ -988,12 +995,17 @@ pub enum Appearance { /// A listbox item. Listitem, /// Menu Bar background + #[parse(condition = "in_ua_or_chrome_sheet")] Menubar, /// <menu> and <menuitem> appearances + #[parse(condition = "in_ua_or_chrome_sheet")] Menuitem, + #[parse(condition = "in_ua_or_chrome_sheet")] Checkmenuitem, + #[parse(condition = "in_ua_or_chrome_sheet")] Radiomenuitem, /// For text on non-iconic menuitems only + #[parse(condition = "in_ua_or_chrome_sheet")] Menuitemtext, /// A dropdown list. Menulist, @@ -1004,13 +1016,19 @@ pub enum Appearance { /// An editable textfield with a dropdown list (a combobox). MenulistTextfield, /// Menu Popup background. + #[parse(condition = "in_ua_or_chrome_sheet")] Menupopup, /// menu checkbox/radio appearances + #[parse(condition = "in_ua_or_chrome_sheet")] Menucheckbox, + #[parse(condition = "in_ua_or_chrome_sheet")] Menuradio, + #[parse(condition = "in_ua_or_chrome_sheet")] Menuseparator, + #[parse(condition = "in_ua_or_chrome_sheet")] Menuarrow, /// An image in the menu gutter, like in bookmarks or history. + #[parse(condition = "in_ua_or_chrome_sheet")] Menuimage, /// A horizontal meter bar. Meterbar, @@ -1035,19 +1053,25 @@ pub enum Appearance { Radio, /// A generic container that always repaints on state changes. This is a /// hack to make XUL checkboxes and radio buttons work. + #[parse(condition = "in_ua_or_chrome_sheet")] CheckboxContainer, + #[parse(condition = "in_ua_or_chrome_sheet")] RadioContainer, /// The label part of a checkbox or radio button, used for painting a focus /// outline. + #[parse(condition = "in_ua_or_chrome_sheet")] CheckboxLabel, + #[parse(condition = "in_ua_or_chrome_sheet")] RadioLabel, /// nsRangeFrame and its subparts Range, RangeThumb, /// The resizer background area in a status bar for the resizer widget in /// the corner of a window. + #[parse(condition = "in_ua_or_chrome_sheet")] Resizerpanel, /// The resizer itself. + #[parse(condition = "in_ua_or_chrome_sheet")] Resizer, /// A slider. ScaleHorizontal, @@ -1061,18 +1085,26 @@ pub enum Appearance { /// The ticks for a slider. Scalethumbtick, /// A scrollbar. + #[parse(condition = "in_ua_or_chrome_sheet")] Scrollbar, /// A small scrollbar. + #[parse(condition = "in_ua_or_chrome_sheet")] ScrollbarSmall, /// The scrollbar slider + #[parse(condition = "in_ua_or_chrome_sheet")] ScrollbarHorizontal, + #[parse(condition = "in_ua_or_chrome_sheet")] ScrollbarVertical, /// A scrollbar button (up/down/left/right). /// Keep these in order (some code casts these values to `int` in order to /// compare them against each other). + #[parse(condition = "in_ua_or_chrome_sheet")] ScrollbarbuttonUp, + #[parse(condition = "in_ua_or_chrome_sheet")] ScrollbarbuttonDown, + #[parse(condition = "in_ua_or_chrome_sheet")] ScrollbarbuttonLeft, + #[parse(condition = "in_ua_or_chrome_sheet")] ScrollbarbuttonRight, /// The scrollbar thumb. ScrollbarthumbHorizontal, @@ -1081,107 +1113,166 @@ pub enum Appearance { ScrollbartrackHorizontal, ScrollbartrackVertical, /// The scroll corner + #[parse(condition = "in_ua_or_chrome_sheet")] Scrollcorner, /// A searchfield. Searchfield, /// A separator. Can be horizontal or vertical. + #[parse(condition = "in_ua_or_chrome_sheet")] Separator, /// A spin control (up/down control for time/date pickers). + #[parse(condition = "in_ua_or_chrome_sheet")] Spinner, /// The up button of a spin control. + #[parse(condition = "in_ua_or_chrome_sheet")] SpinnerUpbutton, /// The down button of a spin control. + #[parse(condition = "in_ua_or_chrome_sheet")] SpinnerDownbutton, /// The textfield of a spin control + #[parse(condition = "in_ua_or_chrome_sheet")] SpinnerTextfield, /// A splitter. Can be horizontal or vertical. + #[parse(condition = "in_ua_or_chrome_sheet")] Splitter, /// A status bar in a main application window. + #[parse(condition = "in_ua_or_chrome_sheet")] Statusbar, /// A single pane of a status bar. + #[parse(condition = "in_ua_or_chrome_sheet")] Statusbarpanel, /// A single tab in a tab widget. + #[parse(condition = "in_ua_or_chrome_sheet")] Tab, /// A single pane (inside the tabpanels container). + #[parse(condition = "in_ua_or_chrome_sheet")] Tabpanel, /// The tab panels container. + #[parse(condition = "in_ua_or_chrome_sheet")] Tabpanels, /// The tabs scroll arrows (left/right). + #[parse(condition = "in_ua_or_chrome_sheet")] TabScrollArrowBack, + #[parse(condition = "in_ua_or_chrome_sheet")] TabScrollArrowForward, /// A textfield or text area. Textfield, /// A multiline text field. TextfieldMultiline, /// A toolbar in an application window. + #[parse(condition = "in_ua_or_chrome_sheet")] Toolbar, /// A single toolbar button (with no associated dropdown). + #[parse(condition = "in_ua_or_chrome_sheet")] Toolbarbutton, /// The dropdown portion of a toolbar button + #[parse(condition = "in_ua_or_chrome_sheet")] ToolbarbuttonDropdown, /// The gripper for a toolbar. + #[parse(condition = "in_ua_or_chrome_sheet")] Toolbargripper, /// The toolbox that contains the toolbars. + #[parse(condition = "in_ua_or_chrome_sheet")] Toolbox, /// A tooltip. + #[parse(condition = "in_ua_or_chrome_sheet")] Tooltip, /// A listbox or tree widget header + #[parse(condition = "in_ua_or_chrome_sheet")] Treeheader, /// An individual header cell + #[parse(condition = "in_ua_or_chrome_sheet")] Treeheadercell, /// The sort arrow for a header. + #[parse(condition = "in_ua_or_chrome_sheet")] Treeheadersortarrow, /// A tree item. + #[parse(condition = "in_ua_or_chrome_sheet")] Treeitem, /// A tree widget branch line + #[parse(condition = "in_ua_or_chrome_sheet")] Treeline, /// A tree widget twisty. + #[parse(condition = "in_ua_or_chrome_sheet")] Treetwisty, /// Open tree widget twisty. + #[parse(condition = "in_ua_or_chrome_sheet")] Treetwistyopen, /// A tree widget. + #[parse(condition = "in_ua_or_chrome_sheet")] Treeview, /// Window and dialog backgrounds. + #[parse(condition = "in_ua_or_chrome_sheet")] Window, + #[parse(condition = "in_ua_or_chrome_sheet")] Dialog, /// Vista Rebars. + #[parse(condition = "in_ua_or_chrome_sheet")] MozWinCommunicationsToolbox, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWinMediaToolbox, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWinBrowsertabbarToolbox, /// Vista glass. + #[parse(condition = "in_ua_or_chrome_sheet")] MozWinGlass, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWinBorderlessGlass, /// -moz-apperance style used in setting proper glass margins. + #[parse(condition = "in_ua_or_chrome_sheet")] MozWinExcludeGlass, /// Titlebar elements on the Mac. + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacFullscreenButton, /// Mac help button. + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacHelpButton, /// Windows themed window frame elements. + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowButtonBox, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowButtonBoxMaximized, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowButtonClose, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowButtonMaximize, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowButtonMinimize, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowButtonRestore, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowFrameBottom, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowFrameLeft, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowFrameRight, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowTitlebar, + #[parse(condition = "in_ua_or_chrome_sheet")] MozWindowTitlebarMaximized, + #[parse(condition = "in_ua_or_chrome_sheet")] MozGtkInfoBar, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacActiveSourceListSelection, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacDisclosureButtonClosed, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacDisclosureButtonOpen, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacSourceList, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacSourceListSelection, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacVibrancyDark, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacVibrancyLight, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacVibrantTitlebarDark, + #[parse(condition = "in_ua_or_chrome_sheet")] MozMacVibrantTitlebarLight, /// A non-disappearing scrollbar. diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index 69631069990..3a28d42223c 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -469,22 +469,22 @@ impl CalcNode { CalcNode::Sub(ref a, ref b) => { let lhs = a.to_angle()?; let rhs = b.to_angle()?; - Angle::from_calc(lhs.radians() - rhs.radians()) + Angle::from_calc(lhs.degrees() - rhs.degrees()) }, CalcNode::Sum(ref a, ref b) => { let lhs = a.to_angle()?; let rhs = b.to_angle()?; - Angle::from_calc(lhs.radians() + rhs.radians()) + Angle::from_calc(lhs.degrees() + rhs.degrees()) }, CalcNode::Mul(ref a, ref b) => match a.to_angle() { Ok(lhs) => { let rhs = b.to_number()?; - Angle::from_calc(lhs.radians() * rhs) + Angle::from_calc(lhs.degrees() * rhs) }, Err(..) => { let lhs = a.to_number()?; let rhs = b.to_angle()?; - Angle::from_calc(lhs * rhs.radians()) + Angle::from_calc(lhs * rhs.degrees()) }, }, CalcNode::Div(ref a, ref b) => { @@ -493,7 +493,7 @@ impl CalcNode { if rhs == 0. { return Err(()); } - Angle::from_calc(lhs.radians() / rhs) + Angle::from_calc(lhs.degrees() / rhs) }, CalcNode::Number(..) | CalcNode::Length(..) | diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index cdfe3228c8b..b7bc40b116e 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -301,7 +301,7 @@ impl SpecifiedFontStyle { } fn compute_angle(angle: &Angle) -> ComputedAngle { - ComputedAngle::Deg(Self::compute_angle_degrees(angle)) + ComputedAngle::from_degrees(Self::compute_angle_degrees(angle)) } /// Parse a suitable angle for font-style: oblique. diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index 0a3a402e9ec..73cec6da7b1 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -15,7 +15,6 @@ use selectors::parser::SelectorParseErrorKind; #[cfg(feature = "servo")] use servo_url::ServoUrl; use std::cmp::Ordering; -use std::f32::consts::PI; use std::fmt::{self, Write}; use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError}; use style_traits::{StyleParseErrorKind, SpecifiedValueInfo, ToCss}; @@ -679,7 +678,7 @@ impl GradientKind { impl generic::LineDirection for LineDirection { fn points_downwards(&self, compat_mode: CompatMode) -> bool { match *self { - LineDirection::Angle(ref angle) => angle.radians() == PI, + LineDirection::Angle(ref angle) => angle.degrees() == 180.0, LineDirection::Vertical(Y::Bottom) if compat_mode == CompatMode::Modern => true, LineDirection::Vertical(Y::Top) if compat_mode != CompatMode::Modern => true, #[cfg(feature = "gecko")] diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 1b4efc4f00d..128ab9959a5 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -19,6 +19,7 @@ use super::{AllowQuirks, Number, Percentage, ToComputedValue}; use values::{Auto, CSSFloat, Either, Normal}; use values::computed::{self, CSSPixelLength, Context, ExtremumLength}; use values::generics::NonNegative; +use values::generics::length::{MaxLength as GenericMaxLength, MozLength as GenericMozLength}; use values::specified::calc::CalcNode; pub use values::specified::calc::CalcLengthOrPercentage; @@ -1188,18 +1189,8 @@ impl LengthOrNumber { } } -/// A value suitable for a `min-width` or `min-height` property. -/// -/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`, -/// and cannot be `none`. -/// -/// Note that it only accepts non-negative values. -#[allow(missing_docs)] -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] -pub enum MozLength { - LengthOrPercentageOrAuto(LengthOrPercentageOrAuto), - ExtremumLength(ExtremumLength), -} +/// A specified value for `min-width`, `min-height`, `width` or `height` property. +pub type MozLength = GenericMozLength<LengthOrPercentageOrAuto>; impl Parse for MozLength { fn parse<'i, 't>( @@ -1219,7 +1210,7 @@ impl MozLength { input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { let length = LengthOrPercentageOrAuto::parse_non_negative(context, input)?; - Ok(MozLength::LengthOrPercentageOrAuto(length)) + Ok(GenericMozLength::LengthOrPercentageOrAuto(length)) } /// Parses, with quirks. @@ -1229,34 +1220,29 @@ impl MozLength { allow_quirks: AllowQuirks, ) -> Result<Self, ParseError<'i>> { if let Ok(l) = input.try(ExtremumLength::parse) { - return Ok(MozLength::ExtremumLength(l)); + return Ok(GenericMozLength::ExtremumLength(l)); } let length = LengthOrPercentageOrAuto::parse_non_negative_quirky(context, input, allow_quirks)?; - Ok(MozLength::LengthOrPercentageOrAuto(length)) + Ok(GenericMozLength::LengthOrPercentageOrAuto(length)) } /// Returns `auto`. #[inline] pub fn auto() -> Self { - MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::auto()) + GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::auto()) } /// Returns `0%`. #[inline] pub fn zero_percent() -> Self { - MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::zero_percent()) + GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::zero_percent()) } } -/// A value suitable for a `max-width` or `max-height` property. -#[allow(missing_docs)] -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] -pub enum MaxLength { - LengthOrPercentageOrNone(LengthOrPercentageOrNone), - ExtremumLength(ExtremumLength), -} +/// A specified value for `max-width` or `max-height` property. +pub type MaxLength = GenericMaxLength<LengthOrPercentageOrNone>; impl Parse for MaxLength { fn parse<'i, 't>( @@ -1276,7 +1262,7 @@ impl MaxLength { input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { let length = LengthOrPercentageOrNone::parse_non_negative(context, input)?; - Ok(MaxLength::LengthOrPercentageOrNone(length)) + Ok(GenericMaxLength::LengthOrPercentageOrNone(length)) } /// Parses, with quirks. @@ -1286,11 +1272,11 @@ impl MaxLength { allow_quirks: AllowQuirks, ) -> Result<Self, ParseError<'i>> { if let Ok(l) = input.try(ExtremumLength::parse) { - return Ok(MaxLength::ExtremumLength(l)); + return Ok(GenericMaxLength::ExtremumLength(l)); } let length = LengthOrPercentageOrNone::parse_non_negative_quirky(context, input, allow_quirks)?; - Ok(MaxLength::LengthOrPercentageOrNone(length)) + Ok(GenericMaxLength::LengthOrPercentageOrNone(length)) } } diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index 4ab79d25a2f..2c5892f1e63 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -611,60 +611,6 @@ mod shorthand_serialization { } } - mod transform { - pub use super::*; - use style::values::generics::transform::TransformOperation; - use style::values::specified::{Angle, Number}; - use style::values::specified::transform::TransformOperation as SpecifiedOperation; - - #[test] - fn should_serialize_none_correctly() { - use style::properties::longhands::transform; - - assert_roundtrip_with_context!(transform::parse, "none"); - } - - #[inline(always)] - fn validate_serialization(op: &SpecifiedOperation, expected_string: &'static str) { - let css_string = op.to_css_string(); - assert_eq!(css_string, expected_string); - } - - #[test] - fn transform_scale() { - validate_serialization(&TransformOperation::Scale(Number::new(1.3), None), "scale(1.3)"); - validate_serialization( - &TransformOperation::Scale(Number::new(2.0), Some(Number::new(2.0))), - "scale(2, 2)"); - validate_serialization(&TransformOperation::ScaleX(Number::new(42.0)), "scaleX(42)"); - validate_serialization(&TransformOperation::ScaleY(Number::new(0.3)), "scaleY(0.3)"); - validate_serialization(&TransformOperation::ScaleZ(Number::new(1.0)), "scaleZ(1)"); - validate_serialization( - &TransformOperation::Scale3D(Number::new(4.0), Number::new(5.0), Number::new(6.0)), - "scale3d(4, 5, 6)"); - } - - #[test] - fn transform_skew() { - validate_serialization( - &TransformOperation::Skew(Angle::from_degrees(42.3, false), None), - "skew(42.3deg)"); - validate_serialization( - &TransformOperation::Skew(Angle::from_gradians(-50.0, false), Some(Angle::from_turns(0.73, false))), - "skew(-50grad, 0.73turn)"); - validate_serialization( - &TransformOperation::SkewX(Angle::from_radians(0.31, false)), "skewX(0.31rad)"); - } - - #[test] - fn transform_rotate() { - validate_serialization( - &TransformOperation::Rotate(Angle::from_turns(35.0, false)), - "rotate(35turn)" - ) - } - } - mod quotes { pub use super::*; diff --git a/tests/wpt/metadata/css/css-conditional/at-supports-040.html.ini b/tests/wpt/metadata/css/css-conditional/at-supports-040.html.ini deleted file mode 100644 index 6869e67b552..00000000000 --- a/tests/wpt/metadata/css/css-conditional/at-supports-040.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[at-supports-040.html] - expected: FAIL diff --git a/tests/wpt/metadata/css/cssom/CSS.html.ini b/tests/wpt/metadata/css/cssom/CSS.html.ini deleted file mode 100644 index 279da1f4d89..00000000000 --- a/tests/wpt/metadata/css/cssom/CSS.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[CSS.html] - [CSS.supports, selector function] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 48be8bbb3bb..824d9a03ef9 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -26166,7 +26166,7 @@ "reftest" ], "css/transform_skew_ref.html": [ - "caf92ca6f50d1cfe27f9202ebf79d76dead03ba0", + "b6ef9bb8fe9c129b02f5f3213865673a42638190", "support" ], "css/transform_stacking_context_a.html": [ diff --git a/tests/wpt/mozilla/tests/css/transform_skew_ref.html b/tests/wpt/mozilla/tests/css/transform_skew_ref.html index caf92ca6f50..b6ef9bb8fe9 100644 --- a/tests/wpt/mozilla/tests/css/transform_skew_ref.html +++ b/tests/wpt/mozilla/tests/css/transform_skew_ref.html @@ -17,15 +17,15 @@ div>div { } .transformed1_ref { - transform: matrix(1, 0, 0.25534192122, 1, 0, 0); + transform: matrix(1, 0, 0.255342, 1, 0, 0); } .transformed2_ref { - transform: matrix(1, 0.54630248984, 0, 1, 0, 0); + transform: matrix(1, 0.546302, 0, 1, 0, 0); } .transformed3_ref { - transform: matrix(1, 0.54630248984, 0.25534192122, 1, 0, 0); + transform: matrix(1, 0.546302, 0.255342, 1, 0, 0); } </style> |