diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-05-29 16:49:16 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-29 16:49:16 -0400 |
commit | b4fb2cda087a4467742681cc27291c803d0dc825 (patch) | |
tree | ec530c726d1e55ca06de9bbb57d8cb0e0671c8bd | |
parent | d8983b51275fa0b67cb56f686510ab5695c024d6 (diff) | |
parent | 324aed53f1d3852caadf33c4c611cb7ed6985996 (diff) | |
download | servo-b4fb2cda087a4467742681cc27291c803d0dc825.tar.gz servo-b4fb2cda087a4467742681cc27291c803d0dc825.zip |
Auto merge of #23456 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central.
See each individual commit for details.
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23456)
<!-- Reviewable:end -->
105 files changed, 1452 insertions, 2512 deletions
diff --git a/Cargo.lock b/Cargo.lock index 179e7109d5d..88bbbeca206 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4562,6 +4562,7 @@ dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of 0.0.1", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.21.0", diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt index a42e998c958..c85d3563e75 100644 --- a/components/atoms/static_atoms.txt +++ b/components/atoms/static_atoms.txt @@ -30,6 +30,8 @@ error fantasy fetch file +fill +fill-opacity formdata fullscreenchange fullscreenerror @@ -100,6 +102,8 @@ serif signalingstatechange srclang statechange +stroke +stroke-opacity storage submit suspend diff --git a/components/layout/display_list/border.rs b/components/layout/display_list/border.rs index dcbef4473fe..848386cb630 100644 --- a/components/layout/display_list/border.rs +++ b/components/layout/display_list/border.rs @@ -159,7 +159,7 @@ fn side_image_width( total_length: Au, ) -> f32 { match border_image_width { - BorderImageSideWidth::Length(v) => v.to_used_value(total_length).to_f32_px(), + BorderImageSideWidth::LengthPercentage(v) => v.to_used_value(total_length).to_f32_px(), BorderImageSideWidth::Number(x) => border_width * x.0, BorderImageSideWidth::Auto => border_width, } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index ccc3de5ec7e..d3e9dbb6779 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -2793,7 +2793,7 @@ impl Fragment { let mut overflow = Overflow::from_rect(&border_box); // Box shadows cause us to draw outside our border box. - for box_shadow in &self.style().get_effects().box_shadow.0 { + for box_shadow in &*self.style().get_effects().box_shadow.0 { let offset = Vector2D::new( Au::from(box_shadow.base.horizontal), Au::from(box_shadow.base.vertical), diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 301a7500713..d738ef1151f 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -888,6 +888,10 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { self.element.namespace() } + fn is_pseudo_element(&self) -> bool { + false + } + fn match_pseudo_element( &self, _pseudo: &PseudoElement, @@ -1394,6 +1398,10 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> { ::selectors::OpaqueElement::new(unsafe { &*(self.as_node().opaque().0 as *const ()) }) } + fn is_pseudo_element(&self) -> bool { + false + } + fn parent_element(&self) -> Option<Self> { warn!("ServoThreadSafeLayoutElement::parent_element called"); None diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 1b918c0537b..c4174309af9 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -685,9 +685,9 @@ impl LayoutElementHelpers for LayoutDom<Element> { if let Some(url) = background { hints.push(from_declaration( shared_lock, - PropertyDeclaration::BackgroundImage(background_image::SpecifiedValue(vec![ - Either::Second(specified::Image::for_cascade(url.into())), - ])), + PropertyDeclaration::BackgroundImage(background_image::SpecifiedValue( + vec![Either::Second(specified::Image::for_cascade(url.into()))].into(), + )), )); } @@ -2945,6 +2945,10 @@ impl<'a> SelectorsElement for DomRoot<Element> { } } + fn is_pseudo_element(&self) -> bool { + false + } + fn match_pseudo_element( &self, _pseudo: &PseudoElement, diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs index b548ceb83ce..c3e733cbeb0 100644 --- a/components/selectors/builder.rs +++ b/components/selectors/builder.rs @@ -84,12 +84,6 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> { self.current_len = 0; } - /// Returns true if no simple selectors have ever been pushed to this builder. - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.simple_selectors.is_empty() - } - /// Returns true if combinators have ever been pushed to this builder. #[inline(always)] pub fn has_combinators(&self) -> bool { diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index aa200cc4b26..6554f2f9cc4 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -331,11 +331,9 @@ where return false; } - // Advance to the non-pseudo-element part of the selector, but let the - // context note that . - if iter.next_sequence().is_none() { - return true; - } + // Advance to the non-pseudo-element part of the selector. + let next_sequence = iter.next_sequence().unwrap(); + debug_assert_eq!(next_sequence, Combinator::PseudoElement); } let result = @@ -452,10 +450,6 @@ where }, Combinator::Part => element.containing_shadow_host(), Combinator::SlotAssignment => { - debug_assert!( - context.current_host.is_some(), - "Should not be trying to match slotted rules in a non-shadow-tree context" - ); debug_assert!(element .assigned_slot() .map_or(true, |s| s.is_html_slot_element())); @@ -677,7 +671,6 @@ where Component::Slotted(ref selector) => { // <slots> are never flattened tree slottables. !element.is_html_slot_element() && - element.assigned_slot().is_some() && context.shared.nest(|context| { matches_complex_selector(selector.iter(), element, context, flags_setter) }) diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index a924bbc17d0..f049555730c 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -2002,9 +2002,7 @@ where }, SimpleSelectorParseResult::SlottedPseudo(selector) => { state.insert(SelectorParsingState::AFTER_SLOTTED); - if !builder.is_empty() { - builder.push_combinator(Combinator::SlotAssignment); - } + builder.push_combinator(Combinator::SlotAssignment); builder.push_simple_selector(Component::Slotted(selector)); }, SimpleSelectorParseResult::PseudoElement(p) => { @@ -2012,9 +2010,7 @@ where if !p.accepts_state_pseudo_classes() { state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT); } - if !builder.is_empty() { - builder.push_combinator(Combinator::PseudoElement); - } + builder.push_combinator(Combinator::PseudoElement); builder.push_simple_selector(Component::PseudoElement(p)); }, } @@ -2828,7 +2824,10 @@ pub mod tests { assert_eq!( parse("::before"), Ok(SelectorList::from_vec(vec![Selector::from_vec( - vec![Component::PseudoElement(PseudoElement::Before)], + vec![ + Component::Combinator(Combinator::PseudoElement), + Component::PseudoElement(PseudoElement::Before), + ], specificity(0, 0, 1) | HAS_PSEUDO_BIT, )])) ); @@ -2836,6 +2835,7 @@ pub mod tests { parse("::before:hover"), Ok(SelectorList::from_vec(vec![Selector::from_vec( vec![ + Component::Combinator(Combinator::PseudoElement), Component::PseudoElement(PseudoElement::Before), Component::NonTSPseudoClass(PseudoClass::Hover), ], @@ -2846,6 +2846,7 @@ pub mod tests { parse("::before:hover:hover"), Ok(SelectorList::from_vec(vec![Selector::from_vec( vec![ + Component::Combinator(Combinator::PseudoElement), Component::PseudoElement(PseudoElement::Before), Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover), @@ -2958,6 +2959,7 @@ pub mod tests { specificity(0, 0, 0), )])) ); + assert_eq!( parse_ns(":not(svg|*)", &parser), Ok(SelectorList::from_vec(vec![Selector::from_vec( @@ -3032,6 +3034,8 @@ pub mod tests { Some(&Component::PseudoElement(PseudoElement::Before)) ); assert_eq!(iter.next(), None); + assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement)); + assert_eq!(iter.next(), None); assert_eq!(iter.next_sequence(), None); } diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs index 52599893d2f..611e40d6027 100644 --- a/components/selectors/tree.rs +++ b/components/selectors/tree.rs @@ -47,9 +47,13 @@ pub trait Element: Sized + Clone + Debug { /// /// This is guaranteed to be called in a pseudo-element. fn pseudo_element_originating_element(&self) -> Option<Self> { + debug_assert!(self.is_pseudo_element()); self.parent_element() } + /// Whether we're matching on a pseudo-element. + fn is_pseudo_element(&self) -> bool; + /// Skips non-element nodes fn prev_sibling_element(&self) -> Option<Self>; diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index f2f9fa00602..09f381c62df 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -612,16 +612,15 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { use std::mem::{align_of, size_of}; assert_ne!(size_of::<T>(), 0, "Need to think about ZST"); + let inner_align = align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>(); + debug_assert!(inner_align >= align_of::<T>()); + // Compute the required size for the allocation. let num_items = items.len(); let size = { - // First, determine the alignment of a hypothetical pointer to a - // HeaderSlice. - let fake_slice_ptr_align: usize = mem::align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>(); - // Next, synthesize a totally garbage (but properly aligned) pointer // to a sequence of T. - let fake_slice_ptr = fake_slice_ptr_align as *const T; + let fake_slice_ptr = inner_align as *const T; // Convert that sequence to a fat pointer. The address component of // the fat pointer will be garbage, but the length will be correct. @@ -641,13 +640,13 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { let ptr: *mut ArcInner<HeaderSlice<H, [T]>>; unsafe { // Allocate the buffer. - let layout = if mem::align_of::<T>() <= mem::align_of::<usize>() { - Layout::from_size_align_unchecked(size, mem::align_of::<usize>()) - } else if mem::align_of::<T>() <= mem::align_of::<u64>() { - // On 32-bit platforms <T> may have 8 byte alignment while usize has 4 byte aligment. - // Use u64 to avoid over-alignment. + let layout = if inner_align <= align_of::<usize>() { + Layout::from_size_align_unchecked(size, align_of::<usize>()) + } else if inner_align <= align_of::<u64>() { + // On 32-bit platforms <T> may have 8 byte alignment while usize + // has 4 byte aligment. Use u64 to avoid over-alignment. // This branch will compile away in optimized builds. - Layout::from_size_align_unchecked(size, mem::align_of::<u64>()) + Layout::from_size_align_unchecked(size, align_of::<u64>()) } else { panic!("Over-aligned type not handled"); }; @@ -689,7 +688,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> { // for some padding from the alignment. debug_assert!( (buffer.offset(size as isize) as usize - current as *mut u8 as usize) < - align_of::<Self>() + inner_align ); } assert!( diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index bf953a13f8f..4d5f3e2e94d 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -22,6 +22,7 @@ servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5eve "cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union", "servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"] gecko_debug = [] +gecko_profiler = [] [dependencies] app_units = "0.7" @@ -79,7 +80,7 @@ void = "1.0.2" [build-dependencies] lazy_static = "1" log = "0.4" -bindgen = { version = "0.49", optional = true, default-features = false } +bindgen = {version = "0.49", optional = true, default-features = false} regex = {version = "1.1", optional = true} walkdir = "2.1.4" toml = {version = "0.4.5", optional = true, default-features = false} diff --git a/components/style/counter_style/mod.rs b/components/style/counter_style/mod.rs index 77de5f52d2b..289281011c3 100644 --- a/components/style/counter_style/mod.rs +++ b/components/style/counter_style/mod.rs @@ -19,7 +19,6 @@ use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; use std::mem; use std::num::Wrapping; -use std::ops::Range; use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError}; use style_traits::{StyleParseErrorKind, ToCss}; @@ -261,7 +260,7 @@ counter_style_descriptors! { "suffix" suffix / set_suffix [_]: Symbol, /// <https://drafts.csswg.org/css-counter-styles/#counter-style-range> - "range" range / set_range [_]: Ranges, + "range" range / set_range [_]: CounterRanges, /// <https://drafts.csswg.org/css-counter-styles/#counter-style-pad> "pad" pad / set_pad [_]: Pad, @@ -371,7 +370,7 @@ impl Parse for System { "additive" => Ok(System::Additive), "fixed" => { let first_symbol_value = input.try(|i| Integer::parse(context, i)).ok(); - Ok(System::Fixed { first_symbol_value: first_symbol_value }) + Ok(System::Fixed { first_symbol_value }) } "extends" => { let other = parse_counter_style_name(input)?; @@ -409,11 +408,10 @@ impl ToCss for System { } /// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol> -#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] pub enum Symbol { /// <string> - String(String), + String(crate::OwnedStr), /// <custom-ident> Ident(CustomIdent), // Not implemented: @@ -428,7 +426,7 @@ impl Parse for Symbol { ) -> Result<Self, ParseError<'i>> { let location = input.current_source_location(); match *input.next()? { - Token::QuotedString(ref s) => Ok(Symbol::String(s.as_ref().to_owned())), + Token::QuotedString(ref s) => Ok(Symbol::String(s.as_ref().to_owned().into())), Token::Ident(ref s) => Ok(Symbol::Ident(CustomIdent::from_ident(location, s, &[])?)), ref t => Err(location.new_unexpected_token_error(t.clone())), } @@ -463,12 +461,22 @@ impl Parse for Negative { } /// <https://drafts.csswg.org/css-counter-styles/#counter-style-range> +#[derive(Clone, Debug, ToCss, ToShmem)] +pub struct CounterRange { + /// The start of the range. + pub start: CounterBound, + /// The end of the range. + pub end: CounterBound, +} + +/// <https://drafts.csswg.org/css-counter-styles/#counter-style-range> /// -/// Empty Vec represents 'auto' -#[derive(Clone, Debug, ToShmem)] -pub struct Ranges(pub Vec<Range<CounterBound>>); +/// Empty represents 'auto' +#[derive(Clone, Debug, ToCss, ToShmem)] +#[css(comma)] +pub struct CounterRanges(#[css(iterable, if_empty = "auto")] pub crate::OwnedSlice<CounterRange>); -/// A bound found in `Ranges`. +/// A bound found in `CounterRanges`. #[derive(Clone, Copy, Debug, ToCss, ToShmem)] pub enum CounterBound { /// An integer bound. @@ -477,7 +485,7 @@ pub enum CounterBound { Infinite, } -impl Parse for Ranges { +impl Parse for CounterRanges { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, @@ -486,25 +494,21 @@ impl Parse for Ranges { .try(|input| input.expect_ident_matching("auto")) .is_ok() { - Ok(Ranges(Vec::new())) - } else { - input - .parse_comma_separated(|input| { - let opt_start = parse_bound(context, input)?; - let opt_end = parse_bound(context, input)?; - if let (CounterBound::Integer(start), CounterBound::Integer(end)) = - (opt_start, opt_end) - { - if start > end { - return Err( - input.new_custom_error(StyleParseErrorKind::UnspecifiedError) - ); - } - } - Ok(opt_start..opt_end) - }) - .map(Ranges) + return Ok(CounterRanges(Default::default())); } + + let ranges = input.parse_comma_separated(|input| { + let start = parse_bound(context, input)?; + let end = parse_bound(context, input)?; + if let (CounterBound::Integer(start), CounterBound::Integer(end)) = (start, end) { + if start > end { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + } + Ok(CounterRange { start, end }) + })?; + + Ok(CounterRanges(ranges.into())) } } @@ -519,34 +523,6 @@ fn parse_bound<'i, 't>( Ok(CounterBound::Infinite) } -impl ToCss for Ranges { - fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result - where - W: Write, - { - let mut iter = self.0.iter(); - if let Some(first) = iter.next() { - range_to_css(first, dest)?; - for item in iter { - dest.write_str(", ")?; - range_to_css(item, dest)?; - } - Ok(()) - } else { - dest.write_str("auto") - } - } -} - -fn range_to_css<W>(range: &Range<CounterBound>, dest: &mut CssWriter<W>) -> fmt::Result -where - W: Write, -{ - range.start.to_css(dest)?; - dest.write_char(' ')?; - range.end.to_css(dest) -} - /// <https://drafts.csswg.org/css-counter-styles/#counter-style-pad> #[derive(Clone, Debug, ToCss, ToShmem)] pub struct Pad(pub Integer, pub Symbol); @@ -572,14 +548,13 @@ impl Parse for Fallback { _context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { - parse_counter_style_name(input).map(Fallback) + Ok(Fallback(parse_counter_style_name(input)?)) } } /// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols> -#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)] -pub struct Symbols(#[css(iterable)] pub Vec<Symbol>); +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>); impl Parse for Symbols { fn parse<'i, 't>( @@ -587,23 +562,20 @@ impl Parse for Symbols { input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { let mut symbols = Vec::new(); - loop { - if let Ok(s) = input.try(|input| Symbol::parse(context, input)) { - symbols.push(s) - } else { - if symbols.is_empty() { - return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); - } else { - return Ok(Symbols(symbols)); - } - } + while let Ok(s) = input.try(|input| Symbol::parse(context, input)) { + symbols.push(s); + } + if symbols.is_empty() { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } + Ok(Symbols(symbols.into())) } } /// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-additive-symbols> #[derive(Clone, Debug, ToCss, ToShmem)] -pub struct AdditiveSymbols(pub Vec<AdditiveTuple>); +#[css(comma)] +pub struct AdditiveSymbols(#[css(iterable)] pub crate::OwnedSlice<AdditiveTuple>); impl Parse for AdditiveSymbols { fn parse<'i, 't>( @@ -618,7 +590,7 @@ impl Parse for AdditiveSymbols { { return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } - Ok(AdditiveSymbols(tuples)) + Ok(AdditiveSymbols(tuples.into())) } } @@ -643,10 +615,7 @@ impl Parse for AdditiveTuple { let symbol = input.try(|input| Symbol::parse(context, input)); let weight = Integer::parse_non_negative(context, input)?; let symbol = symbol.or_else(|_| Symbol::parse(context, input))?; - Ok(AdditiveTuple { - weight: weight, - symbol: symbol, - }) + Ok(Self { weight, symbol }) } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 9a81e2ec774..5ee8443b91d 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -779,7 +779,7 @@ pub trait TElement: /// element-backed pseudo-element, in which case we return the originating /// element. fn rule_hash_target(&self) -> Self { - if self.implemented_pseudo_element().is_some() { + if self.is_pseudo_element() { self.pseudo_element_originating_element() .expect("Trying to collect rules for a detached pseudo-element") } else { @@ -801,24 +801,29 @@ pub trait TElement: { use rule_collector::containing_shadow_ignoring_svg_use; - let mut doc_rules_apply = self.matches_user_and_author_rules(); + let target = self.rule_hash_target(); + if !target.matches_user_and_author_rules() { + return false; + } + + let mut doc_rules_apply = true; // 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(*self) { + if let Some(shadow) = containing_shadow_ignoring_svg_use(target) { doc_rules_apply = false; if let Some(data) = shadow.style_data() { f(data, shadow.host()); } } - if let Some(shadow) = self.shadow_root() { + if let Some(shadow) = target.shadow_root() { if let Some(data) = shadow.style_data() { f(data, shadow.host()); } } - let mut current = self.assigned_slot(); + let mut current = target.assigned_slot(); while let Some(slot) = current { // Slots can only have assigned nodes when in a shadow tree. let shadow = slot.containing_shadow().unwrap(); diff --git a/components/style/driver.rs b/components/style/driver.rs index e9433f73a03..6b05bc85281 100644 --- a/components/style/driver.rs +++ b/components/style/driver.rs @@ -134,6 +134,7 @@ pub fn traverse_dom<E, D>( let drain = discovered.drain(..); pool.install(|| { rayon::scope(|scope| { + profiler_label!(Style); parallel::traverse_nodes( drain, DispatchMode::TailCall, diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index 309f2395085..7aed10b6568 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -23,7 +23,6 @@ use crate::gecko_bindings::structs::RawServoMediaRule; use crate::gecko_bindings::structs::RawServoMozDocumentRule; use crate::gecko_bindings::structs::RawServoNamespaceRule; use crate::gecko_bindings::structs::RawServoPageRule; -use crate::gecko_bindings::structs::RawServoQuotes; use crate::gecko_bindings::structs::RawServoStyleRule; use crate::gecko_bindings::structs::RawServoStyleSheetContents; use crate::gecko_bindings::structs::RawServoSupportsRule; @@ -40,7 +39,6 @@ use crate::stylesheets::{NamespaceRule, PageRule}; use crate::stylesheets::{StyleRule, StylesheetContents, SupportsRule}; use servo_arc::{Arc, ArcBorrow}; use std::{mem, ptr}; -use values::computed::QuotePair; macro_rules! impl_arc_ffi { ($servo_type:ty => $gecko_type:ty[$addref:ident, $release:ident]) => { @@ -115,9 +113,6 @@ impl_arc_ffi!(Locked<CounterStyleRule> => RawServoCounterStyleRule impl_arc_ffi!(CssUrlData => RawServoCssUrlData [Servo_CssUrlData_AddRef, Servo_CssUrlData_Release]); -impl_arc_ffi!(Box<[QuotePair]> => RawServoQuotes - [Servo_Quotes_AddRef, Servo_Quotes_Release]); - // ComputedStyle is not an opaque type on any side of FFI. // This means that doing the HasArcFFI type trick is actually unsound, // since it gives us a way to construct an Arc<ComputedStyle> from diff --git a/components/style/gecko/boxed_types.rs b/components/style/gecko/boxed_types.rs index b61c7708b2a..47fc4fe57dc 100644 --- a/components/style/gecko/boxed_types.rs +++ b/components/style/gecko/boxed_types.rs @@ -5,6 +5,7 @@ //! FFI implementations for types listed in ServoBoxedTypeList.h. use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; +use crate::properties::animated_properties::AnimationValueMap; use to_shmem::SharedMemoryBuilder; // TODO(heycam): The FFI impls for most of the types in ServoBoxedTypeList.h are spread across @@ -12,6 +13,15 @@ use to_shmem::SharedMemoryBuilder; // them more succinctly, like we do in arc_types.rs. #[cfg(feature = "gecko")] +unsafe impl HasFFI for AnimationValueMap { + type FFIType = crate::gecko_bindings::bindings::RawServoAnimationValueMap; +} +#[cfg(feature = "gecko")] +unsafe impl HasSimpleFFI for AnimationValueMap {} +#[cfg(feature = "gecko")] +unsafe impl HasBoxFFI for AnimationValueMap {} + +#[cfg(feature = "gecko")] unsafe impl HasFFI for SharedMemoryBuilder { type FFIType = crate::gecko_bindings::bindings::RawServoSharedMemoryBuilder; } diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 43082a7c04a..06e201bf2b5 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -383,7 +383,6 @@ impl nsStyleImage { let atom = bindings::Gecko_GetImageElement(self); Some(GenericImage::Element(Atom::from_raw(atom))) }, - _ => panic!("Unexpected image type"), } } @@ -535,10 +534,8 @@ pub mod basic_shape { use crate::gecko_bindings::structs::{ StyleGeometryBox, StyleShapeSource, StyleShapeSourceType, }; - use crate::gecko_bindings::sugar::refptr::RefPtr; use crate::values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape}; use crate::values::computed::motion::OffsetPath; - use crate::values::computed::url::ComputedUrl; use crate::values::generics::basic_shape::{GeometryBox, Path, ShapeBox, ShapeSource}; use crate::values::specified::SVGPathData; @@ -564,7 +561,7 @@ pub mod basic_shape { }; Some(ShapeSource::Shape(shape, reference_box)) }, - StyleShapeSourceType::URL | StyleShapeSourceType::Image => None, + StyleShapeSourceType::Image => None, StyleShapeSourceType::Path => { let path = self.to_svg_path().expect("expect an SVGPathData"); let fill = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }.mFillRule; @@ -587,16 +584,15 @@ pub mod basic_shape { impl<'a> From<&'a StyleShapeSource> for ClippingShape { fn from(other: &'a StyleShapeSource) -> Self { + use crate::values::generics::image::Image as GenericImage; match other.mType { - StyleShapeSourceType::URL => unsafe { + StyleShapeSourceType::Image => unsafe { let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; - let other_url = - RefPtr::new(*shape_image.__bindgen_anon_1.mURLValue.as_ref() as *mut _); - let url = ComputedUrl::from_url_value(other_url); - ShapeSource::ImageOrUrl(url) - }, - StyleShapeSourceType::Image => { - unreachable!("ClippingShape doesn't support Image!"); + let image = shape_image.into_image().expect("Cannot convert to Image"); + match image { + GenericImage::Url(url) => ShapeSource::ImageOrUrl(url.0), + _ => panic!("ClippingShape doesn't support non-url images"), + } }, _ => other .into_shape_source() @@ -608,9 +604,6 @@ pub mod basic_shape { impl<'a> From<&'a StyleShapeSource> for FloatAreaShape { fn from(other: &'a StyleShapeSource) -> Self { match other.mType { - StyleShapeSourceType::URL => { - unreachable!("FloatAreaShape doesn't support URL!"); - }, StyleShapeSourceType::Image => unsafe { let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; let image = shape_image.into_image().expect("Cannot convert to Image"); @@ -632,7 +625,6 @@ pub mod basic_shape { StyleShapeSourceType::None => OffsetPath::none(), StyleShapeSourceType::Shape | StyleShapeSourceType::Box | - StyleShapeSourceType::URL | StyleShapeSourceType::Image => unreachable!("Unsupported offset-path type"), } } diff --git a/components/style/gecko/mod.rs b/components/style/gecko/mod.rs index fb332dcce6e..3ff2cfcf140 100644 --- a/components/style/gecko/mod.rs +++ b/components/style/gecko/mod.rs @@ -13,9 +13,10 @@ pub mod conversions; pub mod data; pub mod media_features; pub mod media_queries; +#[cfg(feature = "gecko_profiler")] +pub mod profiler; pub mod pseudo_element; pub mod restyle_damage; -pub mod rules; pub mod selector_parser; pub mod snapshot; pub mod snapshot_helpers; diff --git a/components/style/gecko/profiler.rs b/components/style/gecko/profiler.rs new file mode 100644 index 00000000000..1f25dde04e7 --- /dev/null +++ b/components/style/gecko/profiler.rs @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Gecko profiler support. +//! +//! Use the `profiler_label!` macro from macros.rs. + +use crate::gecko_bindings::structs; + +/// A label describing a category of work that style threads can perform. +pub enum ProfilerLabel { + /// Style computation. + Style, + /// Style sheet parsing. + Parse, +} + +/// RAII object that constructs and destroys a C++ AutoProfilerLabel object +/// pointed to be the specified reference. +#[cfg(feature = "gecko_profiler")] +pub struct AutoProfilerLabel<'a>(&'a mut structs::AutoProfilerLabel); + +#[cfg(feature = "gecko_profiler")] +impl<'a> AutoProfilerLabel<'a> { + /// Creates a new AutoProfilerLabel with the specified label type. + /// + /// unsafe since the caller must ensure that `label` is allocated on the + /// stack. + #[inline] + pub unsafe fn new( + label: &mut structs::AutoProfilerLabel, + label_type: ProfilerLabel, + ) -> AutoProfilerLabel { + let category_pair = match label_type { + ProfilerLabel::Style => structs::JS::ProfilingCategoryPair_LAYOUT_StyleComputation, + ProfilerLabel::Parse => structs::JS::ProfilingCategoryPair_LAYOUT_CSSParsing, + }; + structs::Gecko_Construct_AutoProfilerLabel(label, category_pair); + AutoProfilerLabel(label) + } +} + +#[cfg(feature = "gecko_profiler")] +impl<'a> Drop for AutoProfilerLabel<'a> { + #[inline] + fn drop(&mut self) { + unsafe { + structs::Gecko_Destroy_AutoProfilerLabel(self.0); + } + } +} + +/// Whether the Gecko profiler is currently active. +/// +/// This implementation must be kept in sync with +/// `mozilla::profiler::detail::RacyFeatures::IsActive`. +#[cfg(feature = "gecko_profiler")] +#[inline] +pub fn profiler_is_active() -> bool { + use self::structs::profiler::detail; + use std::mem; + use std::sync::atomic::{AtomicU32, Ordering}; + + let active_and_features: &AtomicU32 = + unsafe { mem::transmute(&detail::RacyFeatures_sActiveAndFeatures) }; + (active_and_features.load(Ordering::Relaxed) & detail::RacyFeatures_Active) != 0 +} + +/// Always false when the Gecko profiler is disabled. +#[cfg(not(feature = "gecko_profiler"))] +#[inline] +pub fn profiler_is_active() -> bool { + false +} diff --git a/components/style/gecko/rules.rs b/components/style/gecko/rules.rs deleted file mode 100644 index 050a95754df..00000000000 --- a/components/style/gecko/rules.rs +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -//! Bindings for CSS Rule objects - -use crate::counter_style::{self, CounterBound}; -use crate::gecko_bindings::structs::{self, nsCSSValue}; -use crate::gecko_bindings::sugar::ns_css_value::ToNsCssValue; - -impl<'a> ToNsCssValue for &'a counter_style::System { - fn convert(self, nscssvalue: &mut nsCSSValue) { - use crate::counter_style::System::*; - match *self { - Cyclic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as i32), - Numeric => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as i32), - Alphabetic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as i32), - Symbolic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32), - Additive => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ADDITIVE as i32), - Fixed { - ref first_symbol_value, - } => { - let mut a = nsCSSValue::null(); - let mut b = nsCSSValue::null(); - a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_FIXED as i32); - b.set_integer(first_symbol_value.map_or(1, |v| v.value())); - nscssvalue.set_pair(&a, &b); - }, - Extends(ref other) => { - let mut a = nsCSSValue::null(); - let mut b = nsCSSValue::null(); - a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS as i32); - b.set_atom_ident(other.0.clone()); - nscssvalue.set_pair(&a, &b); - }, - } - } -} - -impl<'a> ToNsCssValue for &'a counter_style::Negative { - fn convert(self, nscssvalue: &mut nsCSSValue) { - if let Some(ref second) = self.1 { - let mut a = nsCSSValue::null(); - let mut b = nsCSSValue::null(); - a.set_from(&self.0); - b.set_from(second); - nscssvalue.set_pair(&a, &b); - } else { - nscssvalue.set_from(&self.0) - } - } -} - -impl<'a> ToNsCssValue for &'a counter_style::Symbol { - fn convert(self, nscssvalue: &mut nsCSSValue) { - match *self { - counter_style::Symbol::String(ref s) => nscssvalue.set_string(s), - counter_style::Symbol::Ident(ref s) => nscssvalue.set_ident_from_atom(&s.0), - } - } -} - -impl<'a> ToNsCssValue for &'a counter_style::Ranges { - fn convert(self, nscssvalue: &mut nsCSSValue) { - if self.0.is_empty() { - nscssvalue.set_auto(); - } else { - nscssvalue.set_pair_list(self.0.iter().map(|range| { - fn set_bound(bound: CounterBound, nscssvalue: &mut nsCSSValue) { - if let CounterBound::Integer(finite) = bound { - nscssvalue.set_integer(finite.value()) - } else { - nscssvalue.set_enum(structs::NS_STYLE_COUNTER_RANGE_INFINITE as i32) - } - } - let mut start = nsCSSValue::null(); - let mut end = nsCSSValue::null(); - set_bound(range.start, &mut start); - set_bound(range.end, &mut end); - (start, end) - })); - } - } -} - -impl<'a> ToNsCssValue for &'a counter_style::Pad { - fn convert(self, nscssvalue: &mut nsCSSValue) { - let mut min_length = nsCSSValue::null(); - let mut pad_with = nsCSSValue::null(); - min_length.set_integer(self.0.value()); - pad_with.set_from(&self.1); - nscssvalue.set_pair(&min_length, &pad_with); - } -} - -impl<'a> ToNsCssValue for &'a counter_style::Fallback { - fn convert(self, nscssvalue: &mut nsCSSValue) { - nscssvalue.set_atom_ident(self.0 .0.clone()) - } -} - -impl<'a> ToNsCssValue for &'a counter_style::Symbols { - fn convert(self, nscssvalue: &mut nsCSSValue) { - nscssvalue.set_list(self.0.iter().map(|item| { - let mut value = nsCSSValue::null(); - value.set_from(item); - value - })); - } -} - -impl<'a> ToNsCssValue for &'a counter_style::AdditiveSymbols { - fn convert(self, nscssvalue: &mut nsCSSValue) { - nscssvalue.set_pair_list(self.0.iter().map(|tuple| { - let mut weight = nsCSSValue::null(); - let mut symbol = nsCSSValue::null(); - weight.set_integer(tuple.weight.value()); - symbol.set_from(&tuple.symbol); - (weight, symbol) - })); - } -} - -impl<'a> ToNsCssValue for &'a counter_style::SpeakAs { - fn convert(self, nscssvalue: &mut nsCSSValue) { - use crate::counter_style::SpeakAs::*; - match *self { - Auto => nscssvalue.set_auto(), - Bullets => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_BULLETS as i32), - Numbers => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_NUMBERS as i32), - Words => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_WORDS as i32), - Other(ref other) => nscssvalue.set_atom_ident(other.0.clone()), - } - } -} diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index 2da16043779..dbbb3399da7 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -310,13 +310,13 @@ impl ToComputedValue for SpecifiedImageUrl { type ComputedValue = ComputedImageUrl; #[inline] - fn to_computed_value(&self, _: &Context) -> Self::ComputedValue { - ComputedImageUrl(self.clone()) + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + ComputedImageUrl(self.0.to_computed_value(context)) } #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { - computed.0.clone() + SpecifiedImageUrl(ToComputedValue::from_computed_value(&computed.0)) } } @@ -378,7 +378,7 @@ impl ComputedUrl { /// The computed value of a CSS image `url()`. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] -pub struct ComputedImageUrl(pub SpecifiedImageUrl); +pub struct ComputedImageUrl(pub ComputedUrl); impl ToCss for ComputedImageUrl { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result @@ -395,22 +395,17 @@ impl ComputedImageUrl { /// Convert from nsStyleImageReques to ComputedImageUrl. pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self { let url_value = image_request.mImageValue.to_safe(); - let css_url = &*url_value.mCssUrl.mRawPtr; - let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc()); - ComputedImageUrl(SpecifiedImageUrl(SpecifiedUrl { - url, - url_value: Box::new(URLValueSource::URLValue(url_value)), - })) + ComputedImageUrl(ComputedUrl::from_url_value(url_value)) } /// Clone a new, strong reference to the Gecko URLValue. pub fn clone_url_value(&self) -> RefPtr<URLValue> { - (self.0).0.clone_url_value() + self.0.clone_url_value() } /// Get a raw pointer to the URLValue held by this ComputedImageUrl, for FFI. pub fn url_value_ptr(&self) -> *mut URLValue { - (self.0).0.url_value_ptr() + self.0.url_value_ptr() } } diff --git a/components/style/gecko/values.rs b/components/style/gecko/values.rs index 98fe90fe3d0..8df85339265 100644 --- a/components/style/gecko/values.rs +++ b/components/style/gecko/values.rs @@ -12,7 +12,6 @@ use crate::gecko_bindings::structs::{nsStyleCoord, CounterStylePtr}; use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; use crate::values::computed::{Angle, Length, LengthPercentage}; use crate::values::computed::{Number, NumberOrPercentage, Percentage}; -use crate::values::generics::gecko::ScrollSnapPoint; use crate::values::generics::grid::{TrackBreadth, TrackKeyword}; use crate::values::generics::length::LengthPercentageOrAuto; use crate::values::generics::{CounterStyleOrNone, NonNegative}; @@ -217,27 +216,6 @@ impl GeckoStyleCoordConvertible for Angle { } } -impl GeckoStyleCoordConvertible for ScrollSnapPoint<LengthPercentage> { - fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { - match self.repeated() { - None => coord.set_value(CoordDataValue::None), - Some(l) => l.to_gecko_style_coord(coord), - }; - } - - fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> { - use crate::gecko_bindings::structs::root::nsStyleUnit; - - Some(match coord.unit() { - nsStyleUnit::eStyleUnit_None => ScrollSnapPoint::None, - _ => ScrollSnapPoint::Repeat( - LengthPercentage::from_gecko_style_coord(coord) - .expect("coord could not convert to LengthPercentage"), - ), - }) - } -} - /// Convert a given RGBA value to `nscolor`. pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 { ((rgba.alpha as u32) << 24) | @@ -288,7 +266,7 @@ impl CounterStyleOrNone { .0 .iter() .map(|symbol| match *symbol { - Symbol::String(ref s) => nsCStr::from(s), + Symbol::String(ref s) => nsCStr::from(&**s), Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"), }) .collect(); @@ -333,7 +311,7 @@ impl CounterStyleOrNone { let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32); let symbols = symbols .iter() - .map(|gecko_symbol| Symbol::String(gecko_symbol.to_string())) + .map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into())) .collect(); Either::First(CounterStyleOrNone::Symbols(symbol_type, Symbols(symbols))) } diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 9d987c56308..a1443d1ad8d 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -1098,7 +1098,7 @@ impl<'le> TElement for GeckoElement<'le> { type TraversalChildrenIterator = GeckoChildrenIterator<'le>; fn inheritance_parent(&self) -> Option<Self> { - if self.implemented_pseudo_element().is_some() { + if self.is_pseudo_element() { return self.pseudo_element_originating_element(); } @@ -1405,7 +1405,7 @@ impl<'le> TElement for GeckoElement<'le> { #[inline] fn matches_user_and_author_rules(&self) -> bool { - !self.rule_hash_target().is_in_native_anonymous_subtree() + !self.is_in_native_anonymous_subtree() } #[inline] @@ -1471,7 +1471,7 @@ impl<'le> TElement for GeckoElement<'le> { #[inline] fn skip_item_display_fixup(&self) -> bool { debug_assert!( - self.implemented_pseudo_element().is_none(), + !self.is_pseudo_element(), "Just don't call me if I'm a pseudo, you should know the answer already" ); self.is_root_of_native_anonymous_subtree() @@ -1919,8 +1919,13 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } #[inline] + fn is_pseudo_element(&self) -> bool { + self.implemented_pseudo_element().is_some() + } + + #[inline] fn pseudo_element_originating_element(&self) -> Option<Self> { - debug_assert!(self.implemented_pseudo_element().is_some()); + debug_assert!(self.is_pseudo_element()); let parent = self.closest_anon_subtree_root_parent()?; // FIXME(emilio): Special-case for <input type="number">s diff --git a/components/style/gecko_bindings/sugar/mod.rs b/components/style/gecko_bindings/sugar/mod.rs index de981bd289a..338236c175a 100644 --- a/components/style/gecko_bindings/sugar/mod.rs +++ b/components/style/gecko_bindings/sugar/mod.rs @@ -6,9 +6,6 @@ mod ns_com_ptr; mod ns_compatibility; -mod ns_css_shadow_array; -mod ns_css_shadow_item; -pub mod ns_css_value; mod ns_style_auto_array; pub mod ns_style_coord; mod ns_t_array; diff --git a/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs b/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs deleted file mode 100644 index c0c6c2d9e36..00000000000 --- a/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs +++ /dev/null @@ -1,78 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -//! Rust helpers for Gecko's `nsCSSShadowArray`. - -use crate::gecko_bindings::bindings::Gecko_AddRefCSSShadowArrayArbitraryThread; -use crate::gecko_bindings::bindings::Gecko_NewCSSShadowArray; -use crate::gecko_bindings::bindings::Gecko_ReleaseCSSShadowArrayArbitraryThread; -use crate::gecko_bindings::structs::{nsCSSShadowArray, nsCSSShadowItem, RefPtr}; -use std::ops::{Deref, DerefMut}; -use std::{ptr, slice}; - -impl RefPtr<nsCSSShadowArray> { - /// Replaces the current `nsCSSShadowArray` with a new one of len `len`. - pub fn replace_with_new(&mut self, len: u32) { - unsafe { - if !self.mRawPtr.is_null() { - Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr); - } - - self.mRawPtr = if len == 0 { - ptr::null_mut() - } else { - Gecko_NewCSSShadowArray(len) - } - } - } - - /// Sets the value to other `nsCSSShadowArray`, bumping and decreasing - /// refcounts as needed. - /// - /// TODO(emilio): Seems like this could move to `refptr.rs`, and be more - /// generic. - pub fn copy_from(&mut self, other: &Self) { - unsafe { - if !self.mRawPtr.is_null() { - Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr); - } - if !other.mRawPtr.is_null() { - Gecko_AddRefCSSShadowArrayArbitraryThread(other.mRawPtr); - } - - self.mRawPtr = other.mRawPtr; - } - } -} - -impl Deref for RefPtr<nsCSSShadowArray> { - type Target = [nsCSSShadowItem]; - fn deref(&self) -> &[nsCSSShadowItem] { - if self.mRawPtr.is_null() { - &[] - } else { - unsafe { - slice::from_raw_parts( - (*self.mRawPtr).mArray.as_ptr(), - (*self.mRawPtr).mLength as usize, - ) - } - } - } -} - -impl DerefMut for RefPtr<nsCSSShadowArray> { - fn deref_mut(&mut self) -> &mut [nsCSSShadowItem] { - if self.mRawPtr.is_null() { - &mut [] - } else { - unsafe { - slice::from_raw_parts_mut( - (*self.mRawPtr).mArray.as_mut_ptr(), - (*self.mRawPtr).mLength as usize, - ) - } - } - } -} diff --git a/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs b/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs deleted file mode 100644 index 03d68576dea..00000000000 --- a/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs +++ /dev/null @@ -1,59 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -//! Rust helpers for Gecko's `nsCSSShadowItem`. - -use crate::gecko_bindings::structs::nsCSSShadowItem; -use crate::values::computed::effects::{BoxShadow, SimpleShadow}; -use app_units::Au; - -impl nsCSSShadowItem { - /// Sets this item from the given box shadow. - #[inline] - pub fn set_from_box_shadow(&mut self, shadow: BoxShadow) { - self.set_from_simple_shadow(shadow.base); - self.mSpread = shadow.spread.to_i32_au(); - self.mInset = shadow.inset; - } - - /// Returns this item as a box shadow. - #[inline] - pub fn to_box_shadow(&self) -> BoxShadow { - BoxShadow { - base: self.extract_simple_shadow(), - spread: Au(self.mSpread).into(), - inset: self.mInset, - } - } - - /// Sets this item from the given simple shadow. - #[inline] - pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) { - self.mXOffset = shadow.horizontal.to_i32_au(); - self.mYOffset = shadow.vertical.to_i32_au(); - self.mRadius = shadow.blur.0.to_i32_au(); - self.mSpread = 0; - self.mInset = false; - self.mColor = shadow.color.into(); - } - - /// Gets a simple shadow from this item. - #[inline] - fn extract_simple_shadow(&self) -> SimpleShadow { - SimpleShadow { - color: self.mColor.into(), - horizontal: Au(self.mXOffset).into(), - vertical: Au(self.mYOffset).into(), - blur: Au(self.mRadius).into(), - } - } - - /// Returns this item as a simple shadow. - #[inline] - pub fn to_simple_shadow(&self) -> SimpleShadow { - debug_assert_eq!(self.mSpread, 0); - debug_assert_eq!(self.mInset, false); - self.extract_simple_shadow() - } -} diff --git a/components/style/gecko_bindings/sugar/ns_css_value.rs b/components/style/gecko_bindings/sugar/ns_css_value.rs deleted file mode 100644 index b59732bcc8e..00000000000 --- a/components/style/gecko_bindings/sugar/ns_css_value.rs +++ /dev/null @@ -1,424 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -//! Little helpers for `nsCSSValue`. - -use crate::gecko_bindings::bindings; -use crate::gecko_bindings::structs; -use crate::gecko_bindings::structs::{nsCSSUnit, nsCSSValue}; -use crate::gecko_bindings::structs::{nsCSSValueList, nsCSSValue_Array}; -use crate::gecko_string_cache::Atom; -use crate::values::computed::{Angle, Length, LengthPercentage, Percentage}; -use crate::Zero; -use std::marker::PhantomData; -use std::mem; -use std::ops::{Index, IndexMut}; -use std::slice; - -impl nsCSSValue { - /// Create a CSSValue with null unit, useful to be used as a return value. - #[inline] - pub fn null() -> Self { - unsafe { mem::zeroed() } - } - - /// Returns true if this nsCSSValue is none. - #[inline] - pub fn is_none(&self) -> bool { - self.mUnit == nsCSSUnit::eCSSUnit_None - } - - /// Returns this nsCSSValue value as an integer, unchecked in release - /// builds. - pub fn integer_unchecked(&self) -> i32 { - debug_assert!( - self.mUnit == nsCSSUnit::eCSSUnit_Integer || - self.mUnit == nsCSSUnit::eCSSUnit_Enumerated - ); - unsafe { *self.mValue.mInt.as_ref() } - } - - /// Checks if it is an integer and returns it if so - pub fn integer(&self) -> Option<i32> { - if self.mUnit == nsCSSUnit::eCSSUnit_Integer || self.mUnit == nsCSSUnit::eCSSUnit_Enumerated - { - Some(unsafe { *self.mValue.mInt.as_ref() }) - } else { - None - } - } - - /// Returns this nsCSSValue value as a floating point value, unchecked in - /// release builds. - pub fn float_unchecked(&self) -> f32 { - debug_assert!(nsCSSUnit::eCSSUnit_Number as u32 <= self.mUnit as u32); - unsafe { *self.mValue.mFloat.as_ref() } - } - - /// Returns this nsCSSValue as a nsCSSValue::Array, unchecked in release - /// builds. - pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array { - debug_assert!( - nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 && - self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Plus as u32 - ); - let array = *self.mValue.mArray.as_ref(); - debug_assert!(!array.is_null()); - &*array - } - - /// Sets LengthPercentage value to this nsCSSValue. - pub unsafe fn set_length_percentage(&mut self, lp: LengthPercentage) { - if lp.was_calc { - return bindings::Gecko_CSSValue_SetCalc(self, lp.into()); - } - debug_assert!(!lp.has_percentage || lp.unclamped_length() == Length::zero()); - if lp.has_percentage { - return self.set_percentage(lp.percentage()); - } - self.set_px(lp.unclamped_length().px()); - } - - /// Sets a px value to this nsCSSValue. - pub unsafe fn set_px(&mut self, px: f32) { - bindings::Gecko_CSSValue_SetPixelLength(self, px) - } - - /// Sets a percentage value to this nsCSSValue. - pub unsafe fn set_percentage(&mut self, unit_value: f32) { - bindings::Gecko_CSSValue_SetPercentage(self, unit_value) - } - - /// Returns LengthPercentage value. - pub unsafe fn get_length_percentage(&self) -> LengthPercentage { - match self.mUnit { - nsCSSUnit::eCSSUnit_Pixel => { - LengthPercentage::new(Length::new(bindings::Gecko_CSSValue_GetNumber(self)), None) - }, - nsCSSUnit::eCSSUnit_Percent => LengthPercentage::new_percent(Percentage( - bindings::Gecko_CSSValue_GetPercentage(self), - )), - nsCSSUnit::eCSSUnit_Calc => bindings::Gecko_CSSValue_GetCalc(self).into(), - _ => panic!("Unexpected unit"), - } - } - - /// Returns Length value. - pub unsafe fn get_length(&self) -> Length { - match self.mUnit { - nsCSSUnit::eCSSUnit_Pixel => Length::new(bindings::Gecko_CSSValue_GetNumber(self)), - _ => panic!("Unexpected unit"), - } - } - - fn set_valueless_unit(&mut self, unit: nsCSSUnit) { - debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null); - debug_assert!( - unit as u32 <= nsCSSUnit::eCSSUnit_DummyInherit as u32, - "Not a valueless unit" - ); - self.mUnit = unit; - } - - /// Set to an auto value - /// - /// This method requires the current value to be null. - pub fn set_auto(&mut self) { - self.set_valueless_unit(nsCSSUnit::eCSSUnit_Auto); - } - - /// Set to a normal value - /// - /// This method requires the current value to be null. - pub fn set_normal(&mut self) { - self.set_valueless_unit(nsCSSUnit::eCSSUnit_Normal); - } - - fn set_string_internal(&mut self, s: &str, unit: nsCSSUnit) { - unsafe { bindings::Gecko_CSSValue_SetString(self, s.as_ptr(), s.len() as u32, unit) } - } - - fn set_string_from_atom_internal(&mut self, s: &Atom, unit: nsCSSUnit) { - unsafe { bindings::Gecko_CSSValue_SetStringFromAtom(self, s.as_ptr(), unit) } - } - - /// Set to a string value - pub fn set_string(&mut self, s: &str) { - self.set_string_internal(s, nsCSSUnit::eCSSUnit_String) - } - - /// Set to a string value from the given atom - pub fn set_string_from_atom(&mut self, s: &Atom) { - self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_String) - } - - /// Set to a ident value from the given atom - pub fn set_ident_from_atom(&mut self, s: &Atom) { - self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_Ident) - } - - /// Set to an identifier value - pub fn set_ident(&mut self, s: &str) { - self.set_string_internal(s, nsCSSUnit::eCSSUnit_Ident) - } - - /// Set to an atom identifier value - pub fn set_atom_ident(&mut self, s: Atom) { - unsafe { bindings::Gecko_CSSValue_SetAtomIdent(self, s.into_addrefed()) } - } - - fn set_int_internal(&mut self, value: i32, unit: nsCSSUnit) { - unsafe { bindings::Gecko_CSSValue_SetInt(self, value, unit) } - } - - /// Set to an integer value - pub fn set_integer(&mut self, value: i32) { - self.set_int_internal(value, nsCSSUnit::eCSSUnit_Integer) - } - - /// Set to an enumerated value - pub fn set_enum<T: Into<i32>>(&mut self, value: T) { - self.set_int_internal(value.into(), nsCSSUnit::eCSSUnit_Enumerated); - } - - /// Set to a number value - pub fn set_number(&mut self, number: f32) { - unsafe { bindings::Gecko_CSSValue_SetFloat(self, number, nsCSSUnit::eCSSUnit_Number) } - } - - /// Set to an array of given length - pub fn set_array(&mut self, len: i32) -> &mut nsCSSValue_Array { - unsafe { bindings::Gecko_CSSValue_SetArray(self, len) } - unsafe { self.mValue.mArray.as_mut().as_mut() }.unwrap() - } - - /// Generic set from any value that implements the ToNsCssValue trait. - pub fn set_from<T: ToNsCssValue>(&mut self, value: T) { - value.convert(self) - } - - /// Returns an `Angle` value from this `nsCSSValue`. - /// - /// Panics if the unit is not `eCSSUnit_Degree`. - #[inline] - pub fn get_angle(&self) -> Angle { - debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Degree); - Angle::from_degrees(self.float_unchecked()) - } - - /// Sets Angle value to this nsCSSValue. - pub fn set_angle(&mut self, angle: Angle) { - debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null); - self.mUnit = nsCSSUnit::eCSSUnit_Degree; - unsafe { - *self.mValue.mFloat.as_mut() = angle.degrees(); - } - } - - /// Set to a pair value - /// - /// This is only supported on the main thread. - pub fn set_pair(&mut self, x: &nsCSSValue, y: &nsCSSValue) { - unsafe { bindings::Gecko_CSSValue_SetPair(self, x, y) } - } - - /// Set to a list value - /// - /// This is only supported on the main thread. - pub fn set_list<I>(&mut self, values: I) - where - I: ExactSizeIterator<Item = nsCSSValue>, - { - debug_assert!(values.len() > 0, "Empty list is not supported"); - unsafe { - bindings::Gecko_CSSValue_SetList(self, values.len() as u32); - } - debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_List); - let list: &mut structs::nsCSSValueList = &mut unsafe { - self.mValue - .mList - .as_ref() // &*nsCSSValueList_heap - .as_mut() - .expect("List pointer should be non-null") - } - ._base; - for (item, new_value) in list.into_iter().zip(values) { - *item = new_value; - } - } - - /// Set to a pair list value - /// - /// This is only supported on the main thread. - pub fn set_pair_list<I>(&mut self, mut values: I) - where - I: ExactSizeIterator<Item = (nsCSSValue, nsCSSValue)>, - { - debug_assert!(values.len() > 0, "Empty list is not supported"); - unsafe { - bindings::Gecko_CSSValue_SetPairList(self, values.len() as u32); - } - debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_PairList); - let mut item_ptr = &mut unsafe { - self.mValue - .mPairList - .as_ref() // &*nsCSSValuePairList_heap - .as_mut() - .expect("List pointer should be non-null") - } - ._base as *mut structs::nsCSSValuePairList; - while let Some(item) = unsafe { item_ptr.as_mut() } { - let value = values.next().expect("Values shouldn't have been exhausted"); - item.mXValue = value.0; - item.mYValue = value.1; - item_ptr = item.mNext; - } - debug_assert!(values.next().is_none(), "Values should have been exhausted"); - } - - /// Set a shared list - pub fn set_shared_list<I>(&mut self, values: I) - where - I: ExactSizeIterator<Item = nsCSSValue>, - { - debug_assert!(values.len() > 0, "Empty list is not supported"); - unsafe { bindings::Gecko_CSSValue_InitSharedList(self, values.len() as u32) }; - debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_SharedList); - let list = unsafe { - self.mValue - .mSharedList - .as_ref() - .as_mut() - .expect("List pointer should be non-null") - .mHead - .as_mut() - }; - debug_assert!(list.is_some(), "New created shared list shouldn't be null"); - for (item, new_value) in list.unwrap().into_iter().zip(values) { - *item = new_value; - } - } -} - -impl Drop for nsCSSValue { - fn drop(&mut self) { - unsafe { bindings::Gecko_CSSValue_Drop(self) }; - } -} - -/// Iterator of nsCSSValueList. -#[allow(non_camel_case_types)] -pub struct nsCSSValueListIterator<'a> { - current: Option<&'a nsCSSValueList>, -} - -impl<'a> Iterator for nsCSSValueListIterator<'a> { - type Item = &'a nsCSSValue; - fn next(&mut self) -> Option<Self::Item> { - match self.current { - Some(item) => { - self.current = unsafe { item.mNext.as_ref() }; - Some(&item.mValue) - }, - None => None, - } - } -} - -impl<'a> IntoIterator for &'a nsCSSValueList { - type Item = &'a nsCSSValue; - type IntoIter = nsCSSValueListIterator<'a>; - - fn into_iter(self) -> Self::IntoIter { - nsCSSValueListIterator { - current: Some(self), - } - } -} - -/// Mutable Iterator of nsCSSValueList. -#[allow(non_camel_case_types)] -pub struct nsCSSValueListMutIterator<'a> { - current: *mut nsCSSValueList, - phantom: PhantomData<&'a mut nsCSSValue>, -} - -impl<'a> Iterator for nsCSSValueListMutIterator<'a> { - type Item = &'a mut nsCSSValue; - fn next(&mut self) -> Option<Self::Item> { - match unsafe { self.current.as_mut() } { - Some(item) => { - self.current = item.mNext; - Some(&mut item.mValue) - }, - None => None, - } - } -} - -impl<'a> IntoIterator for &'a mut nsCSSValueList { - type Item = &'a mut nsCSSValue; - type IntoIter = nsCSSValueListMutIterator<'a>; - - fn into_iter(self) -> Self::IntoIter { - nsCSSValueListMutIterator { - current: self as *mut nsCSSValueList, - phantom: PhantomData, - } - } -} - -impl nsCSSValue_Array { - /// Return the length of this `nsCSSValue::Array` - #[inline] - pub fn len(&self) -> usize { - self.mCount - } - - #[inline] - fn buffer(&self) -> *const nsCSSValue { - self.mArray.as_ptr() - } - - /// Get the array as a slice of nsCSSValues. - #[inline] - pub fn as_slice(&self) -> &[nsCSSValue] { - unsafe { slice::from_raw_parts(self.buffer(), self.len()) } - } - - /// Get the array as a mutable slice of nsCSSValues. - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [nsCSSValue] { - unsafe { slice::from_raw_parts_mut(self.buffer() as *mut _, self.len()) } - } -} - -impl Index<usize> for nsCSSValue_Array { - type Output = nsCSSValue; - #[inline] - fn index(&self, i: usize) -> &nsCSSValue { - &self.as_slice()[i] - } -} - -impl IndexMut<usize> for nsCSSValue_Array { - #[inline] - fn index_mut(&mut self, i: usize) -> &mut nsCSSValue { - &mut self.as_mut_slice()[i] - } -} - -/// Generic conversion to nsCSSValue -pub trait ToNsCssValue { - /// Convert - fn convert(self, nscssvalue: &mut nsCSSValue); -} - -impl<T: ToNsCssValue> From<T> for nsCSSValue { - fn from(value: T) -> nsCSSValue { - let mut result = nsCSSValue::null(); - value.convert(&mut result); - result - } -} diff --git a/components/style/gecko_bindings/sugar/refptr.rs b/components/style/gecko_bindings/sugar/refptr.rs index 1ad71afa6bc..90cc5284bc4 100644 --- a/components/style/gecko_bindings/sugar/refptr.rs +++ b/components/style/gecko_bindings/sugar/refptr.rs @@ -290,11 +290,6 @@ impl_threadsafe_refcount!( bindings::Gecko_ReleaseURLExtraDataArbitraryThread ); impl_threadsafe_refcount!( - structs::nsCSSValueSharedList, - bindings::Gecko_AddRefCSSValueSharedListArbitraryThread, - bindings::Gecko_ReleaseCSSValueSharedListArbitraryThread -); -impl_threadsafe_refcount!( structs::mozilla::css::URLValue, bindings::Gecko_AddRefCSSURLValueArbitraryThread, bindings::Gecko_ReleaseCSSURLValueArbitraryThread diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index d71d192166a..b8f3ff7f048 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -53,6 +53,7 @@ macro_rules! local_name { /// This is either a strong reference to a dynamic atom (an nsAtom pointer), /// or an offset from gGkAtoms to the nsStaticAtom object. #[derive(Eq, PartialEq)] +#[repr(C)] pub struct Atom(usize); /// An atom *without* a strong reference. diff --git a/components/style/invalidation/element/element_wrapper.rs b/components/style/invalidation/element/element_wrapper.rs index 6e8e504c226..91f0705853c 100644 --- a/components/style/invalidation/element/element_wrapper.rs +++ b/components/style/invalidation/element/element_wrapper.rs @@ -366,6 +366,10 @@ where self.element.is_root() } + fn is_pseudo_element(&self) -> bool { + self.element.is_pseudo_element() + } + fn pseudo_element_originating_element(&self) -> Option<Self> { self.element .pseudo_element_originating_element() diff --git a/components/style/lib.rs b/components/style/lib.rs index 4d523d65c4f..587b926efc6 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -190,6 +190,7 @@ pub use servo_atoms::Atom; pub use style_traits::arc_slice::ArcSlice; pub use style_traits::owned_slice::OwnedSlice; +pub use style_traits::owned_str::OwnedStr; /// The CSS properties supported by the style system. /// Generated from the properties.mako.rs template by build.rs diff --git a/components/style/macros.rs b/components/style/macros.rs index 22f1966071b..229e864977a 100644 --- a/components/style/macros.rs +++ b/components/style/macros.rs @@ -104,3 +104,32 @@ macro_rules! define_keyword_type { } }; } + +/// Place a Gecko profiler label on the stack. +/// +/// The `label_type` argument must be the name of a variant of `ProfilerLabel`. +#[cfg(feature = "gecko_profiler")] +#[macro_export] +macro_rules! profiler_label { + ($label_type:ident) => { + let mut _profiler_label: $crate::gecko_bindings::structs::AutoProfilerLabel = + unsafe { ::std::mem::uninitialized() }; + let _profiler_label = if $crate::gecko::profiler::profiler_is_active() { + unsafe { + Some($crate::gecko::profiler::AutoProfilerLabel::new( + &mut _profiler_label, + $crate::gecko::profiler::ProfilerLabel::$label_type, + )) + } + } else { + None + }; + }; +} + +/// No-op when the Gecko profiler is not available. +#[cfg(not(feature = "gecko_profiler"))] +#[macro_export] +macro_rules! profiler_label { + ($label_type:ident) => {}; +} diff --git a/components/style/parallel.rs b/components/style/parallel.rs index 237453084df..619be351579 100644 --- a/components/style/parallel.rs +++ b/components/style/parallel.rs @@ -277,6 +277,7 @@ pub fn traverse_nodes<'a, 'scope, E, D, I>( top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls); } else { scope.spawn(move |scope| { + profiler_label!(Style); let work = work; top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls); }); @@ -286,6 +287,7 @@ pub fn traverse_nodes<'a, 'scope, E, D, I>( let nodes: WorkUnit<E::ConcreteNode> = chunk.collect(); let traversal_data_copy = traversal_data.clone(); scope.spawn(move |scope| { + profiler_label!(Style); let n = nodes; top_down_dom(&*n, root, traversal_data_copy, scope, pool, traversal, tls) }); diff --git a/components/style/properties/cascade.rs b/components/style/properties/cascade.rs index 1b76aefdd74..9b1cfb8ec04 100644 --- a/components/style/properties/cascade.rs +++ b/components/style/properties/cascade.rs @@ -628,10 +628,6 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { #[cfg(feature = "gecko")] { - if let Some(display) = builder.get_box_if_mutated() { - display.generate_combined_transform(); - } - if let Some(bg) = builder.get_background_if_mutated() { bg.fill_arrays(); } diff --git a/components/style/properties/data.py b/components/style/properties/data.py index ae307077690..e771607b6d9 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -172,8 +172,9 @@ class Longhand(object): gecko_ffi_name=None, allowed_in_keyframe_block=True, cast_type='u8', logical=False, logical_group=None, alias=None, extra_prefixes=None, boxed=False, - flags=None, allowed_in_page_rule=False, allow_quirks=False, + flags=None, allowed_in_page_rule=False, allow_quirks="No", ignored_when_colors_disabled=False, + simple_vector_bindings=False, vector=False, servo_restyle_damage="repaint"): self.name = name if not spec: @@ -210,6 +211,7 @@ class Longhand(object): self.allow_quirks = allow_quirks self.ignored_when_colors_disabled = ignored_when_colors_disabled self.is_vector = vector + self.simple_vector_bindings = simple_vector_bindings # https://drafts.csswg.org/css-animations/#keyframes # > The <declaration-list> inside of <keyframe-block> accepts any CSS property @@ -323,12 +325,14 @@ class Longhand(object): "JustifyContent", "JustifyItems", "JustifySelf", + "LineBreak", "MozForceBrokenImageIcon", "MozListReversed", "MozScriptLevel", "MozScriptMinSize", "MozScriptSizeMultiplier", "NonNegativeNumber", + "OffsetRotate", "Opacity", "OutlineStyle", "Overflow", diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index 1ce083c944f..fcbfb717aa8 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -1301,11 +1301,9 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> { Ok(id) => id, Err(..) => { self.last_parsed_property_id = None; - return Err(input.new_custom_error(if is_non_mozilla_vendor_identifier(&name) { - StyleParseErrorKind::UnknownVendorProperty - } else { + return Err(input.new_custom_error( StyleParseErrorKind::UnknownProperty(name) - })); + )); } }; if self.context.error_reporting_enabled() { @@ -1326,6 +1324,13 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> { type SmallParseErrorVec<'i> = SmallVec<[(ParseError<'i>, &'i str, Option<PropertyId>); 2]>; +fn alias_of_known_property(name: &str) -> Option<PropertyId> { + let mut prefixed = String::with_capacity(name.len() + 5); + prefixed.push_str("-moz-"); + prefixed.push_str(name); + PropertyId::parse_enabled_for_all_content(&prefixed).ok() +} + #[cold] fn report_one_css_error<'i>( context: &ParserContext, @@ -1352,10 +1357,22 @@ fn report_one_css_error<'i>( } } - // If the unrecognized property looks like a vendor-specific property, - // silently ignore it instead of polluting the error output. - if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownVendorProperty) = error.kind { - return; + if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty(ref name)) = error.kind { + if is_non_mozilla_vendor_identifier(name) { + // If the unrecognized property looks like a vendor-specific property, + // silently ignore it instead of polluting the error output. + return; + } + if let Some(alias) = alias_of_known_property(name) { + // This is an unknown property, but its -moz-* version is known. + // We don't want to report error if the -moz-* version is already + // specified. + if let Some(block) = block { + if all_properties_in_block(block, &alias) { + return; + } + } + } } if let Some(ref property) = property { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 703cbed2c0b..dd5bcf2febf 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -28,7 +28,6 @@ use crate::gecko_bindings::bindings::Gecko_CopyListStyleImageFrom; use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength; use crate::gecko_bindings::bindings::Gecko_SetCursorArrayLength; use crate::gecko_bindings::bindings::Gecko_SetCursorImageValue; -use crate::gecko_bindings::bindings::Gecko_NewCSSShadowArray; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom; use crate::gecko_bindings::bindings::Gecko_SetListStyleImageNone; @@ -50,17 +49,19 @@ use crate::rule_tree::StrongRuleNode; use crate::selector_parser::PseudoElement; use servo_arc::{Arc, RawOffsetArc}; use std::marker::PhantomData; -use std::mem::{forget, uninitialized, zeroed}; +use std::mem::{forget, uninitialized, zeroed, ManuallyDrop}; use std::{cmp, ops, ptr}; use crate::values::{self, CustomIdent, Either, KeyframesName, None_}; use crate::values::computed::{NonNegativeLength, Percentage, TransitionProperty}; +use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::BorderStyle; use crate::values::computed::font::FontSize; -use crate::values::computed::effects::{BoxShadow, Filter, SimpleShadow}; +use crate::values::computed::effects::Filter; use crate::values::generics::column::ColumnCount; use crate::values::generics::transform::TransformStyle; use crate::values::generics::url::UrlOrNone; + pub mod style_structs { % for style_struct in data.style_structs: pub use super::${style_struct.gecko_struct_name} as ${style_struct.name}; @@ -303,14 +304,14 @@ impl ${style_struct.gecko_struct_name} { <%def name="impl_simple_clone(ident, gecko_ffi_name)"> #[allow(non_snake_case)] pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - From::from(self.gecko.${gecko_ffi_name}) + From::from(self.gecko.${gecko_ffi_name}.clone()) } </%def> <%def name="impl_simple_copy(ident, gecko_ffi_name, *kwargs)"> #[allow(non_snake_case)] pub fn copy_${ident}_from(&mut self, other: &Self) { - self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}; + self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}.clone(); } #[allow(non_snake_case)] @@ -697,45 +698,6 @@ def set_gecko_property(ffi_name, expr): } </%def> -<%def name="impl_style_coord(ident, gecko_ffi_name)"> - #[allow(non_snake_case)] - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - v.to_gecko_style_coord(&mut self.gecko.${gecko_ffi_name}); - } - #[allow(non_snake_case)] - pub fn copy_${ident}_from(&mut self, other: &Self) { - self.gecko.${gecko_ffi_name}.copy_from(&other.gecko.${gecko_ffi_name}); - } - #[allow(non_snake_case)] - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - #[allow(non_snake_case)] - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - use crate::properties::longhands::${ident}::computed_value::T; - T::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}) - .expect("clone for ${ident} failed") - } -</%def> - -<%def name="impl_style_sides(ident)"> - <% gecko_ffi_name = "m" + to_camel_case(ident) %> - - #[allow(non_snake_case)] - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - v.to_gecko_rect(&mut self.gecko.${gecko_ffi_name}); - } - - <%self:copy_sides_style_coord ident="${ident}"></%self:copy_sides_style_coord> - - #[allow(non_snake_case)] - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - longhands::${ident}::computed_value::T::from_gecko_rect(&self.gecko.${gecko_ffi_name}) - .expect("clone for ${ident} failed") - } -</%def> - <%def name="copy_sides_style_coord(ident)"> <% gecko_ffi_name = "m" + to_camel_case(ident) %> #[allow(non_snake_case)] @@ -812,281 +774,6 @@ def set_gecko_property(ffi_name, expr): } </%def> -<% -transform_functions = [ - ("Matrix3D", "matrix3d", ["number"] * 16), - ("Matrix", "matrix", ["number"] * 6), - ("Translate", "translate", ["lp", "lp"]), - ("Translate3D", "translate3d", ["lp", "lp", "length"]), - ("TranslateX", "translatex", ["lp"]), - ("TranslateY", "translatey", ["lp"]), - ("TranslateZ", "translatez", ["length"]), - ("Scale3D", "scale3d", ["number"] * 3), - ("Scale", "scale", ["number", "number"]), - ("ScaleX", "scalex", ["number"]), - ("ScaleY", "scaley", ["number"]), - ("ScaleZ", "scalez", ["number"]), - ("Rotate", "rotate", ["angle"]), - ("Rotate3D", "rotate3d", ["number"] * 3 + ["angle"]), - ("RotateX", "rotatex", ["angle"]), - ("RotateY", "rotatey", ["angle"]), - ("RotateZ", "rotatez", ["angle"]), - ("Skew", "skew", ["angle", "angle"]), - ("SkewX", "skewx", ["angle"]), - ("SkewY", "skewy", ["angle"]), - ("Perspective", "perspective", ["length"]), - ("InterpolateMatrix", "interpolatematrix", ["list"] * 2 + ["percentage"]), - ("AccumulateMatrix", "accumulatematrix", ["list"] * 2 + ["integer_to_percentage"]) -] -%> - -<%def name="transform_function_arm(name, keyword, items)"> - <% - pattern = None - if keyword == "matrix3d": - # m11: number1, m12: number2, .. - single_patterns = ["m%s: %s" % (str(a / 4 + 1) + str(a % 4 + 1), b + str(a + 1)) for (a, b) - in enumerate(items)] - pattern = "(Matrix3D { %s })" % ", ".join(single_patterns) - elif keyword == "matrix": - # a: number1, b: number2, .. - single_patterns = ["%s: %s" % (chr(ord('a') + a), b + str(a + 1)) for (a, b) - in enumerate(items)] - pattern = "(Matrix { %s })" % ", ".join(single_patterns) - elif keyword == "interpolatematrix": - pattern = " { from_list: ref list1, to_list: ref list2, progress: percentage3 }" - elif keyword == "accumulatematrix": - pattern = " { from_list: ref list1, to_list: ref list2, count: integer_to_percentage3 }" - else: - # Generate contents of pattern from items - pattern = "(%s)" % ", ".join([b + str(a+1) for (a,b) in enumerate(items)]) - - # First %s substituted with the call to GetArrayItem, the second - # %s substituted with the corresponding variable - css_value_setters = { - "length" : "bindings::Gecko_CSSValue_SetPixelLength(%s, %s.px())", - "percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s.0)", - # Note: This is an integer type, but we use it as a percentage value in Gecko, so - # need to cast it to f32. - "integer_to_percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s as f32)", - "lp" : "%s.set_length_percentage(%s)", - "angle" : "%s.set_angle(%s)", - "number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)", - # Note: We use nsCSSValueSharedList here, instead of nsCSSValueList_heap - # because this function is not called on the main thread and - # nsCSSValueList_heap is not thread safe. - "list" : "%s.set_shared_list(%s.0.iter().map(&convert_to_ns_css_value));", - } - %> - crate::values::generics::transform::TransformOperation::${name}${pattern} => { - let len = ${len(items) + 1}; - bindings::Gecko_CSSValue_SetFunction(gecko_value, len); - bindings::Gecko_CSSValue_SetKeyword( - bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0), - structs::nsCSSKeyword::eCSSKeyword_${keyword} - ); - % for index, item in enumerate(items): - % if item == "list": - debug_assert!(!${item}${index + 1}.0.is_empty()); - % endif - ${css_value_setters[item] % ( - "(&mut *bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d))" % (index + 1), - item + str(index + 1) - )}; - % endfor - } -</%def> - -<%def name="computed_operation_arm(name, keyword, items)"> - <% - # %s is substituted with the call to GetArrayItem. - css_value_getters = { - "length" : "Length::new(bindings::Gecko_CSSValue_GetNumber(%s))", - "lp" : "%s.get_length_percentage()", - "angle" : "%s.get_angle()", - "number" : "bindings::Gecko_CSSValue_GetNumber(%s)", - "percentage" : "Percentage(bindings::Gecko_CSSValue_GetPercentage(%s))", - "integer_to_percentage" : "bindings::Gecko_CSSValue_GetPercentage(%s) as i32", - "list" : "Transform(convert_shared_list_to_operations(%s))", - } - pre_symbols = "(" - post_symbols = ")" - if keyword == "interpolatematrix" or keyword == "accumulatematrix": - # We generate this like: "TransformOperation::InterpolateMatrix {", so the space is - # between "InterpolateMatrix"/"AccumulateMatrix" and '{' - pre_symbols = " {" - post_symbols = "}" - elif keyword == "matrix3d": - pre_symbols = "(Matrix3D {" - post_symbols = "})" - elif keyword == "matrix": - pre_symbols = "(Matrix {" - post_symbols = "})" - field_names = None - if keyword == "interpolatematrix": - field_names = ["from_list", "to_list", "progress"] - elif keyword == "accumulatematrix": - field_names = ["from_list", "to_list", "count"] - - %> - structs::nsCSSKeyword::eCSSKeyword_${keyword} => { - crate::values::generics::transform::TransformOperation::${name}${pre_symbols} - % for index, item in enumerate(items): - % if keyword == "matrix3d": - m${index / 4 + 1}${index % 4 + 1}: - % elif keyword == "matrix": - ${chr(ord('a') + index)}: - % elif keyword == "interpolatematrix" or keyword == "accumulatematrix": - ${field_names[index]}: - % endif - <% - getter = css_value_getters[item] % ( - "(&*bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d))" % (index + 1) - ) - %> - ${getter}, - % endfor - ${post_symbols} - }, -</%def> - -#[allow(unused_parens)] -fn set_single_transform_function( - servo_value: &values::computed::TransformOperation, - gecko_value: &mut structs::nsCSSValue /* output */ -) { - use crate::values::computed::TransformOperation; - use crate::values::generics::transform::{Matrix, Matrix3D}; - - let convert_to_ns_css_value = |item: &TransformOperation| -> structs::nsCSSValue { - let mut value = structs::nsCSSValue::null(); - set_single_transform_function(item, &mut value); - value - }; - - unsafe { - match *servo_value { - % for servo, gecko, format in transform_functions: - ${transform_function_arm(servo, gecko, format)} - % endfor - } - } -} - -pub fn convert_transform( - input: &[values::computed::TransformOperation], - output: &mut structs::root::RefPtr<structs::root::nsCSSValueSharedList> -) { - use crate::gecko_bindings::sugar::refptr::RefPtr; - - unsafe { output.clear() }; - - let list = unsafe { - RefPtr::from_addrefed(bindings::Gecko_NewCSSValueSharedList(input.len() as u32)) - }; - let value_list = unsafe { list.mHead.as_mut() }; - if let Some(value_list) = value_list { - for (gecko, servo) in value_list.into_iter().zip(input.into_iter()) { - set_single_transform_function(servo, gecko); - } - } - output.set_move(list); -} - -#[allow(unused_parens)] -fn clone_single_transform_function( - gecko_value: &structs::nsCSSValue -) -> values::computed::TransformOperation { - use crate::values::computed::{Length, Percentage, TransformOperation}; - use crate::values::generics::transform::{Matrix, Matrix3D}; - use crate::values::generics::transform::Transform; - - let convert_shared_list_to_operations = |value: &structs::nsCSSValue| - -> Vec<TransformOperation> { - debug_assert_eq!(value.mUnit, structs::nsCSSUnit::eCSSUnit_SharedList); - let value_list = unsafe { - value.mValue.mSharedList.as_ref() - .as_mut().expect("List pointer should be non-null").mHead.as_ref() - }; - debug_assert!(value_list.is_some(), "An empty shared list is not allowed"); - value_list.unwrap().into_iter() - .map(|item| clone_single_transform_function(item)) - .collect() - }; - - let transform_function = unsafe { - bindings::Gecko_CSSValue_GetKeyword(bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 0)) - }; - - unsafe { - match transform_function { - % for servo, gecko, format in transform_functions: - ${computed_operation_arm(servo, gecko, format)} - % endfor - _ => panic!("unacceptable transform function"), - } - } -} - -pub fn clone_transform_from_list( - list: Option< &structs::root::nsCSSValueList> -) -> values::computed::Transform { - use crate::values::generics::transform::Transform; - - let result = match list { - Some(list) => { - list.into_iter() - .filter_map(|value| { - // Handle none transform. - if value.is_none() { - None - } else { - Some(clone_single_transform_function(value)) - } - }) - .collect::<Vec<_>>() - }, - _ => vec![], - }; - Transform(result) -} - -<%def name="impl_transform(ident, gecko_ffi_name)"> - #[allow(non_snake_case)] - pub fn set_${ident}(&mut self, other: values::computed::Transform) { - use crate::gecko_properties::convert_transform; - if other.0.is_empty() { - unsafe { - self.gecko.${gecko_ffi_name}.clear(); - } - return; - }; - convert_transform(&other.0, &mut self.gecko.${gecko_ffi_name}); - } - - #[allow(non_snake_case)] - pub fn copy_${ident}_from(&mut self, other: &Self) { - unsafe { self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name}); } - } - - #[allow(non_snake_case)] - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - #[allow(non_snake_case)] - pub fn clone_${ident}(&self) -> values::computed::Transform { - use crate::gecko_properties::clone_transform_from_list; - use crate::values::generics::transform::Transform; - - if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() { - return Transform(vec!()); - } - let list = unsafe { (*self.gecko.${gecko_ffi_name}.to_safe().get()).mHead.as_ref() }; - clone_transform_from_list(list) - } -</%def> - <%def name="impl_logical(name, **kwargs)"> ${helpers.logical_setter(name)} </%def> @@ -1095,10 +782,10 @@ pub fn clone_transform_from_list( impl ${style_struct.gecko_struct_name} { #[allow(dead_code, unused_variables)] pub fn default(document: &structs::Document) -> Arc<Self> { - let mut result = Arc::new(${style_struct.gecko_struct_name} { gecko: unsafe { zeroed() } }); + let mut result = Arc::new(${style_struct.gecko_struct_name} { gecko: ManuallyDrop::new(unsafe { zeroed() }) }); unsafe { Gecko_Construct_Default_${style_struct.gecko_ffi_name}( - &mut Arc::get_mut(&mut result).unwrap().gecko, + &mut *Arc::get_mut(&mut result).unwrap().gecko, document, ); } @@ -1108,15 +795,15 @@ impl ${style_struct.gecko_struct_name} { impl Drop for ${style_struct.gecko_struct_name} { fn drop(&mut self) { unsafe { - Gecko_Destroy_${style_struct.gecko_ffi_name}(&mut self.gecko); + Gecko_Destroy_${style_struct.gecko_ffi_name}(&mut *self.gecko); } } } impl Clone for ${style_struct.gecko_struct_name} { fn clone(&self) -> Self { unsafe { - let mut result = ${style_struct.gecko_struct_name} { gecko: zeroed() }; - Gecko_CopyConstruct_${style_struct.gecko_ffi_name}(&mut result.gecko, &self.gecko); + let mut result = ${style_struct.gecko_struct_name} { gecko: ManuallyDrop::new(zeroed()) }; + Gecko_CopyConstruct_${style_struct.gecko_ffi_name}(&mut *result.gecko, &*self.gecko); result } } @@ -1192,7 +879,6 @@ impl Clone for ${style_struct.gecko_struct_name} { "SVGOpacity": impl_svg_opacity, "SVGPaint": impl_svg_paint, "SVGWidth": impl_svg_length, - "Transform": impl_transform, "url::UrlOrNone": impl_css_url, } @@ -1266,7 +952,7 @@ fn static_assert() { <%self:impl_trait style_struct_name="Border" skip_longhands="${skip_border_longhands} border-image-source - border-image-repeat border-image-width"> + border-image-repeat"> % for side in SIDES: pub fn set_border_${side.ident}_style(&mut self, v: BorderStyle) { self.gecko.mBorderStyle[${side.index}] = v; @@ -1405,8 +1091,6 @@ fn static_assert() { % endfor longhands::border_image_repeat::computed_value::T(servo_h, servo_v) } - - <% impl_style_sides("border_image_width") %> </%self:impl_trait> <% skip_scroll_margin_longhands = " ".join(["scroll-margin-%s" % x.ident for x in SIDES]) %> @@ -1545,8 +1229,9 @@ fn static_assert() { % for kind in ["rows", "columns"]: pub fn set_grid_auto_${kind}(&mut self, v: longhands::grid_auto_${kind}::computed_value::T) { - v.to_gecko_style_coords(&mut self.gecko.mGridAuto${kind.title()}Min, - &mut self.gecko.mGridAuto${kind.title()}Max) + let gecko = &mut *self.gecko; + v.to_gecko_style_coords(&mut gecko.mGridAuto${kind.title()}Min, + &mut gecko.mGridAuto${kind.title()}Max) } pub fn copy_grid_auto_${kind}_from(&mut self, other: &Self) { @@ -1566,14 +1251,14 @@ fn static_assert() { pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) { <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %> use crate::gecko_bindings::structs::{nsTArray, nsStyleGridLine_kMaxLine}; - use nsstring::nsStringRepr; + use nsstring::nsString; use std::usize; use crate::values::CustomIdent; use crate::values::generics::grid::TrackListType::Auto; use crate::values::generics::grid::{GridTemplateComponent, RepeatCount}; #[inline] - fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<nsStringRepr>) { + fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<nsString>) { unsafe { bindings::Gecko_ResizeTArrayForStrings(gecko_names, servo_names.len() as u32); } @@ -1693,7 +1378,7 @@ fn static_assert() { pub fn clone_grid_template_${kind}(&self) -> longhands::grid_template_${kind}::computed_value::T { <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %> use crate::gecko_bindings::structs::nsTArray; - use nsstring::nsStringRepr; + use nsstring::nsString; use crate::values::CustomIdent; use crate::values::generics::grid::{GridTemplateComponent, LineNameList, RepeatCount}; use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat, TrackSize}; @@ -1704,7 +1389,7 @@ fn static_assert() { }; #[inline] - fn to_boxed_customident_slice(gecko_names: &nsTArray<nsStringRepr>) -> Box<[CustomIdent]> { + fn to_boxed_customident_slice(gecko_names: &nsTArray<nsString>) -> Box<[CustomIdent]> { let idents: Vec<CustomIdent> = gecko_names.iter().map(|gecko_name| { CustomIdent(Atom::from(gecko_name.to_string())) }).collect(); @@ -1712,7 +1397,7 @@ fn static_assert() { } #[inline] - fn to_line_names_vec(gecko_line_names: &nsTArray<nsTArray<nsStringRepr>>) + fn to_line_names_vec(gecko_line_names: &nsTArray<nsTArray<nsString>>) -> Vec<Box<[CustomIdent]>> { gecko_line_names.iter().map(|gecko_names| { to_boxed_customident_slice(gecko_names) @@ -2129,14 +1814,14 @@ fn static_assert() { let ptr = v.0.as_ptr(); forget(v); unsafe { - Gecko_nsStyleFont_SetLang(&mut self.gecko, ptr); + Gecko_nsStyleFont_SetLang(&mut *self.gecko, ptr); } } #[allow(non_snake_case)] pub fn copy__x_lang_from(&mut self, other: &Self) { unsafe { - Gecko_nsStyleFont_CopyLangFrom(&mut self.gecko, &other.gecko); + Gecko_nsStyleFont_CopyLangFrom(&mut *self.gecko, &*other.gecko); } } @@ -2473,56 +2158,16 @@ fn static_assert() { ${impl_copy_animation_value(ident, gecko_ffi_name)} </%def> -<%def name="impl_individual_transform(ident, type, gecko_ffi_name)"> - pub fn set_${ident}(&mut self, other: values::computed::${type}) { - unsafe { self.gecko.${gecko_ffi_name}.clear() }; - - if let Some(operation) = other.to_transform_operation() { - convert_transform(&[operation], &mut self.gecko.${gecko_ffi_name}) - } - } - - pub fn copy_${ident}_from(&mut self, other: &Self) { - unsafe { self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name}); } - } - - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - pub fn clone_${ident}(&self) -> values::computed::${type} { - use crate::values::generics::transform::${type}; - - if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() { - return ${type}::None; - } - - let list = unsafe { (*self.gecko.${gecko_ffi_name}.to_safe().get()).mHead.as_ref() }; - - let mut transform = clone_transform_from_list(list); - debug_assert_eq!(transform.0.len(), 1); - ${type}::from_transform_operation(&transform.0.pop().unwrap()) - } -</%def> - <% skip_box_longhands= """display animation-name animation-delay animation-duration animation-direction animation-fill-mode animation-play-state animation-iteration-count animation-timing-function clear transition-duration transition-delay transition-timing-function transition-property - transform-style - rotate scroll-snap-points-x scroll-snap-points-y - scroll-snap-coordinate -moz-binding will-change - offset-path shape-outside - translate scale -webkit-line-clamp""" %> + transform-style -moz-binding shape-outside + -webkit-line-clamp""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> #[inline] - pub fn generate_combined_transform(&mut self) { - unsafe { bindings::Gecko_StyleDisplay_GenerateCombinedTransform(&mut self.gecko) }; - } - - #[inline] pub fn set_display(&mut self, v: longhands::display::computed_value::T) { self.gecko.mDisplay = v; self.gecko.mOriginalDisplay = v; @@ -2560,33 +2205,7 @@ fn static_assert() { gecko_inexhaustive=True, ) %> ${impl_keyword('clear', 'mBreakType', clear_keyword)} - - ${impl_style_coord("scroll_snap_points_x", "mScrollSnapPointsX")} - ${impl_style_coord("scroll_snap_points_y", "mScrollSnapPointsY")} - - pub fn set_scroll_snap_coordinate<I>(&mut self, v: I) - where I: IntoIterator<Item = longhands::scroll_snap_coordinate::computed_value::single_value::T>, - I::IntoIter: ExactSizeIterator - { - self.gecko.mScrollSnapCoordinate.assign_from_iter_pod(v.into_iter()); - } - - pub fn copy_scroll_snap_coordinate_from(&mut self, other: &Self) { - let iter = other.gecko.mScrollSnapCoordinate.iter().map(|c| *c); - self.gecko.mScrollSnapCoordinate.assign_from_iter_pod(iter); - } - - pub fn reset_scroll_snap_coordinate(&mut self, other: &Self) { - self.copy_scroll_snap_coordinate_from(other) - } - - pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T { - let vec = self.gecko.mScrollSnapCoordinate.iter().cloned().collect(); - longhands::scroll_snap_coordinate::computed_value::List(vec) - } - ${impl_css_url('_moz_binding', 'mBinding')} - ${impl_transition_time_value('delay', 'Delay')} ${impl_transition_time_value('duration', 'Duration')} ${impl_transition_timing_function()} @@ -2825,105 +2444,8 @@ fn static_assert() { ${impl_animation_timing_function()} - ${impl_individual_transform('rotate', 'Rotate', 'mSpecifiedRotate')} - ${impl_individual_transform('translate', 'Translate', 'mSpecifiedTranslate')} - ${impl_individual_transform('scale', 'Scale', 'mSpecifiedScale')} - - pub fn set_will_change(&mut self, v: longhands::will_change::computed_value::T) { - use crate::gecko_bindings::bindings::{Gecko_AppendWillChange, Gecko_ClearWillChange}; - use crate::values::specified::box_::{WillChangeBits, WillChange}; - - match v { - WillChange::AnimateableFeatures { features, bits } => { - unsafe { - Gecko_ClearWillChange(&mut self.gecko, features.len()); - } - - for feature in features.iter() { - unsafe { - Gecko_AppendWillChange(&mut self.gecko, feature.0.as_ptr()) - } - } - - self.gecko.mWillChangeBitField = bits; - }, - WillChange::Auto => { - unsafe { - Gecko_ClearWillChange(&mut self.gecko, 0); - } - self.gecko.mWillChangeBitField = WillChangeBits::empty(); - }, - }; - } - - pub fn copy_will_change_from(&mut self, other: &Self) { - use crate::gecko_bindings::bindings::Gecko_CopyWillChangeFrom; - - self.gecko.mWillChangeBitField = other.gecko.mWillChangeBitField; - unsafe { - Gecko_CopyWillChangeFrom(&mut self.gecko, &other.gecko); - } - } - - pub fn reset_will_change(&mut self, other: &Self) { - self.copy_will_change_from(other) - } - - pub fn clone_will_change(&self) -> longhands::will_change::computed_value::T { - use crate::values::CustomIdent; - use crate::values::specified::box_::WillChange; - - if self.gecko.mWillChange.len() == 0 { - return WillChange::Auto - } - - let custom_idents: Vec<CustomIdent> = self.gecko.mWillChange.iter().map(|gecko_atom| { - unsafe { - CustomIdent(Atom::from_raw(gecko_atom.mRawPtr)) - } - }).collect(); - - WillChange::AnimateableFeatures { - features: custom_idents.into_boxed_slice(), - bits: self.gecko.mWillChangeBitField, - } - } - <% impl_shape_source("shape_outside", "mShapeOutside") %> - pub fn set_offset_path(&mut self, v: longhands::offset_path::computed_value::T) { - use crate::gecko_bindings::bindings::{Gecko_NewStyleMotion, Gecko_SetStyleMotion}; - use crate::gecko_bindings::structs::StyleShapeSourceType; - use crate::values::generics::basic_shape::FillRule; - use crate::values::specified::OffsetPath; - - let motion = unsafe { Gecko_NewStyleMotion().as_mut().unwrap() }; - match v { - OffsetPath::None => motion.mOffsetPath.mType = StyleShapeSourceType::None, - OffsetPath::Path(p) => { - set_style_svg_path(&mut motion.mOffsetPath, p, FillRule::Nonzero) - }, - } - unsafe { Gecko_SetStyleMotion(&mut self.gecko.mMotion, motion) }; - } - - pub fn clone_offset_path(&self) -> longhands::offset_path::computed_value::T { - use crate::values::specified::OffsetPath; - match unsafe { self.gecko.mMotion.mPtr.as_ref() } { - None => OffsetPath::none(), - Some(v) => (&v.mOffsetPath).into() - } - } - - pub fn copy_offset_path_from(&mut self, other: &Self) { - use crate::gecko_bindings::bindings::Gecko_CopyStyleMotions; - unsafe { Gecko_CopyStyleMotions(&mut self.gecko.mMotion, other.gecko.mMotion.mPtr) }; - } - - pub fn reset_offset_path(&mut self, other: &Self) { - self.copy_offset_path_from(other); - } - #[allow(non_snake_case)] pub fn set__webkit_line_clamp(&mut self, v: longhands::_webkit_line_clamp::computed_value::T) { self.gecko.mLineClamp = match v { @@ -3301,19 +2823,19 @@ fn static_assert() { </%self:impl_trait> <%self:impl_trait style_struct_name="List" - skip_longhands="list-style-image list-style-type quotes -moz-image-region"> + skip_longhands="list-style-image list-style-type -moz-image-region"> pub fn set_list_style_image(&mut self, image: longhands::list_style_image::computed_value::T) { match image { UrlOrNone::None => { unsafe { - Gecko_SetListStyleImageNone(&mut self.gecko); + Gecko_SetListStyleImageNone(&mut *self.gecko); } } UrlOrNone::Url(ref url) => { unsafe { Gecko_SetListStyleImageImageValue( - &mut self.gecko, + &mut *self.gecko, url.url_value_ptr(), ); } @@ -3322,7 +2844,7 @@ fn static_assert() { } pub fn copy_list_style_image_from(&mut self, other: &Self) { - unsafe { Gecko_CopyListStyleImageFrom(&mut self.gecko, &other.gecko); } + unsafe { Gecko_CopyListStyleImageFrom(&mut *self.gecko, &*other.gecko); } } pub fn reset_list_style_image(&mut self, other: &Self) { @@ -3330,8 +2852,6 @@ fn static_assert() { } pub fn clone_list_style_image(&self) -> longhands::list_style_image::computed_value::T { - use crate::values::computed::url::ComputedImageUrl; - if self.gecko.mListStyleImage.mRawPtr.is_null() { return UrlOrNone::None; } @@ -3377,28 +2897,6 @@ fn static_assert() { } } - pub fn set_quotes(&mut self, other: longhands::quotes::computed_value::T) { - self.gecko.mQuotes.set_arc(other.0.clone()); - } - - pub fn copy_quotes_from(&mut self, other: &Self) { - self.set_quotes(other.clone_quotes()); - } - - pub fn reset_quotes(&mut self, other: &Self) { - self.copy_quotes_from(other) - } - - pub fn clone_quotes(&self) -> longhands::quotes::computed_value::T { - use gecko_bindings::sugar::ownership::HasArcFFI; - use values::computed::QuotePair; - - let quote_pairs = unsafe { &*self.gecko.mQuotes.mRawPtr }; - longhands::quotes::computed_value::T( - Box::<[QuotePair]>::as_arc("e_pairs).clone_arc() - ) - } - #[allow(non_snake_case)] pub fn set__moz_image_region(&mut self, v: longhands::_moz_image_region::computed_value::T) { use crate::values::Either; @@ -3476,31 +2974,7 @@ fn static_assert() { </%self:impl_trait> <%self:impl_trait style_struct_name="Effects" - skip_longhands="box-shadow clip filter"> - pub fn set_box_shadow<I>(&mut self, v: I) - where I: IntoIterator<Item = BoxShadow>, - I::IntoIter: ExactSizeIterator - { - let v = v.into_iter(); - self.gecko.mBoxShadow.replace_with_new(v.len() as u32); - for (servo, gecko_shadow) in v.zip(self.gecko.mBoxShadow.iter_mut()) { - gecko_shadow.set_from_box_shadow(servo); - } - } - - pub fn copy_box_shadow_from(&mut self, other: &Self) { - self.gecko.mBoxShadow.copy_from(&other.gecko.mBoxShadow); - } - - pub fn reset_box_shadow(&mut self, other: &Self) { - self.copy_box_shadow_from(other) - } - - pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T { - let buf = self.gecko.mBoxShadow.iter().map(|v| v.to_box_shadow()).collect(); - longhands::box_shadow::computed_value::List(buf) - } - + skip_longhands="clip filter"> pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) { use crate::gecko_bindings::structs::NS_STYLE_CLIP_AUTO; use crate::gecko_bindings::structs::NS_STYLE_CLIP_RECT; @@ -3624,7 +3098,6 @@ fn static_assert() { I::IntoIter: ExactSizeIterator, { use crate::values::generics::effects::Filter::*; - use crate::gecko_bindings::structs::nsCSSShadowArray; use crate::gecko_bindings::structs::nsStyleFilter; use crate::gecko_bindings::structs::NS_STYLE_FILTER_BLUR; use crate::gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS; @@ -3644,7 +3117,7 @@ fn static_assert() { let v = v.into_iter(); unsafe { - Gecko_ResetFilters(&mut self.gecko, v.len()); + Gecko_ResetFilters(&mut *self.gecko, v.len()); } debug_assert_eq!(v.len(), self.gecko.mFilters.len()); @@ -3665,19 +3138,10 @@ fn static_assert() { DropShadow(shadow) => { gecko_filter.mType = NS_STYLE_FILTER_DROP_SHADOW; - - fn init_shadow(filter: &mut nsStyleFilter) -> &mut nsCSSShadowArray { - unsafe { - let ref mut union = filter.__bindgen_anon_1; - let shadow_array: &mut *mut nsCSSShadowArray = union.mDropShadow.as_mut(); - *shadow_array = Gecko_NewCSSShadowArray(1); - - &mut **shadow_array - } + unsafe { + let ref mut union = gecko_filter.__bindgen_anon_1; + ptr::write(union.mDropShadow.as_mut(), shadow); } - - let gecko_shadow = init_shadow(gecko_filter); - gecko_shadow.mArray[0].set_from_simple_shadow(shadow); }, Url(ref url) => { unsafe { @@ -3690,7 +3154,7 @@ fn static_assert() { pub fn copy_filter_from(&mut self, other: &Self) { unsafe { - Gecko_CopyFiltersFrom(&other.gecko as *const _ as *mut _, &mut self.gecko); + Gecko_CopyFiltersFrom(&other.gecko as *const _ as *mut _, &mut *self.gecko); } } @@ -3713,42 +3177,41 @@ fn static_assert() { use crate::gecko_bindings::structs::NS_STYLE_FILTER_DROP_SHADOW; use crate::gecko_bindings::structs::NS_STYLE_FILTER_URL; - let mut filters = Vec::new(); - for filter in self.gecko.mFilters.iter(){ + longhands::filter::computed_value::List(self.gecko.mFilters.iter().map(|filter| { match filter.mType { % for func in FILTER_FUNCTIONS: NS_STYLE_FILTER_${func.upper()} => { - filters.push(Filter::${func}( + Filter::${func}( GeckoStyleCoordConvertible::from_gecko_style_coord( - &filter.mFilterParameter).unwrap())); + &filter.mFilterParameter + ).unwrap() + ) }, % endfor NS_STYLE_FILTER_BLUR => { - filters.push(Filter::Blur(NonNegativeLength::from_gecko_style_coord( - &filter.mFilterParameter).unwrap())); + Filter::Blur(NonNegativeLength::from_gecko_style_coord( + &filter.mFilterParameter + ).unwrap()) }, NS_STYLE_FILTER_HUE_ROTATE => { - filters.push(Filter::HueRotate( - GeckoStyleCoordConvertible::from_gecko_style_coord( - &filter.mFilterParameter).unwrap())); + Filter::HueRotate(GeckoStyleCoordConvertible::from_gecko_style_coord( + &filter.mFilterParameter, + ).unwrap()) }, NS_STYLE_FILTER_DROP_SHADOW => { - filters.push(unsafe { - Filter::DropShadow( - (**filter.__bindgen_anon_1.mDropShadow.as_ref()).mArray[0].to_simple_shadow(), - ) - }); + Filter::DropShadow(unsafe { + (*filter.__bindgen_anon_1.mDropShadow.as_ref()).clone() + }) }, NS_STYLE_FILTER_URL => { - filters.push(Filter::Url(unsafe { + Filter::Url(unsafe { let url = RefPtr::new(*filter.__bindgen_anon_1.mURL.as_ref()); ComputedUrl::from_url_value(url) - })); + }) } - _ => {}, + _ => unreachable!("Unknown filter function?"), } - } - longhands::filter::computed_value::List(filters) + }).collect()) } </%self:impl_trait> @@ -3783,7 +3246,7 @@ fn static_assert() { <%self:impl_trait style_struct_name="InheritedText" - skip_longhands="text-align text-emphasis-style text-shadow + skip_longhands="text-align text-emphasis-style -webkit-text-stroke-width text-emphasis-position"> <% text_align_keyword = Keyword("text-align", @@ -3791,30 +3254,6 @@ fn static_assert() { gecko_strip_moz_prefix=False) %> ${impl_keyword('text_align', 'mTextAlign', text_align_keyword)} - pub fn set_text_shadow<I>(&mut self, v: I) - where I: IntoIterator<Item = SimpleShadow>, - I::IntoIter: ExactSizeIterator - { - let v = v.into_iter(); - self.gecko.mTextShadow.replace_with_new(v.len() as u32); - for (servo, gecko_shadow) in v.zip(self.gecko.mTextShadow.iter_mut()) { - gecko_shadow.set_from_simple_shadow(servo); - } - } - - pub fn copy_text_shadow_from(&mut self, other: &Self) { - self.gecko.mTextShadow.copy_from(&other.gecko.mTextShadow); - } - - pub fn reset_text_shadow(&mut self, other: &Self) { - self.copy_text_shadow_from(other) - } - - pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T { - let buf = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow()).collect(); - longhands::text_shadow::computed_value::List(buf) - } - fn clear_text_emphasis_style_if_string(&mut self) { if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 { self.gecko.mTextEmphasisStyleString.truncate(); @@ -3903,83 +3342,7 @@ fn static_assert() { </%self:impl_trait> -<%self:impl_trait style_struct_name="Text" - skip_longhands="text-overflow initial-letter"> - - fn clear_overflow_sides_if_string(&mut self) { - use crate::gecko_bindings::structs::nsStyleTextOverflowSide; - fn clear_if_string(side: &mut nsStyleTextOverflowSide) { - if side.mType == structs::NS_STYLE_TEXT_OVERFLOW_STRING as u8 { - side.mString.truncate(); - side.mType = structs::NS_STYLE_TEXT_OVERFLOW_CLIP as u8; - } - } - clear_if_string(&mut self.gecko.mTextOverflow.mLeft); - clear_if_string(&mut self.gecko.mTextOverflow.mRight); - } - - pub fn set_text_overflow(&mut self, v: longhands::text_overflow::computed_value::T) { - use crate::gecko_bindings::structs::nsStyleTextOverflowSide; - use crate::values::specified::text::TextOverflowSide; - - fn set(side: &mut nsStyleTextOverflowSide, value: &TextOverflowSide) { - let ty = match *value { - TextOverflowSide::Clip => structs::NS_STYLE_TEXT_OVERFLOW_CLIP, - TextOverflowSide::Ellipsis => structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS, - TextOverflowSide::String(ref s) => { - side.mString.assign_str(s); - structs::NS_STYLE_TEXT_OVERFLOW_STRING - } - }; - side.mType = ty as u8; - } - - self.clear_overflow_sides_if_string(); - self.gecko.mTextOverflow.mLogicalDirections = v.sides_are_logical; - - set(&mut self.gecko.mTextOverflow.mLeft, &v.first); - set(&mut self.gecko.mTextOverflow.mRight, &v.second); - } - - pub fn copy_text_overflow_from(&mut self, other: &Self) { - use crate::gecko_bindings::structs::nsStyleTextOverflowSide; - fn set(side: &mut nsStyleTextOverflowSide, other: &nsStyleTextOverflowSide) { - if other.mType == structs::NS_STYLE_TEXT_OVERFLOW_STRING as u8 { - side.mString.assign(&*other.mString) - } - side.mType = other.mType - } - self.clear_overflow_sides_if_string(); - set(&mut self.gecko.mTextOverflow.mLeft, &other.gecko.mTextOverflow.mLeft); - set(&mut self.gecko.mTextOverflow.mRight, &other.gecko.mTextOverflow.mRight); - self.gecko.mTextOverflow.mLogicalDirections = other.gecko.mTextOverflow.mLogicalDirections; - } - - pub fn reset_text_overflow(&mut self, other: &Self) { - self.copy_text_overflow_from(other) - } - - pub fn clone_text_overflow(&self) -> longhands::text_overflow::computed_value::T { - use crate::gecko_bindings::structs::nsStyleTextOverflowSide; - use crate::values::specified::text::TextOverflowSide; - - fn to_servo(side: &nsStyleTextOverflowSide) -> TextOverflowSide { - match side.mType as u32 { - structs::NS_STYLE_TEXT_OVERFLOW_CLIP => TextOverflowSide::Clip, - structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS => TextOverflowSide::Ellipsis, - structs::NS_STYLE_TEXT_OVERFLOW_STRING => - TextOverflowSide::String(side.mString.to_string().into_boxed_str()), - _ => panic!("Found unexpected value in style struct for text_overflow property"), - } - } - - longhands::text_overflow::computed_value::T { - first: to_servo(&self.gecko.mTextOverflow.mLeft), - second: to_servo(&self.gecko.mTextOverflow.mRight), - sides_are_logical: self.gecko.mTextOverflow.mLogicalDirections - } - } - +<%self:impl_trait style_struct_name="Text" skip_longhands="initial-letter"> pub fn set_initial_letter(&mut self, v: longhands::initial_letter::computed_value::T) { use crate::values::generics::text::InitialLetter; match v { @@ -4050,25 +3413,19 @@ fn set_style_svg_path( ${ident}.mType = StyleShapeSourceType::None; match v { - % if ident == "clip_path": - ShapeSource::ImageOrUrl(ref url) => { - unsafe { - bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.url_value_ptr()) - } - } - % elif ident == "shape_outside": + ShapeSource::None => {} // don't change the type ShapeSource::ImageOrUrl(image) => { + % if ident == "clip_path": + use crate::values::generics::image::Image; + + let image = Image::Url(ComputedImageUrl(image)); + % endif unsafe { bindings::Gecko_NewShapeImage(${ident}); let style_image = &mut *${ident}.__bindgen_anon_1.mShapeImage.as_mut().mPtr; style_image.set(image); } } - % else: - <% raise Exception("Unknown property: %s" % ident) %> - } - % endif - ShapeSource::None => {} // don't change the type ShapeSource::Box(reference) => { ${ident}.mReferenceBox = reference.into(); ${ident}.mType = StyleShapeSourceType::Box; @@ -4118,7 +3475,7 @@ clip-path </%self:impl_trait> <%self:impl_trait style_struct_name="InheritedSVG" - skip_longhands="paint-order stroke-dasharray -moz-context-properties"> + skip_longhands="paint-order stroke-dasharray"> pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) { self.gecko.mPaintOrder = v.0; } @@ -4139,7 +3496,7 @@ clip-path let v = v.into_iter(); self.gecko.mContextFlags &= !CONTEXT_VALUE; unsafe { - bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.len() as u32); + bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut *self.gecko, v.len() as u32); } for (gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) { *gecko = servo; @@ -4148,7 +3505,7 @@ clip-path SVGStrokeDashArray::ContextValue => { self.gecko.mContextFlags |= CONTEXT_VALUE; unsafe { - bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, 0); + bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut *self.gecko, 0); } } } @@ -4157,7 +3514,7 @@ clip-path pub fn copy_stroke_dasharray_from(&mut self, other: &Self) { use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; unsafe { - bindings::Gecko_nsStyleSVG_CopyDashArray(&mut self.gecko, &other.gecko); + bindings::Gecko_nsStyleSVG_CopyDashArray(&mut *self.gecko, &*other.gecko); } self.gecko.mContextFlags = (self.gecko.mContextFlags & !CONTEXT_VALUE) | @@ -4178,61 +3535,6 @@ clip-path } SVGStrokeDashArray::Values(self.gecko.mStrokeDasharray.iter().cloned().collect()) } - - #[allow(non_snake_case)] - pub fn _moz_context_properties_count(&self) -> usize { - self.gecko.mContextProps.len() - } - - #[allow(non_snake_case)] - pub fn _moz_context_properties_at( - &self, - index: usize, - ) -> longhands::_moz_context_properties::computed_value::single_value::T { - longhands::_moz_context_properties::computed_value::single_value::T( - CustomIdent(unsafe { - Atom::from_raw(self.gecko.mContextProps[index].mRawPtr) - }) - ) - } - - #[allow(non_snake_case)] - pub fn set__moz_context_properties<I>(&mut self, v: I) - where - I: IntoIterator<Item = longhands::_moz_context_properties::computed_value::single_value::T>, - I::IntoIter: ExactSizeIterator - { - let v = v.into_iter(); - unsafe { - bindings::Gecko_nsStyleSVG_SetContextPropertiesLength(&mut self.gecko, v.len() as u32); - } - - self.gecko.mContextPropsBits = 0; - for (gecko, servo) in self.gecko.mContextProps.iter_mut().zip(v) { - if (servo.0).0 == atom!("fill") { - self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL as u8; - } else if (servo.0).0 == atom!("stroke") { - self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE as u8; - } else if (servo.0).0 == atom!("fill-opacity") { - self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY as u8; - } else if (servo.0).0 == atom!("stroke-opacity") { - self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY as u8; - } - gecko.mRawPtr = (servo.0).0.into_addrefed(); - } - } - - #[allow(non_snake_case)] - pub fn copy__moz_context_properties_from(&mut self, other: &Self) { - unsafe { - bindings::Gecko_nsStyleSVG_CopyContextProperties(&mut self.gecko, &other.gecko); - } - } - - #[allow(non_snake_case)] - pub fn reset__moz_context_properties(&mut self, other: &Self) { - self.copy__moz_context_properties_from(other) - } </%self:impl_trait> <%self:impl_trait style_struct_name="Color"> @@ -4242,7 +3544,7 @@ clip-path pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) { self.gecko.mCursor = v.keyword; unsafe { - Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len()); + Gecko_SetCursorArrayLength(&mut *self.gecko, v.images.len()); } for i in 0..v.images.len() { unsafe { @@ -4268,7 +3570,7 @@ clip-path pub fn copy_cursor_from(&mut self, other: &Self) { self.gecko.mCursor = other.gecko.mCursor; unsafe { - Gecko_CopyCursorArrayFrom(&mut self.gecko, &other.gecko); + Gecko_CopyCursorArrayFrom(&mut *self.gecko, &*other.gecko); } } @@ -4278,7 +3580,6 @@ clip-path pub fn clone_cursor(&self) -> longhands::cursor::computed_value::T { use crate::values::computed::ui::CursorImage; - use crate::values::computed::url::ComputedImageUrl; let keyword = self.gecko.mCursor; @@ -4387,20 +3688,20 @@ clip-path // Ensure destructors run, otherwise we could leak. if !self.gecko.mContents.is_empty() { unsafe { - Gecko_ClearAndResizeStyleContents(&mut self.gecko, 0); + Gecko_ClearAndResizeStyleContents(&mut *self.gecko, 0); } } }, Content::MozAltContent => { unsafe { - Gecko_ClearAndResizeStyleContents(&mut self.gecko, 1); + Gecko_ClearAndResizeStyleContents(&mut *self.gecko, 1); *self.gecko.mContents[0].mContent.mString.as_mut() = ptr::null_mut(); } self.gecko.mContents[0].mType = StyleContentType::AltContent; }, Content::Items(items) => { unsafe { - Gecko_ClearAndResizeStyleContents(&mut self.gecko, + Gecko_ClearAndResizeStyleContents(&mut *self.gecko, items.len() as u32); } for (i, item) in items.into_vec().into_iter().enumerate() { @@ -4481,7 +3782,7 @@ clip-path pub fn copy_content_from(&mut self, other: &Self) { use crate::gecko_bindings::bindings::Gecko_CopyStyleContentsFrom; unsafe { - Gecko_CopyStyleContentsFrom(&mut self.gecko, &other.gecko) + Gecko_CopyStyleContentsFrom(&mut *self.gecko, &*other.gecko) } } @@ -4494,7 +3795,6 @@ clip-path use crate::gecko::conversions::string_from_chars_pointer; use crate::gecko_bindings::structs::StyleContentType; use crate::values::generics::counters::{Content, ContentItem}; - use crate::values::computed::url::ComputedImageUrl; use crate::values::{CustomIdent, Either}; use crate::values::generics::CounterStyleOrNone; use crate::values::specified::Attr; @@ -4575,7 +3875,7 @@ clip-path v: longhands::counter_${counter_property.lower()}::computed_value::T ) { unsafe { - bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko, v.len() as u32); + bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut *self.gecko, v.len() as u32); for (i, pair) in v.0.into_vec().into_iter().enumerate() { self.gecko.m${counter_property}s[i].mCounter.set_move( RefPtr::from_addrefed(pair.name.0.into_addrefed()) @@ -4587,7 +3887,7 @@ clip-path pub fn copy_counter_${counter_property.lower()}_from(&mut self, other: &Self) { unsafe { - bindings::Gecko_CopyCounter${counter_property}sFrom(&mut self.gecko, &other.gecko) + bindings::Gecko_CopyCounter${counter_property}sFrom(&mut *self.gecko, &*other.gecko) } } diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 8310d537f36..800d50c6220 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -10,7 +10,7 @@ <%def name="predefined_type(name, type, initial_value, parse_method='parse', needs_context=True, vector=False, computed_type=None, initial_specified_value=None, - allow_quirks=False, allow_empty=False, **kwargs)"> + allow_quirks='No', allow_empty=False, **kwargs)"> <%def name="predefined_type_inner(name, type, initial_value, parse_method)"> #[allow(unused_imports)] use app_units::Au; @@ -42,8 +42,8 @@ context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<SpecifiedValue, ParseError<'i>> { - % if allow_quirks: - specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes) + % if allow_quirks != "No": + specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::${allow_quirks}) % elif needs_context: specified::${type}::${parse_method}(context, input) % else: @@ -80,12 +80,26 @@ We assume that the default/initial value is an empty vector for these. `initial_value` need not be defined for these. </%doc> + +// The setup here is roughly: +// +// * UnderlyingList is the list that is stored in the computed value. This may +// be a shared ArcSlice if the property is inherited. +// * UnderlyingOwnedList is the list that is used for animation. +// * Specified values always use OwnedSlice, since it's more compact. +// * computed_value::List is just a convenient alias that you can use for the +// computed value list, since this is in the computed_value module. +// +// If simple_vector_bindings is true, then we don't use the complex iterator +// machinery and set_foo_from, and just compute the value like any other +// longhand. <%def name="vector_longhand(name, animation_value_type=None, vector_animation_type=None, allow_empty=False, + simple_vector_bindings=False, separator='Comma', **kwargs)"> <%call expr="longhand(name, animation_value_type=animation_value_type, vector=True, - **kwargs)"> + simple_vector_bindings=simple_vector_bindings, **kwargs)"> #[allow(unused_imports)] use smallvec::SmallVec; @@ -111,16 +125,46 @@ /// The definition of the computed value for ${name}. pub mod computed_value { + #[allow(unused_imports)] + use crate::values::animated::ToAnimatedValue; + #[allow(unused_imports)] + use crate::values::resolved::ToResolvedValue; pub use super::single_value::computed_value as single_value; pub use self::single_value::T as SingleComputedValue; - % if allow_empty and allow_empty != "NotInitial": - use std::vec::IntoIter; - % else: - use smallvec::{IntoIter, SmallVec}; + % if not allow_empty or allow_empty == "NotInitial": + use smallvec::SmallVec; % endif use crate::values::computed::ComputedVecIter; - /// The generic type defining the value for this property. + <% + is_shared_list = allow_empty and allow_empty != "NotInitial" and \ + data.longhands_by_name[name].style_struct.inherited + %> + + // FIXME(emilio): Add an OwnedNonEmptySlice type, and figure out + // something for transition-name, which is the only remaining user + // of NotInitial. + pub type UnderlyingList<T> = + % if allow_empty and allow_empty != "NotInitial": + % if data.longhands_by_name[name].style_struct.inherited: + crate::ArcSlice<T>; + % else: + crate::OwnedSlice<T>; + % endif + % else: + SmallVec<[T; 1]>; + % endif + + pub type UnderlyingOwnedList<T> = + % if allow_empty and allow_empty != "NotInitial": + crate::OwnedSlice<T>; + % else: + SmallVec<[T; 1]>; + % endif + + + /// The generic type defining the animated and resolved values for + /// this property. /// /// Making this type generic allows the compiler to figure out the /// animated value for us, instead of having to implement it @@ -137,34 +181,115 @@ ToResolvedValue, ToCss, )] - pub struct List<T>( + pub struct OwnedList<T>( % if not allow_empty: #[css(iterable)] % else: #[css(if_empty = "none", iterable)] % endif - % if allow_empty and allow_empty != "NotInitial": - pub Vec<T>, + pub UnderlyingOwnedList<T>, + ); + + /// The computed value for this property. + % if not is_shared_list: + pub type ComputedList = OwnedList<single_value::T>; + pub use self::OwnedList as List; + % else: + pub use self::ComputedList as List; + + % if separator == "Comma": + #[css(comma)] + % endif + #[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + ToCss, + )] + pub struct ComputedList( + % if not allow_empty: + #[css(iterable)] % else: - pub SmallVec<[T; 1]>, + #[css(if_empty = "none", iterable)] + % endif + % if is_shared_list: + #[ignore_malloc_size_of = "Arc"] % endif + pub UnderlyingList<single_value::T>, ); + type ResolvedList = OwnedList<<single_value::T as ToResolvedValue>::ResolvedValue>; + impl ToResolvedValue for ComputedList { + type ResolvedValue = ResolvedList; + + fn to_resolved_value(self, context: &crate::values::resolved::Context) -> Self::ResolvedValue { + OwnedList( + self.0 + .iter() + .cloned() + .map(|v| v.to_resolved_value(context)) + .collect() + ) + } + + fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { + % if not is_shared_list: + use std::iter::FromIterator; + % endif + let iter = + resolved.0.into_iter().map(ToResolvedValue::from_resolved_value); + ComputedList(UnderlyingList::from_iter(iter)) + } + } + % endif + + % if simple_vector_bindings: + impl From<ComputedList> for UnderlyingList<single_value::T> { + #[inline] + fn from(l: ComputedList) -> Self { + l.0 + } + } + impl From<UnderlyingList<single_value::T>> for ComputedList { + #[inline] + fn from(l: UnderlyingList<single_value::T>) -> Self { + List(l) + } + } + % endif - /// The computed value, effectively a list of single values. % if vector_animation_type: % if not animation_value_type: Sorry, this is stupid but needed for now. % endif use crate::properties::animated_properties::ListAnimation; - use crate::values::animated::{Animate, ToAnimatedValue, ToAnimatedZero, Procedure}; + use crate::values::animated::{Animate, ToAnimatedZero, Procedure}; use crate::values::distance::{SquaredDistance, ComputeSquaredDistance}; // FIXME(emilio): For some reason rust thinks that this alias is // unused, even though it's clearly used below? #[allow(unused)] - type AnimatedList = <List<single_value::T> as ToAnimatedValue>::AnimatedValue; + type AnimatedList = OwnedList<<single_value::T as ToAnimatedValue>::AnimatedValue>; + + % if is_shared_list: + impl ToAnimatedValue for ComputedList { + type AnimatedValue = AnimatedList; + + fn to_animated_value(self) -> Self::AnimatedValue { + OwnedList( + self.0.iter().map(|v| v.clone().to_animated_value()).collect() + ) + } + + fn from_animated_value(animated: Self::AnimatedValue) -> Self { + let iter = + animated.0.into_iter().map(ToAnimatedValue::from_animated_value); + ComputedList(UnderlyingList::from_iter(iter)) + } + } + % endif impl ToAnimatedZero for AnimatedList { fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } @@ -176,7 +301,7 @@ other: &Self, procedure: Procedure, ) -> Result<Self, ()> { - Ok(List( + Ok(OwnedList( self.0.animate_${vector_animation_type}(&other.0, procedure)? )) } @@ -191,21 +316,10 @@ } % endif - pub type T = List<single_value::T>; + /// The computed value, effectively a list of single values. + pub use self::ComputedList as T; pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>; - - impl IntoIterator for T { - type Item = single_value::T; - % if allow_empty and allow_empty != "NotInitial": - type IntoIter = IntoIter<single_value::T>; - % else: - type IntoIter = IntoIter<[single_value::T; 1]>; - % endif - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } - } } /// The specified value of ${name}. @@ -219,12 +333,12 @@ % else: #[css(if_empty = "none", iterable)] % endif - pub Vec<single_value::SpecifiedValue>, + pub crate::OwnedSlice<single_value::SpecifiedValue>, ); pub fn get_initial_value() -> computed_value::T { % if allow_empty and allow_empty != "NotInitial": - computed_value::List(vec![]) + computed_value::List(Default::default()) % else: let mut v = SmallVec::new(); v.push(single_value::get_initial_value()); @@ -239,40 +353,47 @@ use style_traits::Separator; % if allow_empty: - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(SpecifiedValue(Vec::new())) - } + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(SpecifiedValue(Default::default())) + } % endif - style_traits::${separator}::parse(input, |parser| { + let v = style_traits::${separator}::parse(input, |parser| { single_value::parse(context, parser) - }).map(SpecifiedValue) + })?; + Ok(SpecifiedValue(v.into())) } pub use self::single_value::SpecifiedValue as SingleSpecifiedValue; + % if not simple_vector_bindings and product == "gecko": impl SpecifiedValue { - pub fn compute_iter<'a, 'cx, 'cx_a>( + fn compute_iter<'a, 'cx, 'cx_a>( &'a self, context: &'cx Context<'cx_a>, ) -> computed_value::Iter<'a, 'cx, 'cx_a> { computed_value::Iter::new(context, &self.0) } } + % endif impl ToComputedValue for SpecifiedValue { type ComputedValue = computed_value::T; #[inline] fn to_computed_value(&self, context: &Context) -> computed_value::T { - computed_value::List(self.compute_iter(context).collect()) + % if not is_shared_list: + use std::iter::FromIterator; + % endif + computed_value::List(computed_value::UnderlyingList::from_iter( + self.0.iter().map(|i| i.to_computed_value(context)) + )) } #[inline] fn from_computed_value(computed: &computed_value::T) -> Self { - SpecifiedValue(computed.0.iter() - .map(ToComputedValue::from_computed_value) - .collect()) + let iter = computed.0.iter().map(ToComputedValue::from_computed_value); + SpecifiedValue(iter.collect()) } } </%call> @@ -375,7 +496,7 @@ .set_writing_mode_dependency(context.builder.writing_mode); % endif - % if property.is_vector: + % if property.is_vector and not property.simple_vector_bindings and product == "gecko": // In the case of a vector property we want to pass down an // iterator so that this can be computed without allocation. // @@ -405,8 +526,8 @@ context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<PropertyDeclaration, ParseError<'i>> { - % if property.allow_quirks: - parse_quirky(context, input, specified::AllowQuirks::Yes) + % if property.allow_quirks != "No": + parse_quirky(context, input, specified::AllowQuirks::${property.allow_quirks}) % else: parse(context, input) % endif @@ -868,7 +989,7 @@ </%def> <%def name="four_sides_shorthand(name, sub_property_pattern, parser_function, - needs_context=True, allow_quirks=False, **kwargs)"> + needs_context=True, allow_quirks='No', **kwargs)"> <% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %> <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)"> #[allow(unused_imports)] @@ -881,8 +1002,8 @@ input: &mut Parser<'i, 't>, ) -> Result<Longhands, ParseError<'i>> { let rect = Rect::parse_with(context, input, |_c, i| { - % if allow_quirks: - ${parser_function}_quirky(_c, i, specified::AllowQuirks::Yes) + % if allow_quirks != "No": + ${parser_function}_quirky(_c, i, specified::AllowQuirks::${allow_quirks}) % elif needs_context: ${parser_function}(_c, i) % else: diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index aa2d0247e82..d3b3ecd11e4 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -9,9 +9,7 @@ from itertools import groupby %> -#[cfg(feature = "gecko")] use crate::gecko_bindings::structs::RawServoAnimationValueMap; #[cfg(feature = "gecko")] use crate::gecko_bindings::structs::nsCSSPropertyID; -#[cfg(feature = "gecko")] use crate::gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI}; use itertools::{EitherOrBoth, Itertools}; use crate::properties::{CSSWideKeyword, PropertyDeclaration}; use crate::properties::longhands; @@ -190,13 +188,6 @@ impl AnimatedProperty { /// composed for each TransitionProperty. pub type AnimationValueMap = FxHashMap<LonghandId, AnimationValue>; -#[cfg(feature = "gecko")] -unsafe impl HasFFI for AnimationValueMap { - type FFIType = RawServoAnimationValueMap; -} -#[cfg(feature = "gecko")] -unsafe impl HasSimpleFFI for AnimationValueMap {} - /// An enum to represent a single computed value belonging to an animated /// property in order to be interpolated with another one. When interpolating, /// both values need to belong to the same property. @@ -773,6 +764,7 @@ macro_rules! animated_list_impl { } } +animated_list_impl!(<T> for crate::OwnedSlice<T>); animated_list_impl!(<T> for SmallVec<[T; 1]>); animated_list_impl!(<T> for Vec<T>); diff --git a/components/style/properties/longhands/background.mako.rs b/components/style/properties/longhands/background.mako.rs index 42344a18cb9..9c66e4676f9 100644 --- a/components/style/properties/longhands/background.mako.rs +++ b/components/style/properties/longhands/background.mako.rs @@ -14,7 +14,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-backgrounds/#background-color", animation_value_type="AnimatedColor", ignored_when_colors_disabled=True, - allow_quirks=True, + allow_quirks="Yes", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER \ CAN_ANIMATE_ON_COMPOSITOR", )} diff --git a/components/style/properties/longhands/border.mako.rs b/components/style/properties/longhands/border.mako.rs index 13a7f237350..7909372be17 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -28,7 +28,7 @@ animation_value_type="AnimatedColor", logical=is_logical, logical_group="border-color", - allow_quirks=not is_logical, + allow_quirks="No" if is_logical else "Yes", flags="APPLIES_TO_FIRST_LETTER", ignored_when_colors_disabled=True, )} @@ -56,7 +56,7 @@ logical=is_logical, logical_group="border-width", flags="APPLIES_TO_FIRST_LETTER GETCS_NEEDS_LAYOUT_FLUSH", - allow_quirks=not is_logical, + allow_quirks="No" if is_logical else "Yes", servo_restyle_damage="reflow rebuild_and_reflow_inline" )} % endfor @@ -159,60 +159,3 @@ ${helpers.predefined_type( 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) { - use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue}; - use crate::gecko::values::GeckoStyleCoordConvertible; - use crate::values::generics::border::BorderImageSideWidth; - - % for i in range(0, 4): - match self.${i} { - BorderImageSideWidth::Auto => { - sides.data_at_mut(${i}).set_value(CoordDataValue::Auto) - }, - BorderImageSideWidth::Length(l) => { - l.to_gecko_style_coord(&mut sides.data_at_mut(${i})) - }, - BorderImageSideWidth::Number(n) => { - sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n.0)) - }, - } - % endfor - } - - pub fn from_gecko_rect( - sides: &crate::gecko_bindings::structs::nsStyleSides, - ) -> Option<crate::values::computed::BorderImageWidth> { - use crate::gecko_bindings::structs::nsStyleUnit::{eStyleUnit_Factor, eStyleUnit_Auto}; - use crate::gecko_bindings::sugar::ns_style_coord::CoordData; - use crate::gecko::values::GeckoStyleCoordConvertible; - use crate::values::computed::{LengthPercentage, Number}; - use crate::values::generics::border::BorderImageSideWidth; - use crate::values::generics::NonNegative; - - Some( - crate::values::computed::BorderImageWidth::new( - % for i in range(0, 4): - match sides.data_at(${i}).unit() { - eStyleUnit_Auto => { - BorderImageSideWidth::Auto - }, - eStyleUnit_Factor => { - BorderImageSideWidth::Number( - NonNegative(Number::from_gecko_style_coord(&sides.data_at(${i})) - .expect("sides[${i}] could not convert to Number"))) - }, - _ => { - BorderImageSideWidth::Length( - NonNegative(LengthPercentage::from_gecko_style_coord(&sides.data_at(${i})) - .expect("sides[${i}] could not convert to LengthPercentage"))) - }, - }, - % endfor - ) - ) - } -} diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 6d754964ecc..da9e5b2e767 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -309,41 +309,6 @@ ${helpers.predefined_type( allowed_in_keyframe_block=False, )} -% for axis in ["x", "y"]: - ${helpers.predefined_type( - "scroll-snap-points-" + axis, - "ScrollSnapPoint", - "computed::ScrollSnapPoint::none()", - animation_value_type="discrete", - gecko_pref="layout.css.scroll-snap.enabled", - products="gecko", - spec="Nonstandard (https://www.w3.org/TR/2015/WD-css-snappoints-1-20150326/#scroll-snap-points)", - )} -% endfor - -${helpers.predefined_type( - "scroll-snap-destination", - "Position", - "computed::Position::zero()", - products="gecko", - gecko_pref="layout.css.scroll-snap.enabled", - boxed=True, - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)", - animation_value_type="discrete", -)} - -${helpers.predefined_type( - "scroll-snap-coordinate", - "Position", - "computed::Position::zero()", - vector=True, - allow_empty=True, - products="gecko", - gecko_pref="layout.css.scroll-snap.enabled", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)", - animation_value_type="discrete", -)} - <% transform_extra_prefixes = "moz:layout.css.prefixes.transforms webkit" %> ${helpers.predefined_type( @@ -352,7 +317,6 @@ ${helpers.predefined_type( "generics::transform::Transform::none()", extra_prefixes=transform_extra_prefixes, animation_value_type="ComputedValue", - gecko_ffi_name="mSpecifiedTransform", flags="CREATES_STACKING_CONTEXT FIXPOS_CB \ GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-transforms/#propdef-transform", @@ -405,6 +369,31 @@ ${helpers.predefined_type( gecko_pref="layout.css.motion-path.enabled", flags="CREATES_STACKING_CONTEXT FIXPOS_CB", spec="https://drafts.fxtf.org/motion-1/#offset-path-property", + servo_restyle_damage="reflow_out_of_flow" +)} + +// Motion Path Module Level 1 +${helpers.predefined_type( + "offset-distance", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + gecko_pref="layout.css.motion-path.enabled", + spec="https://drafts.fxtf.org/motion-1/#offset-distance-property", + servo_restyle_damage="reflow_out_of_flow" +)} + +// Motion Path Module Level 1 +${helpers.predefined_type( + "offset-rotate", + "OffsetRotate", + "computed::OffsetRotate::auto()", + products="gecko", + animation_value_type="none", + gecko_pref="layout.css.motion-path.enabled", + spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property", + servo_restyle_damage="reflow_out_of_flow" )} // CSSOM View Module diff --git a/components/style/properties/longhands/color.mako.rs b/components/style/properties/longhands/color.mako.rs index b367f2bbd86..a83787dd48e 100644 --- a/components/style/properties/longhands/color.mako.rs +++ b/components/style/properties/longhands/color.mako.rs @@ -35,6 +35,7 @@ pub mod system_colors { -moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext -moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight -moz-html-cellhighlighttext -moz-mac-buttonactivetext + -moz-gtk-buttonactivetext -moz-mac-chrome-active -moz-mac-chrome-inactive -moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect -moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect diff --git a/components/style/properties/longhands/effects.mako.rs b/components/style/properties/longhands/effects.mako.rs index 0b3f96f0dde..9bb8adda32e 100644 --- a/components/style/properties/longhands/effects.mako.rs +++ b/components/style/properties/longhands/effects.mako.rs @@ -23,6 +23,7 @@ ${helpers.predefined_type( "BoxShadow", None, vector=True, + simple_vector_bindings=True, animation_value_type="AnimatedBoxShadowList", vector_animation_type="with_zero", extra_prefixes="webkit", @@ -37,7 +38,7 @@ ${helpers.predefined_type( "computed::ClipRectOrAuto::auto()", animation_value_type="ComputedValue", boxed=True, - allow_quirks=True, + allow_quirks="Yes", spec="https://drafts.fxtf.org/css-masking/#clip-property", )} diff --git a/components/style/properties/longhands/font.mako.rs b/components/style/properties/longhands/font.mako.rs index c1d3d8fcc6c..8d84ef34cb3 100644 --- a/components/style/properties/longhands/font.mako.rs +++ b/components/style/properties/longhands/font.mako.rs @@ -64,7 +64,7 @@ ${helpers.predefined_type( initial_value="computed::FontSize::medium()", initial_specified_value="specified::FontSize::medium()", animation_value_type="NonNegativeLength", - allow_quirks=True, + allow_quirks="Yes", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", spec="https://drafts.csswg.org/css-fonts/#propdef-font-size", servo_restyle_damage="rebuild_and_reflow", diff --git a/components/style/properties/longhands/inherited_svg.mako.rs b/components/style/properties/longhands/inherited_svg.mako.rs index 2bbdc2794c2..c3e16ee475f 100644 --- a/components/style/properties/longhands/inherited_svg.mako.rs +++ b/components/style/properties/longhands/inherited_svg.mako.rs @@ -194,11 +194,8 @@ ${helpers.predefined_type( ${helpers.predefined_type( "-moz-context-properties", "MozContextProperties", - initial_value=None, - vector=True, - need_index=True, - animation_value_type="none", + "computed::MozContextProperties::default()", products="gecko", + animation_value_type="none", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)", - allow_empty=True, )} diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index cdd7df93256..e8f56cf2cde 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -56,7 +56,7 @@ ${helpers.predefined_type( "computed::LengthPercentage::zero()", animation_value_type="ComputedValue", spec="https://drafts.csswg.org/css-text/#propdef-text-indent", - allow_quirks=True, + allow_quirks="Yes", servo_restyle_damage = "reflow", )} @@ -218,6 +218,7 @@ ${helpers.predefined_type( vector_animation_type="with_zero", animation_value_type="AnimatedTextShadowList", ignored_when_colors_disabled=True, + simple_vector_bindings=True, flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property", )} @@ -263,6 +264,16 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-text-3/#tab-size-property", )} +${helpers.predefined_type( + "line-break", + "LineBreak", + "computed::LineBreak::Auto", + products="gecko", + animation_value_type="discrete", + spec="https://drafts.csswg.org/css-text-3/#line-break-property", + needs_context=False, +)} + // CSS Compatibility // https://compat.spec.whatwg.org ${helpers.predefined_type( diff --git a/components/style/properties/longhands/margin.mako.rs b/components/style/properties/longhands/margin.mako.rs index d2a3be11d1d..c3289c34b7c 100644 --- a/components/style/properties/longhands/margin.mako.rs +++ b/components/style/properties/longhands/margin.mako.rs @@ -17,7 +17,7 @@ "LengthPercentageOrAuto", "computed::LengthPercentageOrAuto::zero()", alias=maybe_moz_logical_alias(product, side, "-moz-margin-%s"), - allow_quirks=not side[1], + allow_quirks="No" if side[1] else "Yes", animation_value_type="ComputedValue", logical=side[1], logical_group="margin", diff --git a/components/style/properties/longhands/padding.mako.rs b/components/style/properties/longhands/padding.mako.rs index a1262aee0fc..6142bbf901e 100644 --- a/components/style/properties/longhands/padding.mako.rs +++ b/components/style/properties/longhands/padding.mako.rs @@ -24,7 +24,7 @@ logical_group="padding", spec=spec, flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH", - allow_quirks=not side[1], + allow_quirks="No" if side[1] else "Yes", servo_restyle_damage="reflow rebuild_and_reflow_inline" )} % endfor diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 096349f4b1c..34216385fed 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -17,7 +17,7 @@ spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side, flags="GETCS_NEEDS_LAYOUT_FLUSH", animation_value_type="ComputedValue", - allow_quirks=True, + allow_quirks="Yes", servo_restyle_damage="reflow_out_of_flow", logical_group="inset", )} @@ -253,7 +253,7 @@ ${helpers.predefined_type( "computed::Size::auto()", logical=logical, logical_group="size", - allow_quirks=not logical, + allow_quirks="No" if logical else "Yes", spec=spec % size, animation_value_type="Size", flags="GETCS_NEEDS_LAYOUT_FLUSH", @@ -266,7 +266,7 @@ ${helpers.predefined_type( "computed::Size::auto()", logical=logical, logical_group="min-size", - allow_quirks=not logical, + allow_quirks="No" if logical else "Yes", spec=spec % size, animation_value_type="Size", servo_restyle_damage="reflow", @@ -277,7 +277,7 @@ ${helpers.predefined_type( "computed::MaxSize::none()", logical=logical, logical_group="max-size", - allow_quirks=not logical, + allow_quirks="No" if logical else "Yes", spec=spec % size, animation_value_type="MaxSize", servo_restyle_damage="reflow", diff --git a/components/style/properties/longhands/svg.mako.rs b/components/style/properties/longhands/svg.mako.rs index 3e4d207397a..8e93d03dbb1 100644 --- a/components/style/properties/longhands/svg.mako.rs +++ b/components/style/properties/longhands/svg.mako.rs @@ -191,3 +191,66 @@ ${helpers.predefined_type( animation_value_type="discrete", flags="CREATES_STACKING_CONTEXT", )} + +${helpers.predefined_type( + "x", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://svgwg.org/svg2-draft/geometry.html#X", +)} + +${helpers.predefined_type( + "y", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://svgwg.org/svg2-draft/geometry.html#Y", +)} + +${helpers.predefined_type( + "cx", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://svgwg.org/svg2-draft/geometry.html#CX", +)} + +${helpers.predefined_type( + "cy", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://svgwg.org/svg2-draft/geometry.html#CY", +)} + +${helpers.predefined_type( + "rx", + "NonNegativeLengthPercentageOrAuto", + "computed::NonNegativeLengthPercentageOrAuto::auto()", + products="gecko", + animation_value_type="LengthPercentageOrAuto", + spec="https://svgwg.org/svg2-draft/geometry.html#RX", +)} + +${helpers.predefined_type( + "ry", + "NonNegativeLengthPercentageOrAuto", + "computed::NonNegativeLengthPercentageOrAuto::auto()", + products="gecko", + animation_value_type="LengthPercentageOrAuto", + spec="https://svgwg.org/svg2-draft/geometry.html#RY", +)} + +${helpers.predefined_type( + "r", + "NonNegativeLengthPercentage", + "computed::NonNegativeLengthPercentage::zero()", + products="gecko", + animation_value_type="LengthPercentage", + spec="https://svgwg.org/svg2-draft/geometry.html#R", +)} diff --git a/components/style/properties/longhands/ui.mako.rs b/components/style/properties/longhands/ui.mako.rs index c54582e2584..5c51569089c 100644 --- a/components/style/properties/longhands/ui.mako.rs +++ b/components/style/properties/longhands/ui.mako.rs @@ -32,12 +32,11 @@ ${helpers.single_keyword( )} ${helpers.predefined_type( - "-moz-user-select", + "user-select", "UserSelect", "computed::UserSelect::Auto", products="gecko", - gecko_ffi_name="mUserSelect", - alias="-webkit-user-select", + extra_prefixes="moz webkit", animation_value_type="discrete", needs_context=False, spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select", @@ -81,7 +80,6 @@ ${helpers.predefined_type( "Transform", "generics::transform::Transform::none()", products="gecko", - gecko_ffi_name="mSpecifiedWindowTransform", flags="GETCS_NEEDS_LAYOUT_FLUSH", animation_value_type="ComputedValue", spec="None (Nonstandard internal property)", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index a9fa35ba444..520b4a32b51 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2337,6 +2337,14 @@ impl SourcePropertyDeclaration { } } + /// Create one with a single PropertyDeclaration. + #[inline] + pub fn with_one(decl: PropertyDeclaration) -> Self { + let mut result = Self::new(); + result.declarations.push(decl); + result + } + /// Similar to Vec::drain: leaves this empty when the return value is dropped. pub fn drain(&mut self) -> SourcePropertyDeclarationDrain { SourcePropertyDeclarationDrain { @@ -2474,20 +2482,7 @@ pub mod style_structs { % if longhand.logical: ${helpers.logical_setter(name=longhand.name)} % else: - % if longhand.is_vector: - /// Set ${longhand.name}. - #[allow(non_snake_case)] - #[inline] - pub fn set_${longhand.ident}<I>(&mut self, v: I) - where - I: IntoIterator<Item = longhands::${longhand.ident} - ::computed_value::single_value::T>, - I::IntoIter: ExactSizeIterator - { - self.${longhand.ident} = longhands::${longhand.ident}::computed_value - ::List(v.into_iter().collect()); - } - % elif longhand.ident == "display": + % if longhand.ident == "display": /// Set `display`. /// /// We need to keep track of the original display for hypothetical boxes, @@ -3101,7 +3096,7 @@ impl ComputedValuesInner { pub fn transform_requires_layer(&self) -> bool { use crate::values::generics::transform::TransformOperation; // Check if the transform matrix is 2D or 3D - for transform in &self.get_box().transform.0 { + for transform in &*self.get_box().transform.0 { match *transform { TransformOperation::Perspective(..) => { return true; @@ -3444,7 +3439,7 @@ impl<'a> StyleBuilder<'a> { } % endif - % if not property.is_vector: + % if not property.is_vector or property.simple_vector_bindings or product != "gecko": /// Set the `${property.ident}` to the computed value `value`. #[allow(non_snake_case)] pub fn set_${property.ident}( diff --git a/components/style/properties/shorthands/background.mako.rs b/components/style/properties/shorthands/background.mako.rs index c73009ab2ba..af98342bfe6 100644 --- a/components/style/properties/shorthands/background.mako.rs +++ b/components/style/properties/shorthands/background.mako.rs @@ -40,11 +40,11 @@ let mut background_color = None; % for name in "image position_x position_y repeat size attachment origin clip".split(): - // Vec grows from 0 to 4 by default on first push(). So allocate - // with capacity 1, so in the common case of only one item we don't - // way overallocate. Note that we always push at least one item if - // parsing succeeds. - let mut background_${name} = background_${name}::SpecifiedValue(Vec::with_capacity(1)); + // Vec grows from 0 to 4 by default on first push(). So allocate with + // capacity 1, so in the common case of only one item we don't way + // overallocate, then shrink. Note that we always push at least one + // item if parsing succeeds. + let mut background_${name} = Vec::with_capacity(1); % endfor input.parse_comma_separated(|input| { // background-color can only be in the last element, so if it @@ -99,17 +99,17 @@ any = any || background_color.is_some(); if any { if let Some(position) = position { - background_position_x.0.push(position.horizontal); - background_position_y.0.push(position.vertical); + background_position_x.push(position.horizontal); + background_position_y.push(position.vertical); } else { - background_position_x.0.push(PositionComponent::zero()); - background_position_y.0.push(PositionComponent::zero()); + background_position_x.push(PositionComponent::zero()); + background_position_y.push(PositionComponent::zero()); } % for name in "image repeat size attachment origin clip".split(): if let Some(bg_${name}) = ${name} { - background_${name}.0.push(bg_${name}); + background_${name}.push(bg_${name}); } else { - background_${name}.0.push(background_${name}::single_value + background_${name}.push(background_${name}::single_value ::get_initial_specified_value()); } % endfor @@ -121,14 +121,9 @@ Ok(expanded! { background_color: background_color.unwrap_or(Color::transparent()), - background_image: background_image, - background_position_x: background_position_x, - background_position_y: background_position_y, - background_repeat: background_repeat, - background_attachment: background_attachment, - background_size: background_size, - background_origin: background_origin, - background_clip: background_clip, + % for name in "image position_x position_y repeat size attachment origin clip".split(): + background_${name}: background_${name}::SpecifiedValue(background_${name}.into()), + % endfor }) } @@ -209,16 +204,16 @@ ) -> Result<Longhands, ParseError<'i>> { // Vec grows from 0 to 4 by default on first push(). So allocate with // capacity 1, so in the common case of only one item we don't way - // overallocate. Note that we always push at least one item if parsing - // succeeds. - let mut position_x = background_position_x::SpecifiedValue(Vec::with_capacity(1)); - let mut position_y = background_position_y::SpecifiedValue(Vec::with_capacity(1)); + // overallocate, then shrink. Note that we always push at least one + // item if parsing succeeds. + let mut position_x = Vec::with_capacity(1); + let mut position_y = Vec::with_capacity(1); let mut any = false; input.parse_comma_separated(|input| { let value = Position::parse_quirky(context, input, AllowQuirks::Yes)?; - position_x.0.push(value.horizontal); - position_y.0.push(value.vertical); + position_x.push(value.horizontal); + position_y.push(value.vertical); any = true; Ok(()) })?; @@ -227,8 +222,8 @@ } Ok(expanded! { - background_position_x: position_x, - background_position_y: position_y, + background_position_x: background_position_x::SpecifiedValue(position_x.into()), + background_position_y: background_position_y::SpecifiedValue(position_y.into()), }) } diff --git a/components/style/properties/shorthands/border.mako.rs b/components/style/properties/shorthands/border.mako.rs index cd472068793..1f8df0df6a1 100644 --- a/components/style/properties/shorthands/border.mako.rs +++ b/components/style/properties/shorthands/border.mako.rs @@ -7,7 +7,7 @@ ${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::Color::parse", spec="https://drafts.csswg.org/css-backgrounds/#border-color", - allow_quirks=True)} + allow_quirks="Yes")} ${helpers.four_sides_shorthand( "border-style", diff --git a/components/style/properties/shorthands/box.mako.rs b/components/style/properties/shorthands/box.mako.rs index 5c03dba8529..e69593f1cc1 100644 --- a/components/style/properties/shorthands/box.mako.rs +++ b/components/style/properties/shorthands/box.mako.rs @@ -137,7 +137,7 @@ macro_rules! try_parse_one { Ok(expanded! { % for prop in "property duration timing_function delay".split(): - transition_${prop}: transition_${prop}::SpecifiedValue(${prop}s), + transition_${prop}: transition_${prop}::SpecifiedValue(${prop}s.into()), % endfor }) } @@ -266,7 +266,7 @@ macro_rules! try_parse_one { Ok(expanded! { % for prop in props: - animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s), + animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s.into()), % endfor }) } diff --git a/components/style/properties/shorthands/margin.mako.rs b/components/style/properties/shorthands/margin.mako.rs index fd3124a6ae1..9b996abbe86 100644 --- a/components/style/properties/shorthands/margin.mako.rs +++ b/components/style/properties/shorthands/margin.mako.rs @@ -10,7 +10,7 @@ ${helpers.four_sides_shorthand( "specified::LengthPercentageOrAuto::parse", spec="https://drafts.csswg.org/css-box/#propdef-margin", allowed_in_page_rule=True, - allow_quirks=True, + allow_quirks="Yes", )} ${helpers.two_properties_shorthand( diff --git a/components/style/properties/shorthands/padding.mako.rs b/components/style/properties/shorthands/padding.mako.rs index a4e013caabc..8d50c3b9e38 100644 --- a/components/style/properties/shorthands/padding.mako.rs +++ b/components/style/properties/shorthands/padding.mako.rs @@ -9,7 +9,7 @@ ${helpers.four_sides_shorthand( "padding-%s", "specified::NonNegativeLengthPercentage::parse", spec="https://drafts.csswg.org/css-box-3/#propdef-padding", - allow_quirks=True, + allow_quirks="Yes", )} ${helpers.two_properties_shorthand( diff --git a/components/style/properties/shorthands/position.mako.rs b/components/style/properties/shorthands/position.mako.rs index 6fdbe1235cf..63298b86ba1 100644 --- a/components/style/properties/shorthands/position.mako.rs +++ b/components/style/properties/shorthands/position.mako.rs @@ -768,7 +768,7 @@ ${helpers.four_sides_shorthand( "%s", "specified::LengthPercentageOrAuto::parse", spec="https://drafts.csswg.org/css-logical/#propdef-inset", - allow_quirks=False, + allow_quirks="No", )} ${helpers.two_properties_shorthand( diff --git a/components/style/properties/shorthands/svg.mako.rs b/components/style/properties/shorthands/svg.mako.rs index f6941c4e7f8..0acaff426cf 100644 --- a/components/style/properties/shorthands/svg.mako.rs +++ b/components/style/properties/shorthands/svg.mako.rs @@ -42,11 +42,11 @@ input: &mut Parser<'i, 't>, ) -> Result<Longhands, ParseError<'i>> { % for name in "image mode position_x position_y size repeat origin clip composite".split(): - // Vec grows from 0 to 4 by default on first push(). So allocate - // with capacity 1, so in the common case of only one item we don't - // way overallocate. Note that we always push at least one item if - // parsing succeeds. - let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::with_capacity(1)); + // Vec grows from 0 to 4 by default on first push(). So allocate with + // capacity 1, so in the common case of only one item we don't way + // overallocate, then shrink. Note that we always push at least one + // item if parsing succeeds. + let mut mask_${name} = Vec::with_capacity(1); % endfor input.parse_comma_separated(|input| { @@ -96,17 +96,17 @@ % endfor if any { if let Some(position) = position { - mask_position_x.0.push(position.horizontal); - mask_position_y.0.push(position.vertical); + mask_position_x.push(position.horizontal); + mask_position_y.push(position.vertical); } else { - mask_position_x.0.push(PositionComponent::zero()); - mask_position_y.0.push(PositionComponent::zero()); + mask_position_x.push(PositionComponent::zero()); + mask_position_y.push(PositionComponent::zero()); } % for name in "image mode size repeat origin clip composite".split(): if let Some(m_${name}) = ${name} { - mask_${name}.0.push(m_${name}); + mask_${name}.push(m_${name}); } else { - mask_${name}.0.push(mask_${name}::single_value + mask_${name}.push(mask_${name}::single_value ::get_initial_specified_value()); } % endfor @@ -118,7 +118,7 @@ Ok(expanded! { % for name in "image mode position_x position_y size repeat origin clip composite".split(): - mask_${name}: mask_${name}, + mask_${name}: mask_${name}::SpecifiedValue(mask_${name}.into()), % endfor }) } @@ -209,16 +209,16 @@ ) -> Result<Longhands, ParseError<'i>> { // Vec grows from 0 to 4 by default on first push(). So allocate with // capacity 1, so in the common case of only one item we don't way - // overallocate. Note that we always push at least one item if parsing - // succeeds. - let mut position_x = mask_position_x::SpecifiedValue(Vec::with_capacity(1)); - let mut position_y = mask_position_y::SpecifiedValue(Vec::with_capacity(1)); + // overallocate, then shrink. Note that we always push at least one + // item if parsing succeeds. + let mut position_x = Vec::with_capacity(1); + let mut position_y = Vec::with_capacity(1); let mut any = false; input.parse_comma_separated(|input| { let value = Position::parse(context, input)?; - position_x.0.push(value.horizontal); - position_y.0.push(value.vertical); + position_x.push(value.horizontal); + position_y.push(value.vertical); any = true; Ok(()) })?; @@ -227,9 +227,10 @@ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } + Ok(expanded! { - mask_position_x: position_x, - mask_position_y: position_y, + mask_position_x: mask_position_x::SpecifiedValue(position_x.into()), + mask_position_y: mask_position_y::SpecifiedValue(position_y.into()), }) } diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs index e87a86c5e47..360b8101ef1 100644 --- a/components/style/rule_collector.rs +++ b/components/style/rule_collector.rs @@ -13,7 +13,7 @@ use crate::selector_parser::PseudoElement; use crate::shared_lock::Locked; use crate::stylesheets::Origin; use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist}; -use selectors::matching::{ElementSelectorFlags, MatchingContext}; +use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode}; use servo_arc::ArcBorrow; use smallvec::SmallVec; @@ -97,8 +97,15 @@ where context: &'a mut MatchingContext<'b, E::Impl>, flags_setter: &'a mut F, ) -> Self { - let rule_hash_target = element.rule_hash_target(); - let matches_user_and_author_rules = element.matches_user_and_author_rules(); + // When we're matching with matching_mode = + // `ForStatelessPseudoeElement`, the "target" for the rule hash is the + // element itself, since it's what's generating the pseudo-element. + let rule_hash_target = match context.matching_mode() { + MatchingMode::ForStatelessPseudoElement => element, + MatchingMode::Normal => element.rule_hash_target(), + }; + + let matches_user_and_author_rules = rule_hash_target.matches_user_and_author_rules(); // Gecko definitely has pseudo-elements with style attributes, like // ::-moz-color-swatch. @@ -120,8 +127,8 @@ where context, flags_setter, rules, - matches_user_and_author_rules, shadow_cascade_order: 0, + matches_user_and_author_rules, matches_document_author_rules: matches_user_and_author_rules, } } diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs index 63af60e16ab..21b6fbd60ca 100644 --- a/components/style/style_adjuster.rs +++ b/components/style/style_adjuster.rs @@ -734,10 +734,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { E: TElement, { if cfg!(debug_assertions) { - if element - .and_then(|e| e.implemented_pseudo_element()) - .is_some() - { + if element.map_or(false, |e| e.is_pseudo_element()) { // It'd be nice to assert `self.style.pseudo == Some(&pseudo)`, // but we do resolve ::-moz-list pseudos on ::before / ::after // content, sigh. diff --git a/components/style/style_resolver.rs b/components/style/style_resolver.rs index 11c81283a13..180de3ff281 100644 --- a/components/style/style_resolver.rs +++ b/components/style/style_resolver.rs @@ -233,7 +233,7 @@ where let mut pseudo_styles = EagerPseudoStyles::default(); - if self.element.implemented_pseudo_element().is_none() { + if !self.element.is_pseudo_element() { let layout_parent_style_for_pseudo = if primary_style.style().is_display_contents() { layout_parent_style } else { @@ -293,10 +293,6 @@ where layout_parent_style: Option<&ComputedValues>, pseudo: Option<&PseudoElement>, ) -> ResolvedStyle { - debug_assert!( - self.element.implemented_pseudo_element().is_none() || pseudo.is_none(), - "Pseudo-elements can't have other pseudos!" - ); debug_assert!(pseudo.map_or(true, |p| p.is_eager())); let implemented_pseudo = self.element.implemented_pseudo_element(); @@ -477,8 +473,8 @@ where ); debug_assert!(pseudo_element.is_eager()); debug_assert!( - self.element.implemented_pseudo_element().is_none(), - "Element pseudos can't have any other pseudo." + !self.element.is_pseudo_element(), + "Element pseudos can't have any other eager pseudo." ); let mut applicable_declarations = ApplicableDeclarationList::new(); diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 2953e3f0671..cba1cbac524 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -1195,6 +1195,10 @@ impl Stylist { // See [3] for the bug to implement whatever gets resolved, and related // bugs for a bit more context. // + // FIXME(emilio): This should probably work for pseudo-elements (i.e., + // use rule_hash_target().shadow_root() instead of + // element.shadow_root()). + // // [1]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/ // core/css/resolver/style_resolver.cc?l=1267&rcl=90f9f8680ebb4a87d177f3b0833372ae4e0c88d8 // [2]: https://github.com/w3c/csswg-drafts/issues/1995 diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs index 87f58fb2f82..4c559cd4c30 100644 --- a/components/style/values/animated/effects.rs +++ b/components/style/values/animated/effects.rs @@ -9,22 +9,18 @@ use crate::values::computed::length::Length; #[cfg(feature = "gecko")] use crate::values::computed::url::ComputedUrl; use crate::values::computed::{Angle, Number}; -use crate::values::generics::effects::BoxShadow as GenericBoxShadow; use crate::values::generics::effects::Filter as GenericFilter; use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow; #[cfg(not(feature = "gecko"))] use crate::values::Impossible; -/// An animated value for a single `box-shadow`. -pub type BoxShadow = GenericBoxShadow<Color, Length, Length, Length>; +/// An animated value for the `drop-shadow()` filter. +pub type AnimatedSimpleShadow = GenericSimpleShadow<Color, Length, Length>; /// An animated value for a single `filter`. #[cfg(feature = "gecko")] -pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>; +pub type Filter = GenericFilter<Angle, Number, Length, AnimatedSimpleShadow, ComputedUrl>; /// An animated value for a single `filter`. #[cfg(not(feature = "gecko"))] pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>; - -/// An animated value for the `drop-shadow()` filter. -pub type SimpleShadow = GenericSimpleShadow<Color, Length, Length>; diff --git a/components/style/values/animated/transform.rs b/components/style/values/animated/transform.rs index 0c322d8fccc..9ac64c3f2a7 100644 --- a/components/style/values/animated/transform.rs +++ b/components/style/values/animated/transform.rs @@ -861,7 +861,7 @@ impl Animate for ComputedTransform { // animation procedures so we treat it separately here rather than // handling it in TransformOperation. if procedure == Procedure::Add { - let result = self.0.iter().chain(&other.0).cloned().collect::<Vec<_>>(); + let result = self.0.iter().chain(&*other.0).cloned().collect(); return Ok(Transform(result)); } @@ -898,15 +898,15 @@ impl Animate for ComputedTransform { }, Procedure::Interpolate { progress } => { result.push(TransformOperation::InterpolateMatrix { - from_list: Transform(this_remainder.to_vec()), - to_list: Transform(other_remainder.to_vec()), + from_list: Transform(this_remainder.to_vec().into()), + to_list: Transform(other_remainder.to_vec().into()), progress: Percentage(progress as f32), }); }, Procedure::Accumulate { count } => { result.push(TransformOperation::AccumulateMatrix { - from_list: Transform(this_remainder.to_vec()), - to_list: Transform(other_remainder.to_vec()), + from_list: Transform(this_remainder.to_vec().into()), + to_list: Transform(other_remainder.to_vec().into()), count: cmp::min(count, i32::max_value() as u64) as i32, }); }, @@ -927,8 +927,8 @@ impl Animate for ComputedTransform { // matrix. Instead we need to wrap it in another ___Matrix type. TransformOperation::AccumulateMatrix { .. } | TransformOperation::InterpolateMatrix { .. } => { - let transform_list = Transform(vec![transform.clone()]); - let identity_list = Transform(vec![identity]); + let transform_list = Transform(vec![transform.clone()].into()); + let identity_list = Transform(vec![identity].into()); let (from_list, to_list) = if fill_right { (transform_list, identity_list) } else { @@ -970,7 +970,7 @@ impl Animate for ComputedTransform { (None, None) => {}, } - Ok(Transform(result)) + Ok(Transform(result.into())) } } diff --git a/components/style/values/computed/angle.rs b/components/style/values/computed/angle.rs index cdbc0006941..d8cdefb5263 100644 --- a/components/style/values/computed/angle.rs +++ b/components/style/values/computed/angle.rs @@ -26,6 +26,7 @@ use style_traits::{CssWriter, ToCss}; ToAnimatedZero, ToResolvedValue, )] +#[repr(C)] pub struct Angle(CSSFloat); impl ToCss for Angle { diff --git a/components/style/values/computed/border.rs b/components/style/values/computed/border.rs index 62c8e3883f6..abdc28ad848 100644 --- a/components/style/values/computed/border.rs +++ b/components/style/values/computed/border.rs @@ -7,10 +7,10 @@ use crate::values::computed::length::{NonNegativeLength, NonNegativeLengthPercentage}; 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; use crate::values::generics::border::BorderRadius as GenericBorderRadius; use crate::values::generics::border::BorderSpacing as GenericBorderSpacing; +use crate::values::generics::border::GenericBorderImageSideWidth; use crate::values::generics::rect::Rect; use crate::values::generics::size::Size2D; use crate::values::generics::NonNegative; diff --git a/components/style/values/computed/gecko.rs b/components/style/values/computed/gecko.rs deleted file mode 100644 index cbe0802eab8..00000000000 --- a/components/style/values/computed/gecko.rs +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -//! Computed types for legacy Gecko-only properties. - -use crate::values::computed::length::LengthPercentage; -use crate::values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint; - -/// A computed type for scroll snap points. -pub type ScrollSnapPoint = GenericScrollSnapPoint<LengthPercentage>; diff --git a/components/style/values/computed/list.rs b/components/style/values/computed/list.rs index 2bde35e3b6b..3536aa656fe 100644 --- a/components/style/values/computed/list.rs +++ b/components/style/values/computed/list.rs @@ -9,21 +9,19 @@ pub use crate::values::specified::list::ListStyleType; pub use crate::values::specified::list::MozListReversed; pub use crate::values::specified::list::{QuotePair, Quotes}; -use servo_arc::Arc; - lazy_static! { - static ref INITIAL_QUOTES: Arc<Box<[QuotePair]>> = Arc::new( + static ref INITIAL_QUOTES: crate::ArcSlice<QuotePair> = crate::ArcSlice::from_iter( vec![ QuotePair { - opening: "\u{201c}".to_owned().into_boxed_str(), - closing: "\u{201d}".to_owned().into_boxed_str(), + opening: "\u{201c}".to_owned().into(), + closing: "\u{201d}".to_owned().into(), }, QuotePair { - opening: "\u{2018}".to_owned().into_boxed_str(), - closing: "\u{2019}".to_owned().into_boxed_str(), + opening: "\u{2018}".to_owned().into(), + closing: "\u{2019}".to_owned().into(), }, ] - .into_boxed_slice() + .into_iter() ); } diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 5bf0333dbfe..06579238e77 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -56,8 +56,6 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis}; pub use self::font::{FontVariantAlternates, FontWeight}; pub use self::font::{FontVariantEastAsian, FontVariationSettings}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; -#[cfg(feature = "gecko")] -pub use self::gecko::ScrollSnapPoint; pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect}; pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength}; pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber}; @@ -67,7 +65,7 @@ pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageO pub use self::list::ListStyleType; pub use self::list::MozListReversed; pub use self::list::{QuotePair, Quotes}; -pub use self::motion::OffsetPath; +pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::outline::OutlineStyle; pub use self::percentage::{NonNegativePercentage, Percentage}; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex}; @@ -77,7 +75,7 @@ pub use self::svg::MozContextProperties; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::table::XSpan; -pub use self::text::{InitialLetter, LetterSpacing, LineHeight}; +pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight}; pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing}; pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle}; pub use self::time::Time; @@ -106,8 +104,6 @@ pub mod easing; pub mod effects; pub mod flex; pub mod font; -#[cfg(feature = "gecko")] -pub mod gecko; pub mod image; pub mod length; pub mod list; @@ -454,17 +450,12 @@ where fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { self.iter() .map(|item| item.to_computed_value(context)) - .collect::<Vec<_>>() - .into() + .collect() } #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { - computed - .iter() - .map(T::from_computed_value) - .collect::<Vec<_>>() - .into() + computed.iter().map(T::from_computed_value).collect() } } diff --git a/components/style/values/computed/motion.rs b/components/style/values/computed/motion.rs index a5f1fa885c3..932d8074262 100644 --- a/components/style/values/computed/motion.rs +++ b/components/style/values/computed/motion.rs @@ -4,7 +4,41 @@ //! Computed types for CSS values that are related to motion path. +use crate::values::computed::Angle; +use crate::Zero; + /// A computed offset-path. The computed value is as specified value. /// /// https://drafts.fxtf.org/motion-1/#offset-path-property pub use crate::values::specified::motion::OffsetPath; + +#[inline] +fn is_auto_zero_angle(auto: &bool, angle: &Angle) -> bool { + *auto && angle.is_zero() +} + +/// A computed offset-rotate. +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)] +#[repr(C)] +pub struct OffsetRotate { + /// If auto is false, this is a fixed angle which indicates a + /// constant clockwise rotation transformation applied to it by this + /// specified rotation angle. Otherwise, the angle will be added to + /// the angle of the direction in layout. + #[css(represents_keyword)] + pub auto: bool, + /// The angle value. + #[css(contextual_skip_if = "is_auto_zero_angle")] + pub angle: Angle, +} + +impl OffsetRotate { + /// Returns "auto 0deg". + #[inline] + pub fn auto() -> Self { + OffsetRotate { + auto: true, + angle: Zero::zero(), + } + } +} diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index c29d3d45210..bc4086a2b9c 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -20,7 +20,7 @@ use style_traits::{CssWriter, ToCss}; pub use crate::values::specified::TextAlignKeyword as TextAlign; pub use crate::values::specified::TextTransform; -pub use crate::values::specified::{OverflowWrap, WordBreak}; +pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak}; pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition}; /// A computed value for the `initial-letter` property. @@ -105,6 +105,7 @@ impl ToComputedValue for specified::WordSpacing { pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLength>; #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToResolvedValue)] +#[repr(C)] /// text-overflow. /// When the specified value only has one side, that's the "second" /// side, and the sides are logical, so "second" means "end". The diff --git a/components/style/values/computed/transform.rs b/components/style/values/computed/transform.rs index e23ec1524ff..9104a43ae5b 100644 --- a/components/style/values/computed/transform.rs +++ b/components/style/values/computed/transform.rs @@ -16,9 +16,9 @@ pub use crate::values::generics::transform::TransformStyle; /// A single operation in a computed CSS `transform` pub type TransformOperation = - generic::TransformOperation<Angle, Number, Length, Integer, LengthPercentage>; + generic::GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>; /// A computed CSS `transform` -pub type Transform = generic::Transform<TransformOperation>; +pub type Transform = generic::GenericTransform<TransformOperation>; /// The computed value of a CSS `<transform-origin>` pub type TransformOrigin = @@ -540,88 +540,16 @@ impl ToAnimatedZero for Transform { self.0 .iter() .map(|op| op.to_animated_zero()) - .collect::<Result<Vec<_>, _>>()?, + .collect::<Result<crate::OwnedSlice<_>, _>>()?, )) } } /// A computed CSS `rotate` -pub type Rotate = generic::Rotate<Number, Angle>; - -impl Rotate { - /// Convert TransformOperation to Rotate. - pub fn to_transform_operation(&self) -> Option<TransformOperation> { - match *self { - generic::Rotate::None => None, - generic::Rotate::Rotate(angle) => Some(generic::TransformOperation::Rotate(angle)), - generic::Rotate::Rotate3D(rx, ry, rz, angle) => { - Some(generic::TransformOperation::Rotate3D(rx, ry, rz, angle)) - }, - } - } - - /// Convert Rotate to TransformOperation. - pub fn from_transform_operation(operation: &TransformOperation) -> Rotate { - match *operation { - generic::TransformOperation::Rotate(angle) => generic::Rotate::Rotate(angle), - generic::TransformOperation::Rotate3D(rx, ry, rz, angle) => { - generic::Rotate::Rotate3D(rx, ry, rz, angle) - }, - _ => unreachable!("Found unexpected value for rotate property"), - } - } -} +pub type Rotate = generic::GenericRotate<Number, Angle>; /// A computed CSS `translate` -pub type Translate = generic::Translate<LengthPercentage, Length>; - -impl Translate { - /// Convert TransformOperation to Translate. - pub fn to_transform_operation(&self) -> Option<TransformOperation> { - match *self { - generic::Translate::None => None, - generic::Translate::Translate(tx, ty) => { - Some(generic::TransformOperation::Translate(tx, ty)) - }, - generic::Translate::Translate3D(tx, ty, tz) => { - Some(generic::TransformOperation::Translate3D(tx, ty, tz)) - }, - } - } - - /// Convert Translate to TransformOperation. - pub fn from_transform_operation(operation: &TransformOperation) -> Translate { - match *operation { - generic::TransformOperation::Translate(tx, ty) => generic::Translate::Translate(tx, ty), - generic::TransformOperation::Translate3D(tx, ty, tz) => { - generic::Translate::Translate3D(tx, ty, tz) - }, - _ => unreachable!("Found unexpected value for translate"), - } - } -} +pub type Translate = generic::GenericTranslate<LengthPercentage, Length>; /// A computed CSS `scale` -pub type Scale = generic::Scale<Number>; - -impl Scale { - /// Convert TransformOperation to Scale. - pub fn to_transform_operation(&self) -> Option<TransformOperation> { - match *self { - generic::Scale::None => None, - generic::Scale::Scale(sx, sy) => Some(generic::TransformOperation::Scale(sx, sy)), - generic::Scale::Scale3D(sx, sy, sz) => { - Some(generic::TransformOperation::Scale3D(sx, sy, sz)) - }, - } - } - - /// Convert Scale to TransformOperation. - pub fn from_transform_operation(operation: &TransformOperation) -> Scale { - match *operation { - generic::TransformOperation::Scale(sx, sy) => generic::Scale::Scale(sx, sy), - generic::TransformOperation::Scale3D(sx, sy, sz) => generic::Scale::Scale3D(sx, sy, sz), - _ => unreachable!("Found unexpected value for scale"), - } - } -} +pub type Scale = generic::GenericScale<Number>; diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs index ec0ab1c4b07..f36062ce39b 100644 --- a/components/style/values/generics/border.rs +++ b/components/style/values/generics/border.rs @@ -23,15 +23,18 @@ use style_traits::{CssWriter, ToCss}; ToResolvedValue, ToShmem, )] -pub enum BorderImageSideWidth<LengthPercentage, Number> { +#[repr(C, u8)] +pub enum GenericBorderImageSideWidth<LP, N> { /// `<length-or-percentage>` - Length(LengthPercentage), + LengthPercentage(LP), /// `<number>` - Number(Number), + Number(N), /// `auto` Auto, } +pub use self::GenericBorderImageSideWidth as BorderImageSideWidth; + /// A generic value for the `border-image-slice` property. #[derive( Clone, diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs index aa56fc1bbb3..a27adc49e52 100644 --- a/components/style/values/generics/effects.rs +++ b/components/style/values/generics/effects.rs @@ -19,9 +19,10 @@ ToResolvedValue, ToShmem, )] -pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> { +#[repr(C)] +pub struct GenericBoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> { /// The base shadow. - pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>, + pub base: GenericSimpleShadow<Color, SizeLength, BlurShapeLength>, /// The spread radius. pub spread: ShapeLength, /// Whether this is an inset box shadow. @@ -30,6 +31,8 @@ pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> { pub inset: bool, } +pub use self::GenericBoxShadow as BoxShadow; + /// A generic value for a single `filter`. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[animation(no_bound(Url))] @@ -100,7 +103,8 @@ pub enum Filter<Angle, Factor, Length, DropShadow, Url> { ToResolvedValue, ToShmem, )] -pub struct SimpleShadow<Color, SizeLength, ShapeLength> { +#[repr(C)] +pub struct GenericSimpleShadow<Color, SizeLength, ShapeLength> { /// Color. pub color: Color, /// Horizontal radius. @@ -110,3 +114,5 @@ pub struct SimpleShadow<Color, SizeLength, ShapeLength> { /// Blur radius. pub blur: ShapeLength, } + +pub use self::GenericSimpleShadow as SimpleShadow; diff --git a/components/style/values/generics/gecko.rs b/components/style/values/generics/gecko.rs deleted file mode 100644 index ccff3d2a76d..00000000000 --- a/components/style/values/generics/gecko.rs +++ /dev/null @@ -1,44 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -//! Generic types for legacy Gecko-only properties that should probably be -//! un-shipped at some point in the future. - -/// A generic value for scroll snap points. -#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive( - Clone, - Copy, - Debug, - PartialEq, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -pub enum ScrollSnapPoint<LengthPercentage> { - /// `none` - None, - /// `repeat(<length-or-percentage>)` - #[css(function)] - Repeat(LengthPercentage), -} - -impl<L> ScrollSnapPoint<L> { - /// Returns `none`. - #[inline] - pub fn none() -> Self { - ScrollSnapPoint::None - } - - /// Returns the repeat argument, if any. - #[inline] - pub fn repeated(&self) -> Option<&L> { - match *self { - ScrollSnapPoint::None => None, - ScrollSnapPoint::Repeat(ref length) => Some(length), - } - } -} diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index d735e3bbdef..08ae15a4c2c 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -26,8 +26,6 @@ pub mod easing; pub mod effects; pub mod flex; pub mod font; -#[cfg(feature = "gecko")] -pub mod gecko; pub mod grid; pub mod image; pub mod length; diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index 6c6374db941..ba0e320865a 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -30,8 +30,9 @@ use style_traits::{CssWriter, ToCss}; ToResolvedValue, ToShmem, )] -#[css(comma, function)] -pub struct Matrix<T> { +#[css(comma, function = "matrix")] +#[repr(C)] +pub struct GenericMatrix<T> { pub a: T, pub b: T, pub c: T, @@ -40,6 +41,8 @@ pub struct Matrix<T> { pub f: T, } +pub use self::GenericMatrix as Matrix; + #[allow(missing_docs)] #[cfg_attr(rustfmt, rustfmt_skip)] #[css(comma, function = "matrix3d")] @@ -55,13 +58,16 @@ pub struct Matrix<T> { ToResolvedValue, ToShmem, )] -pub struct Matrix3D<T> { +#[repr(C)] +pub struct GenericMatrix3D<T> { pub m11: T, pub m12: T, pub m13: T, pub m14: T, pub m21: T, pub m22: T, pub m23: T, pub m24: T, pub m31: T, pub m32: T, pub m33: T, pub m34: T, pub m41: T, pub m42: T, pub m43: T, pub m44: T, } +pub use self::GenericMatrix3D as Matrix3D; + #[cfg_attr(rustfmt, rustfmt_skip)] impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> { #[inline] @@ -142,17 +148,19 @@ fn is_same<N: PartialEq>(x: &N, y: &N) -> bool { ToResolvedValue, ToShmem, )] +#[repr(C, u8)] /// A single operation in the list of a `transform` value -pub enum TransformOperation<Angle, Number, Length, Integer, LengthPercentage> +/// cbindgen:derive-tagged-enum-copy-constructor=true +pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage> where Angle: Zero, LengthPercentage: Zero, Number: PartialEq, { /// Represents a 2D 2x3 matrix. - Matrix(Matrix<Number>), + Matrix(GenericMatrix<Number>), /// Represents a 3D 4x4 matrix. - Matrix3D(Matrix3D<Number>), + Matrix3D(GenericMatrix3D<Number>), /// A 2D skew. /// /// If the second angle is not provided it is assumed zero. @@ -232,20 +240,30 @@ where #[allow(missing_docs)] #[css(comma, function = "interpolatematrix")] InterpolateMatrix { - from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, - to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, + from_list: GenericTransform< + GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>, + >, + to_list: GenericTransform< + GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>, + >, progress: computed::Percentage, }, /// A intermediate type for accumulation of mismatched transform lists. #[allow(missing_docs)] #[css(comma, function = "accumulatematrix")] AccumulateMatrix { - from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, - to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, + from_list: GenericTransform< + GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>, + >, + to_list: GenericTransform< + GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>, + >, count: Integer, }, } +pub use self::GenericTransformOperation as TransformOperation; + #[derive( Clone, Debug, @@ -257,8 +275,11 @@ where ToResolvedValue, ToShmem, )] +#[repr(C)] /// A value of the `transform` property -pub struct Transform<T>(#[css(if_empty = "none", iterable)] pub Vec<T>); +pub struct GenericTransform<T>(#[css(if_empty = "none", iterable)] pub crate::OwnedSlice<T>); + +pub use self::GenericTransform as Transform; impl<Angle, Number, Length, Integer, LengthPercentage> TransformOperation<Angle, Number, Length, Integer, LengthPercentage> @@ -497,7 +518,7 @@ where impl<T> Transform<T> { /// `none` pub fn none() -> Self { - Transform(vec![]) + Transform(Default::default()) } } @@ -529,7 +550,7 @@ impl<T: ToMatrix> Transform<T> { let mut transform = Transform3D::<f64>::identity(); let mut contain_3d = false; - for operation in &self.0 { + for operation in &*self.0 { let matrix = operation.to_3d_matrix(reference_box)?; contain_3d |= operation.is_3d(); transform = transform.pre_mul(&matrix); @@ -589,10 +610,11 @@ pub fn get_normalized_vector_and_angle<T: Zero>( ToResolvedValue, ToShmem, )] +#[repr(C, u8)] /// A value of the `Rotate` property /// /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum Rotate<Number, Angle> { +pub enum GenericRotate<Number, Angle> { /// 'none' None, /// '<angle>' @@ -601,6 +623,8 @@ pub enum Rotate<Number, Angle> { Rotate3D(Number, Number, Number, Angle), } +pub use self::GenericRotate as Rotate; + /// A trait to check if the current 3D vector is parallel to the DirectionVector. /// This is especially for serialization on Rotate. pub trait IsParallelTo { @@ -660,10 +684,11 @@ where ToResolvedValue, ToShmem, )] +#[repr(C, u8)] /// A value of the `Scale` property /// /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum Scale<Number> { +pub enum GenericScale<Number> { /// 'none' None, /// '<number>{1,2}' @@ -672,6 +697,8 @@ pub enum Scale<Number> { Scale3D(Number, Number, Number), } +pub use self::GenericScale as Scale; + impl<Number: ToCss + PartialEq> ToCss for Scale<Number> { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where @@ -710,6 +737,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> { ToResolvedValue, ToShmem, )] +#[repr(C, u8)] /// A value of the `translate` property /// /// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization: @@ -724,7 +752,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> { /// related spec issue is https://github.com/w3c/csswg-drafts/issues/3305 /// /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum Translate<LengthPercentage, Length> +pub enum GenericTranslate<LengthPercentage, Length> where LengthPercentage: Zero, { @@ -739,6 +767,8 @@ where Translate3D(LengthPercentage, LengthPercentage, Length), } +pub use self::GenericTranslate as Translate; + #[allow(missing_docs)] #[derive( Clone, diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs index e2da4984084..36ea909ab87 100644 --- a/components/style/values/mod.rs +++ b/components/style/values/mod.rs @@ -174,6 +174,7 @@ impl<A: Debug, B: Debug> Debug for Either<A, B> { ToResolvedValue, ToShmem, )] +#[repr(C)] pub struct CustomIdent(pub Atom); impl CustomIdent { diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs index 59f2f7aa284..338b0d18c27 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -183,7 +183,7 @@ impl Parse for BorderImageSideWidth { } if let Ok(len) = input.try(|i| NonNegativeLengthPercentage::parse(context, i)) { - return Ok(GenericBorderImageSideWidth::Length(len)); + return Ok(GenericBorderImageSideWidth::LengthPercentage(len)); } let num = NonNegativeNumber::parse(context, input)?; diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index 31a79c141e1..542976d45ba 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -642,6 +642,7 @@ pub enum OverflowClipBox { #[derive( Clone, Debug, + Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, @@ -650,38 +651,38 @@ pub enum OverflowClipBox { ToResolvedValue, ToShmem, )] -/// Provides a rendering hint to the user agent, -/// stating what kinds of changes the author expects -/// to perform on the element +#[css(comma)] +#[repr(C)] +/// Provides a rendering hint to the user agent, stating what kinds of changes +/// the author expects to perform on the element. +/// +/// `auto` is represented by an empty `features` list. /// /// <https://drafts.csswg.org/css-will-change/#will-change> -pub enum WillChange { - /// Expresses no particular intent - Auto, - /// <custom-ident> - #[css(comma)] - AnimateableFeatures { - /// The features that are supposed to change. - #[css(iterable)] - features: Box<[CustomIdent]>, - /// A bitfield with the kind of change that the value will create, based - /// on the above field. - #[css(skip)] - bits: WillChangeBits, - }, +pub struct WillChange { + /// The features that are supposed to change. + /// + /// TODO(emilio): Consider using ArcSlice since we just clone them from the + /// specified value? That'd save an allocation, which could be worth it. + #[css(iterable, if_empty = "auto")] + features: crate::OwnedSlice<CustomIdent>, + /// A bitfield with the kind of change that the value will create, based + /// on the above field. + #[css(skip)] + bits: WillChangeBits, } impl WillChange { #[inline] /// Get default value of `will-change` as `auto` - pub fn auto() -> WillChange { - WillChange::Auto + pub fn auto() -> Self { + Self::default() } } bitflags! { /// The change bits that we care about. - #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)] + #[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(C)] pub struct WillChangeBits: u8 { /// Whether the stacking context will change. @@ -746,7 +747,7 @@ impl Parse for WillChange { .try(|input| input.expect_ident_matching("auto")) .is_ok() { - return Ok(WillChange::Auto); + return Ok(Self::default()); } let mut bits = WillChangeBits::empty(); @@ -767,8 +768,8 @@ impl Parse for WillChange { Ok(ident) })?; - Ok(WillChange::AnimateableFeatures { - features: custom_idents.into_boxed_slice(), + Ok(Self { + features: custom_idents.into(), bits, }) } diff --git a/components/style/values/specified/effects.rs b/components/style/values/specified/effects.rs index d8c378a8a7b..3ffad2fa89c 100644 --- a/components/style/values/specified/effects.rs +++ b/components/style/values/specified/effects.rs @@ -17,7 +17,7 @@ use crate::values::specified::color::Color; use crate::values::specified::length::{Length, NonNegativeLength}; #[cfg(feature = "gecko")] use crate::values::specified::url::SpecifiedUrl; -use crate::values::specified::{Angle, NumberOrPercentage}; +use crate::values::specified::{Angle, Number, NumberOrPercentage}; #[cfg(not(feature = "gecko"))] use crate::values::Impossible; use crate::Zero; @@ -62,6 +62,10 @@ impl Factor { }, } } + + fn one() -> Self { + Factor(NumberOrPercentage::Number(Number::new(1.0))) + } } impl Parse for Factor { @@ -209,34 +213,61 @@ impl Parse for Filter { }; input.parse_nested_block(|i| { match_ignore_ascii_case! { &*function, - "blur" => Ok(GenericFilter::Blur((Length::parse_non_negative(context, i)?).into())), - "brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)), - "contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)), + "blur" => Ok(GenericFilter::Blur( + i.try(|i| NonNegativeLength::parse(context, i)) + .unwrap_or(Zero::zero()), + )), + "brightness" => Ok(GenericFilter::Brightness( + i.try(|i| Factor::parse(context, i)) + .unwrap_or(Factor::one()), + )), + "contrast" => Ok(GenericFilter::Contrast( + i.try(|i| Factor::parse(context, i)) + .unwrap_or(Factor::one()), + )), "grayscale" => { // Values of amount over 100% are allowed but UAs must clamp the values to 1. // https://drafts.fxtf.org/filter-effects/#funcdef-filter-grayscale - Ok(GenericFilter::Grayscale(Factor::parse_with_clamping_to_one(context, i)?)) + Ok(GenericFilter::Grayscale( + i.try(|i| Factor::parse_with_clamping_to_one(context, i)) + .unwrap_or(Factor::one()), + )) }, "hue-rotate" => { // We allow unitless zero here, see: // https://github.com/w3c/fxtf-drafts/issues/228 - Ok(GenericFilter::HueRotate(Angle::parse_with_unitless(context, i)?)) + Ok(GenericFilter::HueRotate( + i.try(|i| Angle::parse_with_unitless(context, i)) + .unwrap_or(Zero::zero()), + )) }, "invert" => { // Values of amount over 100% are allowed but UAs must clamp the values to 1. // https://drafts.fxtf.org/filter-effects/#funcdef-filter-invert - Ok(GenericFilter::Invert(Factor::parse_with_clamping_to_one(context, i)?)) + Ok(GenericFilter::Invert( + i.try(|i| Factor::parse_with_clamping_to_one(context, i)) + .unwrap_or(Factor::one()), + )) }, "opacity" => { // Values of amount over 100% are allowed but UAs must clamp the values to 1. // https://drafts.fxtf.org/filter-effects/#funcdef-filter-opacity - Ok(GenericFilter::Opacity(Factor::parse_with_clamping_to_one(context, i)?)) + Ok(GenericFilter::Opacity( + i.try(|i| Factor::parse_with_clamping_to_one(context, i)) + .unwrap_or(Factor::one()), + )) }, - "saturate" => Ok(GenericFilter::Saturate(Factor::parse(context, i)?)), + "saturate" => Ok(GenericFilter::Saturate( + i.try(|i| Factor::parse(context, i)) + .unwrap_or(Factor::one()), + )), "sepia" => { // Values of amount over 100% are allowed but UAs must clamp the values to 1. // https://drafts.fxtf.org/filter-effects/#funcdef-filter-sepia - Ok(GenericFilter::Sepia(Factor::parse_with_clamping_to_one(context, i)?)) + Ok(GenericFilter::Sepia( + i.try(|i| Factor::parse_with_clamping_to_one(context, i)) + .unwrap_or(Factor::one()), + )) }, "drop-shadow" => Ok(GenericFilter::DropShadow(Parse::parse(context, i)?)), _ => Err(location.new_custom_error( diff --git a/components/style/values/specified/gecko.rs b/components/style/values/specified/gecko.rs index 42ca5e3e2bf..131c2a1a314 100644 --- a/components/style/values/specified/gecko.rs +++ b/components/style/values/specified/gecko.rs @@ -7,33 +7,12 @@ use crate::parser::{Parse, ParserContext}; use crate::values::computed::length::CSSPixelLength; use crate::values::computed::{self, LengthPercentage}; -use crate::values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint; use crate::values::generics::rect::Rect; -use crate::values::specified::length::LengthPercentage as SpecifiedLengthPercentage; use cssparser::{Parser, Token}; use std::fmt; use style_traits::values::SequenceWriter; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; -/// A specified type for scroll snap points. -pub type ScrollSnapPoint = GenericScrollSnapPoint<SpecifiedLengthPercentage>; - -impl Parse for ScrollSnapPoint { - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result<Self, ParseError<'i>> { - if input.try(|i| i.expect_ident_matching("none")).is_ok() { - return Ok(GenericScrollSnapPoint::None); - } - input.expect_function_matching("repeat")?; - // FIXME(emilio): This won't clamp properly when animating. - let length = input - .parse_nested_block(|i| SpecifiedLengthPercentage::parse_non_negative(context, i))?; - Ok(GenericScrollSnapPoint::Repeat(length)) - } -} - fn parse_pixel_or_percent<'i, 't>( _context: &ParserContext, input: &mut Parser<'i, 't>, diff --git a/components/style/values/specified/list.rs b/components/style/values/specified/list.rs index 8c1e9fa2ad4..0519053b902 100644 --- a/components/style/values/specified/list.rs +++ b/components/style/values/specified/list.rs @@ -10,7 +10,6 @@ use crate::values::generics::CounterStyleOrNone; #[cfg(feature = "gecko")] use crate::values::CustomIdent; use cssparser::{Parser, Token}; -use servo_arc::Arc; use style_traits::{ParseError, StyleParseErrorKind}; /// Specified and computed `list-style-type` property. @@ -96,18 +95,20 @@ impl Parse for ListStyleType { ToResolvedValue, ToShmem, )] +#[repr(C)] pub struct QuotePair { /// The opening quote. - pub opening: Box<str>, + pub opening: crate::OwnedStr, /// The closing quote. - pub closing: Box<str>, + pub closing: crate::OwnedStr, } /// Specified and computed `quotes` property. #[derive( Clone, Debug, + Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, @@ -116,10 +117,11 @@ pub struct QuotePair { ToResolvedValue, ToShmem, )] +#[repr(C)] pub struct Quotes( #[css(iterable, if_empty = "none")] #[ignore_malloc_size_of = "Arc"] - pub Arc<Box<[QuotePair]>>, + pub crate::ArcSlice<QuotePair>, ); impl Parse for Quotes { @@ -131,24 +133,24 @@ impl Parse for Quotes { .try(|input| input.expect_ident_matching("none")) .is_ok() { - return Ok(Quotes(Arc::new(Box::new([])))); + return Ok(Self::default()); } let mut quotes = Vec::new(); loop { let location = input.current_source_location(); let opening = match input.next() { - Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into_boxed_str(), + Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into(), Ok(t) => return Err(location.new_unexpected_token_error(t.clone())), Err(_) => break, }; - let closing = input.expect_string()?.as_ref().to_owned().into_boxed_str(); + let closing = input.expect_string()?.as_ref().to_owned().into(); quotes.push(QuotePair { opening, closing }); } if !quotes.is_empty() { - Ok(Quotes(Arc::new(quotes.into_boxed_slice()))) + Ok(Quotes(crate::ArcSlice::from_iter(quotes.into_iter()))) } else { Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) } diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 83fc71444bb..409f5abe161 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -54,8 +54,6 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis}; pub use self::font::{FontVariantAlternates, FontWeight}; pub use self::font::{FontVariantEastAsian, FontVariationSettings}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; -#[cfg(feature = "gecko")] -pub use self::gecko::ScrollSnapPoint; pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect}; pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth}; @@ -68,7 +66,7 @@ pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageO pub use self::list::ListStyleType; pub use self::list::MozListReversed; pub use self::list::{QuotePair, Quotes}; -pub use self::motion::OffsetPath; +pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::outline::OutlineStyle; pub use self::percentage::Percentage; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position}; @@ -81,7 +79,7 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg_path::SVGPathData; pub use self::table::XSpan; pub use self::text::TextTransform; -pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextAlign}; +pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign}; pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak}; pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; pub use self::time::Time; diff --git a/components/style/values/specified/motion.rs b/components/style/values/specified/motion.rs index 7d72796397e..97609ea20b0 100644 --- a/components/style/values/specified/motion.rs +++ b/components/style/values/specified/motion.rs @@ -5,13 +5,17 @@ //! Specified types for CSS values that are related to motion path. use crate::parser::{Parse, ParserContext}; -use crate::values::specified::SVGPathData; +use crate::values::computed::motion::OffsetRotate as ComputedOffsetRotate; +use crate::values::computed::{Context, ToComputedValue}; +use crate::values::specified::{Angle, SVGPathData}; +use crate::Zero; use cssparser::Parser; use style_traits::{ParseError, StyleParseErrorKind}; /// The offset-path value. /// /// https://drafts.fxtf.org/motion-1/#offset-path-property +/// cbindgen:derive-tagged-enum-copy-constructor=true #[derive( Animate, Clone, @@ -26,6 +30,7 @@ use style_traits::{ParseError, StyleParseErrorKind}; ToResolvedValue, ToShmem, )] +#[repr(C, u8)] pub enum OffsetPath { // We could merge SVGPathData into ShapeSource, so we could reuse them. However, // we don't want to support other value for offset-path, so use SVGPathData only for now. @@ -73,3 +78,104 @@ impl Parse for OffsetPath { }) } } + +/// The direction of offset-rotate. +#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +#[repr(u8)] +pub enum OffsetRotateDirection { + /// Unspecified direction keyword. + #[css(skip)] + None, + /// 0deg offset (face forward). + Auto, + /// 180deg offset (face backward). + Reverse, +} + +impl OffsetRotateDirection { + /// Returns true if it is none (i.e. the keyword is not specified). + #[inline] + fn is_none(&self) -> bool { + *self == OffsetRotateDirection::None + } +} + +#[inline] +fn direction_specified_and_angle_is_zero(direction: &OffsetRotateDirection, angle: &Angle) -> bool { + !direction.is_none() && angle.is_zero() +} + +/// The specified offset-rotate. +/// The syntax is: "[ auto | reverse ] || <angle>" +/// +/// https://drafts.fxtf.org/motion-1/#offset-rotate-property +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +pub struct OffsetRotate { + /// [auto | reverse]. + #[css(skip_if = "OffsetRotateDirection::is_none")] + direction: OffsetRotateDirection, + /// <angle>. + /// If direction is None, this is a fixed angle which indicates a + /// constant clockwise rotation transformation applied to it by this + /// specified rotation angle. Otherwise, the angle will be added to + /// the angle of the direction in layout. + #[css(contextual_skip_if = "direction_specified_and_angle_is_zero")] + angle: Angle, +} + +impl Parse for OffsetRotate { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + let location = input.current_source_location(); + let mut direction = input.try(OffsetRotateDirection::parse); + let angle = input.try(|i| Angle::parse(context, i)); + if direction.is_err() { + // The direction and angle could be any order, so give it a change to parse + // direction again. + direction = input.try(OffsetRotateDirection::parse); + } + + if direction.is_err() && angle.is_err() { + return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + Ok(OffsetRotate { + direction: direction.unwrap_or(OffsetRotateDirection::None), + angle: angle.unwrap_or(Zero::zero()), + }) + } +} + +impl ToComputedValue for OffsetRotate { + type ComputedValue = ComputedOffsetRotate; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + use crate::values::computed::Angle as ComputedAngle; + + ComputedOffsetRotate { + auto: !self.direction.is_none(), + angle: if self.direction == OffsetRotateDirection::Reverse { + // The computed value should always convert "reverse" into "auto". + // e.g. "reverse calc(20deg + 10deg)" => "auto 210deg" + self.angle.to_computed_value(context) + ComputedAngle::from_degrees(180.0) + } else { + self.angle.to_computed_value(context) + }, + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + OffsetRotate { + direction: if computed.auto { + OffsetRotateDirection::Auto + } else { + OffsetRotateDirection::None + }, + angle: ToComputedValue::from_computed_value(&computed.angle), + } + } +} diff --git a/components/style/values/specified/svg.rs b/components/style/values/specified/svg.rs index dd4990782a0..578870a4a91 100644 --- a/components/style/values/specified/svg.rs +++ b/components/style/values/specified/svg.rs @@ -12,7 +12,7 @@ use crate::values::specified::AllowQuirks; use crate::values::specified::LengthPercentage; use crate::values::specified::{NonNegativeLengthPercentage, Opacity}; use crate::values::CustomIdent; -use cssparser::Parser; +use cssparser::{Parser, Token}; use std::fmt::{self, Write}; use style_traits::{CommaWithSpace, CssWriter, ParseError, Separator}; use style_traits::{StyleParseErrorKind, ToCss}; @@ -243,11 +243,28 @@ impl ToCss for SVGPaintOrder { } } +bitflags! { + /// The context properties we understand. + #[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)] + #[repr(C)] + pub struct ContextPropertyBits: u8 { + /// `fill` + const FILL = 1 << 0; + /// `stroke` + const STROKE = 1 << 1; + /// `fill-opacity` + const FILL_OPACITY = 1 << 2; + /// `stroke-opacity` + const STROKE_OPACITY = 1 << 3; + } +} + /// Specified MozContextProperties value. /// Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties) #[derive( Clone, Debug, + Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, @@ -256,19 +273,61 @@ impl ToCss for SVGPaintOrder { ToResolvedValue, ToShmem, )] -pub struct MozContextProperties(pub CustomIdent); +#[repr(C)] +pub struct MozContextProperties { + #[css(iterable, if_empty = "none")] + #[ignore_malloc_size_of = "Arc"] + idents: crate::ArcSlice<CustomIdent>, + #[css(skip)] + bits: ContextPropertyBits, +} impl Parse for MozContextProperties { fn parse<'i, 't>( _context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<MozContextProperties, ParseError<'i>> { - let location = input.current_source_location(); - let i = input.expect_ident()?; - Ok(MozContextProperties(CustomIdent::from_ident( - location, - i, - &["all", "none", "auto"], - )?)) + let mut values = vec![]; + let mut bits = ContextPropertyBits::empty(); + loop { + { + let location = input.current_source_location(); + let ident = input.expect_ident()?; + + if ident.eq_ignore_ascii_case("none") && values.is_empty() { + return Ok(Self::default()); + } + + let ident = CustomIdent::from_ident(location, ident, &["all", "none", "auto"])?; + + if ident.0 == atom!("fill") { + bits.insert(ContextPropertyBits::FILL); + } else if ident.0 == atom!("stroke") { + bits.insert(ContextPropertyBits::STROKE); + } else if ident.0 == atom!("fill-opacity") { + bits.insert(ContextPropertyBits::FILL_OPACITY); + } else if ident.0 == atom!("stroke-opacity") { + bits.insert(ContextPropertyBits::STROKE_OPACITY); + } + + values.push(ident); + } + + let location = input.current_source_location(); + match input.next() { + Ok(&Token::Comma) => continue, + Err(..) => break, + Ok(other) => return Err(location.new_unexpected_token_error(other.clone())), + } + } + + if values.is_empty() { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + Ok(MozContextProperties { + idents: crate::ArcSlice::from_iter(values.into_iter()), + bits, + }) } } diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index 6be20f58618..188eb18f720 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -134,14 +134,16 @@ impl ToComputedValue for LineHeight { } /// A generic value for the `text-overflow` property. +/// cbindgen:derive-tagged-enum-copy-constructor=true #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +#[repr(C, u8)] pub enum TextOverflowSide { /// Clip inline content. Clip, /// Render ellipsis to represent clipped inline content. Ellipsis, /// Render a given string to represent clipped inline content. - String(Box<str>), + String(crate::OwnedStr), } impl Parse for TextOverflowSide { @@ -160,9 +162,9 @@ impl Parse for TextOverflowSide { )) } }, - Token::QuotedString(ref v) => Ok(TextOverflowSide::String( - v.as_ref().to_owned().into_boxed_str(), - )), + Token::QuotedString(ref v) => { + Ok(TextOverflowSide::String(v.as_ref().to_owned().into())) + }, ref t => Err(location.new_unexpected_token_error(t.clone())), } } @@ -1005,6 +1007,31 @@ pub enum WordBreak { BreakWord, } +/// Values for the `line-break` property. +#[repr(u8)] +#[derive( + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[allow(missing_docs)] +pub enum LineBreak { + Auto, + Loose, + Normal, + Strict, + Anywhere, +} + /// Values for the `overflow-wrap` property. #[repr(u8)] #[derive( diff --git a/components/style/values/specified/transform.rs b/components/style/values/specified/transform.rs index a4dc87d3217..e942cf13085 100644 --- a/components/style/values/specified/transform.rs +++ b/components/style/values/specified/transform.rs @@ -42,183 +42,187 @@ impl Transform { .try(|input| input.expect_ident_matching("none")) .is_ok() { - return Ok(generic::Transform(Vec::new())); + return Ok(generic::Transform::none()); } - Ok(generic::Transform(Space::parse(input, |input| { - let function = input.expect_function()?.clone(); - input.parse_nested_block(|input| { - let location = input.current_source_location(); - let result = match_ignore_ascii_case! { &function, - "matrix" => { - let a = Number::parse(context, input)?; - input.expect_comma()?; - let b = Number::parse(context, input)?; - input.expect_comma()?; - let c = Number::parse(context, input)?; - input.expect_comma()?; - let d = Number::parse(context, input)?; - input.expect_comma()?; - // Standard matrix parsing. - let e = Number::parse(context, input)?; - input.expect_comma()?; - let f = Number::parse(context, input)?; - Ok(generic::TransformOperation::Matrix(Matrix { a, b, c, d, e, f })) - }, - "matrix3d" => { - let m11 = Number::parse(context, input)?; - input.expect_comma()?; - let m12 = Number::parse(context, input)?; - input.expect_comma()?; - let m13 = Number::parse(context, input)?; - input.expect_comma()?; - let m14 = Number::parse(context, input)?; - input.expect_comma()?; - let m21 = Number::parse(context, input)?; - input.expect_comma()?; - let m22 = Number::parse(context, input)?; - input.expect_comma()?; - let m23 = Number::parse(context, input)?; - input.expect_comma()?; - let m24 = Number::parse(context, input)?; - input.expect_comma()?; - let m31 = Number::parse(context, input)?; - input.expect_comma()?; - let m32 = Number::parse(context, input)?; - input.expect_comma()?; - let m33 = Number::parse(context, input)?; - input.expect_comma()?; - let m34 = Number::parse(context, input)?; - input.expect_comma()?; - // Standard matrix3d parsing. - let m41 = Number::parse(context, input)?; - input.expect_comma()?; - let m42 = Number::parse(context, input)?; - input.expect_comma()?; - let m43 = Number::parse(context, input)?; - input.expect_comma()?; - let m44 = Number::parse(context, input)?; - Ok(generic::TransformOperation::Matrix3D(Matrix3D { - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44, - })) - }, - "translate" => { - let sx = specified::LengthPercentage::parse(context, input)?; - if input.try(|input| input.expect_comma()).is_ok() { - let sy = specified::LengthPercentage::parse(context, input)?; - Ok(generic::TransformOperation::Translate(sx, sy)) - } else { - Ok(generic::TransformOperation::Translate(sx, Zero::zero())) - } - }, - "translatex" => { - let tx = specified::LengthPercentage::parse(context, input)?; - Ok(generic::TransformOperation::TranslateX(tx)) - }, - "translatey" => { - let ty = specified::LengthPercentage::parse(context, input)?; - Ok(generic::TransformOperation::TranslateY(ty)) - }, - "translatez" => { - let tz = specified::Length::parse(context, input)?; - Ok(generic::TransformOperation::TranslateZ(tz)) - }, - "translate3d" => { - let tx = specified::LengthPercentage::parse(context, input)?; - input.expect_comma()?; - let ty = specified::LengthPercentage::parse(context, input)?; - input.expect_comma()?; - let tz = specified::Length::parse(context, input)?; - Ok(generic::TransformOperation::Translate3D(tx, ty, tz)) - }, - "scale" => { - let sx = Number::parse(context, input)?; - if input.try(|input| input.expect_comma()).is_ok() { + Ok(generic::Transform( + Space::parse(input, |input| { + let function = input.expect_function()?.clone(); + input.parse_nested_block(|input| { + let location = input.current_source_location(); + let result = match_ignore_ascii_case! { &function, + "matrix" => { + let a = Number::parse(context, input)?; + input.expect_comma()?; + let b = Number::parse(context, input)?; + input.expect_comma()?; + let c = Number::parse(context, input)?; + input.expect_comma()?; + let d = Number::parse(context, input)?; + input.expect_comma()?; + // Standard matrix parsing. + let e = Number::parse(context, input)?; + input.expect_comma()?; + let f = Number::parse(context, input)?; + Ok(generic::TransformOperation::Matrix(Matrix { a, b, c, d, e, f })) + }, + "matrix3d" => { + let m11 = Number::parse(context, input)?; + input.expect_comma()?; + let m12 = Number::parse(context, input)?; + input.expect_comma()?; + let m13 = Number::parse(context, input)?; + input.expect_comma()?; + let m14 = Number::parse(context, input)?; + input.expect_comma()?; + let m21 = Number::parse(context, input)?; + input.expect_comma()?; + let m22 = Number::parse(context, input)?; + input.expect_comma()?; + let m23 = Number::parse(context, input)?; + input.expect_comma()?; + let m24 = Number::parse(context, input)?; + input.expect_comma()?; + let m31 = Number::parse(context, input)?; + input.expect_comma()?; + let m32 = Number::parse(context, input)?; + input.expect_comma()?; + let m33 = Number::parse(context, input)?; + input.expect_comma()?; + let m34 = Number::parse(context, input)?; + input.expect_comma()?; + // Standard matrix3d parsing. + let m41 = Number::parse(context, input)?; + input.expect_comma()?; + let m42 = Number::parse(context, input)?; + input.expect_comma()?; + let m43 = Number::parse(context, input)?; + input.expect_comma()?; + let m44 = Number::parse(context, input)?; + Ok(generic::TransformOperation::Matrix3D(Matrix3D { + m11, m12, m13, m14, + m21, m22, m23, m24, + m31, m32, m33, m34, + m41, m42, m43, m44, + })) + }, + "translate" => { + let sx = specified::LengthPercentage::parse(context, input)?; + if input.try(|input| input.expect_comma()).is_ok() { + let sy = specified::LengthPercentage::parse(context, input)?; + Ok(generic::TransformOperation::Translate(sx, sy)) + } else { + Ok(generic::TransformOperation::Translate(sx, Zero::zero())) + } + }, + "translatex" => { + let tx = specified::LengthPercentage::parse(context, input)?; + Ok(generic::TransformOperation::TranslateX(tx)) + }, + "translatey" => { + let ty = specified::LengthPercentage::parse(context, input)?; + Ok(generic::TransformOperation::TranslateY(ty)) + }, + "translatez" => { + let tz = specified::Length::parse(context, input)?; + Ok(generic::TransformOperation::TranslateZ(tz)) + }, + "translate3d" => { + let tx = specified::LengthPercentage::parse(context, input)?; + input.expect_comma()?; + let ty = specified::LengthPercentage::parse(context, input)?; + input.expect_comma()?; + let tz = specified::Length::parse(context, input)?; + Ok(generic::TransformOperation::Translate3D(tx, ty, tz)) + }, + "scale" => { + let sx = Number::parse(context, input)?; + if input.try(|input| input.expect_comma()).is_ok() { + let sy = Number::parse(context, input)?; + Ok(generic::TransformOperation::Scale(sx, sy)) + } else { + Ok(generic::TransformOperation::Scale(sx, sx)) + } + }, + "scalex" => { + let sx = Number::parse(context, input)?; + Ok(generic::TransformOperation::ScaleX(sx)) + }, + "scaley" => { let sy = Number::parse(context, input)?; - Ok(generic::TransformOperation::Scale(sx, sy)) - } else { - Ok(generic::TransformOperation::Scale(sx, sx)) - } - }, - "scalex" => { - let sx = Number::parse(context, input)?; - Ok(generic::TransformOperation::ScaleX(sx)) - }, - "scaley" => { - let sy = Number::parse(context, input)?; - Ok(generic::TransformOperation::ScaleY(sy)) - }, - "scalez" => { - let sz = Number::parse(context, input)?; - Ok(generic::TransformOperation::ScaleZ(sz)) - }, - "scale3d" => { - let sx = Number::parse(context, input)?; - input.expect_comma()?; - let sy = Number::parse(context, input)?; - input.expect_comma()?; - let sz = Number::parse(context, input)?; - Ok(generic::TransformOperation::Scale3D(sx, sy, sz)) - }, - "rotate" => { - let theta = specified::Angle::parse_with_unitless(context, input)?; - Ok(generic::TransformOperation::Rotate(theta)) - }, - "rotatex" => { - let theta = specified::Angle::parse_with_unitless(context, input)?; - Ok(generic::TransformOperation::RotateX(theta)) - }, - "rotatey" => { - let theta = specified::Angle::parse_with_unitless(context, input)?; - Ok(generic::TransformOperation::RotateY(theta)) - }, - "rotatez" => { - let theta = specified::Angle::parse_with_unitless(context, input)?; - Ok(generic::TransformOperation::RotateZ(theta)) - }, - "rotate3d" => { - let ax = Number::parse(context, input)?; - input.expect_comma()?; - let ay = Number::parse(context, input)?; - input.expect_comma()?; - let az = Number::parse(context, input)?; - input.expect_comma()?; - let theta = specified::Angle::parse_with_unitless(context, input)?; - // TODO(gw): Check that the axis can be normalized. - Ok(generic::TransformOperation::Rotate3D(ax, ay, az, theta)) - }, - "skew" => { - let ax = specified::Angle::parse_with_unitless(context, input)?; - if input.try(|input| input.expect_comma()).is_ok() { - let ay = specified::Angle::parse_with_unitless(context, input)?; - Ok(generic::TransformOperation::Skew(ax, ay)) - } else { - Ok(generic::TransformOperation::Skew(ax, Zero::zero())) - } - }, - "skewx" => { - let theta = specified::Angle::parse_with_unitless(context, input)?; - Ok(generic::TransformOperation::SkewX(theta)) - }, - "skewy" => { - let theta = specified::Angle::parse_with_unitless(context, input)?; - Ok(generic::TransformOperation::SkewY(theta)) - }, - "perspective" => { - let d = specified::Length::parse_non_negative(context, input)?; - Ok(generic::TransformOperation::Perspective(d)) - }, - _ => Err(()), - }; - result.map_err(|()| { - location - .new_custom_error(StyleParseErrorKind::UnexpectedFunction(function.clone())) + Ok(generic::TransformOperation::ScaleY(sy)) + }, + "scalez" => { + let sz = Number::parse(context, input)?; + Ok(generic::TransformOperation::ScaleZ(sz)) + }, + "scale3d" => { + let sx = Number::parse(context, input)?; + input.expect_comma()?; + let sy = Number::parse(context, input)?; + input.expect_comma()?; + let sz = Number::parse(context, input)?; + Ok(generic::TransformOperation::Scale3D(sx, sy, sz)) + }, + "rotate" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(generic::TransformOperation::Rotate(theta)) + }, + "rotatex" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(generic::TransformOperation::RotateX(theta)) + }, + "rotatey" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(generic::TransformOperation::RotateY(theta)) + }, + "rotatez" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(generic::TransformOperation::RotateZ(theta)) + }, + "rotate3d" => { + let ax = Number::parse(context, input)?; + input.expect_comma()?; + let ay = Number::parse(context, input)?; + input.expect_comma()?; + let az = Number::parse(context, input)?; + input.expect_comma()?; + let theta = specified::Angle::parse_with_unitless(context, input)?; + // TODO(gw): Check that the axis can be normalized. + Ok(generic::TransformOperation::Rotate3D(ax, ay, az, theta)) + }, + "skew" => { + let ax = specified::Angle::parse_with_unitless(context, input)?; + if input.try(|input| input.expect_comma()).is_ok() { + let ay = specified::Angle::parse_with_unitless(context, input)?; + Ok(generic::TransformOperation::Skew(ax, ay)) + } else { + Ok(generic::TransformOperation::Skew(ax, Zero::zero())) + } + }, + "skewx" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(generic::TransformOperation::SkewX(theta)) + }, + "skewy" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(generic::TransformOperation::SkewY(theta)) + }, + "perspective" => { + let d = specified::Length::parse_non_negative(context, input)?; + Ok(generic::TransformOperation::Perspective(d)) + }, + _ => Err(()), + }; + result.map_err(|()| { + location.new_custom_error(StyleParseErrorKind::UnexpectedFunction( + function.clone(), + )) + }) }) - }) - })?)) + })? + .into(), + )) } } diff --git a/components/style_traits/Cargo.toml b/components/style_traits/Cargo.toml index 846579d462c..acf46422861 100644 --- a/components/style_traits/Cargo.toml +++ b/components/style_traits/Cargo.toml @@ -18,6 +18,7 @@ app_units = "0.7" cssparser = "0.25" bitflags = "1.0" euclid = "0.19" +lazy_static = "1" malloc_size_of = { path = "../malloc_size_of" } malloc_size_of_derive = "0.1" selectors = { path = "../selectors" } diff --git a/components/style_traits/arc_slice.rs b/components/style_traits/arc_slice.rs index dd1b99d3424..6a151e3dc5a 100644 --- a/components/style_traits/arc_slice.rs +++ b/components/style_traits/arc_slice.rs @@ -5,16 +5,19 @@ //! A thin atomically-reference-counted slice. use servo_arc::ThinArc; -use std::mem; use std::ops::Deref; use std::ptr::NonNull; +use std::{iter, mem}; /// A canary that we stash in ArcSlices. /// /// Given we cannot use a zero-sized-type for the header, since well, C++ /// doesn't have zsts, and we want to use cbindgen for this type, we may as well /// assert some sanity at runtime. -const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3; +/// +/// We use an u64, to guarantee that we can use a single singleton for every +/// empty slice, even if the types they hold are aligned differently. +const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3; /// A wrapper type for a refcounted slice using ThinArc. /// @@ -22,7 +25,7 @@ const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3; /// cbindgen:derive-neq=false #[repr(C)] #[derive(Clone, Debug, Eq, PartialEq, ToShmem)] -pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u32, T>); +pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>); impl<T> Deref for ArcSlice<T> { type Target = [T]; @@ -34,12 +37,28 @@ impl<T> Deref for ArcSlice<T> { } } -/// The inner pointer of an ArcSlice<T>, to be sent via FFI. -/// The type of the pointer is a bit of a lie, we just want to preserve the type -/// but these pointers cannot be constructed outside of this crate, so we're -/// good. -#[repr(C)] -pub struct ForgottenArcSlicePtr<T>(NonNull<T>); +lazy_static! { + // ThinArc doesn't support alignments greater than align_of::<u64>. + static ref EMPTY_ARC_SLICE: ArcSlice<u64> = { + ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty())) + }; +} + +impl<T> Default for ArcSlice<T> { + #[allow(unsafe_code)] + fn default() -> Self { + debug_assert!( + mem::align_of::<T>() <= mem::align_of::<u64>(), + "Need to increase the alignment of EMPTY_ARC_SLICE" + ); + unsafe { + let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone(); + let empty: Self = mem::transmute(empty); + debug_assert_eq!(empty.len(), 0); + empty + } + } +} impl<T> ArcSlice<T> { /// Creates an Arc for a slice using the given iterator to generate the @@ -49,6 +68,9 @@ impl<T> ArcSlice<T> { where I: Iterator<Item = T> + ExactSizeIterator, { + if items.len() == 0 { + return Self::default(); + } ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items)) } @@ -63,4 +85,21 @@ impl<T> ArcSlice<T> { mem::forget(self); ret } + + /// Leaks an empty arc slice pointer, and returns it. Only to be used to + /// construct ArcSlices from FFI. + #[inline] + pub fn leaked_empty_ptr() -> *mut std::os::raw::c_void { + let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone(); + let ptr = empty.0.ptr(); + std::mem::forget(empty); + ptr as *mut _ + } } + +/// The inner pointer of an ArcSlice<T>, to be sent via FFI. +/// The type of the pointer is a bit of a lie, we just want to preserve the type +/// but these pointers cannot be constructed outside of this crate, so we're +/// good. +#[repr(C)] +pub struct ForgottenArcSlicePtr<T>(NonNull<T>); diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index d4a907fa956..4e89f6fdf67 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -16,6 +16,8 @@ extern crate bitflags; #[macro_use] extern crate cssparser; extern crate euclid; +#[macro_use] +extern crate lazy_static; extern crate malloc_size_of; #[macro_use] extern crate malloc_size_of_derive; @@ -91,6 +93,7 @@ pub mod values; #[macro_use] pub mod viewport; pub mod owned_slice; +pub mod owned_str; pub use crate::specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo}; pub use crate::values::{ @@ -149,8 +152,6 @@ pub enum StyleParseErrorKind<'i> { /// The property declaration was for an unknown property. UnknownProperty(CowRcStr<'i>), - /// An unknown vendor-specific identifier was encountered. - UnknownVendorProperty, /// The property declaration was for a disabled experimental property. ExperimentalProperty, /// The property declaration contained an invalid color value. diff --git a/components/style_traits/owned_slice.rs b/components/style_traits/owned_slice.rs index f2b0de4a4a0..33d3ac1c2ab 100644 --- a/components/style_traits/owned_slice.rs +++ b/components/style_traits/owned_slice.rs @@ -10,7 +10,7 @@ use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; -use std::{fmt, mem, slice}; +use std::{fmt, iter, mem, slice}; use to_shmem::{SharedMemoryBuilder, ToShmem}; /// A struct that basically replaces a `Box<[T]>`, but which cbindgen can @@ -93,7 +93,7 @@ impl<T: Sized> OwnedSlice<T> { /// Iterate over all the elements in the slice taking ownership of them. #[inline] - pub fn into_iter(self) -> impl Iterator<Item = T> { + pub fn into_iter(self) -> impl Iterator<Item = T> + ExactSizeIterator { self.into_vec().into_iter() } @@ -164,3 +164,10 @@ impl<T: ToShmem + Sized> ToShmem for OwnedSlice<T> { } } } + +impl<T> iter::FromIterator<T> for OwnedSlice<T> { + #[inline] + fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { + Vec::from_iter(iter).into() + } +} diff --git a/components/style_traits/owned_str.rs b/components/style_traits/owned_str.rs new file mode 100644 index 00000000000..42a83a07713 --- /dev/null +++ b/components/style_traits/owned_str.rs @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#![allow(unsafe_code)] + +//! A replacement for `Box<str>` that has a defined layout for FFI. + +use crate::owned_slice::OwnedSlice; +use std::fmt; +use std::ops::{Deref, DerefMut}; + +/// A struct that basically replaces a Box<str>, but with a defined layout, +/// suitable for FFI. +#[repr(C)] +#[derive(Clone, Default, Eq, MallocSizeOf, PartialEq, ToShmem)] +pub struct OwnedStr(OwnedSlice<u8>); + +impl fmt::Debug for OwnedStr { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.deref().fmt(formatter) + } +} + +impl Deref for OwnedStr { + type Target = str; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { std::str::from_utf8_unchecked(&*self.0) } + } +} + +impl DerefMut for OwnedStr { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { std::str::from_utf8_unchecked_mut(&mut *self.0) } + } +} + +impl From<Box<str>> for OwnedStr { + #[inline] + fn from(b: Box<str>) -> Self { + Self::from(b.into_string()) + } +} + +impl From<String> for OwnedStr { + #[inline] + fn from(s: String) -> Self { + OwnedStr(s.into_bytes().into()) + } +} diff --git a/components/style_traits/specified_value_info.rs b/components/style_traits/specified_value_info.rs index 63a7b71d990..5aaf64ac955 100644 --- a/components/style_traits/specified_value_info.rs +++ b/components/style_traits/specified_value_info.rs @@ -5,6 +5,7 @@ //! Value information for devtools. use crate::arc_slice::ArcSlice; +use crate::owned_slice::OwnedSlice; use servo_arc::Arc; use std::ops::Range; use std::sync::Arc as StdArc; @@ -83,6 +84,7 @@ impl SpecifiedValueInfo for u16 {} impl SpecifiedValueInfo for u32 {} impl SpecifiedValueInfo for str {} impl SpecifiedValueInfo for String {} +impl SpecifiedValueInfo for crate::owned_str::OwnedStr {} #[cfg(feature = "servo")] impl SpecifiedValueInfo for ::servo_atoms::Atom {} @@ -114,6 +116,7 @@ macro_rules! impl_generic_specified_value_info { }; } impl_generic_specified_value_info!(Option<T>); +impl_generic_specified_value_info!(OwnedSlice<T>); impl_generic_specified_value_info!(Vec<T>); impl_generic_specified_value_info!(Arc<T>); impl_generic_specified_value_info!(StdArc<T>); diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 5c3f3ab255d..0c3166858a2 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -75,6 +75,16 @@ where } } +impl ToCss for crate::owned_str::OwnedStr { + #[inline] + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: Write, + { + serialize_string(self, dest) + } +} + impl ToCss for str { #[inline] fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result diff --git a/tests/unit/style/animated_properties.rs b/tests/unit/style/animated_properties.rs index dd233f01b89..fd03a1904e8 100644 --- a/tests/unit/style/animated_properties.rs +++ b/tests/unit/style/animated_properties.rs @@ -4,7 +4,6 @@ use cssparser::RGBA; use style::values::animated::{Animate, Procedure, ToAnimatedValue}; -use style::values::generics::transform::{Transform, TransformOperation}; fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA { let from = from.to_animated_value(); @@ -81,14 +80,3 @@ fn test_rgba_color_interepolation_out_of_range_clamped_2() { RGBA::from_floats(0.0, 0.0, 0.0, 0.0) ); } - -#[test] -fn test_transform_interpolation_on_scale() { - let from = Transform(vec![TransformOperation::Scale3D(1.0, 2.0, 1.0)]); - let to = Transform(vec![TransformOperation::Scale3D(2.0, 4.0, 2.0)]); - assert_eq!( - from.animate(&to, Procedure::Interpolate { progress: 0.5 }) - .unwrap(), - Transform(vec![TransformOperation::Scale3D(1.5, 3.0, 1.5)]) - ); -} diff --git a/tests/unit/style/parsing/animation.rs b/tests/unit/style/parsing/animation.rs deleted file mode 100644 index f67d77e9afd..00000000000 --- a/tests/unit/style/parsing/animation.rs +++ /dev/null @@ -1,43 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -use crate::parsing::parse; -use servo_atoms::Atom; -use style::parser::Parse; -use style::properties::longhands::animation_name; -use style::values::specified::AnimationIterationCount; -use style::values::{CustomIdent, KeyframesName}; -use style_traits::ToCss; - -#[test] -fn test_animation_name() { - use self::animation_name::single_value::SpecifiedValue as SingleValue; - let other_name = Atom::from("other-name"); - assert_eq!( - parse_longhand!(animation_name, "none"), - animation_name::SpecifiedValue(vec![SingleValue(None)]) - ); - assert_eq!( - parse_longhand!( - animation_name, - "other-name, none, 'other-name', \"other-name\"" - ), - animation_name::SpecifiedValue(vec![ - SingleValue(Some(KeyframesName::Ident(CustomIdent(other_name.clone())))), - SingleValue(None), - SingleValue(Some(KeyframesName::QuotedString(other_name.clone()))), - SingleValue(Some(KeyframesName::QuotedString(other_name.clone()))) - ]) - ); -} - -#[test] -fn test_animation_iteration() { - assert_roundtrip_with_context!(AnimationIterationCount::parse, "0", "0"); - assert_roundtrip_with_context!(AnimationIterationCount::parse, "0.1", "0.1"); - assert_roundtrip_with_context!(AnimationIterationCount::parse, "infinite", "infinite"); - - // Negative numbers are invalid - assert!(parse(AnimationIterationCount::parse, "-1").is_err()); -} diff --git a/tests/unit/style/parsing/mod.rs b/tests/unit/style/parsing/mod.rs index 095f74c9603..aff8d1fc47c 100644 --- a/tests/unit/style/parsing/mod.rs +++ b/tests/unit/style/parsing/mod.rs @@ -133,7 +133,6 @@ macro_rules! parse_longhand { }; } -mod animation; mod background; mod border; mod box_; diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index fe8a7b84269..c6b02f37eda 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -194,7 +194,7 @@ fn test_parse_stylesheet() { PropertyDeclaration::BackgroundPositionX( longhands::background_position_x::SpecifiedValue(vec![ PositionComponent::zero(), - ]), + ].into()), ), Importance::Normal, ), @@ -202,7 +202,7 @@ fn test_parse_stylesheet() { PropertyDeclaration::BackgroundPositionY( longhands::background_position_y::SpecifiedValue(vec![ PositionComponent::zero(), - ]), + ].into()), ), Importance::Normal, ), @@ -210,7 +210,7 @@ fn test_parse_stylesheet() { PropertyDeclaration::BackgroundRepeat( longhands::background_repeat::SpecifiedValue( vec![longhands::background_repeat::single_value - ::get_initial_specified_value()], + ::get_initial_specified_value()].into(), ), ), Importance::Normal, @@ -219,7 +219,7 @@ fn test_parse_stylesheet() { PropertyDeclaration::BackgroundAttachment( longhands::background_attachment::SpecifiedValue( vec![longhands::background_attachment::single_value - ::get_initial_specified_value()], + ::get_initial_specified_value()].into(), ), ), Importance::Normal, @@ -228,7 +228,7 @@ fn test_parse_stylesheet() { PropertyDeclaration::BackgroundImage( longhands::background_image::SpecifiedValue( vec![longhands::background_image::single_value - ::get_initial_specified_value()], + ::get_initial_specified_value()].into(), ), ), Importance::Normal, @@ -237,7 +237,7 @@ fn test_parse_stylesheet() { PropertyDeclaration::BackgroundSize( longhands::background_size::SpecifiedValue( vec![longhands::background_size::single_value - ::get_initial_specified_value()], + ::get_initial_specified_value()].into(), ), ), Importance::Normal, @@ -246,7 +246,7 @@ fn test_parse_stylesheet() { PropertyDeclaration::BackgroundOrigin( longhands::background_origin::SpecifiedValue( vec![longhands::background_origin::single_value - ::get_initial_specified_value()], + ::get_initial_specified_value()].into(), ), ), Importance::Normal, @@ -255,7 +255,7 @@ fn test_parse_stylesheet() { PropertyDeclaration::BackgroundClip( longhands::background_clip::SpecifiedValue( vec![longhands::background_clip::single_value - ::get_initial_specified_value()], + ::get_initial_specified_value()].into(), ), ), Importance::Normal, diff --git a/tests/wpt/metadata/css/filter-effects/filters-test-brightness-003.html.ini b/tests/wpt/metadata/css/filter-effects/filters-test-brightness-003.html.ini deleted file mode 100644 index df5382158af..00000000000 --- a/tests/wpt/metadata/css/filter-effects/filters-test-brightness-003.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[filters-test-brightness-003.html] - expected: FAIL diff --git a/tests/wpt/metadata/css/filter-effects/parsing/filter-computed.html.ini b/tests/wpt/metadata/css/filter-effects/parsing/filter-computed.html.ini index 5ba47d10857..9b57d470e5b 100644 --- a/tests/wpt/metadata/css/filter-effects/parsing/filter-computed.html.ini +++ b/tests/wpt/metadata/css/filter-effects/parsing/filter-computed.html.ini @@ -2,42 +2,15 @@ [Property filter value 'brightness()' computes to 'brightness(0)'] expected: FAIL - [Property filter value 'sepia()' computes to 'sepia(1)'] - expected: FAIL - - [Property filter value 'saturate()' computes to 'saturate(1)'] - expected: FAIL - - [Property filter value 'grayscale()' computes to 'grayscale(1)'] - expected: FAIL - [Property filter value 'invert()' computes to 'invert(0)'] expected: FAIL - [Property filter value 'hue-rotate()' computes to 'hue-rotate(0deg)'] - expected: FAIL - [Property filter value 'drop-shadow(1px 2px)' computes to 'drop-shadow(rgb(0, 255, 0) 1px 2px 0px)'] expected: FAIL - [Property filter value 'blur()' computes to 'blur(0px)'] - expected: FAIL - [Property filter value 'drop-shadow(rgb(4, 5, 6) 1px 2px 0px)' computes to 'drop-shadow(rgb(4, 5, 6) 1px 2px 0px)'] expected: FAIL [Property filter value 'blur(10px) url("https://www.example.com/picture.svg#f") contrast(20) brightness(30)' computes to 'blur(10px) url("https://www.example.com/picture.svg#f") contrast(20) brightness(30)'] expected: FAIL - [Property filter value 'opacity()' computes to 'opacity(1)'] - expected: FAIL - - [Property filter value 'contrast()' computes to 'contrast(1)'] - expected: FAIL - - [Property filter value 'brightness()' computes to 'brightness(1)'] - expected: FAIL - - [Property filter value 'invert()' computes to 'invert(1)'] - expected: FAIL - diff --git a/tests/wpt/metadata/css/filter-effects/parsing/filter-parsing-valid.html.ini b/tests/wpt/metadata/css/filter-effects/parsing/filter-parsing-valid.html.ini index 274ce737462..b8ca47ff7b3 100644 --- a/tests/wpt/metadata/css/filter-effects/parsing/filter-parsing-valid.html.ini +++ b/tests/wpt/metadata/css/filter-effects/parsing/filter-parsing-valid.html.ini @@ -59,30 +59,3 @@ [Serialization should round-trip after setting e.style['filter'\] = "drop-shadow(rgba(4, 5, 6, 0.75) 1px 2px 3px)"] expected: FAIL - [e.style['filter'\] = "saturate()" should set the property value] - expected: FAIL - - [e.style['filter'\] = "grayscale()" should set the property value] - expected: FAIL - - [e.style['filter'\] = "sepia()" should set the property value] - expected: FAIL - - [e.style['filter'\] = "blur()" should set the property value] - expected: FAIL - - [e.style['filter'\] = "contrast()" should set the property value] - expected: FAIL - - [e.style['filter'\] = "invert()" should set the property value] - expected: FAIL - - [e.style['filter'\] = "brightness()" should set the property value] - expected: FAIL - - [e.style['filter'\] = "opacity()" should set the property value] - expected: FAIL - - [e.style['filter'\] = "hue-rotate()" should set the property value] - expected: FAIL - |