diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2018-09-03 08:12:22 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-03 08:12:22 -0400 |
commit | d8446f85a95723dec3a18b05bdd30514a57bddab (patch) | |
tree | 3e92a0a5fed4315519a34e8cef33c54840ada0d4 | |
parent | eb6aec37e9bde5aba2a3dc6b6ce5374579219f31 (diff) | |
parent | 1254cbf313243e8879a464538a5c78383ba3bc8b (diff) | |
download | servo-d8446f85a95723dec3a18b05bdd30514a57bddab.tar.gz servo-d8446f85a95723dec3a18b05bdd30514a57bddab.zip |
Auto merge of #21588 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central.
See each individual commit for details.
https://bugzilla.mozilla.org/show_bug.cgi?id=1488172
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21588)
<!-- Reviewable:end -->
68 files changed, 2701 insertions, 1391 deletions
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt index 0798179c151..7fbd043dc0f 100644 --- a/components/atoms/static_atoms.txt +++ b/components/atoms/static_atoms.txt @@ -36,6 +36,7 @@ invalid keydown keypress left +ltr load loadeddata loadedmetadata @@ -65,6 +66,7 @@ readystatechange reftest-wait reset right +rtl sans-serif scan screen diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 7b2892f7c9a..4800704fca8 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -70,7 +70,7 @@ use style::dom::{TDocument, TElement, TNode, TShadowRoot}; use style::element_state::*; use style::font_metrics::ServoMetricsProvider; use style::properties::{ComputedValues, PropertyDeclarationBlock}; -use style::selector_parser::{AttrValue as SelectorAttrValue, NonTSPseudoClass, PseudoClassStringArg}; +use style::selector_parser::{AttrValue as SelectorAttrValue, NonTSPseudoClass, Lang}; use style::selector_parser::{PseudoElement, SelectorImpl, extended_filtering}; use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked}; use style::str::is_whitespace; @@ -168,7 +168,7 @@ impl<'lr> TShadowRoot for ShadowRoot<'lr> { match self.0 { } } - fn style_data<'a>(&self) -> &'a CascadeData + fn style_data<'a>(&self) -> Option<&'a CascadeData> where Self: 'a, { @@ -531,7 +531,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { fn match_element_lang( &self, override_lang: Option<Option<SelectorAttrValue>>, - value: &PseudoClassStringArg, + value: &Lang, ) -> bool { // Servo supports :lang() from CSS Selectors 4, which can take a comma- // separated list of language tags in the pseudo-class, and which diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs index f4774d66a3e..11e96254172 100644 --- a/components/malloc_size_of/lib.rs +++ b/components/malloc_size_of/lib.rs @@ -845,8 +845,8 @@ macro_rules! malloc_size_of_is_0( ); malloc_size_of_is_0!(bool, char, str); -malloc_size_of_is_0!(u8, u16, u32, u64, usize); -malloc_size_of_is_0!(i8, i16, i32, i64, isize); +malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize); +malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize); malloc_size_of_is_0!(f32, f64); malloc_size_of_is_0!(std::sync::atomic::AtomicBool); diff --git a/components/script/dom/css.rs b/components/script/dom/css.rs index d642b44a19f..7a42d6b6e68 100644 --- a/components/script/dom/css.rs +++ b/components/script/dom/css.rs @@ -44,6 +44,7 @@ impl CSS { ParsingMode::DEFAULT, QuirksMode::NoQuirks, None, + None, ); decl.eval(&context) } @@ -61,6 +62,7 @@ impl CSS { ParsingMode::DEFAULT, QuirksMode::NoQuirks, None, + None, ); cond.eval(&context) } else { diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index 23f3c46a251..ccc803e4b42 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -81,6 +81,7 @@ impl CSSMediaRule { ParsingMode::DEFAULT, quirks_mode, window.css_error_reporter(), + None, ); let new_medialist = StyleMediaList::parse(&context, &mut input); diff --git a/components/script/dom/csssupportsrule.rs b/components/script/dom/csssupportsrule.rs index a96cd706b86..8b66fbe76cf 100644 --- a/components/script/dom/csssupportsrule.rs +++ b/components/script/dom/csssupportsrule.rs @@ -69,6 +69,7 @@ impl CSSSupportsRule { ParsingMode::DEFAULT, quirks_mode, None, + None, ); let enabled = cond.eval(&context); let mut guard = self.cssconditionrule.shared_lock().write(); diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 62523e61f4e..3aaa7c579cb 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -538,12 +538,17 @@ impl HTMLImageElement { /// https://html.spec.whatwg.org/multipage/#matches-the-environment fn matches_environment(&self, media_query: String) -> bool { let document = document_from_node(self); - let device = document.device(); - if !device.is_some() { - return false; - } + let device = match document.device() { + Some(device) => device, + None => return false, + }; let quirks_mode = document.quirks_mode(); let document_url = &document.url(); + // FIXME(emilio): This should do the same that we do for other media + // lists regarding the rule type and such, though it doesn't really + // matter right now... + // + // Also, ParsingMode::all() is wrong, and should be DEFAULT. let context = ParserContext::new( Origin::Author, document_url, @@ -551,11 +556,12 @@ impl HTMLImageElement { ParsingMode::all(), quirks_mode, None, + None, ); let mut parserInput = ParserInput::new(&media_query); let mut parser = Parser::new(&mut parserInput); let media_list = MediaList::parse(&context, &mut parser); - media_list.evaluate(&device.unwrap(), quirks_mode) + media_list.evaluate(&device, quirks_mode) } /// <https://html.spec.whatwg.org/multipage/#normalise-the-source-densities> @@ -1039,9 +1045,12 @@ pub fn parse_a_sizes_attribute(value: DOMString) -> SourceSizeList { Origin::Author, &url, Some(CssRuleType::Style), + // FIXME(emilio): why ::empty() instead of ::DEFAULT? Also, what do + // browsers do regarding quirks-mode in a media list? ParsingMode::empty(), QuirksMode::NoQuirks, None, + None, ); SourceSizeList::parse(&context, &mut parser) } diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index a86789dcd71..be7b2785ee9 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -287,6 +287,7 @@ impl HTMLLinkElement { ParsingMode::DEFAULT, document.quirks_mode(), window.css_error_reporter(), + None, ); let media = MediaList::parse(&context, &mut css_parser); diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 82da9ba6180..bcecab9088b 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -91,6 +91,7 @@ impl HTMLStyleElement { ParsingMode::DEFAULT, doc.quirks_mode(), css_error_reporter, + None, ); let shared_lock = node.owner_doc().style_shared_lock().clone(); let mut input = ParserInput::new(&mq_str); diff --git a/components/script/dom/medialist.rs b/components/script/dom/medialist.rs index d43f6d3a710..99800f1beb1 100644 --- a/components/script/dom/medialist.rs +++ b/components/script/dom/medialist.rs @@ -83,6 +83,7 @@ impl MediaListMethods for MediaList { ParsingMode::DEFAULT, quirks_mode, window.css_error_reporter(), + None, ); *media_queries = StyleMediaList::parse(&context, &mut parser); } @@ -123,6 +124,7 @@ impl MediaListMethods for MediaList { ParsingMode::DEFAULT, quirks_mode, win.css_error_reporter(), + None, ); let m = MediaQuery::parse(&context, &mut parser); // Step 2 @@ -156,6 +158,7 @@ impl MediaListMethods for MediaList { ParsingMode::DEFAULT, quirks_mode, win.css_error_reporter(), + None, ); let m = MediaQuery::parse(&context, &mut parser); // Step 2 diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index e125aa87fd9..7ccd828f9e3 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1089,6 +1089,7 @@ impl WindowMethods for Window { ParsingMode::DEFAULT, quirks_mode, self.css_error_reporter(), + None, ); let media_query_list = media_queries::MediaList::parse(&context, &mut parser); diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 8387f6513a6..c0655628538 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -406,11 +406,7 @@ mod bindings { fn generate_structs() { let builder = Builder::get_initial_builder() .enable_cxx_namespaces() - .with_codegen_config(CodegenConfig { - types: true, - vars: true, - ..CodegenConfig::nothing() - }); + .with_codegen_config(CodegenConfig::TYPES | CodegenConfig::VARS); let mut fixups = vec![]; let builder = BuilderWithConfig::new(builder, CONFIG["structs"].as_table().unwrap()) .handle_common(&mut fixups) @@ -500,10 +496,7 @@ mod bindings { fn generate_bindings() { let builder = Builder::get_initial_builder() .disable_name_namespacing() - .with_codegen_config(CodegenConfig { - functions: true, - ..CodegenConfig::nothing() - }); + .with_codegen_config(CodegenConfig::FUNCTIONS); let config = CONFIG["bindings"].as_table().unwrap(); let mut structs_types = HashSet::new(); let mut fixups = vec![]; diff --git a/components/style/cbindgen.toml b/components/style/cbindgen.toml index 5a0e5e19ea7..46162e43db5 100644 --- a/components/style/cbindgen.toml +++ b/components/style/cbindgen.toml @@ -7,6 +7,7 @@ autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated usi * a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release * 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h` */""" +include_guard = "mozilla_ServoStyleConsts_h" include_version = true braces = "SameLine" line_length = 80 @@ -22,5 +23,11 @@ derive_helper_methods = true [export] prefix = "Style" -include = ["StyleDisplay", "StyleAppearance", "StyleDisplayMode"] -item_types = ["enums"] +include = [ + "StyleAppearance", + "StyleDisplay", + "StyleDisplayMode", + "StyleFillRule", + "StylePathCommand" +] +item_types = ["enums", "structs", "typedefs"] diff --git a/components/style/dom.rs b/components/style/dom.rs index 42f6e9ba0c0..2f65a266f01 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -19,7 +19,7 @@ use element_state::ElementState; use font_metrics::FontMetricsProvider; use media_queries::Device; use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock}; -use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl}; +use selector_parser::{AttrValue, Lang, PseudoElement, SelectorImpl}; use selectors::Element as SelectorsElement; use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode}; use selectors::sink::Push; @@ -342,7 +342,7 @@ pub trait TShadowRoot: Sized + Copy + Clone + PartialEq { fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement; /// Get the style data for this ShadowRoot. - fn style_data<'a>(&self) -> &'a CascadeData + fn style_data<'a>(&self) -> Option<&'a CascadeData> where Self: 'a; @@ -824,30 +824,36 @@ pub trait TElement: if let Some(shadow) = self.containing_shadow() { doc_rules_apply = false; - f( - shadow.style_data(), - self.as_node().owner_doc().quirks_mode(), - Some(shadow.host()), - ); + if let Some(data) = shadow.style_data() { + f( + data, + self.as_node().owner_doc().quirks_mode(), + Some(shadow.host()), + ); + } } if let Some(shadow) = self.shadow_root() { - f( - shadow.style_data(), - self.as_node().owner_doc().quirks_mode(), - Some(shadow.host()), - ); + if let Some(data) = shadow.style_data() { + f( + data, + self.as_node().owner_doc().quirks_mode(), + Some(shadow.host()), + ); + } } let mut current = self.assigned_slot(); while let Some(slot) = current { // Slots can only have assigned nodes when in a shadow tree. let shadow = slot.containing_shadow().unwrap(); - f( - shadow.style_data(), - self.as_node().owner_doc().quirks_mode(), - Some(shadow.host()), - ); + if let Some(data) = shadow.style_data() { + f( + data, + self.as_node().owner_doc().quirks_mode(), + Some(shadow.host()), + ); + } current = slot.assigned_slot(); } @@ -889,7 +895,7 @@ pub trait TElement: fn match_element_lang( &self, override_lang: Option<Option<AttrValue>>, - value: &PseudoClassStringArg, + value: &Lang, ) -> bool; /// Returns whether this element is the main body element of the HTML diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 3b1f31a1b08..3c1d334f4a8 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -19,6 +19,7 @@ use stylesheets::{Origin, RulesMutateError}; use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image}; use values::computed::{Integer, LengthOrPercentage, LengthOrPercentageOrAuto}; use values::computed::{Percentage, TextAlign}; +use values::computed::image::LineDirection; use values::computed::url::ComputedImageUrl; use values::generics::box_::VerticalAlign; use values::generics::grid::{TrackListValue, TrackSize}; @@ -139,6 +140,68 @@ impl Angle { } } +fn line_direction( + horizontal: LengthOrPercentage, + vertical: LengthOrPercentage, +) -> LineDirection { + use values::computed::position::Position; + use values::specified::position::{X, Y}; + + let horizontal_percentage = match horizontal { + LengthOrPercentage::Percentage(percentage) => Some(percentage.0), + _ => None, + }; + + let vertical_percentage = match vertical { + LengthOrPercentage::Percentage(percentage) => Some(percentage.0), + _ => None, + }; + + let horizontal_as_corner = horizontal_percentage.and_then(|percentage| { + if percentage == 0.0 { + Some(X::Left) + } else if percentage == 1.0 { + Some(X::Right) + } else { + None + } + }); + + let vertical_as_corner = vertical_percentage.and_then(|percentage| { + if percentage == 0.0 { + Some(Y::Top) + } else if percentage == 1.0 { + Some(Y::Bottom) + } else { + None + } + }); + + if let (Some(hc), Some(vc)) = (horizontal_as_corner, vertical_as_corner) { + return LineDirection::Corner(hc, vc) + } + + if let Some(hc) = horizontal_as_corner { + if vertical_percentage == Some(0.5) { + return LineDirection::Horizontal(hc) + } + } + + if let Some(vc) = vertical_as_corner { + if horizontal_percentage == Some(0.5) { + return LineDirection::Vertical(vc) + } + } + + LineDirection::MozPosition( + Some(Position { + horizontal, + vertical, + }), + None, + ) +} + impl nsStyleImage { /// Set a given Servo `Image` value into this `nsStyleImage`. pub fn set(&mut self, image: Image) { @@ -174,13 +237,13 @@ impl nsStyleImage { } } + // FIXME(emilio): This is really complex, we should use cbindgen for this. fn set_gradient(&mut self, gradient: Gradient) { use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER; use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE; use self::structs::nsStyleCoord; - use values::computed::image::LineDirection; use values::generics::image::{Circle, Ellipse, EndingShape, GradientKind, ShapeExtent}; use values::specified::position::{X, Y}; @@ -437,12 +500,11 @@ impl nsStyleImage { use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE; - use values::computed::{Length, LengthOrPercentage}; + use values::computed::Length; use values::computed::image::LineDirection; use values::computed::position::Position; use values::generics::image::{Circle, ColorStop, CompatMode, Ellipse}; use values::generics::image::{EndingShape, GradientKind, ShapeExtent}; - use values::specified::position::{X, Y}; let gecko_gradient = bindings::Gecko_GetGradientImageValue(self) .as_ref() @@ -456,41 +518,7 @@ impl nsStyleImage { let line_direction = match (angle, horizontal_style, vertical_style) { (Some(a), None, None) => LineDirection::Angle(a), (None, Some(horizontal), Some(vertical)) => { - let horizontal_as_corner = match horizontal { - LengthOrPercentage::Percentage(percentage) => { - if percentage.0 == 0.0 { - Some(X::Left) - } else if percentage.0 == 1.0 { - Some(X::Right) - } else { - None - } - }, - _ => None, - }; - let vertical_as_corner = match vertical { - LengthOrPercentage::Percentage(percentage) => { - if percentage.0 == 0.0 { - Some(Y::Top) - } else if percentage.0 == 1.0 { - Some(Y::Bottom) - } else { - None - } - }, - _ => None, - }; - - match (horizontal_as_corner, vertical_as_corner) { - (Some(hc), Some(vc)) => LineDirection::Corner(hc, vc), - _ => LineDirection::MozPosition( - Some(Position { - horizontal, - vertical, - }), - None, - ), - } + line_direction(horizontal, vertical) }, (Some(_), Some(horizontal), Some(vertical)) => LineDirection::MozPosition( Some(Position { @@ -638,13 +666,15 @@ pub mod basic_shape { use values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape, ShapeRadius}; use values::computed::border::{BorderCornerRadius, BorderRadius}; use values::computed::length::LengthOrPercentage; + use values::computed::motion::OffsetPath; use values::computed::position; use values::computed::url::ComputedUrl; use values::generics::basic_shape::{BasicShape as GenericBasicShape, InsetRect, Polygon}; - use values::generics::basic_shape::{Circle, Ellipse, FillRule}; + use values::generics::basic_shape::{Circle, Ellipse, FillRule, Path, PolygonCoord}; use values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource}; use values::generics::border::BorderRadius as GenericBorderRadius; use values::generics::rect::Rect; + use values::specified::SVGPathData; impl StyleShapeSource { /// Convert StyleShapeSource to ShapeSource except URL and Image @@ -669,6 +699,34 @@ pub mod basic_shape { Some(ShapeSource::Shape(shape, reference_box)) }, StyleShapeSourceType::URL | StyleShapeSourceType::Image => None, + StyleShapeSourceType::Path => { + let path = self.to_svg_path().expect("expect an SVGPathData"); + let gecko_path = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }; + let fill = if gecko_path.mFillRule == StyleFillRule::Evenodd { + FillRule::Evenodd + } else { + FillRule::Nonzero + }; + Some(ShapeSource::Path(Path { fill, path })) + }, + } + } + + /// Generate a SVGPathData from StyleShapeSource if possible. + fn to_svg_path(&self) -> Option<SVGPathData> { + use gecko_bindings::structs::StylePathCommand; + use values::specified::svg_path::PathCommand; + match self.mType { + StyleShapeSourceType::Path => { + let gecko_path = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }; + let result: Vec<PathCommand> = + gecko_path.mPath.iter().map(|gecko: &StylePathCommand| { + // unsafe: cbindgen ensures the representation is the same. + unsafe { ::std::mem::transmute(*gecko) } + }).collect(); + Some(SVGPathData::new(result.into_boxed_slice())) + }, + _ => None, } } } @@ -710,6 +768,21 @@ pub mod basic_shape { } } + impl<'a> From<&'a StyleShapeSource> for OffsetPath { + fn from(other: &'a StyleShapeSource) -> Self { + match other.mType { + StyleShapeSourceType::Path => { + OffsetPath::Path(other.to_svg_path().expect("Cannot convert to SVGPathData")) + }, + StyleShapeSourceType::None => OffsetPath::none(), + StyleShapeSourceType::Shape | + StyleShapeSourceType::Box | + StyleShapeSourceType::URL | + StyleShapeSourceType::Image => unreachable!("Unsupported offset-path type"), + } + } + } + impl<'a> From<&'a StyleBasicShape> for BasicShape { fn from(other: &'a StyleBasicShape) -> Self { match other.mType { @@ -718,17 +791,15 @@ pub mod basic_shape { let r = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[1]); let b = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[2]); let l = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[3]); - let round = (&other.mRadius).into(); + let round: BorderRadius = (&other.mRadius).into(); + let round = if round.all_zero() { None } else { Some(round) }; let rect = Rect::new( t.expect("inset() offset should be a length, percentage, or calc value"), r.expect("inset() offset should be a length, percentage, or calc value"), b.expect("inset() offset should be a length, percentage, or calc value"), l.expect("inset() offset should be a length, percentage, or calc value"), ); - GenericBasicShape::Inset(InsetRect { - rect: rect, - round: Some(round), - }) + GenericBasicShape::Inset(InsetRect { rect, round }) }, StyleBasicShapeType::Circle => GenericBasicShape::Circle(Circle { radius: (&other.mCoordinates[0]).into(), @@ -749,11 +820,14 @@ pub mod basic_shape { for i in 0..(other.mCoordinates.len() / 2) { let x = 2 * i; let y = x + 1; - coords.push((LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[x]) - .expect("polygon() coordinate should be a length, percentage, or calc value"), - LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[y]) - .expect("polygon() coordinate should be a length, percentage, or calc value") - )) + coords.push(PolygonCoord( + LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[x]) + .expect("polygon() coordinate should be a length, percentage, \ + or calc value"), + LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[y]) + .expect("polygon() coordinate should be a length, percentage, \ + or calc value") + )) } GenericBasicShape::Polygon(Polygon { fill: fill_rule, diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs index 04f57b73885..813250e4383 100644 --- a/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/components/style/gecko/non_ts_pseudo_class_list.rs @@ -12,22 +12,13 @@ * Expected usage is as follows: * ``` * macro_rules! pseudo_class_macro{ - * (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], - * string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { - * keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { + * ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { * // do stuff * } * } * apply_non_ts_list!(pseudo_class_macro) * ``` * - * The `string` and `keyword` variables will be applied to pseudoclasses that are of the form of - * functions with string or keyword arguments. - * - * Pending pseudo-classes: - * - * :scope -> <style scoped>, pending discussion. - * * $gecko_type can be either "_" or an ident in Gecko's CSSPseudoClassType. * $state can be either "_" or an expression of type ElementState. If present, * the semantics are that the pseudo-class matches if any of the bits in @@ -39,7 +30,7 @@ macro_rules! apply_non_ts_list { ($apply_macro:ident) => { $apply_macro! { - bare: [ + [ ("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), ("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), ("link", Link, link, IN_UNVISITED_STATE, _), @@ -111,9 +102,6 @@ macro_rules! apply_non_ts_list { ("-moz-lwtheme-brighttext", MozLWThemeBrightText, mozLWThemeBrightText, _, _), ("-moz-lwtheme-darktext", MozLWThemeDarkText, mozLWThemeDarkText, _, _), ("-moz-window-inactive", MozWindowInactive, mozWindowInactive, _, _), - ], - string: [ - ("lang", Lang, lang, _, _), ] } } diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs index a08da8d40f1..b30d7764d17 100644 --- a/components/style/gecko/pseudo_element.rs +++ b/components/style/gecko/pseudo_element.rs @@ -14,6 +14,7 @@ use properties::{ComputedValues, PropertyFlags}; use properties::longhands::display::computed_value::T as Display; use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl}; use std::fmt; +use str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase}; use string_cache::Atom; use thin_slice::ThinBoxedSlice; use values::serialize_atom_identifier; diff --git a/components/style/gecko/pseudo_element_definition.mako.rs b/components/style/gecko/pseudo_element_definition.mako.rs index be0318eadea..7c45ee8bfb7 100644 --- a/components/style/gecko/pseudo_element_definition.mako.rs +++ b/components/style/gecko/pseudo_element_definition.mako.rs @@ -13,6 +13,9 @@ pub enum PseudoElement { ${pseudo.capitalized_pseudo()}, % endif % endfor + /// ::-webkit-* that we don't recognize + /// https://github.com/whatwg/compat/issues/103 + UnknownWebkit(Atom), } /// Important: If you change this, you should also update Gecko's @@ -47,11 +50,12 @@ PseudoElement::${pseudo.capitalized_pseudo()}${"({})".format(tree_arg) if pseudo impl PseudoElement { /// Get the pseudo-element as an atom. #[inline] - pub fn atom(&self) -> Atom { + fn atom(&self) -> Atom { match *self { % for pseudo in PSEUDOS: ${pseudo_element_variant(pseudo)} => atom!("${pseudo.value}"), % endfor + PseudoElement::UnknownWebkit(..) => unreachable!(), } } @@ -62,6 +66,7 @@ impl PseudoElement { % for i, pseudo in enumerate(PSEUDOS): ${pseudo_element_variant(pseudo)} => ${i}, % endfor + PseudoElement::UnknownWebkit(..) => unreachable!(), } } @@ -105,6 +110,12 @@ impl PseudoElement { } } + /// Whether this pseudo-element is an unknown Webkit-prefixed pseudo-element. + #[inline] + pub fn is_unknown_webkit_pseudo_element(&self) -> bool { + matches!(*self, PseudoElement::UnknownWebkit(..)) + } + /// Gets the flags associated to this pseudo-element, or 0 if it's an /// anonymous box. pub fn flags(&self) -> u32 { @@ -123,6 +134,7 @@ impl PseudoElement { structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_${pseudo.pseudo_ident}, % endif % endfor + PseudoElement::UnknownWebkit(..) => 0, } } @@ -143,7 +155,7 @@ impl PseudoElement { /// Construct a `CSSPseudoElementType` from a pseudo-element #[inline] - pub fn pseudo_type(&self) -> CSSPseudoElementType { + fn pseudo_type(&self) -> CSSPseudoElementType { use gecko_bindings::structs::CSSPseudoElementType_InheritingAnonBox; match *self { @@ -158,6 +170,7 @@ impl PseudoElement { PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::NonInheritingAnonBox, % endif % endfor + PseudoElement::UnknownWebkit(..) => unreachable!(), } } @@ -242,11 +255,18 @@ impl PseudoElement { return Some(PseudoElement::Placeholder); } _ => { - // FIXME: -moz-tree check should probably be - // ascii-case-insensitive. - if name.starts_with("-moz-tree-") { + if starts_with_ignore_ascii_case(name, "-moz-tree-") { return PseudoElement::tree_pseudo_element(name, Box::new([])) } + if unsafe { + structs::StaticPrefs_sVarCache_layout_css_unknown_webkit_pseudo_element + } { + const WEBKIT_PREFIX: &str = "-webkit-"; + if starts_with_ignore_ascii_case(name, WEBKIT_PREFIX) { + let part = string_as_ascii_lowercase(&name[WEBKIT_PREFIX.len()..]); + return Some(PseudoElement::UnknownWebkit(part.into())); + } + } } } @@ -259,7 +279,7 @@ impl PseudoElement { /// Returns `None` if the pseudo-element is not recognized. #[inline] pub fn tree_pseudo_element(name: &str, args: Box<[Atom]>) -> Option<Self> { - debug_assert!(name.starts_with("-moz-tree-")); + debug_assert!(starts_with_ignore_ascii_case(name, "-moz-tree-")); let tree_part = &name[10..]; % for pseudo in TREE_PSEUDOS: if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") { @@ -277,6 +297,10 @@ impl ToCss for PseudoElement { % for pseudo in PSEUDOS: ${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?, % endfor + PseudoElement::UnknownWebkit(ref atom) => { + dest.write_str(":-webkit-")?; + serialize_atom_identifier(atom, dest)?; + } } if let Some(args) = self.tree_pseudo_args() { if !args.is_empty() { diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index fa514835e8c..3f6fee3c30e 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -17,9 +17,11 @@ use selectors::parser::{SelectorParseErrorKind, Visit}; use selectors::parser::{self as selector_parser, Selector}; use selectors::visitor::SelectorVisitor; use std::fmt; +use str::starts_with_ignore_ascii_case; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_}; use thin_slice::ThinBoxedSlice; +use values::serialize_atom_identifier; pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT}; pub use gecko::snapshot::SnapshotMap; @@ -35,12 +37,11 @@ bitflags! { } } -/// The type used for storing pseudo-class string arguments. -pub type PseudoClassStringArg = ThinBoxedSlice<u16>; +/// The type used to store the language argument to the `:lang` pseudo-class. +pub type Lang = Atom; macro_rules! pseudo_class_name { - (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], - string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { /// Our representation of a non tree-structural pseudo-class. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] pub enum NonTSPseudoClass { @@ -48,19 +49,17 @@ macro_rules! pseudo_class_name { #[doc = $css] $name, )* - $( - #[doc = $s_css] - $s_name(PseudoClassStringArg), - )* + /// The `:lang` pseudo-class. + Lang(Lang), /// The `:dir` pseudo-class. - Dir(Box<Direction>), + Dir(Direction), /// The non-standard `:-moz-any` pseudo-class. /// /// TODO(emilio): We disallow combinators and pseudos here, so we /// should use SimpleSelector instead MozAny(ThinBoxedSlice<Selector<SelectorImpl>>), /// The non-standard `:-moz-locale-dir` pseudo-class. - MozLocaleDir(Box<Direction>), + MozLocaleDir(Direction), } } } @@ -71,25 +70,15 @@ impl ToCss for NonTSPseudoClass { where W: fmt::Write, { - use cssparser::CssStringWriter; - use std::fmt::Write; macro_rules! pseudo_class_serialize { - (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], - string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => concat!(":", $css),)* - $(NonTSPseudoClass::$s_name(ref s) => { - dest.write_str(concat!(":", $s_css, "("))?; - { - // FIXME(emilio): Avoid the extra allocation! - let mut css = CssStringWriter::new(dest); - - // Discount the null char in the end from the - // string. - css.write_str(&String::from_utf16(&s[..s.len() - 1]).unwrap())?; - } - return dest.write_str(")") - }, )* + NonTSPseudoClass::Lang(ref s) => { + dest.write_str(":lang(")?; + serialize_atom_identifier(s, dest)?; + return dest.write_char(')'); + }, NonTSPseudoClass::MozLocaleDir(ref dir) => { dest.write_str(":-moz-locale-dir(")?; dir.to_css(&mut CssWriter::new(dest))?; @@ -109,7 +98,7 @@ impl ToCss for NonTSPseudoClass { dest.write_str(", ")?; selector.to_css(dest)?; } - return dest.write_str(")") + return dest.write_char(')') } } } @@ -144,8 +133,7 @@ impl NonTSPseudoClass { /// in a particular state. pub fn parse_non_functional(name: &str) -> Option<Self> { macro_rules! pseudo_class_parse { - (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], - string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { match_ignore_ascii_case! { &name, $($css => Some(NonTSPseudoClass::$name),)* _ => None, @@ -166,12 +154,11 @@ impl NonTSPseudoClass { }; } macro_rules! pseudo_class_check_is_enabled_in { - (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], - string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => check_flag!($flags),)* - $(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)* NonTSPseudoClass::MozLocaleDir(_) | + NonTSPseudoClass::Lang(_) | NonTSPseudoClass::Dir(_) | NonTSPseudoClass::MozAny(_) => false, } @@ -221,13 +208,12 @@ impl NonTSPseudoClass { }; } macro_rules! pseudo_class_state { - (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], - string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => flag!($state),)* - $(NonTSPseudoClass::$s_name(..) => flag!($s_state),)* NonTSPseudoClass::Dir(..) | NonTSPseudoClass::MozLocaleDir(..) | + NonTSPseudoClass::Lang(..) | NonTSPseudoClass::MozAny(..) => ElementState::empty(), } } @@ -398,42 +384,29 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { name: CowRcStr<'i>, parser: &mut Parser<'i, 't>, ) -> Result<NonTSPseudoClass, ParseError<'i>> { - macro_rules! pseudo_class_string_parse { - (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], - string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => { - match_ignore_ascii_case! { &name, - $($s_css => { - let name = parser.expect_ident_or_string()?; - // convert to null terminated utf16 string - // since that's what Gecko deals with - let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect(); - NonTSPseudoClass::$s_name(utf16.into_boxed_slice().into()) - }, )* - "-moz-locale-dir" => { - NonTSPseudoClass::MozLocaleDir( - Box::new(Direction::parse(parser)?) - ) - }, - "dir" => { - NonTSPseudoClass::Dir( - Box::new(Direction::parse(parser)?) - ) - }, - "-moz-any" => { - NonTSPseudoClass::MozAny( - selector_parser::parse_compound_selector_list( - self, - parser, - )?.into() - ) - } - _ => return Err(parser.new_custom_error( - SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()) - )) - } + let pseudo_class = match_ignore_ascii_case! { &name, + "lang" => { + let name = parser.expect_ident_or_string()?; + NonTSPseudoClass::Lang(Atom::from(name.as_ref())) + }, + "-moz-locale-dir" => { + NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?) + }, + "dir" => { + NonTSPseudoClass::Dir(Direction::parse(parser)?) + }, + "-moz-any" => { + NonTSPseudoClass::MozAny( + selector_parser::parse_compound_selector_list( + self, + parser, + )?.into() + ) } - } - let pseudo_class = apply_non_ts_list!(pseudo_class_string_parse); + _ => return Err(parser.new_custom_error( + SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()) + )) + }; if self.is_pseudo_class_enabled(&pseudo_class) { Ok(pseudo_class) } else { @@ -468,8 +441,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { name: CowRcStr<'i>, parser: &mut Parser<'i, 't>, ) -> Result<PseudoElement, ParseError<'i>> { - // FIXME: -moz-tree check should probably be ascii-case-insensitive. - if name.starts_with("-moz-tree-") { + if starts_with_ignore_ascii_case(&name, "-moz-tree-") { // Tree pseudo-elements can have zero or more arguments, separated // by either comma or space. let mut args = Vec::new(); diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 1ba850696d1..ff5ae599fcb 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -69,7 +69,7 @@ use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock}; use properties::animated_properties::{AnimationValue, AnimationValueMap}; use properties::style_structs::Font; use rule_tree::CascadeLevel as ServoCascadeLevel; -use selector_parser::{AttrValue, Direction, PseudoClassStringArg}; +use selector_parser::{AttrValue, HorizontalDirection, Lang}; use selectors::{Element, OpaqueElement}; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator}; use selectors::attr::{CaseSensitivity, NamespaceConstraint}; @@ -167,15 +167,14 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> { } #[inline] - fn style_data<'a>(&self) -> &'a CascadeData + fn style_data<'a>(&self) -> Option<&'a CascadeData> where Self: 'a, { - debug_assert!(!self.0.mServoStyles.mPtr.is_null()); - let author_styles = unsafe { - &*(self.0.mServoStyles.mPtr as *const structs::RawServoAuthorStyles - as *const bindings::RawServoAuthorStyles) + (self.0.mServoStyles.mPtr + as *const structs::RawServoAuthorStyles + as *const bindings::RawServoAuthorStyles).as_ref()? }; @@ -187,7 +186,7 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> { author_styles.stylesheets.dirty() ); - &author_styles.data + Some(&author_styles.data) } #[inline] @@ -1717,15 +1716,11 @@ impl<'le> TElement for GeckoElement<'le> { fn match_element_lang( &self, override_lang: Option<Option<AttrValue>>, - value: &PseudoClassStringArg, + value: &Lang, ) -> bool { // Gecko supports :lang() from CSS Selectors 3, which only accepts a // single language tag, and which performs simple dash-prefix matching // on it. - debug_assert!( - value.len() > 0 && value[value.len() - 1] == 0, - "expected value to be null terminated" - ); let override_lang_ptr = match &override_lang { &Some(Some(ref atom)) => atom.as_ptr(), _ => ptr::null_mut(), @@ -1735,7 +1730,7 @@ impl<'le> TElement for GeckoElement<'le> { self.0, override_lang_ptr, override_lang.is_some(), - value.as_ptr(), + value.as_slice().as_ptr(), ) } } @@ -2238,24 +2233,22 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::MozLocaleDir(ref dir) => { let state_bit = DocumentState::NS_DOCUMENT_STATE_RTL_LOCALE; if context.extra_data.document_state.intersects(state_bit) { - // NOTE(emilio): We could still return false for - // Direction::Other(..), but we don't bother. + // NOTE(emilio): We could still return false for values + // other than "ltr" and "rtl", but we don't bother. return !context.in_negation(); } let doc_is_rtl = self.document_state().contains(state_bit); - match **dir { - Direction::Ltr => !doc_is_rtl, - Direction::Rtl => doc_is_rtl, - Direction::Other(..) => false, + match dir.as_horizontal_direction() { + Some(HorizontalDirection::Ltr) => !doc_is_rtl, + Some(HorizontalDirection::Rtl) => doc_is_rtl, + None => false, } }, - NonTSPseudoClass::Dir(ref dir) => match **dir { - Direction::Ltr => self.state().intersects(ElementState::IN_LTR_STATE), - Direction::Rtl => self.state().intersects(ElementState::IN_RTL_STATE), - Direction::Other(..) => false, - }, + NonTSPseudoClass::Dir(ref dir) => { + self.state().intersects(dir.element_state()) + } } } diff --git a/components/style/gecko_bindings/sugar/ownership.rs b/components/style/gecko_bindings/sugar/ownership.rs index 2bc85f53ff7..91c7a504eb1 100644 --- a/components/style/gecko_bindings/sugar/ownership.rs +++ b/components/style/gecko_bindings/sugar/ownership.rs @@ -305,6 +305,15 @@ pub struct OwnedOrNull<GeckoType> { } impl<GeckoType> OwnedOrNull<GeckoType> { + /// Returns a null pointer. + #[inline] + pub fn null() -> Self { + Self { + ptr: ptr::null_mut(), + _marker: PhantomData, + } + } + /// Returns whether this pointer is null. #[inline] pub fn is_null(&self) -> bool { diff --git a/components/style/invalidation/element/element_wrapper.rs b/components/style/invalidation/element/element_wrapper.rs index cb4f79e92e1..e788d2dd876 100644 --- a/components/style/invalidation/element/element_wrapper.rs +++ b/components/style/invalidation/element/element_wrapper.rs @@ -188,8 +188,7 @@ where // support we don't forget to update this code? #[cfg(feature = "gecko")] NonTSPseudoClass::Dir(ref dir) => { - use invalidation::element::invalidation_map::dir_selector_to_state; - let selector_flag = dir_selector_to_state(dir); + let selector_flag = dir.element_state(); if selector_flag.is_empty() { // :dir() with some random argument; does not match. return false; diff --git a/components/style/invalidation/element/invalidation_map.rs b/components/style/invalidation/element/invalidation_map.rs index 67849d89627..26a4609760f 100644 --- a/components/style/invalidation/element/invalidation_map.rs +++ b/components/style/invalidation/element/invalidation_map.rs @@ -10,8 +10,6 @@ use element_state::{DocumentState, ElementState}; use fallible::FallibleVec; use hashglobe::FailedAllocationError; use selector_map::{MaybeCaseInsensitiveHashMap, SelectorMap, SelectorMapEntry}; -#[cfg(feature = "gecko")] -use selector_parser::Direction; use selector_parser::SelectorImpl; use selectors::attr::NamespaceConstraint; use selectors::parser::{Combinator, Component}; @@ -19,20 +17,6 @@ use selectors::parser::{Selector, SelectorIter, Visit}; use selectors::visitor::SelectorVisitor; use smallvec::SmallVec; -#[cfg(feature = "gecko")] -/// Gets the element state relevant to the given `:dir` pseudo-class selector. -pub fn dir_selector_to_state(dir: &Direction) -> ElementState { - match *dir { - Direction::Ltr => ElementState::IN_LTR_STATE, - Direction::Rtl => ElementState::IN_RTL_STATE, - Direction::Other(_) => { - // :dir(something-random) is a valid selector, but shouldn't - // match anything. - ElementState::empty() - }, - } -} - /// Mapping between (partial) CompoundSelectors (and the combinator to their /// right) and the states and attributes they depend on. /// @@ -382,7 +366,7 @@ impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> { self.other_attributes |= pc.is_attr_based(); self.state |= match *pc { #[cfg(feature = "gecko")] - NonTSPseudoClass::Dir(ref dir) => dir_selector_to_state(dir), + NonTSPseudoClass::Dir(ref dir) => dir.element_state(), _ => pc.state_flag(), }; *self.document_state |= pc.document_state_flag(); diff --git a/components/style/invalidation/element/state_and_attributes.rs b/components/style/invalidation/element/state_and_attributes.rs index 1eb022b298a..fa0ccdd8be9 100644 --- a/components/style/invalidation/element/state_and_attributes.rs +++ b/components/style/invalidation/element/state_and_attributes.rs @@ -159,13 +159,18 @@ where // force a restyle here. Matching doesn't depend on the actual visited // state at all, so we can't look at matching results to decide what to // do for this case. - if state_changes.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE) { + if state_changes.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE) && + self.shared_context.visited_styles_enabled + { trace!(" > visitedness change, force subtree restyle"); - // If we get here with visited links disabled, we should probably - // just avoid the restyle and remove the state change here, not only - // as an optimization, but also because it kind of would kill the + // We shouldn't get here with visited links disabled, but it's hard + // to assert in cases where you record a visitedness change and + // afterwards you change some of the stuff (like the pref) that + // changes whether visited styles are enabled. + // + // So just avoid the restyle here, because it kind of would kill the // point of disabling visited links. - debug_assert!(self.shared_context.visited_styles_enabled); + // // We can't just return here because there may also be attribute // changes as well that imply additional hints for siblings. self.data.hint.insert(RestyleHint::restyle_subtree()); diff --git a/components/style/lib.rs b/components/style/lib.rs index 1c3630b0986..03caab33e19 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -157,6 +157,7 @@ pub mod thread_state; pub mod timer; pub mod traversal; pub mod traversal_flags; +pub mod use_counters; #[macro_use] #[allow(non_camel_case_types)] pub mod values; diff --git a/components/style/parser.rs b/components/style/parser.rs index a4b7d816203..db5b8f1e7f9 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -9,6 +9,7 @@ use cssparser::{Parser, SourceLocation, UnicodeRange}; use error_reporting::{ContextualParseError, ParseErrorReporter}; use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator}; use stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData}; +use use_counters::UseCounters; /// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko. #[cfg(feature = "gecko")] @@ -53,6 +54,8 @@ pub struct ParserContext<'a> { error_reporter: Option<&'a ParseErrorReporter>, /// The currently active namespaces. pub namespaces: Option<&'a Namespaces>, + /// The use counters we want to record while parsing style rules, if any. + pub use_counters: Option<&'a UseCounters>, } impl<'a> ParserContext<'a> { @@ -65,8 +68,9 @@ impl<'a> ParserContext<'a> { parsing_mode: ParsingMode, quirks_mode: QuirksMode, error_reporter: Option<&'a ParseErrorReporter>, + use_counters: Option<&'a UseCounters>, ) -> Self { - ParserContext { + Self { stylesheet_origin, url_data, rule_type, @@ -74,6 +78,7 @@ impl<'a> ParserContext<'a> { quirks_mode, error_reporter, namespaces: None, + use_counters, } } @@ -85,6 +90,7 @@ impl<'a> ParserContext<'a> { parsing_mode: ParsingMode, quirks_mode: QuirksMode, error_reporter: Option<&'a ParseErrorReporter>, + use_counters: Option<&'a UseCounters>, ) -> Self { Self::new( Origin::Author, @@ -93,17 +99,19 @@ impl<'a> ParserContext<'a> { parsing_mode, quirks_mode, error_reporter, + use_counters, ) } - /// Create a parser context based on a previous context, but with a modified rule type. + /// Create a parser context based on a previous context, but with a modified + /// rule type. #[inline] pub fn new_with_rule_type( context: &'a ParserContext, rule_type: CssRuleType, namespaces: &'a Namespaces, ) -> ParserContext<'a> { - ParserContext { + Self { stylesheet_origin: context.stylesheet_origin, url_data: context.url_data, rule_type: Some(rule_type), @@ -111,6 +119,7 @@ impl<'a> ParserContext<'a> { quirks_mode: context.quirks_mode, namespaces: Some(namespaces), error_reporter: context.error_reporter, + use_counters: context.use_counters, } } diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index ad5aa75e8f2..56aa2fde4f4 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -138,56 +138,9 @@ impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> { } } -/// Iterator over `PropertyDeclaration` for Importance::Normal. -/// -/// TODO(emilio): This should be replaced by `impl Trait`, returning a -/// filter()ed iterator when available instead, and all the boilerplate below -/// should go. -pub struct NormalDeclarationIterator<'a>(DeclarationImportanceIterator<'a>); - -impl<'a> NormalDeclarationIterator<'a> { - #[inline] - fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self { - NormalDeclarationIterator( - DeclarationImportanceIterator::new(declarations, important) - ) - } -} - -impl<'a> Iterator for NormalDeclarationIterator<'a> { - type Item = &'a PropertyDeclaration; - - #[inline] - fn next(&mut self) -> Option<Self::Item> { - loop { - let (decl, importance) = self.0.iter.next()?; - if !importance { - return Some(decl); - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - self.0.iter.size_hint() - } -} - -impl<'a> DoubleEndedIterator for NormalDeclarationIterator<'a> { - #[inline] - fn next_back(&mut self) -> Option<Self::Item> { - loop { - let (decl, importance) = self.0.iter.next_back()?; - if !importance { - return Some(decl); - } - } - } -} - /// Iterator for AnimationValue to be generated from PropertyDeclarationBlock. pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> { - iter: NormalDeclarationIterator<'a>, + iter: DeclarationImportanceIterator<'a>, context: &'cx mut Context<'cx_a>, default_values: &'a ComputedValues, /// Custom properties in a keyframe if exists. @@ -202,7 +155,7 @@ impl<'a, 'cx, 'cx_a:'cx> AnimationValueIterator<'a, 'cx, 'cx_a> { extra_custom_properties: Option<&'a Arc<::custom_properties::CustomPropertiesMap>>, ) -> AnimationValueIterator<'a, 'cx, 'cx_a> { AnimationValueIterator { - iter: declarations.normal_declaration_iter(), + iter: declarations.declaration_importance_iter(), context, default_values, extra_custom_properties, @@ -215,7 +168,11 @@ impl<'a, 'cx, 'cx_a:'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> { #[inline] fn next(&mut self) -> Option<Self::Item> { loop { - let decl = self.iter.next()?; + let (decl, importance) = self.iter.next()?; + + if importance.important() { + continue; + } let animation = AnimationValue::from_declaration( decl, @@ -287,8 +244,12 @@ impl PropertyDeclarationBlock { /// Iterate over `PropertyDeclaration` for Importance::Normal #[inline] - pub fn normal_declaration_iter(&self) -> NormalDeclarationIterator { - NormalDeclarationIterator::new(&self.declarations, &self.declarations_importance) + pub fn normal_declaration_iter<'a>( + &'a self, + ) -> impl DoubleEndedIterator<Item = &'a PropertyDeclaration> { + self.declaration_importance_iter() + .filter(|(_, importance)| !importance.important()) + .map(|(declaration, _)| declaration) } /// Return an iterator of (AnimatableLonghand, AnimationValue). @@ -344,14 +305,8 @@ impl PropertyDeclarationBlock { } } - self.declarations.iter().enumerate().find(|&(_, decl)| decl.id() == property).map(|(i, decl)| { - let importance = if self.declarations_importance[i] { - Importance::Important - } else { - Importance::Normal - }; - (decl, importance) - }) + self.declaration_importance_iter() + .find(|(declaration, _)| declaration.id() == property) } fn shorthand_to_css( @@ -1248,6 +1203,7 @@ pub fn parse_style_attribute( ParsingMode::DEFAULT, quirks_mode, error_reporter, + None, ); let mut input = ParserInput::new(input); @@ -1275,6 +1231,7 @@ pub fn parse_one_declaration_into( parsing_mode, quirks_mode, error_reporter, + None, ); let mut input = ParserInput::new(input); diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 33a66498b2d..9e9a6835a42 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -3053,7 +3053,7 @@ fn static_assert() { scroll-snap-points-x scroll-snap-points-y scroll-snap-type-x scroll-snap-type-y scroll-snap-coordinate perspective-origin -moz-binding will-change - overscroll-behavior-x overscroll-behavior-y + offset-path overscroll-behavior-x overscroll-behavior-y overflow-clip-box-inline overflow-clip-box-block perspective-origin -moz-binding will-change shape-outside contain touch-action translate @@ -3681,6 +3681,40 @@ fn static_assert() { ${impl_simple_copy("contain", "mContain")} ${impl_simple_type_with_conversion("touch_action")} + + pub fn set_offset_path(&mut self, v: longhands::offset_path::computed_value::T) { + use gecko_bindings::bindings::{Gecko_NewStyleMotion, Gecko_SetStyleMotion}; + use gecko_bindings::structs::StyleShapeSourceType; + use values::generics::basic_shape::FillRule; + use values::specified::OffsetPath; + + let motion = unsafe { Gecko_NewStyleMotion().as_mut().unwrap() }; + match v { + OffsetPath::None => motion.mOffsetPath.mType = StyleShapeSourceType::None, + OffsetPath::Path(p) => { + set_style_svg_path(&mut motion.mOffsetPath, &p, FillRule::Nonzero) + }, + } + unsafe { Gecko_SetStyleMotion(&mut self.gecko.mMotion, motion) }; + } + + pub fn clone_offset_path(&self) -> longhands::offset_path::computed_value::T { + use values::specified::OffsetPath; + match unsafe { self.gecko.mMotion.mPtr.as_ref() } { + None => OffsetPath::none(), + Some(v) => (&v.mOffsetPath).into() + } + } + + pub fn copy_offset_path_from(&mut self, other: &Self) { + use gecko_bindings::bindings::Gecko_CopyStyleMotions; + unsafe { Gecko_CopyStyleMotions(&mut self.gecko.mMotion, other.gecko.mMotion.mPtr) }; + } + + pub fn reset_offset_path(&mut self, other: &Self) { + self.copy_offset_path_from(other); + } + </%self:impl_trait> <%def name="simple_image_array_property(name, shorthand, field_name)"> @@ -4937,14 +4971,43 @@ fn static_assert() { } </%self:impl_trait> +// Set SVGPathData to StyleShapeSource. +fn set_style_svg_path( + shape_source: &mut structs::mozilla::StyleShapeSource, + servo_path: &values::specified::svg_path::SVGPathData, + fill: values::generics::basic_shape::FillRule, +) { + use gecko_bindings::bindings::Gecko_NewStyleSVGPath; + use gecko_bindings::structs::StyleShapeSourceType; + + // Setup type. + shape_source.mType = StyleShapeSourceType::Path; + + // Setup path. + let gecko_path = unsafe { + 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()) { + // unsafe: cbindgen ensures the representation is the same. + *gecko = unsafe { transmute(*servo) }; + } + + // Setup fill-rule. + // unsafe: cbindgen ensures the representation is the same. + gecko_path.mFillRule = unsafe { transmute(fill) }; +} + <%def name="impl_shape_source(ident, gecko_ffi_name)"> pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { use gecko_bindings::bindings::{Gecko_NewBasicShape, Gecko_DestroyShapeSource}; use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleShapeSourceType}; - use gecko_bindings::structs::{StyleFillRule, StyleGeometryBox, StyleShapeSource}; + use gecko_bindings::structs::{StyleGeometryBox, StyleShapeSource}; use gecko::conversions::basic_shape::set_corners_from_radius; use gecko::values::GeckoStyleCoordConvertible; - use values::generics::basic_shape::{BasicShape, FillRule, ShapeSource}; + use values::generics::basic_shape::{BasicShape, ShapeSource}; let ref mut ${ident} = self.gecko.${gecko_ffi_name}; @@ -4976,6 +5039,7 @@ fn static_assert() { ${ident}.mReferenceBox = reference.into(); ${ident}.mType = StyleShapeSourceType::Box; } + ShapeSource::Path(p) => set_style_svg_path(${ident}, &p.path, p.fill), ShapeSource::Shape(servo_shape, maybe_box) => { fn init_shape(${ident}: &mut StyleShapeSource, basic_shape_type: StyleBasicShapeType) -> &mut StyleBasicShape { @@ -5038,11 +5102,8 @@ fn static_assert() { coord.0.to_gecko_style_coord(&mut shape.mCoordinates[2 * i]); coord.1.to_gecko_style_coord(&mut shape.mCoordinates[2 * i + 1]); } - shape.mFillRule = if poly.fill == FillRule::Evenodd { - StyleFillRule::Evenodd - } else { - StyleFillRule::Nonzero - }; + // unsafe: cbindgen ensures the representation is the same. + shape.mFillRule = unsafe { transmute(poly.fill) }; } } diff --git a/components/style/properties/longhands/background.mako.rs b/components/style/properties/longhands/background.mako.rs index 9bb4e03e523..65df61a2e71 100644 --- a/components/style/properties/longhands/background.mako.rs +++ b/components/style/properties/longhands/background.mako.rs @@ -18,14 +18,17 @@ ${helpers.predefined_type( flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", )} -${helpers.predefined_type("background-image", "ImageLayer", +${helpers.predefined_type( + "background-image", + "ImageLayer", initial_value="Either::First(None_)", initial_specified_value="Either::First(None_)", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector="True", animation_value_type="discrete", ignored_when_colors_disabled="True", - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")} + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", +)} % for (axis, direction, initial) in [("x", "Horizontal", "left"), ("y", "Vertical", "top")]: ${helpers.predefined_type( @@ -52,13 +55,15 @@ ${helpers.predefined_type( flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", )} -${helpers.single_keyword("background-attachment", - "scroll fixed" + (" local" if product == "gecko" else ""), - vector=True, - gecko_enum_prefix="StyleImageLayerAttachment", - spec="https://drafts.csswg.org/css-backgrounds/#the-background-attachment", - animation_value_type="discrete", - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")} +${helpers.single_keyword( + "background-attachment", + "scroll fixed" + (" local" if product == "gecko" else ""), + vector=True, + gecko_enum_prefix="StyleImageLayerAttachment", + spec="https://drafts.csswg.org/css-backgrounds/#the-background-attachment", + animation_value_type="discrete", + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", +)} ${helpers.single_keyword( "background-clip", @@ -96,12 +101,14 @@ ${helpers.predefined_type( extra_prefixes="webkit")} // https://drafts.fxtf.org/compositing/#background-blend-mode -${helpers.single_keyword("background-blend-mode", - """normal multiply screen overlay darken lighten color-dodge - color-burn hard-light soft-light difference exclusion hue - saturation color luminosity""", - gecko_constant_prefix="NS_STYLE_BLEND", - gecko_pref="layout.css.background-blend-mode.enabled", - vector=True, products="gecko", animation_value_type="discrete", - spec="https://drafts.fxtf.org/compositing/#background-blend-mode", - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")} +${helpers.single_keyword( + "background-blend-mode", + """normal multiply screen overlay darken lighten color-dodge + color-burn hard-light soft-light difference exclusion hue + saturation color luminosity""", + gecko_constant_prefix="NS_STYLE_BLEND", + gecko_pref="layout.css.background-blend-mode.enabled", + vector=True, products="gecko", animation_value_type="discrete", + spec="https://drafts.fxtf.org/compositing/#background-blend-mode", + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", +)} diff --git a/components/style/properties/longhands/border.mako.rs b/components/style/properties/longhands/border.mako.rs index 901d29728b1..1066dbbc619 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -61,51 +61,70 @@ )} % endfor -${helpers.gecko_keyword_conversion(Keyword('border-style', - "none solid double dotted dashed hidden groove ridge inset outset"), - type="::values::specified::BorderStyle")} +${helpers.gecko_keyword_conversion( + Keyword('border-style', + "none solid double dotted dashed hidden groove ridge inset outset"), + type="::values::specified::BorderStyle", +)} // FIXME(#4126): when gfx supports painting it, make this Size2D<LengthOrPercentage> % for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]: - ${helpers.predefined_type("border-" + corner + "-radius", "BorderCornerRadius", - "computed::BorderCornerRadius::zero()", - "parse", extra_prefixes="webkit", - spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner, - boxed=True, - flags="APPLIES_TO_FIRST_LETTER", - animation_value_type="BorderCornerRadius")} + ${helpers.predefined_type( + "border-" + corner + "-radius", + "BorderCornerRadius", + "computed::BorderCornerRadius::zero()", + "parse", + extra_prefixes="webkit", + spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner, + boxed=True, + flags="APPLIES_TO_FIRST_LETTER", + animation_value_type="BorderCornerRadius", + )} % endfor -${helpers.single_keyword("box-decoration-break", "slice clone", - gecko_enum_prefix="StyleBoxDecorationBreak", - gecko_pref="layout.css.box-decoration-break.enabled", - spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break", - products="gecko", animation_value_type="discrete")} +${helpers.single_keyword( + "box-decoration-break", + "slice clone", + gecko_enum_prefix="StyleBoxDecorationBreak", + gecko_pref="layout.css.box-decoration-break.enabled", + spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break", + products="gecko", + animation_value_type="discrete", +)} -${helpers.single_keyword("-moz-float-edge", "content-box margin-box", - gecko_ffi_name="mFloatEdge", - gecko_enum_prefix="StyleFloatEdge", - products="gecko", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)", - animation_value_type="discrete")} +${helpers.single_keyword( + "-moz-float-edge", + "content-box margin-box", + gecko_ffi_name="mFloatEdge", + gecko_enum_prefix="StyleFloatEdge", + products="gecko", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)", + animation_value_type="discrete", +)} -${helpers.predefined_type("border-image-source", "ImageLayer", +${helpers.predefined_type( + "border-image-source", + "ImageLayer", initial_value="Either::First(None_)", initial_specified_value="Either::First(None_)", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector=False, animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER", - boxed=True)} + boxed=True, +)} -${helpers.predefined_type("border-image-outset", "LengthOrNumberRect", +${helpers.predefined_type( + "border-image-outset", + "LengthOrNumberRect", parse_method="parse_non_negative", initial_value="computed::LengthOrNumberRect::all(computed::LengthOrNumber::zero())", initial_specified_value="specified::LengthOrNumberRect::all(specified::LengthOrNumber::zero())", spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset", animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER", - boxed=True)} + boxed=True, +)} ${helpers.predefined_type( "border-image-repeat", @@ -117,21 +136,27 @@ ${helpers.predefined_type( flags="APPLIES_TO_FIRST_LETTER", )} -${helpers.predefined_type("border-image-width", "BorderImageWidth", +${helpers.predefined_type( + "border-image-width", + "BorderImageWidth", initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())", initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())", spec="https://drafts.csswg.org/css-backgrounds/#border-image-width", animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER", - boxed=True)} + boxed=True, +)} -${helpers.predefined_type("border-image-slice", "BorderImageSlice", +${helpers.predefined_type( + "border-image-slice", + "BorderImageSlice", initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()", initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage::new(1.)).into()", spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice", animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER", - boxed=True)} + boxed=True, +)} #[cfg(feature = "gecko")] impl ::values::computed::BorderImageWidth { @@ -155,8 +180,9 @@ impl ::values::computed::BorderImageWidth { % endfor } - pub fn from_gecko_rect(sides: &::gecko_bindings::structs::nsStyleSides) - -> Option<::values::computed::BorderImageWidth> { + pub fn from_gecko_rect( + sides: &::gecko_bindings::structs::nsStyleSides, + ) -> Option<::values::computed::BorderImageWidth> { use gecko_bindings::structs::nsStyleUnit::{eStyleUnit_Factor, eStyleUnit_Auto}; use gecko_bindings::sugar::ns_style_coord::CoordData; use gecko::values::GeckoStyleCoordConvertible; diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 6b6bcf9cbe3..7dfc15cd14e 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -23,36 +23,25 @@ ${helpers.predefined_type( needs_context=product == "gecko" )} -// FIXME(emilio): Listing all the display values here is very unfortunate, we should teach C++ to use the -// Rust enum directly, or generate the conversions to `StyleDisplay`. -${helpers.gecko_keyword_conversion( - Keyword('display', """ - inline block inline-block - table inline-table table-row-group table-header-group table-footer-group - table-row table-column-group table-column table-cell table-caption - list-item none flex inline-flex grid inline-grid ruby ruby-base ruby-base-container - ruby-text ruby-text-container contents flow-root -webkit-box - -webkit-inline-box -moz-box -moz-inline-box -moz-grid -moz-inline-grid - -moz-grid-group -moz-grid-line -moz-stack -moz-inline-stack -moz-deck - -moz-popup -moz-groupbox - """, - gecko_enum_prefix='StyleDisplay', - gecko_strip_moz_prefix=False), - type="::values::specified::Display" -)} - -${helpers.single_keyword("-moz-top-layer", "none top", - gecko_constant_prefix="NS_STYLE_TOP_LAYER", - gecko_ffi_name="mTopLayer", - products="gecko", animation_value_type="none", - enabled_in="ua", - spec="Internal (not web-exposed)")} - -${helpers.single_keyword("position", "static absolute relative fixed sticky", - animation_value_type="discrete", - flags="CREATES_STACKING_CONTEXT ABSPOS_CB", - spec="https://drafts.csswg.org/css-position/#position-property", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.single_keyword( + "-moz-top-layer", + "none top", + gecko_constant_prefix="NS_STYLE_TOP_LAYER", + gecko_ffi_name="mTopLayer", + products="gecko", + animation_value_type="none", + enabled_in="ua", + spec="Internal (not web-exposed)", +)} + +${helpers.single_keyword( + "position", + "static absolute relative fixed sticky", + animation_value_type="discrete", + flags="CREATES_STACKING_CONTEXT ABSPOS_CB", + spec="https://drafts.csswg.org/css-position/#position-property", + servo_restyle_damage="rebuild_and_reflow", +)} ${helpers.predefined_type( "float", @@ -64,7 +53,7 @@ ${helpers.predefined_type( needs_context=False, flags="APPLIES_TO_FIRST_LETTER", servo_restyle_damage="rebuild_and_reflow", - gecko_ffi_name="mFloat" + gecko_ffi_name="mFloat", )} ${helpers.predefined_type( @@ -75,7 +64,7 @@ ${helpers.predefined_type( needs_context=False, gecko_ffi_name="mBreakType", spec="https://drafts.csswg.org/css-box/#propdef-clear", - servo_restyle_damage="rebuild_and_reflow" + servo_restyle_damage="rebuild_and_reflow", )} ${helpers.predefined_type( @@ -85,7 +74,7 @@ ${helpers.predefined_type( animation_value_type="ComputedValue", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", spec="https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align", - servo_restyle_damage = "reflow" + servo_restyle_damage = "reflow", )} // CSS 2.1, Section 11 - Visual effects @@ -118,14 +107,17 @@ ${helpers.single_keyword("-servo-overflow-clip-box", "padding-box content-box", // FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`. // // We allow it to apply to placeholders for UA sheets, which set it !important. -${helpers.single_keyword("overflow-x", "visible hidden scroll auto", - animation_value_type="discrete", - extra_gecko_values="-moz-hidden-unscrollable", - custom_consts=overflow_custom_consts, - gecko_constant_prefix="NS_STYLE_OVERFLOW", - flags="APPLIES_TO_PLACEHOLDER", - spec="https://drafts.csswg.org/css-overflow/#propdef-overflow-x", - servo_restyle_damage = "reflow")} +${helpers.single_keyword( + "overflow-x", + "visible hidden scroll auto", + animation_value_type="discrete", + extra_gecko_values="-moz-hidden-unscrollable", + custom_consts=overflow_custom_consts, + gecko_constant_prefix="NS_STYLE_OVERFLOW", + flags="APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-overflow/#propdef-overflow-x", + servo_restyle_damage = "reflow", +)} // FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`. // @@ -139,26 +131,30 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", <% transition_extra_prefixes = "moz:layout.css.prefixes.transitions webkit" %> -${helpers.predefined_type("transition-duration", - "Time", - "computed::Time::zero()", - initial_specified_value="specified::Time::zero()", - parse_method="parse_non_negative", - vector=True, - need_index=True, - animation_value_type="none", - extra_prefixes=transition_extra_prefixes, - spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration")} - -${helpers.predefined_type("transition-timing-function", - "TimingFunction", - "computed::TimingFunction::ease()", - initial_specified_value="specified::TimingFunction::ease()", - vector=True, - need_index=True, - animation_value_type="none", - extra_prefixes=transition_extra_prefixes, - spec="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function")} +${helpers.predefined_type( + "transition-duration", + "Time", + "computed::Time::zero()", + initial_specified_value="specified::Time::zero()", + parse_method="parse_non_negative", + vector=True, + need_index=True, + animation_value_type="none", + extra_prefixes=transition_extra_prefixes, + spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration", +)} + +${helpers.predefined_type( + "transition-timing-function", + "TimingFunction", + "computed::TimingFunction::ease()", + initial_specified_value="specified::TimingFunction::ease()", + vector=True, + need_index=True, + animation_value_type="none", + extra_prefixes=transition_extra_prefixes, + spec="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function", +)} ${helpers.predefined_type( "transition-property", @@ -173,16 +169,17 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-transitions/#propdef-transition-property", )} -${helpers.predefined_type("transition-delay", - "Time", - "computed::Time::zero()", - initial_specified_value="specified::Time::zero()", - vector=True, - need_index=True, - animation_value_type="none", - extra_prefixes=transition_extra_prefixes, - spec="https://drafts.csswg.org/css-transitions/#propdef-transition-delay")} - +${helpers.predefined_type( + "transition-delay", + "Time", + "computed::Time::zero()", + initial_specified_value="specified::Time::zero()", + vector=True, + need_index=True, + animation_value_type="none", + extra_prefixes=transition_extra_prefixes, + spec="https://drafts.csswg.org/css-transitions/#propdef-transition-delay", +)} <% animation_extra_prefixes = "moz:layout.css.prefixes.animations webkit" %> @@ -199,29 +196,33 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-animations/#propdef-animation-name", )} -${helpers.predefined_type("animation-duration", - "Time", - "computed::Time::zero()", - initial_specified_value="specified::Time::zero()", - parse_method="parse_non_negative", - vector=True, - need_index=True, - animation_value_type="none", - extra_prefixes=animation_extra_prefixes, - spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration")} +${helpers.predefined_type( + "animation-duration", + "Time", + "computed::Time::zero()", + initial_specified_value="specified::Time::zero()", + parse_method="parse_non_negative", + vector=True, + need_index=True, + animation_value_type="none", + extra_prefixes=animation_extra_prefixes, + spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration", +)} // animation-timing-function is the exception to the rule for allowed_in_keyframe_block: // https://drafts.csswg.org/css-animations/#keyframes -${helpers.predefined_type("animation-timing-function", - "TimingFunction", - "computed::TimingFunction::ease()", - initial_specified_value="specified::TimingFunction::ease()", - vector=True, - need_index=True, - animation_value_type="none", - extra_prefixes=animation_extra_prefixes, - allowed_in_keyframe_block=True, - spec="https://drafts.csswg.org/css-transitions/#propdef-animation-timing-function")} +${helpers.predefined_type( + "animation-timing-function", + "TimingFunction", + "computed::TimingFunction::ease()", + initial_specified_value="specified::TimingFunction::ease()", + vector=True, + need_index=True, + animation_value_type="none", + extra_prefixes=animation_extra_prefixes, + allowed_in_keyframe_block=True, + spec="https://drafts.csswg.org/css-transitions/#propdef-animation-timing-function", +)} ${helpers.predefined_type( "animation-iteration-count", @@ -237,46 +238,54 @@ ${helpers.predefined_type( )} <% animation_direction_custom_consts = { "alternate-reverse": "Alternate_reverse" } %> -${helpers.single_keyword("animation-direction", - "normal reverse alternate alternate-reverse", - need_index=True, - animation_value_type="none", - vector=True, - gecko_enum_prefix="PlaybackDirection", - custom_consts=animation_direction_custom_consts, - extra_prefixes=animation_extra_prefixes, - spec="https://drafts.csswg.org/css-animations/#propdef-animation-direction", - allowed_in_keyframe_block=False)} - -${helpers.single_keyword("animation-play-state", - "running paused", - need_index=True, - animation_value_type="none", - vector=True, - extra_prefixes=animation_extra_prefixes, - spec="https://drafts.csswg.org/css-animations/#propdef-animation-play-state", - allowed_in_keyframe_block=False)} - -${helpers.single_keyword("animation-fill-mode", - "none forwards backwards both", - need_index=True, - animation_value_type="none", - vector=True, - gecko_enum_prefix="FillMode", - extra_prefixes=animation_extra_prefixes, - spec="https://drafts.csswg.org/css-animations/#propdef-animation-fill-mode", - allowed_in_keyframe_block=False)} - -${helpers.predefined_type("animation-delay", - "Time", - "computed::Time::zero()", - initial_specified_value="specified::Time::zero()", - vector=True, - need_index=True, - animation_value_type="none", - extra_prefixes=animation_extra_prefixes, - spec="https://drafts.csswg.org/css-animations/#propdef-animation-delay", - allowed_in_keyframe_block=False)} +${helpers.single_keyword( + "animation-direction", + "normal reverse alternate alternate-reverse", + need_index=True, + animation_value_type="none", + vector=True, + gecko_enum_prefix="PlaybackDirection", + custom_consts=animation_direction_custom_consts, + extra_prefixes=animation_extra_prefixes, + spec="https://drafts.csswg.org/css-animations/#propdef-animation-direction", + allowed_in_keyframe_block=False, +)} + +${helpers.single_keyword( + "animation-play-state", + "running paused", + need_index=True, + animation_value_type="none", + vector=True, + extra_prefixes=animation_extra_prefixes, + spec="https://drafts.csswg.org/css-animations/#propdef-animation-play-state", + allowed_in_keyframe_block=False, +)} + +${helpers.single_keyword( + "animation-fill-mode", + "none forwards backwards both", + need_index=True, + animation_value_type="none", + vector=True, + gecko_enum_prefix="FillMode", + extra_prefixes=animation_extra_prefixes, + spec="https://drafts.csswg.org/css-animations/#propdef-animation-fill-mode", + allowed_in_keyframe_block=False, +)} + +${helpers.predefined_type( + "animation-delay", + "Time", + "computed::Time::zero()", + initial_specified_value="specified::Time::zero()", + vector=True, + need_index=True, + animation_value_type="none", + extra_prefixes=animation_extra_prefixes, + spec="https://drafts.csswg.org/css-animations/#propdef-animation-delay", + allowed_in_keyframe_block=False, +)} % for axis in ["x", "y"]: ${helpers.predefined_type( @@ -290,14 +299,16 @@ ${helpers.predefined_type("animation-delay", )} % endfor -${helpers.predefined_type("scroll-snap-destination", - "Position", - "computed::Position::zero()", - products="gecko", - gecko_pref="layout.css.scroll-snap.enabled", - boxed=True, - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)", - animation_value_type="discrete")} +${helpers.predefined_type( + "scroll-snap-destination", + "Position", + "computed::Position::zero()", + products="gecko", + gecko_pref="layout.css.scroll-snap.enabled", + boxed=True, + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)", + animation_value_type="discrete", +)} ${helpers.predefined_type( "scroll-snap-coordinate", @@ -308,7 +319,7 @@ ${helpers.predefined_type( gecko_pref="layout.css.scroll-snap.enabled", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)", animation_value_type="discrete", - allow_empty="NotInitial" + allow_empty="NotInitial", )} <% transform_extra_prefixes = "moz:layout.css.prefixes.transforms webkit" %> @@ -323,26 +334,32 @@ ${helpers.predefined_type( flags="CREATES_STACKING_CONTEXT FIXPOS_CB \ GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-transforms/#propdef-transform", - servo_restyle_damage="reflow_out_of_flow" + servo_restyle_damage="reflow_out_of_flow", )} -${helpers.predefined_type("rotate", "Rotate", - "generics::transform::Rotate::None", - animation_value_type="ComputedValue", - boxed=True, - flags="CREATES_STACKING_CONTEXT FIXPOS_CB", - gecko_pref="layout.css.individual-transform.enabled", - spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms", - servo_restyle_damage = "reflow_out_of_flow")} +${helpers.predefined_type( + "rotate", + "Rotate", + "generics::transform::Rotate::None", + animation_value_type="ComputedValue", + boxed=True, + flags="CREATES_STACKING_CONTEXT FIXPOS_CB", + gecko_pref="layout.css.individual-transform.enabled", + spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms", + servo_restyle_damage = "reflow_out_of_flow", +)} -${helpers.predefined_type("scale", "Scale", - "generics::transform::Scale::None", - animation_value_type="ComputedValue", - boxed=True, - flags="CREATES_STACKING_CONTEXT FIXPOS_CB", - gecko_pref="layout.css.individual-transform.enabled", - spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms", - servo_restyle_damage = "reflow_out_of_flow")} +${helpers.predefined_type( + "scale", + "Scale", + "generics::transform::Scale::None", + animation_value_type="ComputedValue", + boxed=True, + flags="CREATES_STACKING_CONTEXT FIXPOS_CB", + gecko_pref="layout.css.individual-transform.enabled", + spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms", + servo_restyle_damage = "reflow_out_of_flow", +)} ${helpers.predefined_type( "translate", @@ -353,17 +370,31 @@ ${helpers.predefined_type( flags="CREATES_STACKING_CONTEXT FIXPOS_CB GETCS_NEEDS_LAYOUT_FLUSH", gecko_pref="layout.css.individual-transform.enabled", spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms", - servo_restyle_damage="reflow_out_of_flow" + servo_restyle_damage="reflow_out_of_flow", +)} + +// Motion Path Module Level 1 +${helpers.predefined_type( + "offset-path", + "OffsetPath", + "computed::OffsetPath::none()", + products="gecko", + animation_value_type="none", + gecko_pref="layout.css.motion-path.enabled", + flags="CREATES_STACKING_CONTEXT FIXPOS_CB", + spec="https://drafts.fxtf.org/motion-1/#offset-path-property", )} // CSSOM View Module // https://www.w3.org/TR/cssom-view-1/ -${helpers.single_keyword("scroll-behavior", - "auto smooth", - gecko_pref="layout.css.scroll-behavior.property-enabled", - products="gecko", - spec="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior", - animation_value_type="discrete")} +${helpers.single_keyword( + "scroll-behavior", + "auto smooth", + gecko_pref="layout.css.scroll-behavior.property-enabled", + products="gecko", + spec="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior", + animation_value_type="discrete", +)} % for axis in ["x", "y"]: ${helpers.predefined_type( @@ -374,7 +405,7 @@ ${helpers.single_keyword("scroll-behavior", needs_context=False, gecko_pref="layout.css.scroll-snap.enabled", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type-x)", - animation_value_type="discrete" + animation_value_type="discrete", )} % endfor @@ -387,38 +418,48 @@ ${helpers.single_keyword("scroll-behavior", needs_context=False, gecko_pref="layout.css.overscroll-behavior.enabled", spec="https://wicg.github.io/overscroll-behavior/#overscroll-behavior-properties", - animation_value_type="discrete" + animation_value_type="discrete", )} % endfor // Compositing and Blending Level 1 // http://www.w3.org/TR/compositing-1/ -${helpers.single_keyword("isolation", - "auto isolate", - products="gecko", - gecko_pref="layout.css.isolation.enabled", - spec="https://drafts.fxtf.org/compositing/#isolation", - flags="CREATES_STACKING_CONTEXT", - animation_value_type="discrete")} +${helpers.single_keyword( + "isolation", + "auto isolate", + products="gecko", + gecko_pref="layout.css.isolation.enabled", + spec="https://drafts.fxtf.org/compositing/#isolation", + flags="CREATES_STACKING_CONTEXT", + animation_value_type="discrete", +)} // TODO add support for logical values recto and verso -${helpers.single_keyword("page-break-after", - "auto always avoid left right", - products="gecko", - spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-after", - animation_value_type="discrete")} -${helpers.single_keyword("page-break-before", - "auto always avoid left right", - products="gecko", - spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-before", - animation_value_type="discrete")} -${helpers.single_keyword("page-break-inside", - "auto avoid", - products="gecko", - gecko_ffi_name="mBreakInside", - gecko_constant_prefix="NS_STYLE_PAGE_BREAK", - spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-inside", - animation_value_type="discrete")} +${helpers.single_keyword( + "page-break-after", + "auto always avoid left right", + products="gecko", + spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-after", + animation_value_type="discrete", +)} + +${helpers.single_keyword( + "page-break-before", + "auto always avoid left right", + products="gecko", + spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-before", + animation_value_type="discrete", +)} + +${helpers.single_keyword( + "page-break-inside", + "auto avoid", + products="gecko", + gecko_ffi_name="mBreakInside", + gecko_constant_prefix="NS_STYLE_PAGE_BREAK", + spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-inside", + animation_value_type="discrete", +)} // CSS Basic User Interface Module Level 3 // http://dev.w3.org/csswg/css-ui @@ -462,20 +503,24 @@ ${helpers.predefined_type( servo_restyle_damage="reflow_out_of_flow" )} -${helpers.single_keyword("backface-visibility", - "visible hidden", - spec="https://drafts.csswg.org/css-transforms/#backface-visibility-property", - extra_prefixes=transform_extra_prefixes, - animation_value_type="discrete")} +${helpers.single_keyword( + "backface-visibility", + "visible hidden", + spec="https://drafts.csswg.org/css-transforms/#backface-visibility-property", + extra_prefixes=transform_extra_prefixes, + animation_value_type="discrete", +)} -${helpers.single_keyword("transform-box", - "border-box fill-box view-box", - gecko_enum_prefix="StyleGeometryBox", - products="gecko", - gecko_pref="svg.transform-box.enabled", - spec="https://drafts.csswg.org/css-transforms/#transform-box", - gecko_inexhaustive="True", - animation_value_type="discrete")} +${helpers.single_keyword( + "transform-box", + "border-box fill-box view-box", + gecko_enum_prefix="StyleGeometryBox", + products="gecko", + gecko_pref="svg.transform-box.enabled", + spec="https://drafts.csswg.org/css-transforms/#transform-box", + gecko_inexhaustive="True", + animation_value_type="discrete", +)} ${helpers.predefined_type( "transform-style", @@ -499,17 +544,19 @@ ${helpers.predefined_type( boxed=True, flags="GETCS_NEEDS_LAYOUT_FLUSH", spec="https://drafts.csswg.org/css-transforms/#transform-origin-property", - servo_restyle_damage="reflow_out_of_flow" + servo_restyle_damage="reflow_out_of_flow", )} -${helpers.predefined_type("contain", - "Contain", - "specified::Contain::empty()", - animation_value_type="discrete", - products="gecko", - flags="CREATES_STACKING_CONTEXT FIXPOS_CB", - gecko_pref="layout.css.contain.enabled", - spec="https://drafts.csswg.org/css-contain/#contain-property")} +${helpers.predefined_type( + "contain", + "Contain", + "specified::Contain::empty()", + animation_value_type="none", + products="gecko", + flags="CREATES_STACKING_CONTEXT FIXPOS_CB", + gecko_pref="layout.css.contain.enabled", + spec="https://drafts.csswg.org/css-contain/#contain-property", +)} // Non-standard ${helpers.predefined_type( @@ -522,27 +569,33 @@ ${helpers.predefined_type( animation_value_type="discrete", )} -${helpers.predefined_type("-moz-binding", "url::UrlOrNone", "computed::url::UrlOrNone::none()", - products="gecko", - animation_value_type="none", - gecko_ffi_name="mBinding", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding)")} +${helpers.predefined_type( + "-moz-binding", + "url::UrlOrNone", + "computed::url::UrlOrNone::none()", + products="gecko", + animation_value_type="none", + gecko_ffi_name="mBinding", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding)", +)} -${helpers.single_keyword("-moz-orient", - "inline block horizontal vertical", - products="gecko", - gecko_ffi_name="mOrient", - gecko_enum_prefix="StyleOrient", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-orient)", - animation_value_type="discrete")} +${helpers.single_keyword( + "-moz-orient", + "inline block horizontal vertical", + products="gecko", + gecko_ffi_name="mOrient", + gecko_enum_prefix="StyleOrient", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-orient)", + animation_value_type="discrete", +)} ${helpers.predefined_type( "will-change", "WillChange", "computed::WillChange::auto()", products="gecko", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-will-change/#will-change" + animation_value_type="none", + spec="https://drafts.csswg.org/css-will-change/#will-change", )} ${helpers.predefined_type( diff --git a/components/style/properties/longhands/color.mako.rs b/components/style/properties/longhands/color.mako.rs index a4d1830190a..d53632835b6 100644 --- a/components/style/properties/longhands/color.mako.rs +++ b/components/style/properties/longhands/color.mako.rs @@ -15,7 +15,7 @@ ${helpers.predefined_type( animation_value_type="AnimatedRGBA", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", ignored_when_colors_disabled="True", - spec="https://drafts.csswg.org/css-color/#color" + spec="https://drafts.csswg.org/css-color/#color", )} // FIXME(#15973): Add servo support for system colors @@ -96,8 +96,10 @@ pub mod system_colors { #[inline] fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { unsafe { - Gecko_GetLookAndFeelSystemColor(*self as i32, - cx.device().pres_context()) + Gecko_GetLookAndFeelSystemColor( + *self as i32, + cx.device().pres_context(), + ) } } diff --git a/components/style/properties/longhands/column.mako.rs b/components/style/properties/longhands/column.mako.rs index e7305e5b4f3..adc9371e99f 100644 --- a/components/style/properties/longhands/column.mako.rs +++ b/components/style/properties/longhands/column.mako.rs @@ -6,16 +6,17 @@ <% data.new_style_struct("Column", inherited=False) %> -${helpers.predefined_type("column-width", - "length::NonNegativeLengthOrAuto", - "Either::Second(Auto)", - initial_specified_value="Either::Second(Auto)", - extra_prefixes="moz", - animation_value_type="NonNegativeLengthOrAuto", - servo_pref="layout.columns.enabled", - spec="https://drafts.csswg.org/css-multicol/#propdef-column-width", - servo_restyle_damage="rebuild_and_reflow")} - +${helpers.predefined_type( + "column-width", + "length::NonNegativeLengthOrAuto", + "Either::Second(Auto)", + initial_specified_value="Either::Second(Auto)", + extra_prefixes="moz", + animation_value_type="NonNegativeLengthOrAuto", + servo_pref="layout.columns.enabled", + spec="https://drafts.csswg.org/css-multicol/#propdef-column-width", + servo_restyle_damage="rebuild_and_reflow", +)} ${helpers.predefined_type( "column-count", @@ -29,22 +30,27 @@ ${helpers.predefined_type( servo_restyle_damage="rebuild_and_reflow", )} +${helpers.single_keyword( + "column-fill", + "balance auto", + extra_prefixes="moz", + products="gecko", + animation_value_type="discrete", + gecko_enum_prefix="StyleColumnFill", + spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill", +)} - -${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz", - products="gecko", animation_value_type="discrete", - gecko_enum_prefix="StyleColumnFill", - spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill")} - -${helpers.predefined_type("column-rule-width", - "BorderSideWidth", - "::values::computed::NonNegativeLength::new(3.)", - initial_specified_value="specified::BorderSideWidth::Medium", - computed_type="::values::computed::NonNegativeLength", - products="gecko", - spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width", - animation_value_type="NonNegativeLength", - extra_prefixes="moz")} +${helpers.predefined_type( + "column-rule-width", + "BorderSideWidth", + "::values::computed::NonNegativeLength::new(3.)", + initial_specified_value="specified::BorderSideWidth::Medium", + computed_type="::values::computed::NonNegativeLength", + products="gecko", + spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width", + animation_value_type="NonNegativeLength", + extra_prefixes="moz", +)} // https://drafts.csswg.org/css-multicol-1/#crc ${helpers.predefined_type( @@ -59,16 +65,23 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-color", )} -${helpers.single_keyword("column-span", "none all", - products="gecko", animation_value_type="discrete", - gecko_enum_prefix="StyleColumnSpan", - gecko_pref="layout.css.column-span.enabled", - spec="https://drafts.csswg.org/css-multicol/#propdef-column-span", - extra_prefixes="moz:layout.css.column-span.enabled")} +${helpers.single_keyword( + "column-span", + "none all", + products="gecko", + animation_value_type="discrete", + gecko_enum_prefix="StyleColumnSpan", + gecko_pref="layout.css.column-span.enabled", + spec="https://drafts.csswg.org/css-multicol/#propdef-column-span", + extra_prefixes="moz:layout.css.column-span.enabled", +)} -${helpers.single_keyword("column-rule-style", - "none hidden dotted dashed solid double groove ridge inset outset", - products="gecko", extra_prefixes="moz", - gecko_constant_prefix="NS_STYLE_BORDER_STYLE", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-style")} +${helpers.single_keyword( + "column-rule-style", + "none hidden dotted dashed solid double groove ridge inset outset", + products="gecko", + extra_prefixes="moz", + gecko_constant_prefix="NS_STYLE_BORDER_STYLE", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-style", +)} diff --git a/components/style/properties/longhands/counters.mako.rs b/components/style/properties/longhands/counters.mako.rs index ececf58310f..4a8fd0bb6d1 100644 --- a/components/style/properties/longhands/counters.mako.rs +++ b/components/style/properties/longhands/counters.mako.rs @@ -6,13 +6,15 @@ <% data.new_style_struct("Counters", inherited=False, gecko_name="Content") %> -${helpers.predefined_type("content", - "Content", - "computed::Content::normal()", - initial_specified_value="specified::Content::normal()", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-content/#propdef-content", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.predefined_type( + "content", + "Content", + "computed::Content::normal()", + initial_specified_value="specified::Content::normal()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-content/#propdef-content", + servo_restyle_damage="rebuild_and_reflow", +)} ${helpers.predefined_type( "counter-increment", @@ -20,7 +22,7 @@ ${helpers.predefined_type( initial_value="Default::default()", animation_value_type="discrete", spec="https://drafts.csswg.org/css-lists/#propdef-counter-increment", - servo_restyle_damage="rebuild_and_reflow" + servo_restyle_damage="rebuild_and_reflow", )} ${helpers.predefined_type( @@ -29,5 +31,5 @@ ${helpers.predefined_type( initial_value="Default::default()", animation_value_type="discrete", spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset", - servo_restyle_damage="rebuild_and_reflow" + servo_restyle_damage="rebuild_and_reflow", )} diff --git a/components/style/properties/longhands/effects.mako.rs b/components/style/properties/longhands/effects.mako.rs index 674340c391a..6649dc4d55b 100644 --- a/components/style/properties/longhands/effects.mako.rs +++ b/components/style/properties/longhands/effects.mako.rs @@ -15,7 +15,7 @@ ${helpers.predefined_type( flags="CREATES_STACKING_CONTEXT APPLIES_TO_PLACEHOLDER \ CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-color/#opacity", - servo_restyle_damage = "reflow_out_of_flow" + servo_restyle_damage = "reflow_out_of_flow", )} ${helpers.predefined_type( @@ -31,13 +31,15 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-backgrounds/#box-shadow", )} -${helpers.predefined_type("clip", - "ClipRectOrAuto", - "computed::ClipRectOrAuto::auto()", - animation_value_type="ComputedValue", - boxed=True, - allow_quirks=True, - spec="https://drafts.fxtf.org/css-masking/#clip-property")} +${helpers.predefined_type( + "clip", + "ClipRectOrAuto", + "computed::ClipRectOrAuto::auto()", + animation_value_type="ComputedValue", + boxed=True, + allow_quirks=True, + spec="https://drafts.fxtf.org/css-masking/#clip-property", +)} ${helpers.predefined_type( "filter", @@ -52,11 +54,14 @@ ${helpers.predefined_type( spec="https://drafts.fxtf.org/filters/#propdef-filter", )} -${helpers.single_keyword("mix-blend-mode", - """normal multiply screen overlay darken lighten color-dodge - color-burn hard-light soft-light difference exclusion hue - saturation color luminosity""", gecko_constant_prefix="NS_STYLE_BLEND", - animation_value_type="discrete", - flags="CREATES_STACKING_CONTEXT", - gecko_pref="layout.css.mix-blend-mode.enabled", - spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode")} +${helpers.single_keyword( + "mix-blend-mode", + """normal multiply screen overlay darken lighten color-dodge + color-burn hard-light soft-light difference exclusion hue + saturation color luminosity""", + gecko_constant_prefix="NS_STYLE_BLEND", + animation_value_type="discrete", + flags="CREATES_STACKING_CONTEXT", + gecko_pref="layout.css.mix-blend-mode.enabled", + spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode", +)} diff --git a/components/style/properties/longhands/inherited_box.mako.rs b/components/style/properties/longhands/inherited_box.mako.rs index 4482931fd7a..d810ec3d29a 100644 --- a/components/style/properties/longhands/inherited_box.mako.rs +++ b/components/style/properties/longhands/inherited_box.mako.rs @@ -40,15 +40,12 @@ ${helpers.single_keyword( servo_restyle_damage="rebuild_and_reflow", )} -// TODO(emilio): Should text-orientation be non-animatable? It affects the -// WritingMode value, but not the logical -> physical mapping of properties, -// which is the reason direction / writing-mode are non-animatable. ${helpers.single_keyword( "text-orientation", "mixed upright sideways", extra_gecko_aliases="sideways-right=sideways", products="gecko", - animation_value_type="discrete", + animation_value_type="none", spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation", )} diff --git a/components/style/properties/longhands/inherited_svg.mako.rs b/components/style/properties/longhands/inherited_svg.mako.rs index b3bc12b1367..40c61b10129 100644 --- a/components/style/properties/longhands/inherited_svg.mako.rs +++ b/components/style/properties/longhands/inherited_svg.mako.rs @@ -6,61 +6,81 @@ // SVG 1.1 (Second Edition) // https://www.w3.org/TR/SVG/ -<% data.new_style_struct("InheritedSVG", - inherited=True, - gecko_name="SVG") %> +<% data.new_style_struct("InheritedSVG", inherited=True, gecko_name="SVG") %> // Section 10 - Text -${helpers.single_keyword("text-anchor", - "start middle end", - products="gecko", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty")} +${helpers.single_keyword( + "text-anchor", + "start middle end", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty", +)} // Section 11 - Painting: Filling, Stroking and Marker Symbols -${helpers.single_keyword("color-interpolation", - "srgb auto linearrgb", - products="gecko", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty")} - -${helpers.single_keyword("color-interpolation-filters", "linearrgb auto srgb", - products="gecko", - gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty")} +${helpers.single_keyword( + "color-interpolation", + "srgb auto linearrgb", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty", +)} + +${helpers.single_keyword( + "color-interpolation-filters", + "linearrgb auto srgb", + products="gecko", + gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty", +)} ${helpers.predefined_type( - "fill", "SVGPaint", + "fill", + "SVGPaint", "::values::computed::SVGPaint::black()", products="gecko", animation_value_type="IntermediateSVGPaint", boxed=True, - spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")} + spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint", +)} -${helpers.predefined_type("fill-opacity", "SVGOpacity", "Default::default()", - products="gecko", animation_value_type="ComputedValue", - spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")} +${helpers.predefined_type( + "fill-opacity", + "SVGOpacity", + "Default::default()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty", +)} -${helpers.single_keyword("fill-rule", "nonzero evenodd", - gecko_enum_prefix="StyleFillRule", - products="gecko", animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty")} +${helpers.single_keyword( + "fill-rule", + "nonzero evenodd", + gecko_enum_prefix="StyleFillRule", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty", +)} -${helpers.single_keyword("shape-rendering", - "auto optimizespeed crispedges geometricprecision", - products="gecko", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty")} +${helpers.single_keyword( + "shape-rendering", + "auto optimizespeed crispedges geometricprecision", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty", +)} ${helpers.predefined_type( - "stroke", "SVGPaint", + "stroke", + "SVGPaint", "Default::default()", products="gecko", animation_value_type="IntermediateSVGPaint", boxed=True, - spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")} + spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint", +)} ${helpers.predefined_type( "stroke-width", "SVGWidth", @@ -70,23 +90,39 @@ ${helpers.predefined_type( spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth", )} -${helpers.single_keyword("stroke-linecap", "butt round square", - products="gecko", animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")} +${helpers.single_keyword( + "stroke-linecap", + "butt round square", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty", +)} -${helpers.single_keyword("stroke-linejoin", "miter round bevel", - products="gecko", animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")} +${helpers.single_keyword( + "stroke-linejoin", + "miter round bevel", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty", +)} -${helpers.predefined_type("stroke-miterlimit", "GreaterThanOrEqualToOneNumber", - "From::from(4.0)", - products="gecko", - animation_value_type="::values::computed::GreaterThanOrEqualToOneNumber", - spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")} +${helpers.predefined_type( + "stroke-miterlimit", + "GreaterThanOrEqualToOneNumber", + "From::from(4.0)", + products="gecko", + animation_value_type="::values::computed::GreaterThanOrEqualToOneNumber", + spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty", +)} -${helpers.predefined_type("stroke-opacity", "SVGOpacity", "Default::default()", - products="gecko", animation_value_type="ComputedValue", - spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")} +${helpers.predefined_type( + "stroke-opacity", + "SVGOpacity", + "Default::default()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty", +)} ${helpers.predefined_type( "stroke-dasharray", @@ -106,38 +142,59 @@ ${helpers.predefined_type( )} // Section 14 - Clipping, Masking and Compositing -${helpers.single_keyword("clip-rule", "nonzero evenodd", - products="gecko", - gecko_enum_prefix="StyleFillRule", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")} - -${helpers.predefined_type("marker-start", "url::UrlOrNone", "computed::url::UrlOrNone::none()", - products="gecko", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")} - -${helpers.predefined_type("marker-mid", "url::UrlOrNone", "computed::url::UrlOrNone::none()", - products="gecko", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")} - -${helpers.predefined_type("marker-end", "url::UrlOrNone", "computed::url::UrlOrNone::none()", - products="gecko", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")} - -${helpers.predefined_type("paint-order", "SVGPaintOrder", "computed::SVGPaintOrder::normal()", - products="gecko", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder")} - -${helpers.predefined_type("-moz-context-properties", - "MozContextProperties", - initial_value=None, - vector=True, - need_index=True, - animation_value_type="none", - products="gecko", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)", - allow_empty=True)} +${helpers.single_keyword( + "clip-rule", + "nonzero evenodd", + products="gecko", + gecko_enum_prefix="StyleFillRule", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty", +)} + +${helpers.predefined_type( + "marker-start", + "url::UrlOrNone", + "computed::url::UrlOrNone::none()", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties", +)} + +${helpers.predefined_type( + "marker-mid", + "url::UrlOrNone", + "computed::url::UrlOrNone::none()", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties", +)} + +${helpers.predefined_type( + "marker-end", + "url::UrlOrNone", + "computed::url::UrlOrNone::none()", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties", +)} + +${helpers.predefined_type( + "paint-order", + "SVGPaintOrder", + "computed::SVGPaintOrder::normal()", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder", +)} + +${helpers.predefined_type( + "-moz-context-properties", + "MozContextProperties", + initial_value=None, + vector=True, + need_index=True, + animation_value_type="none", + products="gecko", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)", + allow_empty=True, +)} diff --git a/components/style/properties/longhands/inherited_table.mako.rs b/components/style/properties/longhands/inherited_table.mako.rs index 4f55d9b1fa5..177907dc8f7 100644 --- a/components/style/properties/longhands/inherited_table.mako.rs +++ b/components/style/properties/longhands/inherited_table.mako.rs @@ -6,27 +6,40 @@ <% data.new_style_struct("InheritedTable", inherited=True, gecko_name="TableBorder") %> -${helpers.single_keyword("border-collapse", "separate collapse", - gecko_constant_prefix="NS_STYLE_BORDER", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse", - servo_restyle_damage = "reflow")} -${helpers.single_keyword("empty-cells", "show hide", - gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells", - servo_restyle_damage="rebuild_and_reflow")} -${helpers.single_keyword("caption-side", "top bottom", - extra_gecko_values="right left top-outside bottom-outside", - needs_conversion="True", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-tables/#propdef-caption-side", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.single_keyword( + "border-collapse", + "separate collapse", + gecko_constant_prefix="NS_STYLE_BORDER", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse", + servo_restyle_damage = "reflow", +)} -${helpers.predefined_type("border-spacing", - "BorderSpacing", - "computed::BorderSpacing::zero()", - animation_value_type="BorderSpacing", - boxed=True, - spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing", - servo_restyle_damage = "reflow")} +${helpers.single_keyword( + "empty-cells", + "show hide", + gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells", + servo_restyle_damage="rebuild_and_reflow", +)} + +${helpers.single_keyword( + "caption-side", + "top bottom", + extra_gecko_values="right left top-outside bottom-outside", + needs_conversion="True", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-tables/#propdef-caption-side", + servo_restyle_damage="rebuild_and_reflow", +)} + +${helpers.predefined_type( + "border-spacing", + "BorderSpacing", + "computed::BorderSpacing::zero()", + animation_value_type="BorderSpacing", + boxed=True, + spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing", + servo_restyle_damage = "reflow", +)} diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index 62819a78cbc..de7b613a183 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -20,51 +20,68 @@ ${helpers.predefined_type( // CSS Text Module Level 3 // TODO(pcwalton): `full-width` -${helpers.single_keyword("text-transform", - "none capitalize uppercase lowercase", - extra_gecko_values="full-width", - 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", - servo_restyle_damage="rebuild_and_reflow")} - -${helpers.single_keyword("hyphens", "manual none auto", - gecko_enum_prefix="StyleHyphens", - products="gecko", animation_value_type="discrete", extra_prefixes="moz", - spec="https://drafts.csswg.org/css-text/#propdef-hyphens")} +${helpers.single_keyword( + "text-transform", + "none capitalize uppercase lowercase", + extra_gecko_values="full-width", + 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", + servo_restyle_damage="rebuild_and_reflow", +)} + +${helpers.single_keyword( + "hyphens", + "manual none auto", + gecko_enum_prefix="StyleHyphens", + products="gecko", + animation_value_type="discrete", + extra_prefixes="moz", + spec="https://drafts.csswg.org/css-text/#propdef-hyphens", +)} // TODO: Support <percentage> -${helpers.single_keyword("-moz-text-size-adjust", "auto none", - gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST", - gecko_ffi_name="mTextSizeAdjust", - products="gecko", animation_value_type="discrete", - spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control", - alias="-webkit-text-size-adjust")} - -${helpers.predefined_type("text-indent", - "LengthOrPercentage", - "computed::LengthOrPercentage::Length(computed::Length::new(0.))", - animation_value_type="ComputedValue", - spec="https://drafts.csswg.org/css-text/#propdef-text-indent", - allow_quirks=True, servo_restyle_damage = "reflow")} +${helpers.single_keyword( + "-moz-text-size-adjust", + "auto none", + gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST", + gecko_ffi_name="mTextSizeAdjust", + products="gecko", animation_value_type="discrete", + spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control", + alias="-webkit-text-size-adjust", +)} + +${helpers.predefined_type( + "text-indent", + "LengthOrPercentage", + "computed::LengthOrPercentage::Length(computed::Length::new(0.))", + animation_value_type="ComputedValue", + spec="https://drafts.csswg.org/css-text/#propdef-text-indent", + allow_quirks=True, + servo_restyle_damage = "reflow", +)} // Also known as "word-wrap" (which is more popular because of IE), but this is the preferred // name per CSS-TEXT 6.2. -${helpers.single_keyword("overflow-wrap", - "normal break-word", - gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap", - alias="word-wrap", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.single_keyword( + "overflow-wrap", + "normal break-word", + gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap", + alias="word-wrap", + servo_restyle_damage="rebuild_and_reflow", +)} // TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support. -${helpers.single_keyword("word-break", - "normal break-all keep-all", - gecko_constant_prefix="NS_STYLE_WORDBREAK", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-text/#propdef-word-break", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.single_keyword( + "word-break", + "normal break-all keep-all", + gecko_constant_prefix="NS_STYLE_WORDBREAK", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-text/#propdef-word-break", + servo_restyle_damage="rebuild_and_reflow", +)} // TODO(pcwalton): Support `text-justify: distribute`. <%helpers:single_keyword @@ -106,39 +123,45 @@ ${helpers.single_keyword("word-break", % endif </%helpers:single_keyword> -${helpers.single_keyword("text-align-last", - "auto start end left right center justify", - products="gecko", - gecko_constant_prefix="NS_STYLE_TEXT_ALIGN", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-text/#propdef-text-align-last")} +${helpers.single_keyword( + "text-align-last", + "auto start end left right center justify", + products="gecko", + gecko_constant_prefix="NS_STYLE_TEXT_ALIGN", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-text/#propdef-text-align-last", +)} // TODO make this a shorthand and implement text-align-last/text-align-all -// -// FIXME(emilio): This can't really be that complicated. -${helpers.predefined_type("text-align", - "TextAlign", - "computed::TextAlign::start()", - animation_value_type="discrete", - flags="APPLIES_TO_PLACEHOLDER", - spec="https://drafts.csswg.org/css-text/#propdef-text-align", - servo_restyle_damage = "reflow")} - -${helpers.predefined_type("letter-spacing", - "LetterSpacing", - "computed::LetterSpacing::normal()", - animation_value_type="ComputedValue", - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", - spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing", - servo_restyle_damage="rebuild_and_reflow")} - -${helpers.predefined_type("word-spacing", - "WordSpacing", - "computed::WordSpacing::normal()", - animation_value_type="ComputedValue", - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", - spec="https://drafts.csswg.org/css-text/#propdef-word-spacing", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.predefined_type( + "text-align", + "TextAlign", + "computed::TextAlign::start()", + animation_value_type="discrete", + flags="APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-text/#propdef-text-align", + servo_restyle_damage = "reflow", +)} + +${helpers.predefined_type( + "letter-spacing", + "LetterSpacing", + "computed::LetterSpacing::normal()", + animation_value_type="ComputedValue", + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing", + servo_restyle_damage="rebuild_and_reflow", +)} + +${helpers.predefined_type( + "word-spacing", + "WordSpacing", + "computed::WordSpacing::normal()", + animation_value_type="ComputedValue", + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-text/#propdef-word-spacing", + servo_restyle_damage="rebuild_and_reflow", +)} <%helpers:single_keyword name="white-space" @@ -267,47 +290,65 @@ ${helpers.predefined_type( spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color", )} -${helpers.predefined_type("-webkit-text-stroke-width", - "BorderSideWidth", - "::values::computed::NonNegativeLength::new(0.)", - initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())", - computed_type="::values::computed::NonNegativeLength", - products="gecko", - gecko_pref="layout.css.prefixes.webkit", - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", - spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width", - animation_value_type="discrete")} +${helpers.predefined_type( + "-webkit-text-stroke-width", + "BorderSideWidth", + "::values::computed::NonNegativeLength::new(0.)", + initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())", + computed_type="::values::computed::NonNegativeLength", + products="gecko", + gecko_pref="layout.css.prefixes.webkit", + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", + spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width", + animation_value_type="discrete", +)} // CSS Ruby Layout Module Level 1 // https://drafts.csswg.org/css-ruby/ -${helpers.single_keyword("ruby-align", "space-around start center space-between", - products="gecko", animation_value_type="discrete", - spec="https://drafts.csswg.org/css-ruby/#ruby-align-property")} +${helpers.single_keyword( + "ruby-align", + "space-around start center space-between", + products="gecko", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-ruby/#ruby-align-property", +)} -${helpers.single_keyword("ruby-position", "over under", - products="gecko", animation_value_type="discrete", - spec="https://drafts.csswg.org/css-ruby/#ruby-position-property")} +${helpers.single_keyword( + "ruby-position", + "over under", + products="gecko", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-ruby/#ruby-position-property", +)} // CSS Writing Modes Module Level 3 // https://drafts.csswg.org/css-writing-modes-3/ -${helpers.single_keyword("text-combine-upright", "none all", - products="gecko", animation_value_type="discrete", - spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright")} +${helpers.single_keyword( + "text-combine-upright", + "none all", + products="gecko", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright", +)} // SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols -${helpers.single_keyword("text-rendering", - "auto optimizespeed optimizelegibility geometricprecision", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.single_keyword( + "text-rendering", + "auto optimizespeed optimizelegibility geometricprecision", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty", + servo_restyle_damage="rebuild_and_reflow", +)} // FIXME Firefox expects the initial value of this property to change depending // on the value of the layout.css.control-characters.visible pref. -${helpers.single_keyword("-moz-control-character-visibility", - "hidden visible", - gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY", - gecko_ffi_name="mControlCharacterVisibility", - animation_value_type="none", - products="gecko", - spec="Nonstandard")} +${helpers.single_keyword( + "-moz-control-character-visibility", + "hidden visible", + gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY", + gecko_ffi_name="mControlCharacterVisibility", + animation_value_type="none", + products="gecko", + spec="Nonstandard", +)} diff --git a/components/style/properties/longhands/inherited_ui.mako.rs b/components/style/properties/longhands/inherited_ui.mako.rs index e597f97ce8c..0b2b590cf7f 100644 --- a/components/style/properties/longhands/inherited_ui.mako.rs +++ b/components/style/properties/longhands/inherited_ui.mako.rs @@ -6,40 +6,56 @@ <% data.new_style_struct("InheritedUI", inherited=True, gecko_name="UI") %> -${helpers.predefined_type("cursor", - "Cursor", - "computed::Cursor::auto()", - initial_specified_value="specified::Cursor::auto()", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-ui/#cursor")} +${helpers.predefined_type( + "cursor", + "Cursor", + "computed::Cursor::auto()", + initial_specified_value="specified::Cursor::auto()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-ui/#cursor", +)} // NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact) // is nonstandard, slated for CSS4-UI. // TODO(pcwalton): SVG-only values. -${helpers.single_keyword("pointer-events", "auto none", animation_value_type="discrete", - extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all", - flags="APPLIES_TO_PLACEHOLDER", - spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty")} +${helpers.single_keyword( + "pointer-events", + "auto none", + animation_value_type="discrete", + extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all", + flags="APPLIES_TO_PLACEHOLDER", + spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty", +)} -${helpers.single_keyword("-moz-user-input", "auto none", - products="gecko", gecko_ffi_name="mUserInput", - gecko_enum_prefix="StyleUserInput", - animation_value_type="discrete", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input)")} +${helpers.single_keyword( + "-moz-user-input", + "auto none", + products="gecko", + gecko_ffi_name="mUserInput", + gecko_enum_prefix="StyleUserInput", + animation_value_type="discrete", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input)", +)} -${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only", - products="gecko", gecko_ffi_name="mUserModify", - gecko_enum_prefix="StyleUserModify", - needs_conversion=True, - animation_value_type="discrete", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)")} +${helpers.single_keyword( + "-moz-user-modify", + "read-only read-write write-only", + products="gecko", + gecko_ffi_name="mUserModify", + gecko_enum_prefix="StyleUserModify", + needs_conversion=True, + animation_value_type="discrete", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)", +)} -${helpers.single_keyword("-moz-user-focus", - "none ignore normal select-after select-before select-menu select-same select-all", - products="gecko", gecko_ffi_name="mUserFocus", - gecko_enum_prefix="StyleUserFocus", - animation_value_type="discrete", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-focus)")} +${helpers.single_keyword( + "-moz-user-focus", + "none ignore normal select-after select-before select-menu select-same select-all", + products="gecko", gecko_ffi_name="mUserFocus", + gecko_enum_prefix="StyleUserFocus", + animation_value_type="discrete", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-focus)", +)} ${helpers.predefined_type( "caret-color", diff --git a/components/style/properties/longhands/list.mako.rs b/components/style/properties/longhands/list.mako.rs index 5ed1ea44831..732275fb03e 100644 --- a/components/style/properties/longhands/list.mako.rs +++ b/components/style/properties/longhands/list.mako.rs @@ -40,25 +40,31 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu )} % endif -${helpers.predefined_type("list-style-image", - "url::ImageUrlOrNone", - initial_value="computed::url::ImageUrlOrNone::none()", - initial_specified_value="specified::url::ImageUrlOrNone::none()", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.predefined_type( + "list-style-image", + "url::ImageUrlOrNone", + initial_value="computed::url::ImageUrlOrNone::none()", + initial_specified_value="specified::url::ImageUrlOrNone::none()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image", + servo_restyle_damage="rebuild_and_reflow", +)} -${helpers.predefined_type("quotes", - "Quotes", - "computed::Quotes::get_initial_value()", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-content/#propdef-quotes", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.predefined_type( + "quotes", + "Quotes", + "computed::Quotes::get_initial_value()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-content/#propdef-quotes", + servo_restyle_damage="rebuild_and_reflow", +)} -${helpers.predefined_type("-moz-image-region", - "ClipRectOrAuto", - "computed::ClipRectOrAuto::auto()", - animation_value_type="ComputedValue", - products="gecko", - boxed=True, - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)")} +${helpers.predefined_type( + "-moz-image-region", + "ClipRectOrAuto", + "computed::ClipRectOrAuto::auto()", + animation_value_type="ComputedValue", + products="gecko", + boxed=True, + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)", +)} diff --git a/components/style/properties/longhands/outline.mako.rs b/components/style/properties/longhands/outline.mako.rs index 9446745ec3e..a61aae06d7c 100644 --- a/components/style/properties/longhands/outline.mako.rs +++ b/components/style/properties/longhands/outline.mako.rs @@ -29,24 +29,34 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-ui/#propdef-outline-style", )} -${helpers.predefined_type("outline-width", - "BorderSideWidth", - "::values::computed::NonNegativeLength::new(3.)", - initial_specified_value="specified::BorderSideWidth::Medium", - computed_type="::values::computed::NonNegativeLength", - animation_value_type="NonNegativeLength", - spec="https://drafts.csswg.org/css-ui/#propdef-outline-width")} +${helpers.predefined_type( + "outline-width", + "BorderSideWidth", + "::values::computed::NonNegativeLength::new(3.)", + initial_specified_value="specified::BorderSideWidth::Medium", + computed_type="::values::computed::NonNegativeLength", + animation_value_type="NonNegativeLength", + spec="https://drafts.csswg.org/css-ui/#propdef-outline-width", +)} // The -moz-outline-radius-* properties are non-standard and not on a standards track. % for corner in ["topleft", "topright", "bottomright", "bottomleft"]: - ${helpers.predefined_type("-moz-outline-radius-" + corner, "BorderCornerRadius", + ${helpers.predefined_type( + "-moz-outline-radius-" + corner, + "BorderCornerRadius", "computed::BorderCornerRadius::zero()", products="gecko", boxed=True, animation_value_type="BorderCornerRadius", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)")} + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)", + )} % endfor -${helpers.predefined_type("outline-offset", "Length", "::values::computed::Length::new(0.)", - products="servo gecko", animation_value_type="ComputedValue", - spec="https://drafts.csswg.org/css-ui/#propdef-outline-offset")} +${helpers.predefined_type( + "outline-offset", + "Length", + "::values::computed::Length::new(0.)", + products="servo gecko", + animation_value_type="ComputedValue", + spec="https://drafts.csswg.org/css-ui/#propdef-outline-offset", +)} diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 957335d32b2..5ec34961d22 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -68,73 +68,93 @@ ${helpers.predefined_type( // http://www.w3.org/TR/css3-flexbox/ // Flex container properties -${helpers.single_keyword("flex-direction", "row row-reverse column column-reverse", - spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property", - extra_prefixes="webkit", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} - -${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse", - spec="https://drafts.csswg.org/css-flexbox/#flex-wrap-property", - extra_prefixes="webkit", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} +${helpers.single_keyword( + "flex-direction", + "row row-reverse column column-reverse", + spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property", + extra_prefixes="webkit", + animation_value_type="discrete", + servo_restyle_damage = "reflow", +)} + +${helpers.single_keyword( + "flex-wrap", + "nowrap wrap wrap-reverse", + spec="https://drafts.csswg.org/css-flexbox/#flex-wrap-property", + extra_prefixes="webkit", + animation_value_type="discrete", + servo_restyle_damage = "reflow", +)} % if product == "servo": // FIXME: Update Servo to support the same Syntax as Gecko. - ${helpers.single_keyword("justify-content", "flex-start stretch flex-end center space-between space-around", - extra_prefixes="webkit", - spec="https://drafts.csswg.org/css-align/#propdef-justify-content", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} + ${helpers.single_keyword( + "justify-content", + "flex-start stretch flex-end center space-between space-around", + extra_prefixes="webkit", + spec="https://drafts.csswg.org/css-align/#propdef-justify-content", + animation_value_type="discrete", + servo_restyle_damage = "reflow", + )} % else: - ${helpers.predefined_type(name="justify-content", - type="JustifyContent", - initial_value="specified::JustifyContent(specified::ContentDistribution::normal())", - spec="https://drafts.csswg.org/css-align/#propdef-justify-content", - extra_prefixes="webkit", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} + ${helpers.predefined_type( + "justify-content", + "JustifyContent", + "specified::JustifyContent(specified::ContentDistribution::normal())", + spec="https://drafts.csswg.org/css-align/#propdef-justify-content", + extra_prefixes="webkit", + animation_value_type="discrete", + servo_restyle_damage="reflow", + )} % endif % if product == "servo": // FIXME: Update Servo to support the same Syntax as Gecko. - ${helpers.single_keyword("align-content", "stretch flex-start flex-end center space-between space-around", - extra_prefixes="webkit", - spec="https://drafts.csswg.org/css-align/#propdef-align-content", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} - - ${helpers.single_keyword("align-items", - "stretch flex-start flex-end center baseline", - extra_prefixes="webkit", - spec="https://drafts.csswg.org/css-flexbox/#align-items-property", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} + ${helpers.single_keyword( + "align-content", + "stretch flex-start flex-end center space-between space-around", + extra_prefixes="webkit", + spec="https://drafts.csswg.org/css-align/#propdef-align-content", + animation_value_type="discrete", + servo_restyle_damage="reflow", + )} + + ${helpers.single_keyword( + "align-items", + "stretch flex-start flex-end center baseline", + extra_prefixes="webkit", + spec="https://drafts.csswg.org/css-flexbox/#align-items-property", + animation_value_type="discrete", + servo_restyle_damage="reflow", + )} % else: - ${helpers.predefined_type(name="align-content", - type="AlignContent", - initial_value="specified::AlignContent(specified::ContentDistribution::normal())", - spec="https://drafts.csswg.org/css-align/#propdef-align-content", - extra_prefixes="webkit", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} - - ${helpers.predefined_type(name="align-items", - type="AlignItems", - initial_value="specified::AlignItems::normal()", - spec="https://drafts.csswg.org/css-align/#propdef-align-items", - extra_prefixes="webkit", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} + ${helpers.predefined_type( + "align-content", + "AlignContent", + "specified::AlignContent(specified::ContentDistribution::normal())", + spec="https://drafts.csswg.org/css-align/#propdef-align-content", + extra_prefixes="webkit", + animation_value_type="discrete", + servo_restyle_damage="reflow", + )} + + ${helpers.predefined_type( + "align-items", + "AlignItems", + "specified::AlignItems::normal()", + spec="https://drafts.csswg.org/css-align/#propdef-align-items", + extra_prefixes="webkit", + animation_value_type="discrete", + servo_restyle_damage="reflow", + )} #[cfg(feature = "gecko")] impl_align_conversions!(::values::specified::align::AlignItems); ${helpers.predefined_type( - name="justify-items", - type="JustifyItems", - initial_value="computed::JustifyItems::legacy()", + "justify-items", + "JustifyItems", + "computed::JustifyItems::legacy()", spec="https://drafts.csswg.org/css-align/#propdef-justify-items", animation_value_type="discrete", )} @@ -144,52 +164,69 @@ ${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse", % endif // Flex item properties -${helpers.predefined_type("flex-grow", "NonNegativeNumber", - "From::from(0.0)", - spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property", - extra_prefixes="webkit", - animation_value_type="NonNegativeNumber", - servo_restyle_damage = "reflow")} - -${helpers.predefined_type("flex-shrink", "NonNegativeNumber", - "From::from(1.0)", - spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property", - extra_prefixes="webkit", - animation_value_type="NonNegativeNumber", - servo_restyle_damage = "reflow")} +${helpers.predefined_type( + "flex-grow", + "NonNegativeNumber", + "From::from(0.0)", + spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property", + extra_prefixes="webkit", + animation_value_type="NonNegativeNumber", + servo_restyle_damage="reflow", +)} + +${helpers.predefined_type( + "flex-shrink", + "NonNegativeNumber", + "From::from(1.0)", + spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property", + extra_prefixes="webkit", + animation_value_type="NonNegativeNumber", + servo_restyle_damage = "reflow", +)} // https://drafts.csswg.org/css-align/#align-self-property % if product == "servo": // FIXME: Update Servo to support the same syntax as Gecko. - ${helpers.single_keyword("align-self", "auto stretch flex-start flex-end center baseline", - extra_prefixes="webkit", - spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self", - animation_value_type="discrete", - servo_restyle_damage = "reflow")} + ${helpers.single_keyword( + "align-self", + "auto stretch flex-start flex-end center baseline", + extra_prefixes="webkit", + spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self", + animation_value_type="discrete", + servo_restyle_damage = "reflow", + )} % else: - ${helpers.predefined_type(name="align-self", - type="AlignSelf", - initial_value="specified::AlignSelf(specified::SelfAlignment::auto())", - spec="https://drafts.csswg.org/css-align/#align-self-property", - extra_prefixes="webkit", - animation_value_type="discrete")} - - ${helpers.predefined_type(name="justify-self", - type="JustifySelf", - initial_value="specified::JustifySelf(specified::SelfAlignment::auto())", - spec="https://drafts.csswg.org/css-align/#justify-self-property", - animation_value_type="discrete")} + ${helpers.predefined_type( + "align-self", + "AlignSelf", + "specified::AlignSelf(specified::SelfAlignment::auto())", + spec="https://drafts.csswg.org/css-align/#align-self-property", + extra_prefixes="webkit", + animation_value_type="discrete", + )} + + ${helpers.predefined_type( + "justify-self", + "JustifySelf", + "specified::JustifySelf(specified::SelfAlignment::auto())", + spec="https://drafts.csswg.org/css-align/#justify-self-property", + animation_value_type="discrete", + )} #[cfg(feature = "gecko")] impl_align_conversions!(::values::specified::align::SelfAlignment); % endif // https://drafts.csswg.org/css-flexbox/#propdef-order -${helpers.predefined_type("order", "Integer", "0", - extra_prefixes="webkit", - animation_value_type="ComputedValue", - spec="https://drafts.csswg.org/css-flexbox/#order-property", - servo_restyle_damage = "reflow")} +${helpers.predefined_type( + "order", + "Integer", + "0", + extra_prefixes="webkit", + animation_value_type="ComputedValue", + spec="https://drafts.csswg.org/css-flexbox/#order-property", + servo_restyle_damage = "reflow", +)} ${helpers.predefined_type( "flex-basis", @@ -198,7 +235,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property", extra_prefixes="webkit", animation_value_type="FlexBasis", - servo_restyle_damage = "reflow" + servo_restyle_damage = "reflow", )} % for (size, logical) in ALL_SIZES: @@ -228,7 +265,7 @@ ${helpers.predefined_type( spec=spec % size, animation_value_type="MozLength", flags="GETCS_NEEDS_LAYOUT_FLUSH", - servo_restyle_damage="reflow" + servo_restyle_damage="reflow", )} // min-width, min-height, min-block-size, min-inline-size, ${helpers.predefined_type( @@ -241,7 +278,7 @@ ${helpers.predefined_type( allow_quirks=not logical, spec=spec % size, animation_value_type="MozLength", - servo_restyle_damage = "reflow" + servo_restyle_damage="reflow", )} ${helpers.predefined_type( "max-%s" % size, @@ -253,7 +290,7 @@ ${helpers.predefined_type( allow_quirks=not logical, spec=spec % size, animation_value_type="MaxLength", - servo_restyle_damage = "reflow" + servo_restyle_damage="reflow", )} % else: // servo versions (no keyword support) @@ -266,7 +303,7 @@ ${helpers.predefined_type( logical_group="size", allow_quirks=not logical, animation_value_type="ComputedValue", logical = logical, - servo_restyle_damage = "reflow", + servo_restyle_damage="reflow", )} ${helpers.predefined_type( "min-%s" % size, @@ -278,7 +315,7 @@ ${helpers.predefined_type( animation_value_type="ComputedValue", logical=logical, allow_quirks=not logical, - servo_restyle_damage = "reflow", + servo_restyle_damage="reflow", )} ${helpers.predefined_type( "max-%s" % size, @@ -290,52 +327,64 @@ ${helpers.predefined_type( animation_value_type="ComputedValue", logical=logical, allow_quirks=not logical, - servo_restyle_damage = "reflow", + servo_restyle_damage="reflow", )} % endif % endfor -${helpers.single_keyword("box-sizing", - "content-box border-box", - extra_prefixes="moz:layout.css.prefixes.box-sizing webkit", - spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing", - gecko_enum_prefix="StyleBoxSizing", - custom_consts={ "content-box": "Content", "border-box": "Border" }, - animation_value_type="discrete", - servo_restyle_damage = "reflow")} - -${helpers.single_keyword("object-fit", "fill contain cover none scale-down", - products="gecko", animation_value_type="discrete", - spec="https://drafts.csswg.org/css-images/#propdef-object-fit")} - -${helpers.predefined_type("object-position", - "Position", - "computed::Position::zero()", - products="gecko", - boxed=True, - spec="https://drafts.csswg.org/css-images-3/#the-object-position", - animation_value_type="ComputedValue")} +${helpers.single_keyword( + "box-sizing", + "content-box border-box", + extra_prefixes="moz:layout.css.prefixes.box-sizing webkit", + spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing", + gecko_enum_prefix="StyleBoxSizing", + custom_consts={ "content-box": "Content", "border-box": "Border" }, + animation_value_type="discrete", + servo_restyle_damage = "reflow", +)} + +${helpers.single_keyword( + "object-fit", + "fill contain cover none scale-down", + products="gecko", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-images/#propdef-object-fit", +)} + +${helpers.predefined_type( + "object-position", + "Position", + "computed::Position::zero()", + products="gecko", + boxed=True, + spec="https://drafts.csswg.org/css-images-3/#the-object-position", + animation_value_type="ComputedValue", +)} % for kind in ["row", "column"]: % for range in ["start", "end"]: - ${helpers.predefined_type("grid-%s-%s" % (kind, range), - "GridLine", - "Default::default()", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range), - products="gecko", - boxed=True)} + ${helpers.predefined_type( + "grid-%s-%s" % (kind, range), + "GridLine", + "Default::default()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range), + products="gecko", + boxed=True, + )} % endfor // NOTE: According to the spec, this should handle multiple values of `<track-size>`, // but gecko supports only a single value - ${helpers.predefined_type("grid-auto-%ss" % kind, - "TrackSize", - "Default::default()", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind, - products="gecko", - boxed=True)} + ${helpers.predefined_type( + "grid-auto-%ss" % kind, + "TrackSize", + "Default::default()", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind, + products="gecko", + boxed=True, + )} ${helpers.predefined_type( "grid-template-%ss" % kind, @@ -345,41 +394,49 @@ ${helpers.predefined_type("object-position", spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind, boxed=True, flags="GETCS_NEEDS_LAYOUT_FLUSH", - animation_value_type="discrete" + animation_value_type="discrete", )} % endfor -${helpers.predefined_type("grid-auto-flow", - "GridAutoFlow", - initial_value="computed::GridAutoFlow::row()", - products="gecko", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow")} - -${helpers.predefined_type("grid-template-areas", - "GridTemplateAreas", - initial_value="computed::GridTemplateAreas::none()", - products="gecko", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas")} - -${helpers.predefined_type("column-gap", - "length::NonNegativeLengthOrPercentageOrNormal", - "Either::Second(Normal)", - alias="grid-column-gap" if product == "gecko" else "", - extra_prefixes="moz", - servo_pref="layout.columns.enabled", - spec="https://drafts.csswg.org/css-align-3/#propdef-column-gap", - animation_value_type="NonNegativeLengthOrPercentageOrNormal", - servo_restyle_damage = "reflow")} +${helpers.predefined_type( + "grid-auto-flow", + "GridAutoFlow", + "computed::GridAutoFlow::row()", + products="gecko", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow", +)} + +${helpers.predefined_type( + "grid-template-areas", + "GridTemplateAreas", + "computed::GridTemplateAreas::none()", + products="gecko", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas", +)} + +${helpers.predefined_type( + "column-gap", + "length::NonNegativeLengthOrPercentageOrNormal", + "Either::Second(Normal)", + alias="grid-column-gap" if product == "gecko" else "", + extra_prefixes="moz", + servo_pref="layout.columns.enabled", + spec="https://drafts.csswg.org/css-align-3/#propdef-column-gap", + animation_value_type="NonNegativeLengthOrPercentageOrNormal", + servo_restyle_damage="reflow", +)} // no need for -moz- prefixed alias for this property -${helpers.predefined_type("row-gap", - "length::NonNegativeLengthOrPercentageOrNormal", - "Either::Second(Normal)", - alias="grid-row-gap", - products="gecko", - spec="https://drafts.csswg.org/css-align-3/#propdef-row-gap", - animation_value_type="NonNegativeLengthOrPercentageOrNormal", - servo_restyle_damage = "reflow")} +${helpers.predefined_type( + "row-gap", + "length::NonNegativeLengthOrPercentageOrNormal", + "Either::Second(Normal)", + alias="grid-row-gap", + products="gecko", + spec="https://drafts.csswg.org/css-align-3/#propdef-row-gap", + animation_value_type="NonNegativeLengthOrPercentageOrNormal", + servo_restyle_damage="reflow", +)} diff --git a/components/style/properties/longhands/svg.mako.rs b/components/style/properties/longhands/svg.mako.rs index 6d7bf803f1e..36105247676 100644 --- a/components/style/properties/longhands/svg.mako.rs +++ b/components/style/properties/longhands/svg.mako.rs @@ -6,16 +6,22 @@ <% data.new_style_struct("SVG", inherited=False, gecko_name="SVGReset") %> -${helpers.single_keyword("dominant-baseline", - """auto use-script no-change reset-size ideographic alphabetic hanging - mathematical central middle text-after-edge text-before-edge""", - products="gecko", - animation_value_type="discrete", - spec="https://www.w3.org/TR/SVG11/text.html#DominantBaselineProperty")} +${helpers.single_keyword( + "dominant-baseline", + """auto use-script no-change reset-size ideographic alphabetic hanging + mathematical central middle text-after-edge text-before-edge""", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVG11/text.html#DominantBaselineProperty", +)} -${helpers.single_keyword("vector-effect", "none non-scaling-stroke", - products="gecko", animation_value_type="discrete", - spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty")} +${helpers.single_keyword( + "vector-effect", + "none non-scaling-stroke", + products="gecko", + animation_value_type="discrete", + spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty", +)} // Section 13 - Gradients and Patterns @@ -28,10 +34,14 @@ ${helpers.predefined_type( spec="https://www.w3.org/TR/SVGTiny12/painting.html#StopColorProperty", )} -${helpers.predefined_type("stop-opacity", "Opacity", "1.0", - products="gecko", - animation_value_type="ComputedValue", - spec="https://www.w3.org/TR/SVGTiny12/painting.html#propdef-stop-opacity")} +${helpers.predefined_type( + "stop-opacity", + "Opacity", + "1.0", + products="gecko", + animation_value_type="ComputedValue", + spec="https://www.w3.org/TR/SVGTiny12/painting.html#propdef-stop-opacity", +)} // Section 15 - Filter Effects @@ -44,9 +54,14 @@ ${helpers.predefined_type( spec="https://www.w3.org/TR/SVG/filters.html#FloodColorProperty", )} -${helpers.predefined_type("flood-opacity", "Opacity", - "1.0", products="gecko", animation_value_type="ComputedValue", - spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty")} +${helpers.predefined_type( + "flood-opacity", + "Opacity", + "1.0", + products="gecko", + animation_value_type="ComputedValue", + spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty", +)} ${helpers.predefined_type( "lighting-color", @@ -59,9 +74,13 @@ ${helpers.predefined_type( // CSS Masking Module Level 1 // https://drafts.fxtf.org/css-masking -${helpers.single_keyword("mask-type", "luminance alpha", - products="gecko", animation_value_type="discrete", - spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")} +${helpers.single_keyword( + "mask-type", + "luminance alpha", + products="gecko", + animation_value_type="discrete", + spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type", +)} ${helpers.predefined_type( "clip-path", @@ -74,12 +93,14 @@ ${helpers.predefined_type( spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path", )} -${helpers.single_keyword("mask-mode", - "match-source alpha luminance", - vector=True, - products="gecko", - animation_value_type="discrete", - spec="https://drafts.fxtf.org/css-masking/#propdef-mask-mode")} +${helpers.single_keyword( + "mask-mode", + "match-source alpha luminance", + vector=True, + products="gecko", + animation_value_type="discrete", + spec="https://drafts.fxtf.org/css-masking/#propdef-mask-mode", +)} ${helpers.predefined_type( "mask-repeat", @@ -97,9 +118,9 @@ ${helpers.predefined_type( ${helpers.predefined_type( "mask-position-" + axis, "position::" + direction + "Position", + "computed::LengthOrPercentage::zero()", products="gecko", extra_prefixes="webkit", - initial_value="computed::LengthOrPercentage::zero()", initial_specified_value="specified::PositionComponent::Center", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position", animation_value_type="ComputedValue", @@ -147,20 +168,25 @@ ${helpers.predefined_type( vector_animation_type="repeatable_list", )} -${helpers.single_keyword("mask-composite", - "add subtract intersect exclude", - vector=True, - products="gecko", - extra_prefixes="webkit", - animation_value_type="discrete", - spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")} +${helpers.single_keyword( + "mask-composite", + "add subtract intersect exclude", + vector=True, + products="gecko", + extra_prefixes="webkit", + animation_value_type="discrete", + spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite", +)} -${helpers.predefined_type("mask-image", "ImageLayer", - initial_value="Either::First(None_)", +${helpers.predefined_type( + "mask-image", + "ImageLayer", + "Either::First(None_)", initial_specified_value="Either::First(None_)", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image", vector=True, products="gecko", extra_prefixes="webkit", animation_value_type="discrete", - flags="CREATES_STACKING_CONTEXT")} + flags="CREATES_STACKING_CONTEXT", +)} diff --git a/components/style/properties/longhands/table.mako.rs b/components/style/properties/longhands/table.mako.rs index 2af39e1d6e3..8a371f269a6 100644 --- a/components/style/properties/longhands/table.mako.rs +++ b/components/style/properties/longhands/table.mako.rs @@ -6,15 +6,21 @@ <% data.new_style_struct("Table", inherited=False) %> -${helpers.single_keyword("table-layout", "auto fixed", - gecko_ffi_name="mLayoutStrategy", animation_value_type="discrete", - spec="https://drafts.csswg.org/css-tables/#propdef-table-layout", - servo_restyle_damage = "reflow")} +${helpers.single_keyword( + "table-layout", + "auto fixed", + gecko_ffi_name="mLayoutStrategy", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-tables/#propdef-table-layout", + servo_restyle_damage="reflow", +)} -${helpers.predefined_type("-x-span", - "XSpan", - "computed::XSpan(1)", - products="gecko", - spec="Internal-only (for `<col span>` pres attr)", - animation_value_type="none", - enabled_in="")} +${helpers.predefined_type( + "-x-span", + "XSpan", + "computed::XSpan(1)", + products="gecko", + spec="Internal-only (for `<col span>` pres attr)", + animation_value_type="none", + enabled_in="", +)} diff --git a/components/style/properties/longhands/text.mako.rs b/components/style/properties/longhands/text.mako.rs index 613ed6c5f67..715019f9c08 100644 --- a/components/style/properties/longhands/text.mako.rs +++ b/components/style/properties/longhands/text.mako.rs @@ -5,43 +5,55 @@ <%namespace name="helpers" file="/helpers.mako.rs" /> <% from data import Method %> -<% data.new_style_struct("Text", - inherited=False, - gecko_name="TextReset", - additional_methods=[Method("has_underline", "bool"), - Method("has_overline", "bool"), - Method("has_line_through", "bool")]) %> +<% data.new_style_struct( + "Text", + inherited=False, + gecko_name="TextReset", + additional_methods=[ + Method("has_underline", "bool"), + Method("has_overline", "bool"), + Method("has_line_through", "bool"), + ] +) %> -${helpers.predefined_type("text-overflow", - "TextOverflow", - "computed::TextOverflow::get_initial_value()", - animation_value_type="discrete", - boxed=True, - flags="APPLIES_TO_PLACEHOLDER", - spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.predefined_type( + "text-overflow", + "TextOverflow", + "computed::TextOverflow::get_initial_value()", + animation_value_type="discrete", + boxed=True, + flags="APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow", + servo_restyle_damage="rebuild_and_reflow", +)} -${helpers.single_keyword("unicode-bidi", - "normal embed isolate bidi-override isolate-override plaintext", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-writing-modes/#propdef-unicode-bidi", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.single_keyword( + "unicode-bidi", + "normal embed isolate bidi-override isolate-override plaintext", + animation_value_type="none", + spec="https://drafts.csswg.org/css-writing-modes/#propdef-unicode-bidi", + servo_restyle_damage="rebuild_and_reflow", +)} -${helpers.predefined_type("text-decoration-line", - "TextDecorationLine", - "specified::TextDecorationLine::none()", - initial_specified_value="specified::TextDecorationLine::none()", - animation_value_type="discrete", - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", - spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line", - servo_restyle_damage="rebuild_and_reflow")} +${helpers.predefined_type( + "text-decoration-line", + "TextDecorationLine", + "specified::TextDecorationLine::none()", + initial_specified_value="specified::TextDecorationLine::none()", + animation_value_type="discrete", + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line", + servo_restyle_damage="rebuild_and_reflow", +)} -${helpers.single_keyword("text-decoration-style", - "solid double dotted dashed wavy -moz-none", - products="gecko", - animation_value_type="discrete", - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", - spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style")} +${helpers.single_keyword( + "text-decoration-style", + "solid double dotted dashed wavy -moz-none", + products="gecko", + animation_value_type="discrete", + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style", +)} ${helpers.predefined_type( "text-decoration-color", @@ -64,4 +76,5 @@ ${helpers.predefined_type( products="gecko", flags="APPLIES_TO_FIRST_LETTER", gecko_pref="layout.css.initial-letter.enabled", - spec="https://drafts.csswg.org/css-inline/#sizing-drop-initials")} + spec="https://drafts.csswg.org/css-inline/#sizing-drop-initials", +)} diff --git a/components/style/properties/longhands/ui.mako.rs b/components/style/properties/longhands/ui.mako.rs index 419024862d4..b8a188d896b 100644 --- a/components/style/properties/longhands/ui.mako.rs +++ b/components/style/properties/longhands/ui.mako.rs @@ -11,10 +11,14 @@ // TODO spec says that UAs should not support this // we should probably remove from gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=1328331) -${helpers.single_keyword("ime-mode", "auto normal active disabled inactive", - products="gecko", gecko_ffi_name="mIMEMode", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-ui/#input-method-editor")} +${helpers.single_keyword( + "ime-mode", + "auto normal active disabled inactive", + products="gecko", + gecko_ffi_name="mIMEMode", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-ui/#input-method-editor", +)} ${helpers.single_keyword( "scrollbar-width", @@ -27,30 +31,40 @@ ${helpers.single_keyword( spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-width" )} -${helpers.single_keyword("-moz-user-select", "auto text none all element elements" + - " toggle tri-state -moz-all -moz-text", - products="gecko", - alias="-webkit-user-select", - gecko_ffi_name="mUserSelect", - gecko_enum_prefix="StyleUserSelect", - gecko_strip_moz_prefix=False, - aliases="-moz-none=none", - animation_value_type="discrete", - spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")} +${helpers.single_keyword( + "-moz-user-select", + "auto text none all element elements toggle tri-state -moz-all -moz-text", + products="gecko", + alias="-webkit-user-select", + gecko_ffi_name="mUserSelect", + gecko_enum_prefix="StyleUserSelect", + gecko_strip_moz_prefix=False, + aliases="-moz-none=none", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select", +)} // TODO(emilio): This probably should be hidden from content. -${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", products="gecko", - gecko_ffi_name="mWindowDragging", - gecko_enum_prefix="StyleWindowDragging", - animation_value_type="discrete", - spec="None (Nonstandard Firefox-only property)")} +${helpers.single_keyword( + "-moz-window-dragging", + "default drag no-drag", + products="gecko", + gecko_ffi_name="mWindowDragging", + gecko_enum_prefix="StyleWindowDragging", + animation_value_type="discrete", + spec="None (Nonstandard Firefox-only property)", +)} -${helpers.single_keyword("-moz-window-shadow", "none default menu tooltip sheet", products="gecko", - gecko_ffi_name="mWindowShadow", - gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW", - animation_value_type="discrete", - enabled_in="chrome", - spec="None (Nonstandard internal property)")} +${helpers.single_keyword( + "-moz-window-shadow", + "none default menu tooltip sheet", + products="gecko", + gecko_ffi_name="mWindowShadow", + gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW", + animation_value_type="discrete", + enabled_in="chrome", + spec="None (Nonstandard internal property)", +)} ${helpers.predefined_type( "-moz-window-opacity", @@ -89,9 +103,11 @@ ${helpers.predefined_type( )} // TODO(emilio): Probably also should be hidden from content. -${helpers.predefined_type("-moz-force-broken-image-icon", - "MozForceBrokenImageIcon", - "computed::MozForceBrokenImageIcon::false_value()", - animation_value_type="discrete", - products="gecko", - spec="None (Nonstandard Firefox-only property)")} +${helpers.predefined_type( + "-moz-force-broken-image-icon", + "MozForceBrokenImageIcon", + "computed::MozForceBrokenImageIcon::false_value()", + animation_value_type="discrete", + products="gecko", + spec="None (Nonstandard Firefox-only property)", +)} diff --git a/components/style/properties/longhands/xul.mako.rs b/components/style/properties/longhands/xul.mako.rs index 15b8a695411..5089bbf985b 100644 --- a/components/style/properties/longhands/xul.mako.rs +++ b/components/style/properties/longhands/xul.mako.rs @@ -8,51 +8,79 @@ // Non-standard properties that Gecko uses for XUL elements. <% data.new_style_struct("XUL", inherited=False) %> -${helpers.single_keyword("-moz-box-align", "stretch start center baseline end", - products="gecko", gecko_ffi_name="mBoxAlign", - gecko_enum_prefix="StyleBoxAlign", - animation_value_type="discrete", - alias="-webkit-box-align", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-align)")} - -${helpers.single_keyword("-moz-box-direction", "normal reverse", - products="gecko", gecko_ffi_name="mBoxDirection", - gecko_enum_prefix="StyleBoxDirection", - animation_value_type="discrete", - alias="-webkit-box-direction", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-direction)")} - -${helpers.predefined_type("-moz-box-flex", "NonNegativeNumber", "From::from(0.)", - products="gecko", gecko_ffi_name="mBoxFlex", - animation_value_type="NonNegativeNumber", - alias="-webkit-box-flex", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")} - -${helpers.single_keyword("-moz-box-orient", "horizontal vertical", - products="gecko", gecko_ffi_name="mBoxOrient", - extra_gecko_aliases="inline-axis=horizontal block-axis=vertical", - gecko_enum_prefix="StyleBoxOrient", - animation_value_type="discrete", - alias="-webkit-box-orient", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-orient)")} - -${helpers.single_keyword("-moz-box-pack", "start center end justify", - products="gecko", gecko_ffi_name="mBoxPack", - gecko_enum_prefix="StyleBoxPack", - animation_value_type="discrete", - alias="-webkit-box-pack", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)")} - -${helpers.single_keyword("-moz-stack-sizing", "stretch-to-fit ignore ignore-horizontal ignore-vertical", - products="gecko", gecko_ffi_name="mStackSizing", - gecko_enum_prefix="StyleStackSizing", - animation_value_type="discrete", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)")} - -${helpers.predefined_type("-moz-box-ordinal-group", "Integer", "0", - parse_method="parse_non_negative", - products="gecko", - alias="-webkit-box-ordinal-group", - gecko_ffi_name="mBoxOrdinal", - animation_value_type="discrete", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-box-ordinal-group)")} +${helpers.single_keyword( + "-moz-box-align", + "stretch start center baseline end", + products="gecko", + gecko_ffi_name="mBoxAlign", + gecko_enum_prefix="StyleBoxAlign", + animation_value_type="discrete", + alias="-webkit-box-align", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-align)", +)} + +${helpers.single_keyword( + "-moz-box-direction", + "normal reverse", + products="gecko", + gecko_ffi_name="mBoxDirection", + gecko_enum_prefix="StyleBoxDirection", + animation_value_type="discrete", + alias="-webkit-box-direction", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-direction)", +)} + +${helpers.predefined_type( + "-moz-box-flex", + "NonNegativeNumber", + "From::from(0.)", + products="gecko", + gecko_ffi_name="mBoxFlex", + animation_value_type="NonNegativeNumber", + alias="-webkit-box-flex", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)", +)} + +${helpers.single_keyword( + "-moz-box-orient", + "horizontal vertical", + products="gecko", + gecko_ffi_name="mBoxOrient", + extra_gecko_aliases="inline-axis=horizontal block-axis=vertical", + gecko_enum_prefix="StyleBoxOrient", + animation_value_type="discrete", + alias="-webkit-box-orient", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-orient)", +)} + +${helpers.single_keyword( + "-moz-box-pack", + "start center end justify", + products="gecko", gecko_ffi_name="mBoxPack", + gecko_enum_prefix="StyleBoxPack", + animation_value_type="discrete", + alias="-webkit-box-pack", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)", +)} + +${helpers.single_keyword( + "-moz-stack-sizing", + "stretch-to-fit ignore ignore-horizontal ignore-vertical", + products="gecko", + gecko_ffi_name="mStackSizing", + gecko_enum_prefix="StyleStackSizing", + animation_value_type="discrete", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)", +)} + +${helpers.predefined_type( + "-moz-box-ordinal-group", + "Integer", + "0", + parse_method="parse_non_negative", + products="gecko", + alias="-webkit-box-ordinal-group", + gecko_ffi_name="mBoxOrdinal", + animation_value_type="discrete", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-box-ordinal-group)", +)} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 64e99ba205d..681e9556653 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -425,6 +425,10 @@ pub mod animated_properties { #[derive(Clone, Copy, Debug)] pub struct NonCustomPropertyId(usize); +/// The length of all the non-custom properties. +pub const NON_CUSTOM_PROPERTY_ID_COUNT: usize = + ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}; + % if product == "gecko": #[allow(dead_code)] unsafe fn static_assert_nscsspropertyid() { @@ -435,6 +439,11 @@ unsafe fn static_assert_nscsspropertyid() { % endif impl NonCustomPropertyId { + /// Returns the underlying index, used for use counter. + pub fn bit(self) -> usize { + self.0 + } + #[cfg(feature = "gecko")] #[inline] fn to_nscsspropertyid(self) -> nsCSSPropertyID { @@ -450,7 +459,7 @@ impl NonCustomPropertyId { if prop < 0 { return Err(()); } - if prop >= ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} { + if prop >= NON_CUSTOM_PROPERTY_ID_COUNT as i32 { return Err(()); } // unsafe: guaranteed by static_assert_nscsspropertyid above. @@ -460,7 +469,7 @@ impl NonCustomPropertyId { /// Get the property name. #[inline] pub fn name(self) -> &'static str { - static MAP: [&'static str; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [ + static MAP: [&'static str; NON_CUSTOM_PROPERTY_ID_COUNT] = [ % for property in data.longhands + data.shorthands + data.all_aliases(): "${property.name}", % endfor @@ -635,7 +644,7 @@ impl NonCustomPropertyId { PropertyId::Shorthand(transmute((self.0 - ${len(data.longhands)}) as u16)) } } - assert!(self.0 < ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}); + assert!(self.0 < NON_CUSTOM_PROPERTY_ID_COUNT); let alias_id: AliasId = unsafe { transmute((self.0 - ${len(data.longhands) + len(data.shorthands)}) as u16) }; @@ -671,7 +680,7 @@ impl From<AliasId> for NonCustomPropertyId { /// A set of all properties #[derive(Clone, PartialEq)] pub struct NonCustomPropertyIdSet { - storage: [u32; (${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} - 1 + 32) / 32] + storage: [u32; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + 32) / 32] } impl NonCustomPropertyIdSet { @@ -1554,6 +1563,7 @@ impl UnparsedValue { ParsingMode::DEFAULT, quirks_mode, None, + None, ); let mut input = ParserInput::new(&css); @@ -1853,7 +1863,8 @@ impl PropertyId { } } - fn non_custom_id(&self) -> Option<NonCustomPropertyId> { + /// Returns the `NonCustomPropertyId` corresponding to this property id. + pub fn non_custom_id(&self) -> Option<NonCustomPropertyId> { Some(match *self { PropertyId::Custom(_) => return None, PropertyId::Shorthand(shorthand_id) => shorthand_id.into(), @@ -2198,7 +2209,7 @@ impl PropertyDeclaration { // FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774 // before adding skip_whitespace here. // This probably affects some test results. - let value = match input.try(|i| CSSWideKeyword::parse(i)) { + let value = match input.try(CSSWideKeyword::parse) { Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword), Err(()) => match ::custom_properties::SpecifiedValue::parse(input) { Ok(value) => DeclaredValueOwned::Value(value), @@ -2212,12 +2223,12 @@ impl PropertyDeclaration { name: property_name, value, })); - Ok(()) + return Ok(()); } PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => { input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. - input.try(|i| CSSWideKeyword::parse(i)).map(|keyword| { + input.try(CSSWideKeyword::parse).map(|keyword| { PropertyDeclaration::CSSWideKeyword( WideKeywordDeclaration { id, keyword }, ) @@ -2253,12 +2264,12 @@ impl PropertyDeclaration { }) }).map(|declaration| { declarations.push(declaration) - }) + })?; } PropertyId::ShorthandAlias(id, _) | PropertyId::Shorthand(id) => { input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. - if let Ok(keyword) = input.try(|i| CSSWideKeyword::parse(i)) { + if let Ok(keyword) = input.try(CSSWideKeyword::parse) { if id == ShorthandId::All { declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword) } else { @@ -2271,51 +2282,55 @@ impl PropertyDeclaration { )) } } - Ok(()) } else { input.look_for_var_functions(); // Not using parse_entirely here: each ${shorthand.ident}::parse_into function // needs to do so *before* pushing to `declarations`. id.parse_into(declarations, context, input).or_else(|err| { while let Ok(_) = input.next() {} // Look for var() after the error. - if input.seen_var_functions() { - input.reset(&start); - let (first_token_type, css) = - ::custom_properties::parse_non_custom_with_var(input).map_err(|e| { - StyleParseErrorKind::new_invalid( - non_custom_id.unwrap().name(), - e, - ) - })?; - let unparsed = Arc::new(UnparsedValue { - css: css.into_owned(), - first_token_type: first_token_type, - url_data: context.url_data.clone(), - from_shorthand: Some(id), - }); - if id == ShorthandId::All { - declarations.all_shorthand = AllShorthand::WithVariables(unparsed) - } else { - for id in id.longhands() { - declarations.push( - PropertyDeclaration::WithVariables(VariableDeclaration { - id, - value: unparsed.clone(), - }) - ) - } - } - Ok(()) - } else { - Err(StyleParseErrorKind::new_invalid( + if !input.seen_var_functions() { + return Err(StyleParseErrorKind::new_invalid( non_custom_id.unwrap().name(), err, - )) + )); } - }) + + input.reset(&start); + let (first_token_type, css) = + ::custom_properties::parse_non_custom_with_var(input).map_err(|e| { + StyleParseErrorKind::new_invalid( + non_custom_id.unwrap().name(), + e, + ) + })?; + let unparsed = Arc::new(UnparsedValue { + css: css.into_owned(), + first_token_type: first_token_type, + url_data: context.url_data.clone(), + from_shorthand: Some(id), + }); + if id == ShorthandId::All { + declarations.all_shorthand = AllShorthand::WithVariables(unparsed) + } else { + for id in id.longhands() { + declarations.push( + PropertyDeclaration::WithVariables(VariableDeclaration { + id, + value: unparsed.clone(), + }) + ) + } + } + Ok(()) + })?; } } } + debug_assert!(non_custom_id.is_some(), "Custom properties should've returned earlier"); + if let Some(use_counters) = context.use_counters { + use_counters.non_custom_properties.record(non_custom_id.unwrap()); + } + Ok(()) } } diff --git a/components/style/selector_parser.rs b/components/style/selector_parser.rs index 7250502b1ad..5d6ddbb0e3f 100644 --- a/components/style/selector_parser.rs +++ b/components/style/selector_parser.rs @@ -6,11 +6,14 @@ #![deny(missing_docs)] +use Atom; use cssparser::{Parser as CssParser, ParserInput}; +use element_state::ElementState; use selectors::parser::SelectorList; use std::fmt::{self, Debug, Write}; use style_traits::{CssWriter, ParseError, ToCss}; use stylesheets::{Namespaces, Origin, UrlExtraData}; +use values::serialize_atom_identifier; /// A convenient alias for the type that represents an attribute value used for /// selector parser implementation. @@ -172,27 +175,49 @@ impl<T> PerPseudoElementMap<T> { } /// Values for the :dir() pseudo class +/// +/// "ltr" and "rtl" values are normalized to lowercase. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] -pub enum Direction { - /// left-to-right semantic directionality +pub struct Direction(pub Atom); + +/// Horizontal values for the :dir() pseudo class +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum HorizontalDirection { + /// :dir(ltr) Ltr, - /// right-to-left semantic directionality + /// :dir(rtl) Rtl, - /// Some other provided directionality value - /// - /// TODO(emilio): If we atomize we can then unbox in NonTSPseudoClass. - Other(Box<str>), } impl Direction { /// Parse a direction value. pub fn parse<'i, 't>(parser: &mut CssParser<'i, 't>) -> Result<Self, ParseError<'i>> { let ident = parser.expect_ident()?; - Ok(match_ignore_ascii_case! { &ident, - "rtl" => Direction::Rtl, - "ltr" => Direction::Ltr, - _ => Direction::Other(Box::from(ident.as_ref())), - }) + Ok(Direction(match_ignore_ascii_case! { &ident, + "rtl" => atom!("rtl"), + "ltr" => atom!("ltr"), + _ => Atom::from(ident.as_ref()), + })) + } + + /// Convert this Direction into a HorizontalDirection, if applicable + pub fn as_horizontal_direction(&self) -> Option<HorizontalDirection> { + if self.0 == atom!("ltr") { + Some(HorizontalDirection::Ltr) + } else if self.0 == atom!("rtl") { + Some(HorizontalDirection::Rtl) + } else { + None + } + } + + /// Gets the element state relevant to this :dir() selector. + pub fn element_state(&self) -> ElementState { + match self.as_horizontal_direction() { + Some(HorizontalDirection::Ltr) => ElementState::IN_LTR_STATE, + Some(HorizontalDirection::Rtl) => ElementState::IN_RTL_STATE, + None => ElementState::empty(), + } } } @@ -201,12 +226,6 @@ impl ToCss for Direction { where W: Write, { - let dir_str = match *self { - Direction::Rtl => "rtl", - Direction::Ltr => "ltr", - // FIXME: This should be escaped as an identifier; see #19231 - Direction::Other(ref other) => other, - }; - dest.write_str(dir_str) + serialize_atom_identifier(&self.0, dest) } } diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index 2083539f51b..c608cd8488d 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -135,6 +135,10 @@ impl PseudoElement { self.is_before() || self.is_after() } + /// Whether this is an unknown ::-webkit- pseudo-element. + #[inline] + pub fn is_unknown_webkit_pseudo_element(&self) -> bool { false } + /// Whether this pseudo-element is the ::before pseudo. #[inline] pub fn is_before(&self) -> bool { @@ -284,8 +288,8 @@ impl PseudoElement { } } -/// The type used for storing pseudo-class string arguments. -pub type PseudoClassStringArg = Box<str>; +/// The type used for storing `:lang` arguments. +pub type Lang = Box<str>; /// A non tree-structural pseudo-class. /// See https://drafts.csswg.org/selectors-4/#structural-pseudos @@ -302,7 +306,7 @@ pub enum NonTSPseudoClass { Fullscreen, Hover, Indeterminate, - Lang(PseudoClassStringArg), + Lang(Lang), Link, PlaceholderShown, ReadWrite, diff --git a/components/style/stylesheets/keyframes_rule.rs b/components/style/stylesheets/keyframes_rule.rs index 91bc14be5b5..0246efa6780 100644 --- a/components/style/stylesheets/keyframes_rule.rs +++ b/components/style/stylesheets/keyframes_rule.rs @@ -219,6 +219,7 @@ impl Keyframe { ParsingMode::DEFAULT, parent_stylesheet_contents.quirks_mode, None, + None, ); context.namespaces = Some(&*namespaces); let mut input = ParserInput::new(css); diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index e3641f3e515..80766c289f8 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -264,6 +264,7 @@ impl CssRule { ParsingMode::DEFAULT, parent_stylesheet_contents.quirks_mode, None, + None, ); let mut input = ParserInput::new(css); diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs index 02730f7090d..1403a1d2547 100644 --- a/components/style/stylesheets/stylesheet.rs +++ b/components/style/stylesheets/stylesheet.rs @@ -24,6 +24,7 @@ use stylesheets::loader::StylesheetLoader; use stylesheets::rule_parser::{State, TopLevelRuleParser}; use stylesheets::rules_iterator::{EffectiveRules, EffectiveRulesIterator}; use stylesheets::rules_iterator::{NestedRuleIterationCondition, RulesIterator}; +use use_counters::UseCounters; /// This structure holds the user-agent and user stylesheets. pub struct UserAgentStylesheets { @@ -78,6 +79,7 @@ impl StylesheetContents { error_reporter: Option<&ParseErrorReporter>, quirks_mode: QuirksMode, line_number_offset: u32, + use_counters: Option<&UseCounters>, ) -> Self { let namespaces = RwLock::new(Namespaces::default()); let (rules, source_map_url, source_url) = Stylesheet::parse_rules( @@ -90,6 +92,7 @@ impl StylesheetContents { error_reporter, quirks_mode, line_number_offset, + use_counters, ); Self { @@ -315,6 +318,8 @@ impl Stylesheet { line_number_offset: u32, ) { let namespaces = RwLock::new(Namespaces::default()); + + // FIXME: Consider adding use counters to Servo? let (rules, source_map_url, source_url) = Self::parse_rules( css, &url_data, @@ -325,6 +330,7 @@ impl Stylesheet { error_reporter, existing.contents.quirks_mode, line_number_offset, + /* use_counters = */ None, ); *existing.contents.url_data.write() = url_data; @@ -350,6 +356,7 @@ impl Stylesheet { error_reporter: Option<&ParseErrorReporter>, quirks_mode: QuirksMode, line_number_offset: u32, + use_counters: Option<&UseCounters>, ) -> (Vec<CssRule>, Option<String>, Option<String>) { let mut rules = Vec::new(); let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset); @@ -362,6 +369,7 @@ impl Stylesheet { ParsingMode::DEFAULT, quirks_mode, error_reporter, + use_counters, ); let rule_parser = TopLevelRuleParser { @@ -421,6 +429,7 @@ impl Stylesheet { quirks_mode: QuirksMode, line_number_offset: u32, ) -> Self { + // FIXME: Consider adding use counters to Servo? let contents = StylesheetContents::from_str( css, url_data, @@ -430,6 +439,7 @@ impl Stylesheet { error_reporter, quirks_mode, line_number_offset, + /* use_counters = */ None, ); Stylesheet { diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 1fbf493667f..038c41ab103 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -24,11 +24,11 @@ use properties::{self, CascadeMode, ComputedValues}; use properties::{AnimationRules, PropertyDeclarationBlock}; use rule_cache::{RuleCache, RuleCacheConditions}; use rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource}; -use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry}; +use selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry}; use selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap}; use selectors::NthIndexCache; use selectors::attr::{CaseSensitivity, NamespaceConstraint}; -use selectors::bloom::{BloomFilter, NonCountingBloomFilter}; +use selectors::bloom::BloomFilter; use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext, MatchingMode}; use selectors::matching::VisitedHandlingMode; use selectors::parser::{AncestorHashes, Combinator, Component, Selector}; @@ -1206,7 +1206,7 @@ impl Stylist { // to add some sort of AuthorScoped cascade level or something. if matches_author_rules { if let Some(shadow) = rule_hash_target.shadow_root() { - if let Some(map) = shadow.style_data().host_rules(pseudo_element) { + if let Some(map) = shadow.style_data().and_then(|data| data.host_rules(pseudo_element)) { context.with_shadow_host(Some(rule_hash_target), |context| { map.get_all_matching_rules( element, @@ -1233,8 +1233,7 @@ impl Stylist { for slot in slots.iter().rev() { let shadow = slot.containing_shadow().unwrap(); - let styles = shadow.style_data(); - if let Some(map) = styles.slotted_rules(pseudo_element) { + if let Some(map) = shadow.style_data().and_then(|data| data.slotted_rules(pseudo_element)) { context.with_shadow_host(Some(shadow.host()), |context| { map.get_all_matching_rules( element, @@ -1253,7 +1252,7 @@ impl Stylist { if let Some(containing_shadow) = rule_hash_target.containing_shadow() { let cascade_data = containing_shadow.style_data(); let host = containing_shadow.host(); - if let Some(map) = cascade_data.normal_rules(pseudo_element) { + if let Some(map) = cascade_data.and_then(|data| data.normal_rules(pseudo_element)) { context.with_shadow_host(Some(host), |context| { map.get_all_matching_rules( element, @@ -1283,6 +1282,11 @@ impl Stylist { // // See: https://github.com/w3c/svgwg/issues/505 // + // FIXME(emilio, bug 1487259): We now do after bug 1483882, we + // should jump out of the <svg:use> shadow tree chain now. + // + // Unless the used node is cross-doc, I guess, in which case doc + // rules are probably ok... let host_is_svg_use = host.is_svg_element() && host.local_name() == &*local_name!("use"); @@ -1392,8 +1396,7 @@ impl Stylist { CaseSensitivity::CaseSensitive => {}, } - let hash = id.get_hash(); - self.any_applicable_rule_data(element, |data| data.mapped_ids.might_contain_hash(hash)) + self.any_applicable_rule_data(element, |data| data.mapped_ids.contains(id)) } /// Returns the registered `@keyframes` animation for the specified name. @@ -1431,11 +1434,15 @@ impl Stylist { // [2]: https://github.com/w3c/csswg-drafts/issues/1995 // [3]: https://bugzil.la/1458189 if let Some(shadow) = element.shadow_root() { - try_find_in!(shadow.style_data()); + if let Some(data) = shadow.style_data() { + try_find_in!(data); + } } if let Some(shadow) = element.containing_shadow() { - try_find_in!(shadow.style_data()); + if let Some(data) = shadow.style_data() { + try_find_in!(data); + } } else { try_find_in!(self.cascade_data.author); } @@ -1745,11 +1752,9 @@ struct StylistSelectorVisitor<'a> { passed_rightmost_selector: bool, /// The filter with all the id's getting referenced from rightmost /// selectors. - mapped_ids: &'a mut NonCountingBloomFilter, + mapped_ids: &'a mut PrecomputedHashSet<Atom>, /// The filter with the local names of attributes there are selectors for. - attribute_dependencies: &'a mut NonCountingBloomFilter, - /// Whether there's any attribute selector for the [style] attribute. - style_attribute_dependency: &'a mut bool, + attribute_dependencies: &'a mut PrecomputedHashSet<LocalName>, /// All the states selectors in the page reference. state_dependencies: &'a mut ElementState, /// All the document states selectors in the page reference. @@ -1814,13 +1819,8 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> { name: &LocalName, lower_name: &LocalName, ) -> bool { - if *lower_name == local_name!("style") { - *self.style_attribute_dependency = true; - } else { - self.attribute_dependencies.insert_hash(name.get_hash()); - self.attribute_dependencies - .insert_hash(lower_name.get_hash()); - } + self.attribute_dependencies.insert(name.clone()); + self.attribute_dependencies.insert(lower_name.clone()); true } @@ -1846,7 +1846,7 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> { // // NOTE(emilio): See the comment regarding on when this may // break in visit_complex_selector. - self.mapped_ids.insert_hash(id.get_hash()); + self.mapped_ids.insert(id.clone()); }, _ => {}, } @@ -1878,7 +1878,9 @@ impl ElementAndPseudoRules { pseudo_element: Option<&PseudoElement>, quirks_mode: QuirksMode, ) -> Result<(), FailedAllocationError> { - debug_assert!(pseudo_element.map_or(true, |pseudo| !pseudo.is_precomputed())); + debug_assert!(pseudo_element.map_or(true, |pseudo| { + !pseudo.is_precomputed() && !pseudo.is_unknown_webkit_pseudo_element() + })); let map = match pseudo_element { None => &mut self.element_map, @@ -1944,18 +1946,9 @@ pub struct CascadeData { /// The attribute local names that appear in attribute selectors. Used /// to avoid taking element snapshots when an irrelevant attribute changes. - /// (We don't bother storing the namespace, since namespaced attributes - /// are rare.) - #[ignore_malloc_size_of = "just an array"] - attribute_dependencies: NonCountingBloomFilter, - - /// Whether `"style"` appears in an attribute selector. This is not common, - /// and by tracking this explicitly, we can avoid taking an element snapshot - /// in the common case of style=""` changing due to modifying - /// `element.style`. (We could track this in `attribute_dependencies`, like - /// all other attributes, but we should probably not risk incorrectly - /// returning `true` for `"style"` just due to a hash collision.) - style_attribute_dependency: bool, + /// (We don't bother storing the namespace, since namespaced attributes are + /// rare.) + attribute_dependencies: PrecomputedHashSet<LocalName>, /// The element state bits that are relied on by selectors. Like /// `attribute_dependencies`, this is used to avoid taking element snapshots @@ -1971,8 +1964,7 @@ pub struct CascadeData { /// hence in our selector maps). Used to determine when sharing styles is /// safe: we disallow style sharing for elements whose id matches this /// filter, and hence might be in one of our selector maps. - #[ignore_malloc_size_of = "just an array"] - mapped_ids: NonCountingBloomFilter, + mapped_ids: PrecomputedHashSet<Atom>, /// Selectors that require explicit cache revalidation (i.e. which depend /// on state that is not otherwise visible to the cache, like attributes or @@ -2009,11 +2001,10 @@ impl CascadeData { host_rules: None, slotted_rules: None, invalidation_map: InvalidationMap::new(), - attribute_dependencies: NonCountingBloomFilter::new(), - style_attribute_dependency: false, + attribute_dependencies: PrecomputedHashSet::default(), state_dependencies: ElementState::empty(), document_state_dependencies: DocumentState::empty(), - mapped_ids: NonCountingBloomFilter::new(), + mapped_ids: PrecomputedHashSet::default(), selectors_for_cache_revalidation: SelectorMap::new(), animations: Default::default(), extra_data: ExtraStyleData::default(), @@ -2078,13 +2069,9 @@ impl CascadeData { /// selector of some rule. #[inline] pub fn might_have_attribute_dependency(&self, local_name: &LocalName) -> bool { - if *local_name == local_name!("style") { - return self.style_attribute_dependency; - } - - self.attribute_dependencies - .might_contain_hash(local_name.get_hash()) + self.attribute_dependencies.contains(local_name) } + #[inline] fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> { self.normal_rules.rules(pseudo) @@ -2191,6 +2178,9 @@ impl CascadeData { )); continue; } + if pseudo.is_unknown_webkit_pseudo_element() { + continue; + } } let hashes = AncestorHashes::new(&selector, quirks_mode); @@ -2208,7 +2198,6 @@ impl CascadeData { needs_revalidation: false, passed_rightmost_selector: false, attribute_dependencies: &mut self.attribute_dependencies, - style_attribute_dependency: &mut self.style_attribute_dependency, state_dependencies: &mut self.state_dependencies, document_state_dependencies: &mut self.document_state_dependencies, mapped_ids: &mut self.mapped_ids, @@ -2418,7 +2407,6 @@ impl CascadeData { self.clear_cascade_data(); self.invalidation_map.clear(); self.attribute_dependencies.clear(); - self.style_attribute_dependency = false; self.state_dependencies = ElementState::empty(); self.document_state_dependencies = DocumentState::empty(); self.mapped_ids.clear(); @@ -2514,16 +2502,14 @@ impl Rule { /// A function to be able to test the revalidation stuff. pub fn needs_revalidation_for_testing(s: &Selector<SelectorImpl>) -> bool { - let mut attribute_dependencies = NonCountingBloomFilter::new(); - let mut mapped_ids = NonCountingBloomFilter::new(); - let mut style_attribute_dependency = false; + let mut attribute_dependencies = Default::default(); + let mut mapped_ids = Default::default(); let mut state_dependencies = ElementState::empty(); let mut document_state_dependencies = DocumentState::empty(); let mut visitor = StylistSelectorVisitor { needs_revalidation: false, passed_rightmost_selector: false, attribute_dependencies: &mut attribute_dependencies, - style_attribute_dependency: &mut style_attribute_dependency, state_dependencies: &mut state_dependencies, document_state_dependencies: &mut document_state_dependencies, mapped_ids: &mut mapped_ids, diff --git a/components/style/use_counters/mod.rs b/components/style/use_counters/mod.rs new file mode 100644 index 00000000000..92bc6adb01a --- /dev/null +++ b/components/style/use_counters/mod.rs @@ -0,0 +1,87 @@ +/* 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/. */ + +//! Various stuff for CSS property use counters. + +#[cfg(feature = "gecko")] +use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; +use properties::{NonCustomPropertyId, NON_CUSTOM_PROPERTY_ID_COUNT}; +use std::cell::Cell; + +#[cfg(target_pointer_width = "64")] +const BITS_PER_ENTRY: usize = 64; + +#[cfg(target_pointer_width = "32")] +const BITS_PER_ENTRY: usize = 32; + +/// One bit per each non-custom CSS property. +#[derive(Default)] +pub struct NonCustomPropertyUseCounters { + storage: [Cell<usize>; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + BITS_PER_ENTRY) / BITS_PER_ENTRY], +} + +impl NonCustomPropertyUseCounters { + /// Returns the bucket a given property belongs in, and the bitmask for that + /// property. + #[inline(always)] + fn bucket_and_pattern(id: NonCustomPropertyId) -> (usize, usize) { + let bit = id.bit(); + let bucket = bit / BITS_PER_ENTRY; + let bit_in_bucket = bit % BITS_PER_ENTRY; + (bucket, 1 << bit_in_bucket) + } + + /// Record that a given non-custom property ID has been parsed. + #[inline] + pub fn record(&self, id: NonCustomPropertyId) { + let (bucket, pattern) = Self::bucket_and_pattern(id); + let bucket = &self.storage[bucket]; + bucket.set(bucket.get() | pattern) + } + + /// Returns whether a given non-custom property ID has been recorded + /// earlier. + #[inline] + pub fn recorded(&self, id: NonCustomPropertyId) -> bool { + let (bucket, pattern) = Self::bucket_and_pattern(id); + self.storage[bucket].get() & pattern != 0 + } + + /// Merge `other` into `self`. + #[inline] + fn merge(&self, other: &Self) { + for (bucket, other_bucket) in self.storage.iter().zip(other.storage.iter()) { + bucket.set(bucket.get() | other_bucket.get()) + } + } +} + +/// The use-counter data related to a given document we want to store. +#[derive(Default)] +pub struct UseCounters { + /// The counters for non-custom properties that have been parsed in the + /// document's stylesheets. + pub non_custom_properties: NonCustomPropertyUseCounters, +} + +impl UseCounters { + /// Merge the use counters. + /// + /// Used for parallel parsing, where we parse off-main-thread. + #[inline] + pub fn merge(&self, other: &Self) { + self.non_custom_properties.merge(&other.non_custom_properties) + } +} + +#[cfg(feature = "gecko")] +unsafe impl HasFFI for UseCounters { + type FFIType = ::gecko_bindings::structs::StyleUseCounters; +} + +#[cfg(feature = "gecko")] +unsafe impl HasSimpleFFI for UseCounters {} + +#[cfg(feature = "gecko")] +unsafe impl HasBoxFFI for UseCounters {} diff --git a/components/style/values/computed/border.rs b/components/style/values/computed/border.rs index cf97a96ad73..8c54aeba43b 100644 --- a/components/style/values/computed/border.rs +++ b/components/style/values/computed/border.rs @@ -81,3 +81,19 @@ impl ToAnimatedZero for BorderCornerRadius { Err(()) } } + +impl BorderRadius { + /// Returns whether all the values are `0px`. + pub fn all_zero(&self) -> bool { + fn all(corner: &BorderCornerRadius) -> bool { + fn is_zero(l: &LengthOrPercentage) -> bool { + *l == LengthOrPercentage::zero() + } + is_zero(corner.0.width()) && is_zero(corner.0.height()) + } + all(&self.top_left) && + all(&self.top_right) && + all(&self.bottom_left) && + all(&self.bottom_right) + } +} diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 9a6b5fd76b5..d8cc938c1f3 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -65,6 +65,7 @@ pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercent pub use self::list::Quotes; #[cfg(feature = "gecko")] pub use self::list::ListStyleType; +pub use self::motion::OffsetPath; pub use self::outline::OutlineStyle; pub use self::percentage::{Percentage, NonNegativePercentage}; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex}; @@ -100,6 +101,7 @@ pub mod gecko; pub mod image; pub mod length; pub mod list; +pub mod motion; pub mod outline; pub mod percentage; pub mod position; diff --git a/components/style/values/computed/motion.rs b/components/style/values/computed/motion.rs new file mode 100644 index 00000000000..935ba57f845 --- /dev/null +++ b/components/style/values/computed/motion.rs @@ -0,0 +1,10 @@ +/* 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/. */ + +//! Computed types for CSS values that are related to motion path. + +/// A computed offset-path. The computed value is as specified value. +/// +/// https://drafts.fxtf.org/motion-1/#offset-path-property +pub use values::specified::motion::OffsetPath as OffsetPath; diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index 3bad738c1e6..0eccf011c71 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -12,6 +12,7 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::generics::border::BorderRadius; use values::generics::position::Position; use values::generics::rect::Rect; +use values::specified::SVGPathData; /// A clipping shape, for `clip-path`. pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, Url>; @@ -54,6 +55,9 @@ pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> { #[animation(error)] Box(ReferenceBox), #[animation(error)] + #[css(function)] + Path(Path), + #[animation(error)] None, } @@ -113,16 +117,23 @@ pub enum ShapeRadius<LengthOrPercentage> { /// A generic type for representing the `polygon()` function /// /// <https://drafts.csswg.org/css-shapes/#funcdef-polygon> -#[css(function)] +#[css(comma, function)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue)] + ToComputedValue, ToCss)] pub struct Polygon<LengthOrPercentage> { /// The filling rule for a polygon. + #[css(skip_if = "fill_is_default")] pub fill: FillRule, /// A collection of (x, y) coordinates to draw the polygon. - pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>, + #[css(iterable)] + pub coordinates: Vec<PolygonCoord<LengthOrPercentage>>, } +/// Coordinates for Polygon. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] +pub struct PolygonCoord<LengthOrPercentage>(pub LengthOrPercentage, pub LengthOrPercentage); + // https://drafts.csswg.org/css-shapes/#typedef-fill-rule // NOTE: Basic shapes spec says that these are the only two values, however // https://www.w3.org/TR/SVG/painting.html#FillRuleProperty @@ -131,11 +142,25 @@ pub struct Polygon<LengthOrPercentage> { #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] +#[repr(u8)] pub enum FillRule { Nonzero, Evenodd, } +/// The path function defined in css-shape-2. +/// +/// https://drafts.csswg.org/css-shapes-2/#funcdef-path +#[css(comma)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] +pub struct Path { + /// The filling rule for the svg path. + #[css(skip_if = "fill_is_default")] + pub fill: FillRule, + /// The svg path data. + pub path: SVGPathData, +} + // FIXME(nox): Implement ComputeSquaredDistance for T types and stop // using PartialEq here, this will let us derive this impl. impl<B, T, U> ComputeSquaredDistance for ShapeSource<B, T, U> @@ -203,7 +228,7 @@ where .iter() .zip(other.coordinates.iter()) .map(|(this, other)| { - Ok(( + Ok(PolygonCoord( this.0.animate(&other.0, procedure)?, this.1.animate(&other.1, procedure)?, )) @@ -239,34 +264,14 @@ where } } -impl<L: ToCss> ToCss for Polygon<L> { - fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result - where - W: Write, - { - dest.write_str("polygon(")?; - if self.fill != FillRule::default() { - self.fill.to_css(dest)?; - dest.write_str(", ")?; - } - - for (i, coord) in self.coordinates.iter().enumerate() { - if i > 0 { - dest.write_str(", ")?; - } - - coord.0.to_css(dest)?; - dest.write_str(" ")?; - coord.1.to_css(dest)?; - } - - dest.write_str(")") - } -} - impl Default for FillRule { #[inline] fn default() -> Self { FillRule::Nonzero } } + +#[inline] +fn fill_is_default(fill: &FillRule) -> bool { + *fill == FillRule::default() +} diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index 23ae91d564e..824c13f1f01 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -14,9 +14,11 @@ use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use values::computed::Percentage; use values::generics::basic_shape as generic; -use values::generics::basic_shape::{FillRule, GeometryBox, ShapeBox, ShapeSource}; +use values::generics::basic_shape::{FillRule, GeometryBox, Path, PolygonCoord}; +use values::generics::basic_shape::{ShapeBox, ShapeSource}; use values::generics::rect::Rect; use values::specified::LengthOrPercentage; +use values::specified::SVGPathData; use values::specified::border::BorderRadius; use values::specified::image::Image; use values::specified::position::{HorizontalPosition, Position, PositionComponent}; @@ -47,12 +49,42 @@ pub type ShapeRadius = generic::ShapeRadius<LengthOrPercentage>; /// The specified value of `Polygon` pub type Polygon = generic::Polygon<LengthOrPercentage>; -impl<ReferenceBox, ImageOrUrl> Parse for ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> +impl Parse for ClippingShape { + #[inline] + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + // |clip-path:path()| is a chrome-only property value support for now. `path()` is + // defined in css-shape-2, but the spec is not stable enough, and we haven't decided + // to make it public yet. However, it has some benefits for the front-end, so we + // implement it. + if context.chrome_rules_enabled() { + if let Ok(p) = input.try(|i| Path::parse(context, i)) { + return Ok(ShapeSource::Path(p)); + } + } + Self::parse_internal(context, input) + } +} + +impl Parse for FloatAreaShape { + #[inline] + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + Self::parse_internal(context, input) + } +} + +impl<ReferenceBox, ImageOrUrl> ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> where ReferenceBox: Parse, ImageOrUrl: Parse, { - fn parse<'i, 't>( + /// The internal parser for ShapeSource. + fn parse_internal<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { @@ -381,7 +413,7 @@ impl Polygon { .unwrap_or_default(); let buf = input.parse_comma_separated(|i| { - Ok(( + Ok(PolygonCoord( LengthOrPercentage::parse(context, i)?, LengthOrPercentage::parse(context, i)?, )) @@ -393,3 +425,29 @@ impl Polygon { }) } } + +impl Parse for Path { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + input.expect_function_matching("path")?; + input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) + } +} + +impl Path { + /// Parse the inner arguments of a `path` function. + fn parse_function_arguments<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + let fill = input.try(|i| -> Result<_, ParseError> { + let fill = FillRule::parse(i)?; + i.expect_comma()?; + Ok(fill) + }).unwrap_or_default(); + let path = SVGPathData::parse(context, input)?; + Ok(Path { fill, path }) + } +} diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index 6b474689df3..9554d76890c 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -57,8 +57,8 @@ fn moz_box_display_values_enabled(context: &ParserContext) -> bool { /// Also, when you change this from Gecko you may need to regenerate the /// C++-side bindings (see components/style/cbindgen.toml). #[allow(missing_docs)] -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, - SpecifiedValueInfo, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, Parse, + PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[repr(u8)] pub enum Display { diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 2da4c7e93d3..6a395c21e58 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -58,6 +58,7 @@ pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercent pub use self::list::Quotes; #[cfg(feature = "gecko")] pub use self::list::ListStyleType; +pub use self::motion::OffsetPath; pub use self::outline::OutlineStyle; pub use self::rect::LengthOrNumberRect; pub use self::resolution::Resolution; @@ -67,6 +68,7 @@ pub use self::position::{PositionComponent, ZIndex}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::MozContextProperties; +pub use self::svg_path::SVGPathData; pub use self::table::XSpan; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign}; pub use self::text::{TextEmphasisPosition, TextEmphasisStyle}; @@ -100,6 +102,7 @@ pub mod grid; pub mod image; pub mod length; pub mod list; +pub mod motion; pub mod outline; pub mod percentage; pub mod position; @@ -107,6 +110,7 @@ pub mod rect; pub mod resolution; pub mod source_size_list; pub mod svg; +pub mod svg_path; pub mod table; pub mod text; pub mod time; diff --git a/components/style/values/specified/motion.rs b/components/style/values/specified/motion.rs new file mode 100644 index 00000000000..87ff39d9a3a --- /dev/null +++ b/components/style/values/specified/motion.rs @@ -0,0 +1,61 @@ +/* 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/. */ + +//! Specified types for CSS values that are related to motion path. + +use cssparser::Parser; +use parser::{Parse, ParserContext}; +use style_traits::{ParseError, StyleParseErrorKind}; +use values::specified::SVGPathData; + +/// The offset-path value. +/// +/// https://drafts.fxtf.org/motion-1/#offset-path-property +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] +pub enum OffsetPath { + // We could merge SVGPathData into ShapeSource, so we could reuse them. However, + // we don't want to support other value for offset-path, so use SVGPathData only for now. + /// Path value for path(<string>). + #[css(function)] + Path(SVGPathData), + /// None value. + None, + // Bug 1186329: Implement ray(), <basic-shape>, <geometry-box>, and <url>. +} + +impl OffsetPath { + /// Return None. + #[inline] + pub fn none() -> Self { + OffsetPath::None + } +} + +impl Parse for OffsetPath { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't> + ) -> Result<Self, ParseError<'i>> { + // Parse none. + if input.try(|i| i.expect_ident_matching("none")).is_ok() { + return Ok(OffsetPath::none()); + } + + // Parse possible functions. + let location = input.current_source_location(); + let function = input.expect_function()?.clone(); + input.parse_nested_block(move |i| { + match_ignore_ascii_case! { &function, + // Bug 1186329: Implement the parser for ray(), <basic-shape>, <geometry-box>, + // and <url>. + "path" => SVGPathData::parse(context, i).map(OffsetPath::Path), + _ => { + Err(location.new_custom_error( + StyleParseErrorKind::UnexpectedFunction(function.clone()) + )) + }, + } + }) + } +} diff --git a/components/style/values/specified/svg_path.rs b/components/style/values/specified/svg_path.rs new file mode 100644 index 00000000000..48ae185477d --- /dev/null +++ b/components/style/values/specified/svg_path.rs @@ -0,0 +1,515 @@ +/* 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/. */ + +//! Specified types for SVG Path. + +use cssparser::Parser; +use parser::{Parse, ParserContext}; +use std::fmt::{self, Write}; +use std::iter::{Cloned, Peekable}; +use std::slice; +use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::values::SequenceWriter; +use values::CSSFloat; + + +/// The SVG path data. +/// +/// https://www.w3.org/TR/SVG11/paths.html#PathData +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] +pub struct SVGPathData(Box<[PathCommand]>); + +impl SVGPathData { + /// Return SVGPathData by a slice of PathCommand. + #[inline] + pub fn new(cmd: Box<[PathCommand]>) -> Self { + debug_assert!(!cmd.is_empty()); + SVGPathData(cmd) + } + + /// Get the array of PathCommand. + #[inline] + pub fn commands(&self) -> &[PathCommand] { + debug_assert!(!self.0.is_empty()); + &self.0 + } +} + +impl ToCss for SVGPathData { + #[inline] + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: fmt::Write + { + dest.write_char('"')?; + { + let mut writer = SequenceWriter::new(dest, " "); + for command in self.0.iter() { + writer.item(command)?; + } + } + dest.write_char('"') + } +} + +impl Parse for SVGPathData { + // We cannot use cssparser::Parser to parse a SVG path string because the spec wants to make + // the SVG path string as compact as possible. (i.e. The whitespaces may be dropped.) + // e.g. "M100 200L100 200" is a valid SVG path string. If we use tokenizer, the first ident + // is "M100", instead of "M", and this is not correct. Therefore, we use a Peekable + // str::Char iterator to check each character. + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't> + ) -> Result<Self, ParseError<'i>> { + let location = input.current_source_location(); + let path_string = input.expect_string()?.as_ref(); + if path_string.is_empty() { + // Treat an empty string as invalid, so we will not set it. + return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + // Parse the svg path string as multiple sub-paths. + let mut path_parser = PathParser::new(path_string); + while skip_wsp(&mut path_parser.chars) { + if path_parser.parse_subpath().is_err() { + return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + } + + Ok(SVGPathData::new(path_parser.path.into_boxed_slice())) + } +} + + +/// The SVG path command. +/// The fields of these commands are self-explanatory, so we skip the documents. +/// Note: the index of the control points, e.g. control1, control2, are mapping to the control +/// points of the Bézier curve in the spec. +/// +/// https://www.w3.org/TR/SVG11/paths.html#PathData +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)] +#[allow(missing_docs)] +#[repr(C, u8)] +pub enum PathCommand { + /// The unknown type. + /// https://www.w3.org/TR/SVG/paths.html#__svg__SVGPathSeg__PATHSEG_UNKNOWN + Unknown, + /// The "moveto" command. + MoveTo { point: CoordPair, absolute: bool }, + /// The "lineto" command. + LineTo { point: CoordPair, absolute: bool }, + /// The horizontal "lineto" command. + HorizontalLineTo { x: CSSFloat, absolute: bool }, + /// The vertical "lineto" command. + VerticalLineTo { y: CSSFloat, absolute: bool }, + /// The cubic Bézier curve command. + CurveTo { control1: CoordPair, control2: CoordPair, point: CoordPair, absolute: bool }, + /// The smooth curve command. + SmoothCurveTo { control2: CoordPair, point: CoordPair, absolute: bool }, + /// The quadratic Bézier curve command. + QuadBezierCurveTo { control1: CoordPair, point: CoordPair, absolute: bool }, + /// The smooth quadratic Bézier curve command. + SmoothQuadBezierCurveTo { point: CoordPair, absolute: bool }, + /// The elliptical arc curve command. + EllipticalArc { + rx: CSSFloat, + ry: CSSFloat, + angle: CSSFloat, + large_arc_flag: bool, + sweep_flag: bool, + point: CoordPair, + absolute: bool + }, + /// The "closepath" command. + ClosePath, +} + +impl ToCss for PathCommand { + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: fmt::Write + { + use self::PathCommand::*; + match *self { + Unknown => dest.write_char('X'), + ClosePath => dest.write_char('Z'), + MoveTo { point, absolute } => { + dest.write_char(if absolute { 'M' } else { 'm' })?; + dest.write_char(' ')?; + point.to_css(dest) + } + LineTo { point, absolute } => { + dest.write_char(if absolute { 'L' } else { 'l' })?; + dest.write_char(' ')?; + point.to_css(dest) + } + CurveTo { control1, control2, point, absolute } => { + dest.write_char(if absolute { 'C' } else { 'c' })?; + dest.write_char(' ')?; + control1.to_css(dest)?; + dest.write_char(' ')?; + control2.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest) + }, + QuadBezierCurveTo { control1, point, absolute } => { + dest.write_char(if absolute { 'Q' } else { 'q' })?; + dest.write_char(' ')?; + control1.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest) + }, + EllipticalArc { rx, ry, angle, large_arc_flag, sweep_flag, point, absolute } => { + dest.write_char(if absolute { 'A' } else { 'a' })?; + dest.write_char(' ')?; + rx.to_css(dest)?; + dest.write_char(' ')?; + ry.to_css(dest)?; + dest.write_char(' ')?; + angle.to_css(dest)?; + dest.write_char(' ')?; + (large_arc_flag as i32).to_css(dest)?; + dest.write_char(' ')?; + (sweep_flag as i32).to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest) + }, + HorizontalLineTo { x, absolute } => { + dest.write_char(if absolute { 'H' } else { 'h' })?; + dest.write_char(' ')?; + x.to_css(dest) + }, + VerticalLineTo { y, absolute } => { + dest.write_char(if absolute { 'V' } else { 'v' })?; + dest.write_char(' ')?; + y.to_css(dest) + }, + SmoothCurveTo { control2, point, absolute } => { + dest.write_char(if absolute { 'S' } else { 's' })?; + dest.write_char(' ')?; + control2.to_css(dest)?; + dest.write_char(' ')?; + point.to_css(dest) + }, + SmoothQuadBezierCurveTo { point, absolute } => { + dest.write_char(if absolute { 'T' } else { 't' })?; + dest.write_char(' ')?; + point.to_css(dest) + }, + } + } +} + + +/// The path coord type. +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] +#[repr(C)] +pub struct CoordPair(CSSFloat, CSSFloat); + +impl CoordPair { + /// Create a CoordPair. + #[inline] + pub fn new(x: CSSFloat, y: CSSFloat) -> Self { + CoordPair(x, y) + } +} + + +/// SVG Path parser. +struct PathParser<'a> { + chars: Peekable<Cloned<slice::Iter<'a, u8>>>, + path: Vec<PathCommand>, +} + +macro_rules! parse_arguments { + ( + $parser:ident, + $abs:ident, + $enum:ident, + [ $para:ident => $func:ident $(, $other_para:ident => $other_func:ident)* ] + ) => { + { + loop { + let $para = $func(&mut $parser.chars)?; + $( + skip_comma_wsp(&mut $parser.chars); + let $other_para = $other_func(&mut $parser.chars)?; + )* + $parser.path.push(PathCommand::$enum { $para $(, $other_para)*, $abs }); + + // End of string or the next character is a possible new command. + if !skip_wsp(&mut $parser.chars) || + $parser.chars.peek().map_or(true, |c| c.is_ascii_alphabetic()) { + break; + } + skip_comma_wsp(&mut $parser.chars); + } + Ok(()) + } + } +} + +impl<'a> PathParser<'a> { + /// Return a PathParser. + #[inline] + fn new(string: &'a str) -> Self { + PathParser { + chars: string.as_bytes().iter().cloned().peekable(), + path: Vec::new(), + } + } + + /// Parse a sub-path. + fn parse_subpath(&mut self) -> Result<(), ()> { + // Handle "moveto" Command first. If there is no "moveto", this is not a valid sub-path + // (i.e. not a valid moveto-drawto-command-group). + self.parse_moveto()?; + + // Handle other commands. + loop { + skip_wsp(&mut self.chars); + if self.chars.peek().map_or(true, |&m| m == b'M' || m == b'm') { + break; + } + + match self.chars.next() { + Some(command) => { + let abs = command.is_ascii_uppercase(); + macro_rules! parse_command { + ( $($($p:pat)|+ => $parse_func:ident,)* ) => { + match command { + $( + $($p)|+ => { + skip_wsp(&mut self.chars); + self.$parse_func(abs)?; + }, + )* + _ => return Err(()), + } + } + } + parse_command!( + b'Z' | b'z' => parse_closepath, + b'L' | b'l' => parse_lineto, + b'H' | b'h' => parse_h_lineto, + b'V' | b'v' => parse_v_lineto, + b'C' | b'c' => parse_curveto, + b'S' | b's' => parse_smooth_curveto, + b'Q' | b'q' => parse_quadratic_bezier_curveto, + b'T' | b't' => parse_smooth_quadratic_bezier_curveto, + b'A' | b'a' => parse_elliprical_arc, + ); + }, + _ => break, // no more commands. + } + } + Ok(()) + } + + /// Parse "moveto" command. + fn parse_moveto(&mut self) -> Result<(), ()> { + let command = match self.chars.next() { + Some(c) if c == b'M' || c == b'm' => c, + _ => return Err(()), + }; + + skip_wsp(&mut self.chars); + let point = parse_coord(&mut self.chars)?; + let absolute = command == b'M'; + self.path.push(PathCommand::MoveTo { point, absolute } ); + + // End of string or the next character is a possible new command. + if !skip_wsp(&mut self.chars) || + self.chars.peek().map_or(true, |c| c.is_ascii_alphabetic()) { + return Ok(()); + } + skip_comma_wsp(&mut self.chars); + + // If a moveto is followed by multiple pairs of coordinates, the subsequent + // pairs are treated as implicit lineto commands. + self.parse_lineto(absolute) + } + + /// Parse "closepath" command. + fn parse_closepath(&mut self, _absolute: bool) -> Result<(), ()> { + self.path.push(PathCommand::ClosePath); + Ok(()) + } + + /// Parse "lineto" command. + fn parse_lineto(&mut self, absolute: bool) -> Result<(), ()> { + parse_arguments!(self, absolute, LineTo, [ point => parse_coord ]) + } + + /// Parse horizontal "lineto" command. + fn parse_h_lineto(&mut self, absolute: bool) -> Result<(), ()> { + parse_arguments!(self, absolute, HorizontalLineTo, [ x => parse_number ]) + } + + /// Parse vertical "lineto" command. + fn parse_v_lineto(&mut self, absolute: bool) -> Result<(), ()> { + parse_arguments!(self, absolute, VerticalLineTo, [ y => parse_number ]) + } + + /// Parse cubic Bézier curve command. + fn parse_curveto(&mut self, absolute: bool) -> Result<(), ()> { + parse_arguments!(self, absolute, CurveTo, [ + control1 => parse_coord, control2 => parse_coord, point => parse_coord + ]) + } + + /// Parse smooth "curveto" command. + fn parse_smooth_curveto(&mut self, absolute: bool) -> Result<(), ()> { + parse_arguments!(self, absolute, SmoothCurveTo, [ + control2 => parse_coord, point => parse_coord + ]) + } + + /// Parse quadratic Bézier curve command. + fn parse_quadratic_bezier_curveto(&mut self, absolute: bool) -> Result<(), ()> { + parse_arguments!(self, absolute, QuadBezierCurveTo, [ + control1 => parse_coord, point => parse_coord + ]) + } + + /// Parse smooth quadratic Bézier curveto command. + fn parse_smooth_quadratic_bezier_curveto(&mut self, absolute: bool) -> Result<(), ()> { + parse_arguments!(self, absolute, SmoothQuadBezierCurveTo, [ point => parse_coord ]) + } + + /// Parse elliptical arc curve command. + fn parse_elliprical_arc(&mut self, absolute: bool) -> Result<(), ()> { + // Parse a flag whose value is '0' or '1'; otherwise, return Err(()). + let parse_flag = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| -> Result<bool, ()> { + match iter.next() { + Some(c) if c == b'0' || c == b'1' => Ok(c == b'1'), + _ => Err(()), + } + }; + parse_arguments!(self, absolute, EllipticalArc, [ + rx => parse_number, + ry => parse_number, + angle => parse_number, + large_arc_flag => parse_flag, + sweep_flag => parse_flag, + point => parse_coord + ]) + } +} + + +/// Parse a pair of numbers into CoordPair. +fn parse_coord(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> Result<CoordPair, ()> { + let x = parse_number(iter)?; + skip_comma_wsp(iter); + let y = parse_number(iter)?; + Ok(CoordPair::new(x, y)) +} + +/// This is a special version which parses the number for SVG Path. e.g. "M 0.6.5" should be parsed +/// as MoveTo with a coordinate of ("0.6", ".5"), instead of treating 0.6.5 as a non-valid floating +/// point number. In other words, the logic here is similar with that of +/// tokenizer::consume_numeric, which also consumes the number as many as possible, but here the +/// input is a Peekable and we only accept an integer of a floating point number. +/// +/// The "number" syntax in https://www.w3.org/TR/SVG/paths.html#PathDataBNF +fn parse_number(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> Result<CSSFloat, ()> { + // 1. Check optional sign. + let sign = if iter.peek().map_or(false, |&sign| sign == b'+' || sign == b'-') { + if iter.next().unwrap() == b'-' { -1. } else { 1. } + } else { + 1. + }; + + // 2. Check integer part. + let mut integral_part: f64 = 0.; + let got_dot = if !iter.peek().map_or(false, |&n| n == b'.') { + // If the first digit in integer part is neither a dot nor a digit, this is not a number. + if iter.peek().map_or(true, |n| !n.is_ascii_digit()) { + return Err(()); + } + + while iter.peek().map_or(false, |n| n.is_ascii_digit()) { + integral_part = + integral_part * 10. + (iter.next().unwrap() - b'0') as f64; + } + + iter.peek().map_or(false, |&n| n == b'.') + } else { + true + }; + + // 3. Check fractional part. + let mut fractional_part: f64 = 0.; + if got_dot { + // Consume '.'. + iter.next(); + // If the first digit in fractional part is not a digit, this is not a number. + if iter.peek().map_or(true, |n| !n.is_ascii_digit()) { + return Err(()); + } + + let mut factor = 0.1; + while iter.peek().map_or(false, |n| n.is_ascii_digit()) { + fractional_part += (iter.next().unwrap() - b'0') as f64 * factor; + factor *= 0.1; + } + } + + let mut value = sign * (integral_part + fractional_part); + + // 4. Check exp part. The segment name of SVG Path doesn't include 'E' or 'e', so it's ok to + // treat the numbers after 'E' or 'e' are in the exponential part. + if iter.peek().map_or(false, |&exp| exp == b'E' || exp == b'e') { + // Consume 'E' or 'e'. + iter.next(); + let exp_sign = if iter.peek().map_or(false, |&sign| sign == b'+' || sign == b'-') { + if iter.next().unwrap() == b'-' { -1. } else { 1. } + } else { + 1. + }; + + let mut exp: f64 = 0.; + while iter.peek().map_or(false, |n| n.is_ascii_digit()) { + exp = exp * 10. + (iter.next().unwrap() - b'0') as f64; + } + + value *= f64::powf(10., exp * exp_sign); + } + + if value.is_finite() { + Ok(value.min(::std::f32::MAX as f64).max(::std::f32::MIN as f64) as CSSFloat) + } else { + Err(()) + } +} + +/// Skip all svg whitespaces, and return true if |iter| hasn't finished. +#[inline] +fn skip_wsp(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> bool { + // Note: SVG 1.1 defines the whitespaces as \u{9}, \u{20}, \u{A}, \u{D}. + // However, SVG 2 has one extra whitespace: \u{C}. + // Therefore, we follow the newest spec for the definition of whitespace, + // i.e. \u{9}, \u{20}, \u{A}, \u{C}, \u{D}. + while iter.peek().map_or(false, |c| c.is_ascii_whitespace()) { + iter.next(); + } + iter.peek().is_some() +} + +/// Skip all svg whitespaces and one comma, and return true if |iter| hasn't finished. +#[inline] +fn skip_comma_wsp(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> bool { + if !skip_wsp(iter) { + return false; + } + + if *iter.peek().unwrap() != b',' { + return true; + } + iter.next(); + + skip_wsp(iter) +} diff --git a/tests/unit/style/parsing/mod.rs b/tests/unit/style/parsing/mod.rs index b75e3a7ce42..6f76b2efea6 100644 --- a/tests/unit/style/parsing/mod.rs +++ b/tests/unit/style/parsing/mod.rs @@ -19,9 +19,15 @@ where F: for<'t> Fn(&ParserContext, &mut Parser<'static, 't>) -> Result<T, Parse fn parse_input<'i: 't, 't, T, F>(f: F, input: &'t mut ParserInput<'i>) -> Result<T, ParseError<'i>> where F: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>> { let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap(); - let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, None); + let context = ParserContext::new( + Origin::Author, + &url, + Some(CssRuleType::Style), + ParsingMode::DEFAULT, + QuirksMode::NoQuirks, + None, + None, + ); let mut parser = Parser::new(input); f(&context, &mut parser) } diff --git a/tests/unit/style/properties/mod.rs b/tests/unit/style/properties/mod.rs index 725aabc42a4..5210b663168 100644 --- a/tests/unit/style/properties/mod.rs +++ b/tests/unit/style/properties/mod.rs @@ -24,9 +24,15 @@ where F: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>>, { let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap(); - let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, None); + let context = ParserContext::new( + Origin::Author, + &url, + Some(CssRuleType::Style), + ParsingMode::DEFAULT, + QuirksMode::NoQuirks, + None, + None, + ); let mut parser = Parser::new(input); f(&context, &mut parser) } diff --git a/tests/unit/style/viewport.rs b/tests/unit/style/viewport.rs index 9243dbcb403..a8d01651c3d 100644 --- a/tests/unit/style/viewport.rs +++ b/tests/unit/style/viewport.rs @@ -301,9 +301,15 @@ fn multiple_stylesheets_cascading() { #[test] fn constrain_viewport() { let url = ServoUrl::parse("http://localhost").unwrap(); - let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Viewport), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, None); + let context = ParserContext::new( + Origin::Author, + &url, + Some(CssRuleType::Viewport), + ParsingMode::DEFAULT, + QuirksMode::NoQuirks, + None, + None, + ); macro_rules! from_css { ($css:expr) => { |