diff options
44 files changed, 512 insertions, 775 deletions
diff --git a/Cargo.lock b/Cargo.lock index 25d1dd886b9..9d5b7d5f676 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -684,7 +684,7 @@ dependencies = [ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -772,7 +772,7 @@ dependencies = [ "procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1123,7 +1123,7 @@ name = "fallible" version = "0.0.1" dependencies = [ "hashglobe 0.1.0", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1287,7 +1287,7 @@ dependencies = [ "servo_arc 0.1.1", "servo_atoms 0.0.1", "servo_url 0.0.1", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "truetype 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2012,7 +2012,7 @@ dependencies = [ "servo_geometry 0.0.1", "servo_url 0.0.1", "size_of_test 0.0.1", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "style_traits 0.0.1", "unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2136,7 +2136,7 @@ dependencies = [ "libservo 0.0.1", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2275,8 +2275,8 @@ dependencies = [ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "servo_arc 0.1.1", - "smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2850,7 +2850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3284,7 +3284,7 @@ dependencies = [ "servo_geometry 0.0.1", "servo_rand 0.0.1", "servo_url 0.0.1", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "style_traits 0.0.1", "swapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3400,7 +3400,7 @@ dependencies = [ "phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "servo_arc 0.1.1", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3528,7 +3528,7 @@ dependencies = [ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "servo_media_derive 0.1.0 (git+https://github.com/servo/media)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3762,12 +3762,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallbitvec" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.3" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3894,8 +3894,8 @@ dependencies = [ "servo_atoms 0.0.1", "servo_config 0.0.1", "servo_url 0.0.1", - "smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "style_derive 0.0.1", "style_traits 0.0.1", @@ -4575,7 +4575,7 @@ dependencies = [ "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_api 0.57.2 (git+https://github.com/servo/webrender)", @@ -5115,8 +5115,8 @@ dependencies = [ "checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "<none>" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" -"checksum smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c63726029f0069f88467873e47f392575f28f9f16b72ac65465263db4b3a13c" -"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8" +"checksum smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1764fe2b30ee783bfe3b9b37b2649d8d590b3148bb12e0079715d4d5c673562e" +"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" "checksum smithay-client-toolkit 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ef227bd9251cf8f8e54f8dd9a4b164307e515f5312cd632ebc87b56f723893a2" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "48fa7d3136d8645909de1f7c7eb5416cc43057a75ace08fc39ae736bc9da8af1" diff --git a/components/layout/display_list/border.rs b/components/layout/display_list/border.rs index 265b25a2805..d5909abee84 100644 --- a/components/layout/display_list/border.rs +++ b/components/layout/display_list/border.rs @@ -14,6 +14,7 @@ use style::values::computed::{BorderCornerRadius, BorderImageWidth}; use style::values::computed::{BorderImageSideWidth, LengthOrNumber}; use style::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; use style::values::generics::rect::Rect as StyleRect; +use style::values::generics::NonNegative; use style::values::Either; use webrender_api::{BorderRadius, BorderSide, BorderStyle, ColorF}; use webrender_api::{LayoutSideOffsets, LayoutSize, NormalBorder}; @@ -163,7 +164,7 @@ fn side_image_width( ) -> f32 { match border_image_width { GenericBorderImageSideWidth::Length(v) => v.to_used_value(total_length).to_f32_px(), - GenericBorderImageSideWidth::Number(x) => border_width * x, + GenericBorderImageSideWidth::Number(x) => border_width * x.0, GenericBorderImageSideWidth::Auto => border_width, } } @@ -181,15 +182,15 @@ pub fn image_width( ) } -fn resolve_percentage(value: NumberOrPercentage, length: i32) -> i32 { - match value { +fn resolve_percentage(value: NonNegative<NumberOrPercentage>, length: i32) -> i32 { + match value.0 { NumberOrPercentage::Percentage(p) => (p.0 * length as f32).round() as i32, NumberOrPercentage::Number(n) => n.round() as i32, } } pub fn image_slice( - border_image_slice: &StyleRect<NumberOrPercentage>, + border_image_slice: &StyleRect<NonNegative<NumberOrPercentage>>, width: i32, height: i32, ) -> SideOffsets2D<i32> { diff --git a/components/malloc_size_of/Cargo.toml b/components/malloc_size_of/Cargo.toml index 22840c89d8a..92b3db44c15 100644 --- a/components/malloc_size_of/Cargo.toml +++ b/components/malloc_size_of/Cargo.toml @@ -37,7 +37,7 @@ selectors = { path = "../selectors" } serde = { version = "1.0.27", optional = true } serde_bytes = { version = "0.10", optional = true } servo_arc = { path = "../servo_arc" } -smallbitvec = "2.1.0" +smallbitvec = "2.3.0" smallvec = "0.6" string_cache = { version = "0.7", optional = true } thin-slice = "0.1.0" diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 91cc8939590..233d4a01bb3 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -128,6 +128,7 @@ use style::selector_parser::{ }; use style::shared_lock::{Locked, SharedRwLock}; use style::thread_state; +use style::values::generics::NonNegative; use style::values::{computed, specified}; use style::values::{CSSFloat, Either}; use style::CaseSensitivityExt; @@ -847,8 +848,9 @@ impl LayoutElementHelpers for LayoutDom<Element> { }; if let Some(border) = border { - let width_value = - specified::BorderSideWidth::Length(specified::Length::from_px(border as f32)); + let width_value = specified::BorderSideWidth::Length(NonNegative( + specified::Length::from_px(border as f32), + )); hints.push(from_declaration( shared_lock, PropertyDeclaration::BorderTopWidth(width_value.clone()), diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 9ae935c0e4d..17612eff900 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -60,8 +60,8 @@ serde = {version = "1.0", optional = true, features = ["derive"]} servo_arc = { path = "../servo_arc" } servo_atoms = {path = "../atoms", optional = true} servo_config = {path = "../config", optional = true} -smallbitvec = "2.1.1" -smallvec = "0.6" +smallbitvec = "2.3.0" +smallvec = "0.6.6" string_cache = { version = "0.7", optional = true } style_derive = {path = "../style_derive"} style_traits = {path = "../style_traits"} diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 9b627a4a82e..734d09569f5 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -139,7 +139,9 @@ mod bindings { // Disable rust unions, because we replace some types inside of // them. - let mut builder = Builder::default().rust_target(RustTarget::Stable_1_0); + let mut builder = Builder::default() + .rust_target(RustTarget::Stable_1_25) + .disable_untagged_union(); let rustfmt_path = env::var_os("RUSTFMT") // This can be replaced with diff --git a/components/style/cbindgen.toml b/components/style/cbindgen.toml index 6005126fb27..27ad7bc80a1 100644 --- a/components/style/cbindgen.toml +++ b/components/style/cbindgen.toml @@ -50,6 +50,7 @@ include = [ "ComputedTimingFunction", "Display", "DisplayMode", + "ExtremumLength", "FillRule", "FontDisplay", "FontFaceSourceListComponent", diff --git a/components/style/element_state.rs b/components/style/element_state.rs index a646a2a37bf..8165c73ef14 100644 --- a/components/style/element_state.rs +++ b/components/style/element_state.rs @@ -144,7 +144,7 @@ bitflags! { /// Event-based document states. /// /// NB: Is important for this to remain in sync with Gecko's - /// dom/base/nsIDocument.h. + /// dom/base/Document.h. #[derive(MallocSizeOf)] pub struct DocumentState: u64 { /// RTL locale: specific to the XUL localedir attribute diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index c48d56f56e1..266ebbd750a 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -5,6 +5,8 @@ //! This module contains conversion helpers between Servo and Gecko types //! Ideally, it would be in geckolib itself, but coherence //! forces us to keep the traits and implementations here +//! +//! FIXME(emilio): This file should generally just die. #![allow(unsafe_code)] @@ -26,6 +28,7 @@ use crate::values::generics::box_::VerticalAlign; use crate::values::generics::grid::{TrackListValue, TrackSize}; use crate::values::generics::image::{CompatMode, GradientItem, Image as GenericImage}; use crate::values::generics::rect::Rect; +use crate::values::generics::NonNegative; use app_units::Au; use std::f32::consts::PI; @@ -113,7 +116,6 @@ impl From<nsStyleCoord_CalcValue> for LengthOrPercentageOrAuto { // disappear as we move more stuff to cbindgen. impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto { fn from(other: nsStyleCoord_CalcValue) -> Self { - use crate::values::generics::NonNegative; use style_traits::values::specified::AllowedNumericType; NonNegative(if other.mLength < 0 || other.mPercent < 0. { LengthOrPercentageOrAuto::Calc(CalcLengthOrPercentage::with_clamping_mode( @@ -679,6 +681,7 @@ pub mod basic_shape { use crate::values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource}; use crate::values::generics::border::BorderRadius as GenericBorderRadius; use crate::values::generics::rect::Rect; + use crate::values::generics::NonNegative; use crate::values::specified::SVGPathData; use std::borrow::Borrow; @@ -838,10 +841,17 @@ pub mod basic_shape { fn from(other: &'a nsStyleCorners) -> Self { let get_corner = |index| { BorderCornerRadius::new( - LengthOrPercentage::from_gecko_style_coord(&other.data_at(index)) - .expect("<border-radius> should be a length, percentage, or calc value"), - LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1)) - .expect("<border-radius> should be a length, percentage, or calc value"), + NonNegative( + LengthOrPercentage::from_gecko_style_coord(&other.data_at(index)).expect( + "<border-radius> should be a length, percentage, or calc value", + ), + ), + NonNegative( + LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1)) + .expect( + "<border-radius> should be a length, percentage, or calc value", + ), + ), ) }; diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index d4c976cc2a6..80e34fe2e7e 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -7,9 +7,8 @@ use crate::context::QuirksMode; use crate::dom::TElement; use crate::gecko_bindings::bindings::{self, RawServoStyleSet}; -use crate::gecko_bindings::structs::StyleSheet as DomStyleSheet; -use crate::gecko_bindings::structs::{nsIDocument, StyleSheetInfo}; use crate::gecko_bindings::structs::{RawGeckoPresContextBorrowed, ServoStyleSetSizes}; +use crate::gecko_bindings::structs::{StyleSheet as DomStyleSheet, StyleSheetInfo}; use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI}; use crate::invalidation::media_queries::{MediaListKey, ToMediaListKey}; use crate::media_queries::{Device, MediaList}; @@ -151,8 +150,7 @@ impl PerDocumentStyleData { // right now not always honored, see bug 1405543... // // Should we just force XBL Stylists to be NoQuirks? - let quirks_mode = - unsafe { (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode }; + let quirks_mode = unsafe { (*device.pres_context().mDocument.mRawPtr).mCompatMode }; PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl { stylist: Stylist::new(device, quirks_mode.into()), @@ -193,12 +191,7 @@ impl PerDocumentStyleDataImpl { /// Returns whether visited styles are enabled. #[inline] pub fn visited_styles_enabled(&self) -> bool { - let doc = self - .stylist - .device() - .pres_context() - .mDocument - .raw::<nsIDocument>(); + let doc = self.stylist.device().pres_context().mDocument.mRawPtr; unsafe { bindings::Gecko_VisitedStylesEnabled(doc) } } diff --git a/components/style/gecko/media_features.rs b/components/style/gecko/media_features.rs index 25355c45d70..82613c9e245 100644 --- a/components/style/gecko/media_features.rs +++ b/components/style/gecko/media_features.rs @@ -9,7 +9,7 @@ use crate::gecko_bindings::structs; use crate::media_queries::media_feature::{AllowsRanges, ParsingRequirements}; use crate::media_queries::media_feature::{Evaluator, MediaFeatureDescription}; use crate::media_queries::media_feature_expression::{AspectRatio, RangeOrOperator}; -use crate::media_queries::Device; +use crate::media_queries::{Device, MediaType}; use crate::values::computed::CSSPixelLength; use crate::values::computed::Resolution; use crate::Atom; @@ -295,6 +295,59 @@ fn eval_prefers_reduced_motion(device: &Device, query_value: Option<PrefersReduc } } +#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)] +#[repr(u8)] +enum OverflowBlock { + None, + Scroll, + OptionalPaged, + Paged, +} + +/// https://drafts.csswg.org/mediaqueries-4/#mf-overflow-block +fn eval_overflow_block(device: &Device, query_value: Option<OverflowBlock>) -> bool { + // For the time being, assume that printing (including previews) + // is the only time when we paginate, and we are otherwise always + // scrolling. This is true at the moment in Firefox, but may need + // updating in the future (e.g., ebook readers built with Stylo, a + // billboard mode that doesn't support overflow at all). + // + // If this ever changes, don't forget to change eval_overflow_inline too. + let scrolling = device.media_type() != MediaType::print(); + let query_value = match query_value { + Some(v) => v, + None => return true, + }; + + match query_value { + OverflowBlock::None | OverflowBlock::OptionalPaged => false, + OverflowBlock::Scroll => scrolling, + OverflowBlock::Paged => !scrolling, + } +} + +#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)] +#[repr(u8)] +enum OverflowInline { + None, + Scroll, +} + +/// https://drafts.csswg.org/mediaqueries-4/#mf-overflow-inline +fn eval_overflow_inline(device: &Device, query_value: Option<OverflowInline>) -> bool { + // See the note in eval_overflow_block. + let scrolling = device.media_type() != MediaType::print(); + let query_value = match query_value { + Some(v) => v, + None => return scrolling, + }; + + match query_value { + OverflowInline::None => !scrolling, + OverflowInline::Scroll => scrolling, + } +} + /// https://drafts.csswg.org/mediaqueries-4/#mf-interaction bitflags! { struct PointerCapabilities: u8 { @@ -473,7 +526,7 @@ lazy_static! { /// to support new types in these entries and (2) ensuring that either /// nsPresContext::MediaFeatureValuesChanged is called when the value that /// would be returned by the evaluator function could change. - pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 48] = [ + pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 50] = [ feature!( atom!("width"), AllowsRanges::Yes, @@ -593,6 +646,18 @@ lazy_static! { ParsingRequirements::empty(), ), feature!( + atom!("overflow-block"), + AllowsRanges::No, + keyword_evaluator!(eval_overflow_block, OverflowBlock), + ParsingRequirements::empty(), + ), + feature!( + atom!("overflow-inline"), + AllowsRanges::No, + keyword_evaluator!(eval_overflow_inline, OverflowInline), + ParsingRequirements::empty(), + ), + feature!( atom!("pointer"), AllowsRanges::No, keyword_evaluator!(eval_pointer, Pointer), diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index ab3f3a0de80..851422467ce 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -162,8 +162,8 @@ impl Device { /// Gets the document pointer. #[inline] - pub fn document(&self) -> *mut structs::nsIDocument { - self.pres_context().mDocument.raw::<structs::nsIDocument>() + pub fn document(&self) -> *mut structs::Document { + self.pres_context().mDocument.mRawPtr } /// Recreates the default computed values. diff --git a/components/style/gecko/pseudo_element_definition.mako.rs b/components/style/gecko/pseudo_element_definition.mako.rs index aaa3d7c8c99..613bbd281ee 100644 --- a/components/style/gecko/pseudo_element_definition.mako.rs +++ b/components/style/gecko/pseudo_element_definition.mako.rs @@ -156,8 +156,6 @@ impl PseudoElement { /// Construct a `CSSPseudoElementType` from a pseudo-element #[inline] fn pseudo_type(&self) -> CSSPseudoElementType { - use crate::gecko_bindings::structs::CSSPseudoElementType_InheritingAnonBox; - match *self { % for pseudo in PSEUDOS: % if not pseudo.is_anon_box(): @@ -165,7 +163,7 @@ impl PseudoElement { % elif pseudo.is_tree_pseudo_element(): PseudoElement::${pseudo.capitalized_pseudo()}(..) => CSSPseudoElementType::XULTree, % elif pseudo.is_inheriting_anon_box(): - PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType_InheritingAnonBox, + PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::InheritingAnonBox, % else: PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::NonInheritingAnonBox, % endif diff --git a/components/style/gecko/restyle_damage.rs b/components/style/gecko/restyle_damage.rs index b2b14b413e3..9c9d07b7112 100644 --- a/components/style/gecko/restyle_damage.rs +++ b/components/style/gecko/restyle_damage.rs @@ -83,7 +83,7 @@ impl GeckoRestyleDamage { /// Gets restyle damage to reconstruct the entire frame, subsuming all /// other damage. pub fn reconstruct() -> Self { - GeckoRestyleDamage(structs::nsChangeHint_nsChangeHint_ReconstructFrame) + GeckoRestyleDamage(structs::nsChangeHint::nsChangeHint_ReconstructFrame) } } diff --git a/components/style/gecko/values.rs b/components/style/gecko/values.rs index 98dafcd070f..39a5ac2de89 100644 --- a/components/style/gecko/values.rs +++ b/components/style/gecko/values.rs @@ -13,12 +13,10 @@ use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, Coor use crate::media_queries::Device; use crate::values::computed::basic_shape::ShapeRadius as ComputedShapeRadius; use crate::values::computed::FlexBasis as ComputedFlexBasis; -use crate::values::computed::NonNegativeNumber; use crate::values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage}; use crate::values::computed::{LengthOrPercentageOrAuto, Percentage}; use crate::values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage}; use crate::values::computed::{MaxLength as ComputedMaxLength, MozLength as ComputedMozLength}; -use crate::values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage}; use crate::values::generics::basic_shape::ShapeRadius; use crate::values::generics::box_::Perspective; use crate::values::generics::flex::FlexBasis; @@ -34,6 +32,9 @@ use nsstring::{nsACString, nsCStr}; use std::cmp::max; /// A trait that defines an interface to convert from and to `nsStyleCoord`s. +/// +/// TODO(emilio): Almost everything that is in this file should be somehow +/// switched to cbindgen. pub trait GeckoStyleCoordConvertible: Sized { /// Convert this to a `nsStyleCoord`. fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T); @@ -66,6 +67,19 @@ impl<A: GeckoStyleCoordConvertible, B: GeckoStyleCoordConvertible> GeckoStyleCoo } } +impl<Inner> GeckoStyleCoordConvertible for NonNegative<Inner> +where + Inner: GeckoStyleCoordConvertible, +{ + fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { + self.0.to_gecko_style_coord(coord) + } + + fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> { + Some(NonNegative(Inner::from_gecko_style_coord(coord)?)) + } +} + impl GeckoStyleCoordConvertible for ComputedFlexBasis { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { match *self { @@ -152,16 +166,6 @@ impl GeckoStyleCoordConvertible for LengthOrPercentage { } } -impl GeckoStyleCoordConvertible for NonNegativeLengthOrPercentage { - fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { - self.0.to_gecko_style_coord(coord); - } - - fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> { - LengthOrPercentage::from_gecko_style_coord(coord).map(NonNegative::<LengthOrPercentage>) - } -} - impl GeckoStyleCoordConvertible for Length { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { coord.set_value(CoordDataValue::Coord(self.to_i32_au())); @@ -175,26 +179,6 @@ impl GeckoStyleCoordConvertible for Length { } } -impl GeckoStyleCoordConvertible for NonNegativeLength { - fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { - self.0.to_gecko_style_coord(coord); - } - - fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> { - Length::from_gecko_style_coord(coord).map(NonNegative::<Length>) - } -} - -impl GeckoStyleCoordConvertible for NonNegativeNumber { - fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { - self.0.to_gecko_style_coord(coord); - } - - fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> { - Number::from_gecko_style_coord(coord).map(NonNegative::<Number>) - } -} - impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { let value = match *self { @@ -302,7 +286,7 @@ impl GeckoStyleCoordConvertible for ComputedShapeRadius { None } }, - _ => LengthOrPercentage::from_gecko_style_coord(coord).map(ShapeRadius::Length), + _ => GeckoStyleCoordConvertible::from_gecko_style_coord(coord).map(ShapeRadius::Length), } } } @@ -378,40 +362,13 @@ impl GeckoStyleCoordConvertible for Normal { impl GeckoStyleCoordConvertible for ExtremumLength { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { - use crate::gecko_bindings::structs::{ - NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT, - }; - use crate::gecko_bindings::structs::{ - NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT, - }; - coord.set_value(CoordDataValue::Enumerated(match *self { - ExtremumLength::MozMaxContent => NS_STYLE_WIDTH_MAX_CONTENT, - ExtremumLength::MozMinContent => NS_STYLE_WIDTH_MIN_CONTENT, - ExtremumLength::MozFitContent => NS_STYLE_WIDTH_FIT_CONTENT, - ExtremumLength::MozAvailable => NS_STYLE_WIDTH_AVAILABLE, - })) + coord.set_value(CoordDataValue::Enumerated(*self as u32)); } fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> { - use crate::gecko_bindings::structs::{ - NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT, - }; - use crate::gecko_bindings::structs::{ - NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT, - }; + use num_traits::FromPrimitive; match coord.as_value() { - CoordDataValue::Enumerated(NS_STYLE_WIDTH_MAX_CONTENT) => { - Some(ExtremumLength::MozMaxContent) - }, - CoordDataValue::Enumerated(NS_STYLE_WIDTH_MIN_CONTENT) => { - Some(ExtremumLength::MozMinContent) - }, - CoordDataValue::Enumerated(NS_STYLE_WIDTH_FIT_CONTENT) => { - Some(ExtremumLength::MozFitContent) - }, - CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => { - Some(ExtremumLength::MozAvailable) - }, + CoordDataValue::Enumerated(v) => ExtremumLength::from_u32(v), _ => None, } } diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 0768e9e26af..97f0f887a00 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -22,7 +22,6 @@ use crate::dom::{LayoutIterator, NodeInfo, OpaqueNode, TDocument, TElement, TNod use crate::element_state::{DocumentState, ElementState}; use crate::font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult}; use crate::gecko::data::GeckoStyleSheet; -use crate::gecko::global_style_data::GLOBAL_STYLE_DATA; use crate::gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl}; use crate::gecko::snapshot_helpers; use crate::gecko_bindings::bindings; @@ -45,8 +44,8 @@ use crate::gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWThe use crate::gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags}; use crate::gecko_bindings::structs; use crate::gecko_bindings::structs::nsChangeHint; -use crate::gecko_bindings::structs::nsIDocument_DocumentTheme as DocumentTheme; use crate::gecko_bindings::structs::nsRestyleHint; +use crate::gecko_bindings::structs::Document_DocumentTheme as DocumentTheme; use crate::gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel; use crate::gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT; use crate::gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO; @@ -57,6 +56,7 @@ use crate::gecko_bindings::structs::NODE_NEEDS_FRAME; use crate::gecko_bindings::structs::{nsAtom, nsIContent, nsINode_BooleanFlag}; use crate::gecko_bindings::structs::{RawGeckoElement, RawGeckoNode, RawGeckoXBLBinding}; use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI}; +use crate::global_style_data::GLOBAL_STYLE_DATA; use crate::hash::FxHashMap; use crate::logical_geometry::WritingMode; use crate::media_queries::Device; @@ -107,9 +107,9 @@ fn elements_with_id<'a, 'le>( } } -/// A simple wrapper over `nsIDocument`. +/// A simple wrapper over `Document`. #[derive(Clone, Copy)] -pub struct GeckoDocument<'ld>(pub &'ld structs::nsIDocument); +pub struct GeckoDocument<'ld>(pub &'ld structs::Document); impl<'ld> TDocument for GeckoDocument<'ld> { type ConcreteNode = GeckoNode<'ld>; @@ -121,7 +121,7 @@ impl<'ld> TDocument for GeckoDocument<'ld> { #[inline] fn is_html_document(&self) -> bool { - self.0.mType == structs::root::nsIDocument_Type::eHTML + self.0.mType == structs::Document_Type::eHTML } #[inline] @@ -1242,11 +1242,8 @@ impl<'le> TElement for GeckoElement<'le> { } fn owner_doc_matches_for_testing(&self, device: &Device) -> bool { - self.as_node().owner_doc().0 as *const structs::nsIDocument == - device - .pres_context() - .mDocument - .raw::<structs::nsIDocument>() + self.as_node().owner_doc().0 as *const structs::Document == + device.pres_context().mDocument.mRawPtr } fn style_attribute(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> { @@ -1501,9 +1498,6 @@ impl<'le> TElement for GeckoElement<'le> { /// Process various tasks that are a result of animation-only restyle. fn process_post_animation(&self, tasks: PostAnimationTasks) { - use crate::gecko_bindings::structs::nsChangeHint_nsChangeHint_Empty; - use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_Subtree; - debug_assert!(!tasks.is_empty(), "Should be involved a task"); // If display style was changed from none to other, we need to resolve @@ -1519,8 +1513,8 @@ impl<'le> TElement for GeckoElement<'le> { ); unsafe { self.note_explicit_hints( - nsRestyleHint_eRestyle_Subtree, - nsChangeHint_nsChangeHint_Empty, + nsRestyleHint::eRestyle_Subtree, + nsChangeHint::nsChangeHint_Empty, ); } } diff --git a/components/style/gecko_bindings/sugar/origin_flags.rs b/components/style/gecko_bindings/sugar/origin_flags.rs index b7250b53930..e0f0981c5d8 100644 --- a/components/style/gecko_bindings/sugar/origin_flags.rs +++ b/components/style/gecko_bindings/sugar/origin_flags.rs @@ -5,17 +5,17 @@ //! Helper to iterate over `OriginFlags` bits. use crate::gecko_bindings::structs::OriginFlags; -use crate::gecko_bindings::structs::OriginFlags_Author; -use crate::gecko_bindings::structs::OriginFlags_User; -use crate::gecko_bindings::structs::OriginFlags_UserAgent; use crate::stylesheets::OriginSet; /// Checks that the values for OriginFlags are the ones we expect. pub fn assert_flags_match() { use crate::stylesheets::origin::*; - debug_assert_eq!(OriginFlags_UserAgent.0, OriginSet::ORIGIN_USER_AGENT.bits()); - debug_assert_eq!(OriginFlags_Author.0, OriginSet::ORIGIN_AUTHOR.bits()); - debug_assert_eq!(OriginFlags_User.0, OriginSet::ORIGIN_USER.bits()); + debug_assert_eq!( + OriginFlags::UserAgent.0, + OriginSet::ORIGIN_USER_AGENT.bits() + ); + debug_assert_eq!(OriginFlags::Author.0, OriginSet::ORIGIN_AUTHOR.bits()); + debug_assert_eq!(OriginFlags::User.0, OriginSet::ORIGIN_USER.bits()); } impl From<OriginFlags> for OriginSet { diff --git a/components/style/invalidation/element/restyle_hints.rs b/components/style/invalidation/element/restyle_hints.rs index 1d8a7f5bd14..de84fe56c85 100644 --- a/components/style/invalidation/element/restyle_hints.rs +++ b/components/style/invalidation/element/restyle_hints.rs @@ -193,38 +193,35 @@ impl Default for RestyleHint { #[cfg(feature = "gecko")] impl From<nsRestyleHint> for RestyleHint { fn from(mut raw: nsRestyleHint) -> Self { - use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_Force as eRestyle_Force; - use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_ForceDescendants as eRestyle_ForceDescendants; - use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_LaterSiblings as eRestyle_LaterSiblings; - use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_Self as eRestyle_Self; - use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_SomeDescendants as eRestyle_SomeDescendants; - use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_Subtree as eRestyle_Subtree; - let mut hint = RestyleHint::empty(); debug_assert!( - raw.0 & eRestyle_LaterSiblings.0 == 0, + raw.0 & nsRestyleHint::eRestyle_LaterSiblings.0 == 0, "Handle later siblings manually if necessary plz." ); - if (raw.0 & (eRestyle_Self.0 | eRestyle_Subtree.0)) != 0 { - raw.0 &= !eRestyle_Self.0; + if (raw.0 & (nsRestyleHint::eRestyle_Self.0 | nsRestyleHint::eRestyle_Subtree.0)) != 0 { + raw.0 &= !nsRestyleHint::eRestyle_Self.0; hint.insert(RestyleHint::RESTYLE_SELF); } - if (raw.0 & (eRestyle_Subtree.0 | eRestyle_SomeDescendants.0)) != 0 { - raw.0 &= !eRestyle_Subtree.0; - raw.0 &= !eRestyle_SomeDescendants.0; + if (raw.0 & (nsRestyleHint::eRestyle_Subtree.0 | nsRestyleHint::eRestyle_SomeDescendants.0)) != + 0 + { + raw.0 &= !nsRestyleHint::eRestyle_Subtree.0; + raw.0 &= !nsRestyleHint::eRestyle_SomeDescendants.0; hint.insert(RestyleHint::RESTYLE_DESCENDANTS); } - if (raw.0 & (eRestyle_ForceDescendants.0 | eRestyle_Force.0)) != 0 { - raw.0 &= !eRestyle_Force.0; + if (raw.0 & (nsRestyleHint::eRestyle_ForceDescendants.0 | nsRestyleHint::eRestyle_Force.0)) != + 0 + { + raw.0 &= !nsRestyleHint::eRestyle_Force.0; hint.insert(RestyleHint::RECASCADE_SELF); } - if (raw.0 & eRestyle_ForceDescendants.0) != 0 { - raw.0 &= !eRestyle_ForceDescendants.0; + if (raw.0 & nsRestyleHint::eRestyle_ForceDescendants.0) != 0 { + raw.0 &= !nsRestyleHint::eRestyle_ForceDescendants.0; hint.insert(RestyleHint::RECASCADE_DESCENDANTS); } @@ -248,7 +245,7 @@ pub fn assert_restyle_hints_match() { if cfg!(debug_assertions) { let mut replacements = RestyleHint::replacements(); $( - assert_eq!(structs::$a.0 as usize, $b.bits() as usize, stringify!($b)); + assert_eq!(structs::nsRestyleHint::$a.0 as usize, $b.bits() as usize, stringify!($b)); replacements.remove($b); )* assert_eq!(replacements, RestyleHint::empty(), @@ -259,9 +256,9 @@ pub fn assert_restyle_hints_match() { } check_restyle_hints! { - nsRestyleHint_eRestyle_CSSTransitions => RestyleHint::RESTYLE_CSS_TRANSITIONS, - nsRestyleHint_eRestyle_CSSAnimations => RestyleHint::RESTYLE_CSS_ANIMATIONS, - nsRestyleHint_eRestyle_StyleAttribute => RestyleHint::RESTYLE_STYLE_ATTRIBUTE, - nsRestyleHint_eRestyle_StyleAttribute_Animations => RestyleHint::RESTYLE_SMIL, + eRestyle_CSSTransitions => RestyleHint::RESTYLE_CSS_TRANSITIONS, + eRestyle_CSSAnimations => RestyleHint::RESTYLE_CSS_ANIMATIONS, + eRestyle_StyleAttribute => RestyleHint::RESTYLE_STYLE_ATTRIBUTE, + eRestyle_StyleAttribute_Animations => RestyleHint::RESTYLE_SMIL, } } diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 8faaa163823..4d980039d1e 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -388,12 +388,12 @@ class Shorthand(object): and allowed_in_keyframe_block != "False" def get_animatable(self): - animatable = False + if self.ident == "all": + return False for sub in self.sub_properties: if sub.animatable: - animatable = True - break - return animatable + return True + return False def get_transitionable(self): transitionable = False diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 5f96b42c10a..d969f14f54a 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -39,7 +39,6 @@ use crate::gecko_bindings::bindings::RawGeckoPresContextBorrowed; use crate::gecko_bindings::structs; use crate::gecko_bindings::structs::nsCSSPropertyID; use crate::gecko_bindings::structs::mozilla::CSSPseudoElementType; -use crate::gecko_bindings::structs::mozilla::CSSPseudoElementType_InheritingAnonBox; use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut}; use crate::gecko_bindings::sugar::refptr::RefPtr; use crate::gecko::values::convert_nscolor_to_rgba; @@ -138,7 +137,7 @@ impl ComputedValues { #[inline] pub fn is_anon_box(&self) -> bool { let our_type = self.get_pseudo_type(); - return our_type == CSSPseudoElementType_InheritingAnonBox || + return our_type == CSSPseudoElementType::InheritingAnonBox || our_type == CSSPseudoElementType::NonInheritingAnonBox; } @@ -1687,8 +1686,8 @@ fn static_assert() { pub fn clone_border_image_slice(&self) -> longhands::border_image_slice::computed_value::T { use crate::gecko_bindings::structs::NS_STYLE_BORDER_IMAGE_SLICE_FILL; - use crate::values::computed::{BorderImageSlice, NumberOrPercentage}; - type NumberOrPercentageRect = crate::values::generics::rect::Rect<NumberOrPercentage>; + use crate::values::computed::{BorderImageSlice, NonNegativeNumberOrPercentage}; + type NumberOrPercentageRect = crate::values::generics::rect::Rect<NonNegativeNumberOrPercentage>; BorderImageSlice { offsets: diff --git a/components/style/properties/longhands/background.mako.rs b/components/style/properties/longhands/background.mako.rs index 934814567ba..b97545898c2 100644 --- a/components/style/properties/longhands/background.mako.rs +++ b/components/style/properties/longhands/background.mako.rs @@ -108,7 +108,6 @@ ${helpers.single_keyword( 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 5a5cdbeb552..3fcf73bf2f4 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -88,7 +88,6 @@ ${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", @@ -153,14 +152,15 @@ ${helpers.predefined_type( ${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()", + initial_value="computed::BorderImageSlice::hundred_percent()", + initial_specified_value="specified::BorderImageSlice::hundred_percent()", spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice", animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER", boxed=True, )} +// FIXME(emilio): Why does this live here? ;_; #[cfg(feature = "gecko")] impl crate::values::computed::BorderImageWidth { pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) { @@ -177,7 +177,7 @@ impl crate::values::computed::BorderImageWidth { l.to_gecko_style_coord(&mut sides.data_at_mut(${i})) }, BorderImageSideWidth::Number(n) => { - sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n)) + sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n.0)) }, } % endfor @@ -191,6 +191,7 @@ impl crate::values::computed::BorderImageWidth { use crate::gecko::values::GeckoStyleCoordConvertible; use crate::values::computed::{LengthOrPercentage, Number}; use crate::values::generics::border::BorderImageSideWidth; + use crate::values::generics::NonNegative; Some( crate::values::computed::BorderImageWidth::new( @@ -201,13 +202,13 @@ impl crate::values::computed::BorderImageWidth { }, eStyleUnit_Factor => { BorderImageSideWidth::Number( - Number::from_gecko_style_coord(&sides.data_at(${i})) - .expect("sides[${i}] could not convert to Number")) + NonNegative(Number::from_gecko_style_coord(&sides.data_at(${i})) + .expect("sides[${i}] could not convert to Number"))) }, _ => { BorderImageSideWidth::Length( - LengthOrPercentage::from_gecko_style_coord(&sides.data_at(${i})) - .expect("sides[${i}] could not convert to LengthOrPercentager")) + NonNegative(LengthOrPercentage::from_gecko_style_coord(&sides.data_at(${i})) + .expect("sides[${i}] could not convert to LengthOrPercentage"))) }, }, % endfor diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 1e0629861e4..48b83271d9b 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -389,7 +389,6 @@ ${helpers.predefined_type( ${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", @@ -427,7 +426,6 @@ ${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", @@ -559,6 +557,7 @@ ${helpers.predefined_type( flags="CREATES_STACKING_CONTEXT FIXPOS_CB", gecko_pref="layout.css.contain.enabled", spec="https://drafts.csswg.org/css-contain/#contain-property", + enabled_in="chrome", )} // Non-standard @@ -626,7 +625,7 @@ ${helpers.predefined_type( "generics::basic_shape::ShapeSource::None", products="gecko", boxed=True, - animation_value_type="ComputedValue", + animation_value_type="basic_shape::FloatAreaShape", flags="APPLIES_TO_FIRST_LETTER", spec="https://drafts.csswg.org/css-shapes/#shape-outside-property", )} diff --git a/components/style/properties/longhands/effects.mako.rs b/components/style/properties/longhands/effects.mako.rs index 066ac4ca02a..0b3f96f0dde 100644 --- a/components/style/properties/longhands/effects.mako.rs +++ b/components/style/properties/longhands/effects.mako.rs @@ -62,6 +62,5 @@ ${helpers.single_keyword( 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 65d5727f11a..0e3799f6c46 100644 --- a/components/style/properties/longhands/inherited_box.mako.rs +++ b/components/style/properties/longhands/inherited_box.mako.rs @@ -54,7 +54,7 @@ ${helpers.single_keyword( ${helpers.single_keyword( "color-adjust", "economy exact", products="gecko", - gecko_pref="layout.css.color-adjust.enabled", + gecko_enum_prefix="StyleColorAdjust", animation_value_type="discrete", spec="https://drafts.csswg.org/css-color/#propdef-color-adjust", )} @@ -77,6 +77,5 @@ ${helpers.single_keyword( products="gecko", gecko_enum_prefix="StyleImageOrientation", animation_value_type="discrete", - gecko_pref="layout.css.image-orientation.enabled", spec="https://drafts.csswg.org/css-images/#propdef-image-orientation", )} diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index f751b29ae68..5a7b88e3823 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -295,7 +295,7 @@ ${helpers.predefined_type( "-webkit-text-stroke-width", "BorderSideWidth", "crate::values::computed::NonNegativeLength::new(0.)", - initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())", + initial_specified_value="specified::BorderSideWidth::zero()", computed_type="crate::values::computed::NonNegativeLength", products="gecko", gecko_pref="layout.css.prefixes.webkit", diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index c5e507da10e..53a3acf81ec 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -244,21 +244,12 @@ ${helpers.predefined_type( if logical: spec = "https://drafts.csswg.org/css-logical-props/#propdef-%s" %> - // NOTE: Block-size doesn't support -moz-*-content keywords, since they make - // no sense on the block axis, but it simplifies things the have that it has - // the same type as the other properties, since otherwise we'd need to - // handle logical props where the types are different, which looks like a - // pain. % if product == "gecko": - <% - parse_function = "parse" if size != "block-size" else "parse_disallow_keyword" - %> // width, height, block-size, inline-size ${helpers.predefined_type( size, "MozLength", "computed::MozLength::auto()", - parse_function, logical=logical, logical_group="size", allow_quirks=not logical, @@ -272,7 +263,6 @@ ${helpers.predefined_type( "min-%s" % size, "MozLength", "computed::MozLength::auto()", - parse_function, logical=logical, logical_group="min-size", allow_quirks=not logical, @@ -284,7 +274,6 @@ ${helpers.predefined_type( "max-%s" % size, "MaxLength", "computed::MaxLength::none()", - parse_function, logical=logical, logical_group="max-size", allow_quirks=not logical, diff --git a/components/style/properties/longhands/svg.mako.rs b/components/style/properties/longhands/svg.mako.rs index d6e76f6f1f6..43a8952d86e 100644 --- a/components/style/properties/longhands/svg.mako.rs +++ b/components/style/properties/longhands/svg.mako.rs @@ -88,7 +88,7 @@ ${helpers.predefined_type( "generics::basic_shape::ShapeSource::None", products="gecko", boxed=True, - animation_value_type="ComputedValue", + animation_value_type="basic_shape::ClippingShape", flags="CREATES_STACKING_CONTEXT", spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path", )} diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs index 6424cc237db..ba602ddca83 100644 --- a/components/style/rule_collector.rs +++ b/components/style/rule_collector.rs @@ -5,7 +5,7 @@ //! Collects a series of applicable rules for a given element. use crate::applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList}; -use crate::dom::{TElement, TShadowRoot}; +use crate::dom::{TElement, TNode, TShadowRoot}; use crate::properties::{AnimationRules, PropertyDeclarationBlock}; use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder}; use crate::selector_map::SelectorMap; @@ -17,6 +17,43 @@ use selectors::matching::{ElementSelectorFlags, MatchingContext}; use servo_arc::ArcBorrow; use smallvec::SmallVec; +/// This is a bit of a hack so <svg:use> matches the rules of the enclosing +/// tree. +/// +/// This function returns the containing shadow host ignoring <svg:use> shadow +/// trees, since those match the enclosing tree's rules. +/// +/// Only a handful of places need to really care about this. This is not a +/// problem for invalidation and that kind of stuff because they still don't +/// match rules based on elements outside of the shadow tree, and because the +/// <svg:use> subtrees are immutable and recreated each time the source tree +/// changes. +/// +/// We historically allow cross-document <svg:use> to have these rules applied, +/// but I think that's not great. Gecko is the only engine supporting that. +/// +/// See https://github.com/w3c/svgwg/issues/504 for the relevant spec +/// discussion. +#[inline] +pub fn containing_shadow_ignoring_svg_use<E: TElement>( + element: E, +) -> Option<<E::ConcreteNode as TNode>::ConcreteShadowRoot> { + let mut shadow = element.containing_shadow()?; + loop { + let host = shadow.host(); + let host_is_svg_use_element = + host.is_svg_element() && host.local_name() == &*local_name!("use"); + if !host_is_svg_use_element { + return Some(shadow); + } + debug_assert!( + shadow.style_data().is_none(), + "We allow no stylesheets in <svg:use> subtrees" + ); + shadow = host.containing_shadow()?; + } +} + /// An object that we use with all the intermediate state needed for the /// cascade. /// @@ -213,43 +250,18 @@ where return; } - let mut current_containing_shadow = self.rule_hash_target.containing_shadow(); - while let Some(containing_shadow) = current_containing_shadow { - let cascade_data = containing_shadow.style_data(); - let host = containing_shadow.host(); - if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) - { - self.collect_rules_in_shadow_tree(host, map, CascadeLevel::SameTreeAuthorNormal); - } - let host_is_svg_use_element = - host.is_svg_element() && host.local_name() == &*local_name!("use"); - if !host_is_svg_use_element { - self.matches_document_author_rules = false; - break; - } + let containing_shadow = containing_shadow_ignoring_svg_use(self.rule_hash_target); + let containing_shadow = match containing_shadow { + Some(s) => s, + None => return, + }; - debug_assert!( - cascade_data.is_none(), - "We allow no stylesheets in <svg:use> subtrees" - ); + self.matches_document_author_rules = false; - // NOTE(emilio): Hack so <svg:use> matches the rules of the - // enclosing tree. - // - // This is not a problem for invalidation and that kind of stuff - // because they still don't match rules based on elements - // outside of the shadow tree, and because the <svg:use> - // subtrees are immutable and recreated each time the source - // tree changes. - // - // We historically allow cross-document <svg:use> to have these - // rules applied, but I think that's not great. Gecko is the - // only engine supporting that. - // - // See https://github.com/w3c/svgwg/issues/504 for the relevant - // spec discussion. - current_containing_shadow = host.containing_shadow(); - self.matches_document_author_rules = current_containing_shadow.is_none(); + let cascade_data = containing_shadow.style_data(); + let host = containing_shadow.host(); + if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) { + self.collect_rules_in_shadow_tree(host, map, CascadeLevel::SameTreeAuthorNormal); } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 592e4e81081..74b055e099b 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -17,7 +17,7 @@ use crate::media_queries::Device; use crate::properties::{self, CascadeMode, ComputedValues}; use crate::properties::{AnimationRules, PropertyDeclarationBlock}; use crate::rule_cache::{RuleCache, RuleCacheConditions}; -use crate::rule_collector::RuleCollector; +use crate::rule_collector::{containing_shadow_ignoring_svg_use, RuleCollector}; use crate::rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource}; use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry}; use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap}; @@ -1187,7 +1187,9 @@ impl Stylist { } } - if let Some(shadow) = element.containing_shadow() { + // Use the same rules to look for the containing host as we do for rule + // collection. + if let Some(shadow) = containing_shadow_ignoring_svg_use(element) { if let Some(data) = shadow.style_data() { try_find_in!(data); } diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index 38de8a359a1..a7c947f810a 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -12,7 +12,8 @@ use crate::properties::PropertyId; use crate::values::computed::length::CalcLengthOrPercentage; use crate::values::computed::url::ComputedUrl; use crate::values::computed::Angle as ComputedAngle; -use crate::values::computed::BorderCornerRadius as ComputedBorderCornerRadius; +use crate::values::computed::Image; +use crate::values::specified::SVGPathData; use crate::values::CSSFloat; use app_units::Au; use euclid::{Point2D, Size2D}; @@ -339,23 +340,19 @@ trivial_to_animated_value!(ComputedAngle); trivial_to_animated_value!(ComputedUrl); trivial_to_animated_value!(bool); trivial_to_animated_value!(f32); - -impl ToAnimatedValue for ComputedBorderCornerRadius { - type AnimatedValue = Self; - - #[inline] - fn to_animated_value(self) -> Self { - self - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - ComputedBorderCornerRadius::new( - (animated.0).0.width.clamp_to_non_negative(), - (animated.0).0.height.clamp_to_non_negative(), - ) - } -} +// Note: This implementation is for ToAnimatedValue of ShapeSource. +// +// SVGPathData uses Box<[T]>. If we want to derive ToAnimatedValue for all the +// types, we have to do "impl ToAnimatedValue for Box<[T]>" first. +// However, the general version of "impl ToAnimatedValue for Box<[T]>" needs to +// clone |T| and convert it into |T::AnimatedValue|. However, for SVGPathData +// that is unnecessary--moving |T| is sufficient. So here, we implement this +// trait manually. +trivial_to_animated_value!(SVGPathData); +// FIXME: Bug 1514342, Image is not animatable, but we still need to implement +// this to avoid adding this derive to generic::Image and all its arms. We can +// drop this after landing Bug 1514342. +trivial_to_animated_value!(Image); impl ToAnimatedZero for Au { #[inline] diff --git a/components/style/values/computed/basic_shape.rs b/components/style/values/computed/basic_shape.rs index 6a7b02cadcd..f808e0bf9f5 100644 --- a/components/style/values/computed/basic_shape.rs +++ b/components/style/values/computed/basic_shape.rs @@ -8,7 +8,7 @@ //! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape use crate::values::computed::url::ComputedUrl; -use crate::values::computed::{Image, LengthOrPercentage}; +use crate::values::computed::{Image, LengthOrPercentage, NonNegativeLengthOrPercentage}; use crate::values::generics::basic_shape as generic; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; @@ -23,20 +23,26 @@ pub type ClippingShape = generic::ClippingShape<BasicShape, ComputedUrl>; pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>; /// A computed basic shape. -pub type BasicShape = - generic::BasicShape<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>; +pub type BasicShape = generic::BasicShape< + LengthOrPercentage, + LengthOrPercentage, + LengthOrPercentage, + NonNegativeLengthOrPercentage, +>; /// The computed value of `inset()` -pub type InsetRect = generic::InsetRect<LengthOrPercentage>; +pub type InsetRect = generic::InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>; /// A computed circle. -pub type Circle = generic::Circle<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>; +pub type Circle = + generic::Circle<LengthOrPercentage, LengthOrPercentage, NonNegativeLengthOrPercentage>; /// A computed ellipse. -pub type Ellipse = generic::Ellipse<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>; +pub type Ellipse = + generic::Ellipse<LengthOrPercentage, LengthOrPercentage, NonNegativeLengthOrPercentage>; /// The computed value of `ShapeRadius` -pub type ShapeRadius = generic::ShapeRadius<LengthOrPercentage>; +pub type ShapeRadius = generic::ShapeRadius<NonNegativeLengthOrPercentage>; impl ToCss for Circle { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result diff --git a/components/style/values/computed/border.rs b/components/style/values/computed/border.rs index 676e8c1b6be..c6ab4abc5a5 100644 --- a/components/style/values/computed/border.rs +++ b/components/style/values/computed/border.rs @@ -4,9 +4,8 @@ //! Computed types for CSS values related to borders. -use crate::values::animated::ToAnimatedZero; -use crate::values::computed::length::{LengthOrPercentage, NonNegativeLength}; -use crate::values::computed::{Number, NumberOrPercentage}; +use crate::values::computed::length::{NonNegativeLength, NonNegativeLengthOrPercentage}; +use crate::values::computed::{NonNegativeNumber, NonNegativeNumberOrPercentage}; use crate::values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use crate::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; use crate::values::generics::border::BorderImageSlice as GenericBorderImageSlice; @@ -14,6 +13,7 @@ use crate::values::generics::border::BorderRadius as GenericBorderRadius; use crate::values::generics::border::BorderSpacing as GenericBorderSpacing; use crate::values::generics::rect::Rect; use crate::values::generics::size::Size; +use crate::values::generics::NonNegative; use app_units::Au; pub use crate::values::specified::border::BorderImageRepeat; @@ -22,16 +22,17 @@ pub use crate::values::specified::border::BorderImageRepeat; pub type BorderImageWidth = Rect<BorderImageSideWidth>; /// A computed value for a single side of a `border-image-width` property. -pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>; +pub type BorderImageSideWidth = + GenericBorderImageSideWidth<NonNegativeLengthOrPercentage, NonNegativeNumber>; /// A computed value for the `border-image-slice` property. -pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>; +pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>; /// A computed value for the `border-radius` property. -pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>; +pub type BorderRadius = GenericBorderRadius<NonNegativeLengthOrPercentage>; /// A computed value for the `border-*-radius` longhand properties. -pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>; +pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthOrPercentage>; /// A computed value for the `border-spacing` longhand property. pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>; @@ -40,7 +41,18 @@ impl BorderImageSideWidth { /// Returns `1`. #[inline] pub fn one() -> Self { - GenericBorderImageSideWidth::Number(1.) + GenericBorderImageSideWidth::Number(NonNegative(1.)) + } +} + +impl BorderImageSlice { + /// Returns the `100%` value. + #[inline] + pub fn hundred_percent() -> Self { + GenericBorderImageSlice { + offsets: Rect::all(NonNegativeNumberOrPercentage::hundred_percent()), + fill: false, + } } } @@ -68,26 +80,18 @@ impl BorderCornerRadius { /// Returns `0 0`. pub fn zero() -> Self { GenericBorderCornerRadius(Size::new( - LengthOrPercentage::zero(), - LengthOrPercentage::zero(), + NonNegativeLengthOrPercentage::zero(), + NonNegativeLengthOrPercentage::zero(), )) } } -impl ToAnimatedZero for BorderCornerRadius { - #[inline] - fn to_animated_zero(&self) -> Result<Self, ()> { - // FIXME(nox): Why? - 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() + fn is_zero(l: &NonNegativeLengthOrPercentage) -> bool { + *l == NonNegativeLengthOrPercentage::zero() } is_zero(corner.0.width()) && is_zero(corner.0.height()) } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 96886e9096a..240b5ceb1ee 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -975,6 +975,7 @@ pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPerce Copy, Debug, Eq, + FromPrimitive, MallocSizeOf, Parse, PartialEq, @@ -982,9 +983,12 @@ pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPerce ToComputedValue, ToCss, )] +#[repr(u8)] pub enum ExtremumLength { - MozMaxContent, - MozMinContent, + #[parse(aliases = "-moz-max-content")] + MaxContent, + #[parse(aliases = "-moz-min-content")] + MinContent, MozFitContent, MozAvailable, } diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 93ee3e73cc1..4051511e28e 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -543,6 +543,17 @@ pub enum NumberOrPercentage { Number(Number), } +impl NumberOrPercentage { + fn clamp_to_non_negative(self) -> Self { + match self { + NumberOrPercentage::Percentage(p) => { + NumberOrPercentage::Percentage(p.clamp_to_non_negative()) + }, + NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.max(0.)), + } + } +} + impl ToComputedValue for specified::NumberOrPercentage { type ComputedValue = NumberOrPercentage; @@ -572,6 +583,31 @@ impl ToComputedValue for specified::NumberOrPercentage { } } +/// A non-negative <number-percentage>. +pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>; + +impl NonNegativeNumberOrPercentage { + /// Returns the `100%` value. + #[inline] + pub fn hundred_percent() -> Self { + NonNegative(NumberOrPercentage::Percentage(Percentage::hundred())) + } +} + +impl ToAnimatedValue for NonNegativeNumberOrPercentage { + type AnimatedValue = NumberOrPercentage; + + #[inline] + fn to_animated_value(self) -> Self::AnimatedValue { + self.0 + } + + #[inline] + fn from_animated_value(animated: Self::AnimatedValue) -> Self { + NonNegative(animated.clamp_to_non_negative()) + } +} + /// A type used for opacity. pub type Opacity = CSSFloat; diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index cbcdadd055f..bfe709ceb4b 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -20,7 +20,16 @@ pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, U /// <https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box> #[allow(missing_docs)] #[derive( - Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, + Animate, + Clone, + Copy, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToCss, )] pub enum GeometryBox { FillBox, @@ -45,6 +54,7 @@ pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, I Parse, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, ToCss, )] @@ -59,7 +69,15 @@ pub enum ShapeBox { #[allow(missing_docs)] #[animation(no_bound(ImageOrUrl))] #[derive( - Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, + Animate, + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToCss, )] pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> { #[animation(error)] @@ -82,13 +100,14 @@ pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> { MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, ToCss, )] -pub enum BasicShape<H, V, LengthOrPercentage> { - Inset(#[css(field_bound)] InsetRect<LengthOrPercentage>), - Circle(#[css(field_bound)] Circle<H, V, LengthOrPercentage>), - Ellipse(#[css(field_bound)] Ellipse<H, V, LengthOrPercentage>), +pub enum BasicShape<H, V, LengthOrPercentage, NonNegativeLengthOrPercentage> { + Inset(#[css(field_bound)] InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>), + Circle(#[css(field_bound)] Circle<H, V, NonNegativeLengthOrPercentage>), + Ellipse(#[css(field_bound)] Ellipse<H, V, NonNegativeLengthOrPercentage>), Polygon(Polygon<LengthOrPercentage>), } @@ -103,11 +122,12 @@ pub enum BasicShape<H, V, LengthOrPercentage> { MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, )] -pub struct InsetRect<LengthOrPercentage> { +pub struct InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage> { pub rect: Rect<LengthOrPercentage>, - pub round: Option<BorderRadius<LengthOrPercentage>>, + pub round: Option<BorderRadius<NonNegativeLengthOrPercentage>>, } /// <https://drafts.csswg.org/css-shapes/#funcdef-circle> @@ -122,11 +142,12 @@ pub struct InsetRect<LengthOrPercentage> { MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, )] -pub struct Circle<H, V, LengthOrPercentage> { +pub struct Circle<H, V, NonNegativeLengthOrPercentage> { pub position: Position<H, V>, - pub radius: ShapeRadius<LengthOrPercentage>, + pub radius: ShapeRadius<NonNegativeLengthOrPercentage>, } /// <https://drafts.csswg.org/css-shapes/#funcdef-ellipse> @@ -141,12 +162,13 @@ pub struct Circle<H, V, LengthOrPercentage> { MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, )] -pub struct Ellipse<H, V, LengthOrPercentage> { +pub struct Ellipse<H, V, NonNegativeLengthOrPercentage> { pub position: Position<H, V>, - pub semiaxis_x: ShapeRadius<LengthOrPercentage>, - pub semiaxis_y: ShapeRadius<LengthOrPercentage>, + pub semiaxis_x: ShapeRadius<NonNegativeLengthOrPercentage>, + pub semiaxis_y: ShapeRadius<NonNegativeLengthOrPercentage>, } /// <https://drafts.csswg.org/css-shapes/#typedef-shape-radius> @@ -160,11 +182,12 @@ pub struct Ellipse<H, V, LengthOrPercentage> { MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, ToCss, )] -pub enum ShapeRadius<LengthOrPercentage> { - Length(LengthOrPercentage), +pub enum ShapeRadius<NonNegativeLengthOrPercentage> { + Length(NonNegativeLengthOrPercentage), #[animation(error)] ClosestSide, #[animation(error)] @@ -175,7 +198,16 @@ pub enum ShapeRadius<LengthOrPercentage> { /// /// <https://drafts.csswg.org/css-shapes/#funcdef-polygon> #[css(comma, function)] -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToCss, +)] pub struct Polygon<LengthOrPercentage> { /// The filling rule for a polygon. #[css(skip_if = "fill_is_default")] @@ -186,7 +218,16 @@ pub struct Polygon<LengthOrPercentage> { } /// Coordinates for Polygon. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToCss, +)] pub struct PolygonCoord<LengthOrPercentage>(pub LengthOrPercentage, pub LengthOrPercentage); // https://drafts.csswg.org/css-shapes/#typedef-fill-rule @@ -204,6 +245,7 @@ pub struct PolygonCoord<LengthOrPercentage>(pub LengthOrPercentage, pub LengthOr Parse, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, ToCss, )] @@ -218,7 +260,15 @@ pub enum FillRule { /// https://drafts.csswg.org/css-shapes-2/#funcdef-path #[css(comma)] #[derive( - Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, + Animate, + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToAnimatedValue, + ToComputedValue, + ToCss, )] pub struct Path { /// The filling rule for the svg path. @@ -258,9 +308,10 @@ impl<B, T, U> ToAnimatedZero for ShapeSource<B, T, U> { } } -impl<L> ToCss for InsetRect<L> +impl<Length, NonNegativeLength> ToCss for InsetRect<Length, NonNegativeLength> where - L: ToCss + PartialEq, + Length: ToCss + PartialEq, + NonNegativeLength: ToCss + PartialEq, { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs index 0a50721bcda..20274816615 100644 --- a/components/style/values/generics/border.rs +++ b/components/style/values/generics/border.rs @@ -45,6 +45,8 @@ pub struct BorderImageSlice<NumberOrPercentage> { MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, + ToAnimatedZero, ToComputedValue, ToCss, )] @@ -93,6 +95,7 @@ impl<L> BorderSpacing<L> { MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, )] pub struct BorderRadius<LengthOrPercentage> { @@ -106,19 +109,6 @@ pub struct BorderRadius<LengthOrPercentage> { pub bottom_left: BorderCornerRadius<LengthOrPercentage>, } -impl<N> From<N> for BorderImageSlice<N> -where - N: Clone, -{ - #[inline] - fn from(value: N) -> Self { - Self { - offsets: Rect::all(value), - fill: false, - } - } -} - impl<L> BorderRadius<L> { /// Returns a new `BorderRadius<L>`. #[inline] diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index 0bde0067def..07612913c0a 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -15,6 +15,7 @@ MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToAnimatedZero, ToComputedValue, )] diff --git a/components/style/values/generics/rect.rs b/components/style/values/generics/rect.rs index dfffb3a4834..985a9c4a320 100644 --- a/components/style/values/generics/rect.rs +++ b/components/style/values/generics/rect.rs @@ -20,6 +20,7 @@ use style_traits::{CssWriter, ParseError, ToCss}; MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToComputedValue, )] pub struct Rect<T>(pub T, pub T, pub T, pub T); diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index 981cad00aaa..84624671ffe 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -16,8 +16,8 @@ use crate::values::specified::border::BorderRadius; use crate::values::specified::image::Image; use crate::values::specified::position::{HorizontalPosition, Position, VerticalPosition}; use crate::values::specified::url::SpecifiedUrl; -use crate::values::specified::LengthOrPercentage; use crate::values::specified::SVGPathData; +use crate::values::specified::{LengthOrPercentage, NonNegativeLengthOrPercentage}; use cssparser::Parser; use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; @@ -32,19 +32,26 @@ pub type ClippingShape = generic::ClippingShape<BasicShape, SpecifiedUrl>; pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>; /// A specified basic shape. -pub type BasicShape = generic::BasicShape<HorizontalPosition, VerticalPosition, LengthOrPercentage>; +pub type BasicShape = generic::BasicShape< + HorizontalPosition, + VerticalPosition, + LengthOrPercentage, + NonNegativeLengthOrPercentage, +>; /// The specified value of `inset()` -pub type InsetRect = generic::InsetRect<LengthOrPercentage>; +pub type InsetRect = generic::InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>; /// A specified circle. -pub type Circle = generic::Circle<HorizontalPosition, VerticalPosition, LengthOrPercentage>; +pub type Circle = + generic::Circle<HorizontalPosition, VerticalPosition, NonNegativeLengthOrPercentage>; /// A specified ellipse. -pub type Ellipse = generic::Ellipse<HorizontalPosition, VerticalPosition, LengthOrPercentage>; +pub type Ellipse = + generic::Ellipse<HorizontalPosition, VerticalPosition, NonNegativeLengthOrPercentage>; /// The specified value of `ShapeRadius` -pub type ShapeRadius = generic::ShapeRadius<LengthOrPercentage>; +pub type ShapeRadius = generic::ShapeRadius<NonNegativeLengthOrPercentage>; /// The specified value of `Polygon` pub type Polygon = generic::Polygon<LengthOrPercentage>; @@ -199,10 +206,7 @@ impl InsetRect { } else { None }; - Ok(generic::InsetRect { - rect: rect, - round: round, - }) + Ok(generic::InsetRect { rect, round }) } } @@ -312,7 +316,7 @@ impl Parse for ShapeRadius { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { - if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { + if let Ok(lop) = input.try(|i| NonNegativeLengthOrPercentage::parse(context, i)) { return Ok(generic::ShapeRadius::Length(lop)); } diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs index cf60c91b329..acd38ea5ba4 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -13,8 +13,8 @@ use crate::values::generics::border::BorderRadius as GenericBorderRadius; use crate::values::generics::border::BorderSpacing as GenericBorderSpacing; use crate::values::generics::rect::Rect; use crate::values::generics::size::Size; -use crate::values::specified::length::{Length, LengthOrPercentage, NonNegativeLength}; -use crate::values::specified::{AllowQuirks, Number, NumberOrPercentage}; +use crate::values::specified::length::{NonNegativeLength, NonNegativeLengthOrPercentage}; +use crate::values::specified::{AllowQuirks, NonNegativeNumber, NonNegativeNumberOrPercentage}; use cssparser::Parser; use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, ToCss}; @@ -71,36 +71,53 @@ pub enum BorderSideWidth { /// `thick` Thick, /// `<length>` - Length(Length), + Length(NonNegativeLength), } /// A specified value for the `border-image-width` property. pub type BorderImageWidth = Rect<BorderImageSideWidth>; /// A specified value for a single side of a `border-image-width` property. -pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>; +pub type BorderImageSideWidth = + GenericBorderImageSideWidth<NonNegativeLengthOrPercentage, NonNegativeNumber>; /// A specified value for the `border-image-slice` property. -pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>; +pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>; /// A specified value for the `border-radius` property. -pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>; +pub type BorderRadius = GenericBorderRadius<NonNegativeLengthOrPercentage>; /// A specified value for the `border-*-radius` longhand properties. -pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>; +pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthOrPercentage>; /// A specified value for the `border-spacing` longhand properties. pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>; +impl BorderImageSlice { + /// Returns the `100%` value. + #[inline] + pub fn hundred_percent() -> Self { + GenericBorderImageSlice { + offsets: Rect::all(NonNegativeNumberOrPercentage::hundred_percent()), + fill: false, + } + } +} + impl BorderSideWidth { + /// Returns the `0px` value. + #[inline] + pub fn zero() -> Self { + BorderSideWidth::Length(NonNegativeLength::zero()) + } + /// Parses, with quirks. pub fn parse_quirky<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, allow_quirks: AllowQuirks, ) -> Result<Self, ParseError<'i>> { - if let Ok(length) = - input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) + if let Ok(length) = input.try(|i| NonNegativeLength::parse_quirky(context, i, allow_quirks)) { return Ok(BorderSideWidth::Length(length)); } @@ -130,9 +147,9 @@ impl ToComputedValue for BorderSideWidth { // Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width // Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0 match *self { - BorderSideWidth::Thin => Length::from_px(1.).to_computed_value(context), - BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context), - BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context), + BorderSideWidth::Thin => NonNegativeLength::from_px(1.).to_computed_value(context), + BorderSideWidth::Medium => NonNegativeLength::from_px(3.).to_computed_value(context), + BorderSideWidth::Thick => NonNegativeLength::from_px(5.).to_computed_value(context), BorderSideWidth::Length(ref length) => length.to_computed_value(context), } .into() @@ -140,7 +157,7 @@ impl ToComputedValue for BorderSideWidth { #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { - BorderSideWidth::Length(ToComputedValue::from_computed_value(&computed.0)) + BorderSideWidth::Length(ToComputedValue::from_computed_value(computed)) } } @@ -148,7 +165,7 @@ impl BorderImageSideWidth { /// Returns `1`. #[inline] pub fn one() -> Self { - GenericBorderImageSideWidth::Number(Number::new(1.)) + GenericBorderImageSideWidth::Number(NonNegativeNumber::new(1.)) } } @@ -161,11 +178,11 @@ impl Parse for BorderImageSideWidth { return Ok(GenericBorderImageSideWidth::Auto); } - if let Ok(len) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { + if let Ok(len) = input.try(|i| NonNegativeLengthOrPercentage::parse(context, i)) { return Ok(GenericBorderImageSideWidth::Length(len)); } - let num = Number::parse_non_negative(context, input)?; + let num = NonNegativeNumber::parse(context, input)?; Ok(GenericBorderImageSideWidth::Number(num)) } } @@ -176,14 +193,11 @@ impl Parse for BorderImageSlice { input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok(); - let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?; + let offsets = Rect::parse_with(context, input, NonNegativeNumberOrPercentage::parse)?; if !fill { fill = input.try(|i| i.expect_ident_matching("fill")).is_ok(); } - Ok(GenericBorderImageSlice { - offsets: offsets, - fill: fill, - }) + Ok(GenericBorderImageSlice { offsets, fill }) } } @@ -192,9 +206,9 @@ impl Parse for BorderRadius { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { - let widths = Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?; + let widths = Rect::parse_with(context, input, NonNegativeLengthOrPercentage::parse)?; let heights = if input.try(|i| i.expect_delim('/')).is_ok() { - Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)? + Rect::parse_with(context, input, NonNegativeLengthOrPercentage::parse)? } else { widths.clone() }; @@ -213,7 +227,7 @@ impl Parse for BorderCornerRadius { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { - Size::parse_with(context, input, LengthOrPercentage::parse_non_negative) + Size::parse_with(context, input, NonNegativeLengthOrPercentage::parse) .map(GenericBorderCornerRadius) } } @@ -224,7 +238,7 @@ impl Parse for BorderSpacing { input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { Size::parse_with(context, input, |context, input| { - Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes).map(From::from) + NonNegativeLength::parse_quirky(context, input, AllowQuirks::Yes).map(From::from) }) .map(GenericBorderSpacing) } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 13877dbe594..e64385472a0 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -717,6 +717,20 @@ impl NonNegativeLength { pub fn from_px(px_value: CSSFloat) -> Self { Length::from_px(px_value.max(0.)).into() } + + /// Parses a non-negative length, optionally with quirks. + #[inline] + pub fn parse_quirky<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + allow_quirks: AllowQuirks, + ) -> Result<Self, ParseError<'i>> { + Ok(NonNegative(Length::parse_non_negative_quirky( + context, + input, + allow_quirks, + )?)) + } } /// Either a NonNegativeLength or the `auto` keyword. @@ -1246,17 +1260,6 @@ impl Parse for MozLength { } impl MozLength { - /// Parses, without quirks, and disallowing ExtremumLength values. - /// - /// Used for logical props in the block direction. - pub fn parse_disallow_keyword<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result<Self, ParseError<'i>> { - let length = LengthOrPercentageOrAuto::parse_non_negative(context, input)?; - Ok(GenericMozLength::LengthOrPercentageOrAuto(length)) - } - /// Parses, with quirks. pub fn parse_quirky<'i, 't>( context: &ParserContext, @@ -1298,17 +1301,6 @@ impl Parse for MaxLength { } impl MaxLength { - /// Parses, without quirks, and disallowing ExtremumLength values. - /// - /// Used for logical props in the block direction. - pub fn parse_disallow_keyword<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result<Self, ParseError<'i>> { - let length = LengthOrPercentageOrNone::parse_non_negative(context, input)?; - Ok(GenericMaxLength::LengthOrPercentageOrNone(length)) - } - /// Parses, with quirks. pub fn parse_quirky<'i, 't>( context: &ParserContext, diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index d3df66a0eea..17d1ea04186 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -359,6 +359,28 @@ impl Parse for NumberOrPercentage { } } +/// A non-negative <number> | <percentage>. +pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>; + +impl NonNegativeNumberOrPercentage { + /// Returns the `100%` value. + #[inline] + pub fn hundred_percent() -> Self { + NonNegative(NumberOrPercentage::Percentage(Percentage::hundred())) + } +} + +impl Parse for NonNegativeNumberOrPercentage { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + Ok(NonNegative(NumberOrPercentage::parse_non_negative( + context, input, + )?)) + } +} + #[allow(missing_docs)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, ToCss)] pub struct Opacity(Number); diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index 38326dcd1fd..035f9a9385c 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -10,9 +10,7 @@ use style::properties::parse_property_declaration_list; use style::properties::{Importance, PropertyDeclaration}; use style::values::specified::url::SpecifiedUrl; use style::values::specified::NoCalcLength; -use style::values::specified::{BorderSideWidth, BorderStyle, Color}; use style::values::specified::{Length, LengthOrPercentage, LengthOrPercentageOrAuto}; -use style::values::RGBA; use style_traits::ToCss; trait ToCssString { @@ -83,408 +81,6 @@ mod shorthand_serialization { block.to_css_string() } - mod four_sides_shorthands { - pub use super::*; - - // we can use margin as a base to test out the different combinations - // but afterwards, we only need to to one test per "four sides shorthand" - #[test] - fn all_equal_properties_should_serialize_to_one_value() { - let mut properties = Vec::new(); - - let px_70 = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(70f32)); - properties.push(PropertyDeclaration::MarginTop(px_70.clone())); - properties.push(PropertyDeclaration::MarginRight(px_70.clone())); - properties.push(PropertyDeclaration::MarginBottom(px_70.clone())); - properties.push(PropertyDeclaration::MarginLeft(px_70)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "margin: 70px;"); - } - - #[test] - fn equal_vertical_and_equal_horizontal_properties_should_serialize_to_two_value() { - let mut properties = Vec::new(); - - let vertical_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32)); - let horizontal_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(5f32)); - - properties.push(PropertyDeclaration::MarginTop(vertical_px.clone())); - properties.push(PropertyDeclaration::MarginRight(horizontal_px.clone())); - properties.push(PropertyDeclaration::MarginBottom(vertical_px)); - properties.push(PropertyDeclaration::MarginLeft(horizontal_px)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "margin: 10px 5px;"); - } - - #[test] - fn different_vertical_and_equal_horizontal_properties_should_serialize_to_three_values() { - let mut properties = Vec::new(); - - let top_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(8f32)); - let bottom_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32)); - let horizontal_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(5f32)); - - properties.push(PropertyDeclaration::MarginTop(top_px)); - properties.push(PropertyDeclaration::MarginRight(horizontal_px.clone())); - properties.push(PropertyDeclaration::MarginBottom(bottom_px)); - properties.push(PropertyDeclaration::MarginLeft(horizontal_px)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "margin: 8px 5px 10px;"); - } - - #[test] - fn different_properties_should_serialize_to_four_values() { - let mut properties = Vec::new(); - - let top_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(8f32)); - let right_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(12f32)); - let bottom_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32)); - let left_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(14f32)); - - properties.push(PropertyDeclaration::MarginTop(top_px)); - properties.push(PropertyDeclaration::MarginRight(right_px)); - properties.push(PropertyDeclaration::MarginBottom(bottom_px)); - properties.push(PropertyDeclaration::MarginLeft(left_px)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "margin: 8px 12px 10px 14px;"); - } - - #[test] - fn different_longhands_should_serialize_to_long_form() { - let mut properties = Vec::new(); - - let solid = BorderStyle::Solid; - - properties.push(PropertyDeclaration::BorderTopStyle(solid.clone())); - properties.push(PropertyDeclaration::BorderRightStyle(solid.clone())); - properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone())); - properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone())); - - let px_30 = BorderSideWidth::Length(Length::from_px(30f32)); - let px_10 = BorderSideWidth::Length(Length::from_px(10f32)); - - properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone())); - properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone())); - properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone())); - properties.push(PropertyDeclaration::BorderLeftWidth(px_10.clone())); - - let blue = Color::rgba(RGBA::new(0, 0, 255, 255)); - - properties.push(PropertyDeclaration::BorderTopColor(blue.clone())); - properties.push(PropertyDeclaration::BorderRightColor(blue.clone())); - properties.push(PropertyDeclaration::BorderBottomColor(blue.clone())); - properties.push(PropertyDeclaration::BorderLeftColor(blue.clone())); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, - "border-style: solid; border-width: 30px 30px 30px 10px; border-color: rgb(0, 0, 255);"); - } - - #[test] - fn same_longhands_should_serialize_correctly() { - let mut properties = Vec::new(); - - let solid = BorderStyle::Solid; - - properties.push(PropertyDeclaration::BorderTopStyle(solid.clone())); - properties.push(PropertyDeclaration::BorderRightStyle(solid.clone())); - properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone())); - properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone())); - - let px_30 = BorderSideWidth::Length(Length::from_px(30f32)); - - properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone())); - properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone())); - properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone())); - properties.push(PropertyDeclaration::BorderLeftWidth(px_30.clone())); - - let blue = Color::rgba(RGBA::new(0, 0, 255, 255)); - - properties.push(PropertyDeclaration::BorderTopColor(blue.clone())); - properties.push(PropertyDeclaration::BorderRightColor(blue.clone())); - properties.push(PropertyDeclaration::BorderBottomColor(blue.clone())); - properties.push(PropertyDeclaration::BorderLeftColor(blue.clone())); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!( - serialization, - "border-style: solid; border-width: 30px; border-color: rgb(0, 0, 255);" - ); - } - - #[test] - fn padding_should_serialize_correctly() { - use style::values::specified::NonNegativeLengthOrPercentage; - - let mut properties = Vec::new(); - - let px_10: NonNegativeLengthOrPercentage = NoCalcLength::from_px(10f32).into(); - let px_15: NonNegativeLengthOrPercentage = NoCalcLength::from_px(15f32).into(); - properties.push(PropertyDeclaration::PaddingTop(px_10.clone())); - properties.push(PropertyDeclaration::PaddingRight(px_15.clone())); - properties.push(PropertyDeclaration::PaddingBottom(px_10)); - properties.push(PropertyDeclaration::PaddingLeft(px_15)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "padding: 10px 15px;"); - } - - #[test] - fn border_width_should_serialize_correctly() { - let mut properties = Vec::new(); - - let top_px = BorderSideWidth::Length(Length::from_px(10f32)); - let bottom_px = BorderSideWidth::Length(Length::from_px(10f32)); - - let right_px = BorderSideWidth::Length(Length::from_px(15f32)); - let left_px = BorderSideWidth::Length(Length::from_px(15f32)); - - properties.push(PropertyDeclaration::BorderTopWidth(top_px)); - properties.push(PropertyDeclaration::BorderRightWidth(right_px)); - properties.push(PropertyDeclaration::BorderBottomWidth(bottom_px)); - properties.push(PropertyDeclaration::BorderLeftWidth(left_px)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-width: 10px 15px;"); - } - - #[test] - fn border_width_with_keywords_should_serialize_correctly() { - let mut properties = Vec::new(); - - let top_px = BorderSideWidth::Thin; - let right_px = BorderSideWidth::Medium; - let bottom_px = BorderSideWidth::Thick; - let left_px = BorderSideWidth::Length(Length::from_px(15f32)); - - properties.push(PropertyDeclaration::BorderTopWidth(top_px)); - properties.push(PropertyDeclaration::BorderRightWidth(right_px)); - properties.push(PropertyDeclaration::BorderBottomWidth(bottom_px)); - properties.push(PropertyDeclaration::BorderLeftWidth(left_px)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-width: thin medium thick 15px;"); - } - - #[test] - fn border_color_should_serialize_correctly() { - let mut properties = Vec::new(); - - let red = Color::rgba(RGBA::new(255, 0, 0, 255)); - let blue = Color::rgba(RGBA::new(0, 0, 255, 255)); - - properties.push(PropertyDeclaration::BorderTopColor(blue.clone())); - properties.push(PropertyDeclaration::BorderRightColor(red.clone())); - properties.push(PropertyDeclaration::BorderBottomColor(blue)); - properties.push(PropertyDeclaration::BorderLeftColor(red)); - - let serialization = shorthand_properties_to_string(properties); - - // TODO: Make the rgb test show border-color as blue red instead of below tuples - assert_eq!( - serialization, - "border-color: rgb(0, 0, 255) rgb(255, 0, 0);" - ); - } - - #[test] - fn border_style_should_serialize_correctly() { - let mut properties = Vec::new(); - - let solid = BorderStyle::Solid; - let dotted = BorderStyle::Dotted; - properties.push(PropertyDeclaration::BorderTopStyle(solid.clone())); - properties.push(PropertyDeclaration::BorderRightStyle(dotted.clone())); - properties.push(PropertyDeclaration::BorderBottomStyle(solid)); - properties.push(PropertyDeclaration::BorderLeftStyle(dotted)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-style: solid dotted;"); - } - - use style::values::specified::{BorderCornerRadius, Percentage}; - - #[test] - fn border_radius_should_serialize_correctly() { - let mut properties = Vec::new(); - properties.push(PropertyDeclaration::BorderTopLeftRadius(Box::new( - BorderCornerRadius::new(Percentage::new(0.01).into(), Percentage::new(0.05).into()), - ))); - properties.push(PropertyDeclaration::BorderTopRightRadius(Box::new( - BorderCornerRadius::new(Percentage::new(0.02).into(), Percentage::new(0.06).into()), - ))); - properties.push(PropertyDeclaration::BorderBottomRightRadius(Box::new( - BorderCornerRadius::new(Percentage::new(0.03).into(), Percentage::new(0.07).into()), - ))); - properties.push(PropertyDeclaration::BorderBottomLeftRadius(Box::new( - BorderCornerRadius::new(Percentage::new(0.04).into(), Percentage::new(0.08).into()), - ))); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-radius: 1% 2% 3% 4% / 5% 6% 7% 8%;"); - } - } - - mod border_shorthands { - use super::*; - - #[test] - fn border_top_and_color() { - let mut properties = Vec::new(); - properties.push(PropertyDeclaration::BorderTopWidth( - BorderSideWidth::Length(Length::from_px(1.)), - )); - properties.push(PropertyDeclaration::BorderTopStyle(BorderStyle::Solid)); - let c = Color::Numeric { - parsed: RGBA::new(255, 0, 0, 255), - authored: Some("green".to_string().into_boxed_str()), - }; - properties.push(PropertyDeclaration::BorderTopColor(c)); - let c = Color::Numeric { - parsed: RGBA::new(0, 255, 0, 255), - authored: Some("red".to_string().into_boxed_str()), - }; - properties.push(PropertyDeclaration::BorderTopColor(c.clone())); - properties.push(PropertyDeclaration::BorderBottomColor(c.clone())); - properties.push(PropertyDeclaration::BorderLeftColor(c.clone())); - properties.push(PropertyDeclaration::BorderRightColor(c.clone())); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!( - serialization, - "border-top: 1px solid red; border-color: red;" - ); - } - - #[test] - fn border_color_and_top() { - let mut properties = Vec::new(); - let c = Color::Numeric { - parsed: RGBA::new(0, 255, 0, 255), - authored: Some("red".to_string().into_boxed_str()), - }; - properties.push(PropertyDeclaration::BorderTopColor(c.clone())); - properties.push(PropertyDeclaration::BorderBottomColor(c.clone())); - properties.push(PropertyDeclaration::BorderLeftColor(c.clone())); - properties.push(PropertyDeclaration::BorderRightColor(c.clone())); - - properties.push(PropertyDeclaration::BorderTopWidth( - BorderSideWidth::Length(Length::from_px(1.)), - )); - properties.push(PropertyDeclaration::BorderTopStyle(BorderStyle::Solid)); - let c = Color::Numeric { - parsed: RGBA::new(255, 0, 0, 255), - authored: Some("green".to_string().into_boxed_str()), - }; - properties.push(PropertyDeclaration::BorderTopColor(c)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!( - serialization, - "border-color: green red red; border-top: 1px solid green;" - ); - } - - // we can use border-top as a base to test out the different combinations - // but afterwards, we only need to to one test per "directional border shorthand" - - #[test] - fn directional_border_should_show_all_properties_when_values_are_set() { - let mut properties = Vec::new(); - - let width = BorderSideWidth::Length(Length::from_px(4f32)); - let style = BorderStyle::Solid; - let color = RGBA::new(255, 0, 0, 255).into(); - - properties.push(PropertyDeclaration::BorderTopWidth(width)); - properties.push(PropertyDeclaration::BorderTopStyle(style)); - properties.push(PropertyDeclaration::BorderTopColor(color)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-top: 4px solid rgb(255, 0, 0);"); - } - - fn get_border_property_values() -> (BorderSideWidth, BorderStyle, Color) { - ( - BorderSideWidth::Length(Length::from_px(4f32)), - BorderStyle::Solid, - Color::currentcolor(), - ) - } - - #[test] - fn border_top_should_serialize_correctly() { - let mut properties = Vec::new(); - let (width, style, color) = get_border_property_values(); - properties.push(PropertyDeclaration::BorderTopWidth(width)); - properties.push(PropertyDeclaration::BorderTopStyle(style)); - properties.push(PropertyDeclaration::BorderTopColor(color)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-top: 4px solid;"); - } - - #[test] - fn border_right_should_serialize_correctly() { - let mut properties = Vec::new(); - let (width, style, color) = get_border_property_values(); - properties.push(PropertyDeclaration::BorderRightWidth(width)); - properties.push(PropertyDeclaration::BorderRightStyle(style)); - properties.push(PropertyDeclaration::BorderRightColor(color)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-right: 4px solid;"); - } - - #[test] - fn border_bottom_should_serialize_correctly() { - let mut properties = Vec::new(); - let (width, style, color) = get_border_property_values(); - properties.push(PropertyDeclaration::BorderBottomWidth(width)); - properties.push(PropertyDeclaration::BorderBottomStyle(style)); - properties.push(PropertyDeclaration::BorderBottomColor(color)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-bottom: 4px solid;"); - } - - #[test] - fn border_left_should_serialize_correctly() { - let mut properties = Vec::new(); - let (width, style, color) = get_border_property_values(); - properties.push(PropertyDeclaration::BorderLeftWidth(width)); - properties.push(PropertyDeclaration::BorderLeftStyle(style)); - properties.push(PropertyDeclaration::BorderLeftColor(color)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "border-left: 4px solid;"); - } - - #[test] - fn border_should_serialize_correctly() { - // According to https://drafts.csswg.org/css-backgrounds-3/#the-border-shorthands, - // the ‘border’ shorthand resets ‘border-image’ to its initial value. To verify the - // serialization of 'border' shorthand, we need to set 'border-image' as well. - let block_text = "\ - border-top: 4px solid; \ - border-right: 4px solid; \ - border-bottom: 4px solid; \ - border-left: 4px solid; \ - border-image: none;"; - - let block = - parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap(); - - let serialization = block.to_css_string(); - - assert_eq!(serialization, "border: 4px solid;"); - } - } - mod list_style { use super::*; use style::properties::longhands::list_style_position::SpecifiedValue as ListStylePosition; |