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 -->
This commit is contained in:
bors-servo 2019-05-29 16:49:16 -04:00 committed by GitHub
commit b4fb2cda08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
105 changed files with 1455 additions and 2515 deletions

1
Cargo.lock generated
View file

@ -4562,6 +4562,7 @@ dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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 0.0.1",
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.21.0", "selectors 0.21.0",

View file

@ -30,6 +30,8 @@ error
fantasy fantasy
fetch fetch
file file
fill
fill-opacity
formdata formdata
fullscreenchange fullscreenchange
fullscreenerror fullscreenerror
@ -100,6 +102,8 @@ serif
signalingstatechange signalingstatechange
srclang srclang
statechange statechange
stroke
stroke-opacity
storage storage
submit submit
suspend suspend

View file

@ -159,7 +159,7 @@ fn side_image_width(
total_length: Au, total_length: Au,
) -> f32 { ) -> f32 {
match border_image_width { 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::Number(x) => border_width * x.0,
BorderImageSideWidth::Auto => border_width, BorderImageSideWidth::Auto => border_width,
} }

View file

@ -2793,7 +2793,7 @@ impl Fragment {
let mut overflow = Overflow::from_rect(&border_box); let mut overflow = Overflow::from_rect(&border_box);
// Box shadows cause us to draw outside our 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( let offset = Vector2D::new(
Au::from(box_shadow.base.horizontal), Au::from(box_shadow.base.horizontal),
Au::from(box_shadow.base.vertical), Au::from(box_shadow.base.vertical),

View file

@ -888,6 +888,10 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
self.element.namespace() self.element.namespace()
} }
fn is_pseudo_element(&self) -> bool {
false
}
fn match_pseudo_element( fn match_pseudo_element(
&self, &self,
_pseudo: &PseudoElement, _pseudo: &PseudoElement,
@ -1394,6 +1398,10 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
::selectors::OpaqueElement::new(unsafe { &*(self.as_node().opaque().0 as *const ()) }) ::selectors::OpaqueElement::new(unsafe { &*(self.as_node().opaque().0 as *const ()) })
} }
fn is_pseudo_element(&self) -> bool {
false
}
fn parent_element(&self) -> Option<Self> { fn parent_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::parent_element called"); warn!("ServoThreadSafeLayoutElement::parent_element called");
None None

View file

@ -685,9 +685,9 @@ impl LayoutElementHelpers for LayoutDom<Element> {
if let Some(url) = background { if let Some(url) = background {
hints.push(from_declaration( hints.push(from_declaration(
shared_lock, shared_lock,
PropertyDeclaration::BackgroundImage(background_image::SpecifiedValue(vec![ PropertyDeclaration::BackgroundImage(background_image::SpecifiedValue(
Either::Second(specified::Image::for_cascade(url.into())), 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( fn match_pseudo_element(
&self, &self,
_pseudo: &PseudoElement, _pseudo: &PseudoElement,

View file

@ -84,12 +84,6 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
self.current_len = 0; 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. /// Returns true if combinators have ever been pushed to this builder.
#[inline(always)] #[inline(always)]
pub fn has_combinators(&self) -> bool { pub fn has_combinators(&self) -> bool {

View file

@ -331,11 +331,9 @@ where
return false; return false;
} }
// Advance to the non-pseudo-element part of the selector, but let the // Advance to the non-pseudo-element part of the selector.
// context note that . let next_sequence = iter.next_sequence().unwrap();
if iter.next_sequence().is_none() { debug_assert_eq!(next_sequence, Combinator::PseudoElement);
return true;
}
} }
let result = let result =
@ -452,10 +450,6 @@ where
}, },
Combinator::Part => element.containing_shadow_host(), Combinator::Part => element.containing_shadow_host(),
Combinator::SlotAssignment => { 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 debug_assert!(element
.assigned_slot() .assigned_slot()
.map_or(true, |s| s.is_html_slot_element())); .map_or(true, |s| s.is_html_slot_element()));
@ -677,7 +671,6 @@ where
Component::Slotted(ref selector) => { Component::Slotted(ref selector) => {
// <slots> are never flattened tree slottables. // <slots> are never flattened tree slottables.
!element.is_html_slot_element() && !element.is_html_slot_element() &&
element.assigned_slot().is_some() &&
context.shared.nest(|context| { context.shared.nest(|context| {
matches_complex_selector(selector.iter(), element, context, flags_setter) matches_complex_selector(selector.iter(), element, context, flags_setter)
}) })

View file

@ -2002,9 +2002,7 @@ where
}, },
SimpleSelectorParseResult::SlottedPseudo(selector) => { SimpleSelectorParseResult::SlottedPseudo(selector) => {
state.insert(SelectorParsingState::AFTER_SLOTTED); 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)); builder.push_simple_selector(Component::Slotted(selector));
}, },
SimpleSelectorParseResult::PseudoElement(p) => { SimpleSelectorParseResult::PseudoElement(p) => {
@ -2012,9 +2010,7 @@ where
if !p.accepts_state_pseudo_classes() { if !p.accepts_state_pseudo_classes() {
state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT); 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)); builder.push_simple_selector(Component::PseudoElement(p));
}, },
} }
@ -2828,7 +2824,10 @@ pub mod tests {
assert_eq!( assert_eq!(
parse("::before"), parse("::before"),
Ok(SelectorList::from_vec(vec![Selector::from_vec( 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, specificity(0, 0, 1) | HAS_PSEUDO_BIT,
)])) )]))
); );
@ -2836,6 +2835,7 @@ pub mod tests {
parse("::before:hover"), parse("::before:hover"),
Ok(SelectorList::from_vec(vec![Selector::from_vec( Ok(SelectorList::from_vec(vec![Selector::from_vec(
vec![ vec![
Component::Combinator(Combinator::PseudoElement),
Component::PseudoElement(PseudoElement::Before), Component::PseudoElement(PseudoElement::Before),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
], ],
@ -2846,6 +2846,7 @@ pub mod tests {
parse("::before:hover:hover"), parse("::before:hover:hover"),
Ok(SelectorList::from_vec(vec![Selector::from_vec( Ok(SelectorList::from_vec(vec![Selector::from_vec(
vec![ vec![
Component::Combinator(Combinator::PseudoElement),
Component::PseudoElement(PseudoElement::Before), Component::PseudoElement(PseudoElement::Before),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
@ -2958,6 +2959,7 @@ pub mod tests {
specificity(0, 0, 0), specificity(0, 0, 0),
)])) )]))
); );
assert_eq!( assert_eq!(
parse_ns(":not(svg|*)", &parser), parse_ns(":not(svg|*)", &parser),
Ok(SelectorList::from_vec(vec![Selector::from_vec( Ok(SelectorList::from_vec(vec![Selector::from_vec(
@ -3032,6 +3034,8 @@ pub mod tests {
Some(&Component::PseudoElement(PseudoElement::Before)) Some(&Component::PseudoElement(PseudoElement::Before))
); );
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_sequence(), None); assert_eq!(iter.next_sequence(), None);
} }

View file

@ -47,9 +47,13 @@ pub trait Element: Sized + Clone + Debug {
/// ///
/// This is guaranteed to be called in a pseudo-element. /// This is guaranteed to be called in a pseudo-element.
fn pseudo_element_originating_element(&self) -> Option<Self> { fn pseudo_element_originating_element(&self) -> Option<Self> {
debug_assert!(self.is_pseudo_element());
self.parent_element() self.parent_element()
} }
/// Whether we're matching on a pseudo-element.
fn is_pseudo_element(&self) -> bool;
/// Skips non-element nodes /// Skips non-element nodes
fn prev_sibling_element(&self) -> Option<Self>; fn prev_sibling_element(&self) -> Option<Self>;

View file

@ -612,16 +612,15 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
use std::mem::{align_of, size_of}; use std::mem::{align_of, size_of};
assert_ne!(size_of::<T>(), 0, "Need to think about ZST"); 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. // Compute the required size for the allocation.
let num_items = items.len(); let num_items = items.len();
let size = { 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 // Next, synthesize a totally garbage (but properly aligned) pointer
// to a sequence of T. // 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 // Convert that sequence to a fat pointer. The address component of
// the fat pointer will be garbage, but the length will be correct. // 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]>>; let ptr: *mut ArcInner<HeaderSlice<H, [T]>>;
unsafe { unsafe {
// Allocate the buffer. // Allocate the buffer.
let layout = if mem::align_of::<T>() <= mem::align_of::<usize>() { let layout = if inner_align <= align_of::<usize>() {
Layout::from_size_align_unchecked(size, mem::align_of::<usize>()) Layout::from_size_align_unchecked(size, align_of::<usize>())
} else if mem::align_of::<T>() <= mem::align_of::<u64>() { } else if inner_align <= align_of::<u64>() {
// On 32-bit platforms <T> may have 8 byte alignment while usize has 4 byte aligment. // On 32-bit platforms <T> may have 8 byte alignment while usize
// Use u64 to avoid over-alignment. // has 4 byte aligment. Use u64 to avoid over-alignment.
// This branch will compile away in optimized builds. // 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 { } else {
panic!("Over-aligned type not handled"); panic!("Over-aligned type not handled");
}; };
@ -689,7 +688,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
// for some padding from the alignment. // for some padding from the alignment.
debug_assert!( debug_assert!(
(buffer.offset(size as isize) as usize - current as *mut u8 as usize) < (buffer.offset(size as isize) as usize - current as *mut u8 as usize) <
align_of::<Self>() inner_align
); );
} }
assert!( assert!(

View file

@ -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", "cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union",
"servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"] "servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"]
gecko_debug = [] gecko_debug = []
gecko_profiler = []
[dependencies] [dependencies]
app_units = "0.7" app_units = "0.7"
@ -79,7 +80,7 @@ void = "1.0.2"
[build-dependencies] [build-dependencies]
lazy_static = "1" lazy_static = "1"
log = "0.4" 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} regex = {version = "1.1", optional = true}
walkdir = "2.1.4" walkdir = "2.1.4"
toml = {version = "0.4.5", optional = true, default-features = false} toml = {version = "0.4.5", optional = true, default-features = false}

View file

@ -19,7 +19,6 @@ use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::mem; use std::mem;
use std::num::Wrapping; use std::num::Wrapping;
use std::ops::Range;
use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError}; use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError};
use style_traits::{StyleParseErrorKind, ToCss}; use style_traits::{StyleParseErrorKind, ToCss};
@ -261,7 +260,7 @@ counter_style_descriptors! {
"suffix" suffix / set_suffix [_]: Symbol, "suffix" suffix / set_suffix [_]: Symbol,
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-range> /// <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> /// <https://drafts.csswg.org/css-counter-styles/#counter-style-pad>
"pad" pad / set_pad [_]: Pad, "pad" pad / set_pad [_]: Pad,
@ -371,7 +370,7 @@ impl Parse for System {
"additive" => Ok(System::Additive), "additive" => Ok(System::Additive),
"fixed" => { "fixed" => {
let first_symbol_value = input.try(|i| Integer::parse(context, i)).ok(); 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" => { "extends" => {
let other = parse_counter_style_name(input)?; let other = parse_counter_style_name(input)?;
@ -409,11 +408,10 @@ impl ToCss for System {
} }
/// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol> /// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol>
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)]
pub enum Symbol { pub enum Symbol {
/// <string> /// <string>
String(String), String(crate::OwnedStr),
/// <custom-ident> /// <custom-ident>
Ident(CustomIdent), Ident(CustomIdent),
// Not implemented: // Not implemented:
@ -428,7 +426,7 @@ impl Parse for Symbol {
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location(); let location = input.current_source_location();
match *input.next()? { 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, &[])?)), Token::Ident(ref s) => Ok(Symbol::Ident(CustomIdent::from_ident(location, s, &[])?)),
ref t => Err(location.new_unexpected_token_error(t.clone())), 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> /// <https://drafts.csswg.org/css-counter-styles/#counter-style-range>
/// #[derive(Clone, Debug, ToCss, ToShmem)]
/// Empty Vec represents 'auto' pub struct CounterRange {
#[derive(Clone, Debug, ToShmem)] /// The start of the range.
pub struct Ranges(pub Vec<Range<CounterBound>>); pub start: CounterBound,
/// The end of the range.
pub end: CounterBound,
}
/// A bound found in `Ranges`. /// <https://drafts.csswg.org/css-counter-styles/#counter-style-range>
///
/// 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 `CounterRanges`.
#[derive(Clone, Copy, Debug, ToCss, ToShmem)] #[derive(Clone, Copy, Debug, ToCss, ToShmem)]
pub enum CounterBound { pub enum CounterBound {
/// An integer bound. /// An integer bound.
@ -477,7 +485,7 @@ pub enum CounterBound {
Infinite, Infinite,
} }
impl Parse for Ranges { impl Parse for CounterRanges {
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
@ -486,25 +494,21 @@ impl Parse for Ranges {
.try(|input| input.expect_ident_matching("auto")) .try(|input| input.expect_ident_matching("auto"))
.is_ok() .is_ok()
{ {
Ok(Ranges(Vec::new())) return Ok(CounterRanges(Default::default()));
} 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)
} }
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) 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> /// <https://drafts.csswg.org/css-counter-styles/#counter-style-pad>
#[derive(Clone, Debug, ToCss, ToShmem)] #[derive(Clone, Debug, ToCss, ToShmem)]
pub struct Pad(pub Integer, pub Symbol); pub struct Pad(pub Integer, pub Symbol);
@ -572,14 +548,13 @@ impl Parse for Fallback {
_context: &ParserContext, _context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> 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> /// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols>
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)] pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>);
pub struct Symbols(#[css(iterable)] pub Vec<Symbol>);
impl Parse for Symbols { impl Parse for Symbols {
fn parse<'i, 't>( fn parse<'i, 't>(
@ -587,23 +562,20 @@ impl Parse for Symbols {
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
let mut symbols = Vec::new(); let mut symbols = Vec::new();
loop { while let Ok(s) = input.try(|input| Symbol::parse(context, input)) {
if let Ok(s) = input.try(|input| Symbol::parse(context, input)) { symbols.push(s);
symbols.push(s)
} else {
if symbols.is_empty() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} else {
return Ok(Symbols(symbols));
}
}
} }
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> /// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-additive-symbols>
#[derive(Clone, Debug, ToCss, ToShmem)] #[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 { impl Parse for AdditiveSymbols {
fn parse<'i, 't>( fn parse<'i, 't>(
@ -618,7 +590,7 @@ impl Parse for AdditiveSymbols {
{ {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); 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 symbol = input.try(|input| Symbol::parse(context, input));
let weight = Integer::parse_non_negative(context, input)?; let weight = Integer::parse_non_negative(context, input)?;
let symbol = symbol.or_else(|_| Symbol::parse(context, input))?; let symbol = symbol.or_else(|_| Symbol::parse(context, input))?;
Ok(AdditiveTuple { Ok(Self { weight, symbol })
weight: weight,
symbol: symbol,
})
} }
} }

View file

@ -779,7 +779,7 @@ pub trait TElement:
/// element-backed pseudo-element, in which case we return the originating /// element-backed pseudo-element, in which case we return the originating
/// element. /// element.
fn rule_hash_target(&self) -> Self { fn rule_hash_target(&self) -> Self {
if self.implemented_pseudo_element().is_some() { if self.is_pseudo_element() {
self.pseudo_element_originating_element() self.pseudo_element_originating_element()
.expect("Trying to collect rules for a detached pseudo-element") .expect("Trying to collect rules for a detached pseudo-element")
} else { } else {
@ -801,24 +801,29 @@ pub trait TElement:
{ {
use rule_collector::containing_shadow_ignoring_svg_use; 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 // Use the same rules to look for the containing host as we do for rule
// collection. // 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; doc_rules_apply = false;
if let Some(data) = shadow.style_data() { if let Some(data) = shadow.style_data() {
f(data, shadow.host()); 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() { if let Some(data) = shadow.style_data() {
f(data, shadow.host()); f(data, shadow.host());
} }
} }
let mut current = self.assigned_slot(); let mut current = target.assigned_slot();
while let Some(slot) = current { while let Some(slot) = current {
// Slots can only have assigned nodes when in a shadow tree. // Slots can only have assigned nodes when in a shadow tree.
let shadow = slot.containing_shadow().unwrap(); let shadow = slot.containing_shadow().unwrap();

View file

@ -134,6 +134,7 @@ pub fn traverse_dom<E, D>(
let drain = discovered.drain(..); let drain = discovered.drain(..);
pool.install(|| { pool.install(|| {
rayon::scope(|scope| { rayon::scope(|scope| {
profiler_label!(Style);
parallel::traverse_nodes( parallel::traverse_nodes(
drain, drain,
DispatchMode::TailCall, DispatchMode::TailCall,

View file

@ -23,7 +23,6 @@ use crate::gecko_bindings::structs::RawServoMediaRule;
use crate::gecko_bindings::structs::RawServoMozDocumentRule; use crate::gecko_bindings::structs::RawServoMozDocumentRule;
use crate::gecko_bindings::structs::RawServoNamespaceRule; use crate::gecko_bindings::structs::RawServoNamespaceRule;
use crate::gecko_bindings::structs::RawServoPageRule; use crate::gecko_bindings::structs::RawServoPageRule;
use crate::gecko_bindings::structs::RawServoQuotes;
use crate::gecko_bindings::structs::RawServoStyleRule; use crate::gecko_bindings::structs::RawServoStyleRule;
use crate::gecko_bindings::structs::RawServoStyleSheetContents; use crate::gecko_bindings::structs::RawServoStyleSheetContents;
use crate::gecko_bindings::structs::RawServoSupportsRule; use crate::gecko_bindings::structs::RawServoSupportsRule;
@ -40,7 +39,6 @@ use crate::stylesheets::{NamespaceRule, PageRule};
use crate::stylesheets::{StyleRule, StylesheetContents, SupportsRule}; use crate::stylesheets::{StyleRule, StylesheetContents, SupportsRule};
use servo_arc::{Arc, ArcBorrow}; use servo_arc::{Arc, ArcBorrow};
use std::{mem, ptr}; use std::{mem, ptr};
use values::computed::QuotePair;
macro_rules! impl_arc_ffi { macro_rules! impl_arc_ffi {
($servo_type:ty => $gecko_type:ty[$addref:ident, $release:ident]) => { ($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 impl_arc_ffi!(CssUrlData => RawServoCssUrlData
[Servo_CssUrlData_AddRef, Servo_CssUrlData_Release]); [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. // ComputedStyle is not an opaque type on any side of FFI.
// This means that doing the HasArcFFI type trick is actually unsound, // This means that doing the HasArcFFI type trick is actually unsound,
// since it gives us a way to construct an Arc<ComputedStyle> from // since it gives us a way to construct an Arc<ComputedStyle> from

View file

@ -5,12 +5,22 @@
//! FFI implementations for types listed in ServoBoxedTypeList.h. //! FFI implementations for types listed in ServoBoxedTypeList.h.
use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use crate::properties::animated_properties::AnimationValueMap;
use to_shmem::SharedMemoryBuilder; use to_shmem::SharedMemoryBuilder;
// TODO(heycam): The FFI impls for most of the types in ServoBoxedTypeList.h are spread across // TODO(heycam): The FFI impls for most of the types in ServoBoxedTypeList.h are spread across
// various files at the moment, but should probably all move here, and use macros to define // various files at the moment, but should probably all move here, and use macros to define
// them more succinctly, like we do in arc_types.rs. // 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")] #[cfg(feature = "gecko")]
unsafe impl HasFFI for SharedMemoryBuilder { unsafe impl HasFFI for SharedMemoryBuilder {
type FFIType = crate::gecko_bindings::bindings::RawServoSharedMemoryBuilder; type FFIType = crate::gecko_bindings::bindings::RawServoSharedMemoryBuilder;

View file

@ -383,7 +383,6 @@ impl nsStyleImage {
let atom = bindings::Gecko_GetImageElement(self); let atom = bindings::Gecko_GetImageElement(self);
Some(GenericImage::Element(Atom::from_raw(atom))) Some(GenericImage::Element(Atom::from_raw(atom)))
}, },
_ => panic!("Unexpected image type"),
} }
} }
@ -535,10 +534,8 @@ pub mod basic_shape {
use crate::gecko_bindings::structs::{ use crate::gecko_bindings::structs::{
StyleGeometryBox, StyleShapeSource, StyleShapeSourceType, StyleGeometryBox, StyleShapeSource, StyleShapeSourceType,
}; };
use crate::gecko_bindings::sugar::refptr::RefPtr;
use crate::values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape}; use crate::values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape};
use crate::values::computed::motion::OffsetPath; 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::generics::basic_shape::{GeometryBox, Path, ShapeBox, ShapeSource};
use crate::values::specified::SVGPathData; use crate::values::specified::SVGPathData;
@ -564,7 +561,7 @@ pub mod basic_shape {
}; };
Some(ShapeSource::Shape(shape, reference_box)) Some(ShapeSource::Shape(shape, reference_box))
}, },
StyleShapeSourceType::URL | StyleShapeSourceType::Image => None, StyleShapeSourceType::Image => None,
StyleShapeSourceType::Path => { StyleShapeSourceType::Path => {
let path = self.to_svg_path().expect("expect an SVGPathData"); let path = self.to_svg_path().expect("expect an SVGPathData");
let fill = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }.mFillRule; 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 { impl<'a> From<&'a StyleShapeSource> for ClippingShape {
fn from(other: &'a StyleShapeSource) -> Self { fn from(other: &'a StyleShapeSource) -> Self {
use crate::values::generics::image::Image as GenericImage;
match other.mType { match other.mType {
StyleShapeSourceType::URL => unsafe { StyleShapeSourceType::Image => unsafe {
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
let other_url = let image = shape_image.into_image().expect("Cannot convert to Image");
RefPtr::new(*shape_image.__bindgen_anon_1.mURLValue.as_ref() as *mut _); match image {
let url = ComputedUrl::from_url_value(other_url); GenericImage::Url(url) => ShapeSource::ImageOrUrl(url.0),
ShapeSource::ImageOrUrl(url) _ => panic!("ClippingShape doesn't support non-url images"),
}, }
StyleShapeSourceType::Image => {
unreachable!("ClippingShape doesn't support Image!");
}, },
_ => other _ => other
.into_shape_source() .into_shape_source()
@ -608,9 +604,6 @@ pub mod basic_shape {
impl<'a> From<&'a StyleShapeSource> for FloatAreaShape { impl<'a> From<&'a StyleShapeSource> for FloatAreaShape {
fn from(other: &'a StyleShapeSource) -> Self { fn from(other: &'a StyleShapeSource) -> Self {
match other.mType { match other.mType {
StyleShapeSourceType::URL => {
unreachable!("FloatAreaShape doesn't support URL!");
},
StyleShapeSourceType::Image => unsafe { StyleShapeSourceType::Image => unsafe {
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
let image = shape_image.into_image().expect("Cannot convert to Image"); let image = shape_image.into_image().expect("Cannot convert to Image");
@ -632,7 +625,6 @@ pub mod basic_shape {
StyleShapeSourceType::None => OffsetPath::none(), StyleShapeSourceType::None => OffsetPath::none(),
StyleShapeSourceType::Shape | StyleShapeSourceType::Shape |
StyleShapeSourceType::Box | StyleShapeSourceType::Box |
StyleShapeSourceType::URL |
StyleShapeSourceType::Image => unreachable!("Unsupported offset-path type"), StyleShapeSourceType::Image => unreachable!("Unsupported offset-path type"),
} }
} }

View file

@ -13,9 +13,10 @@ pub mod conversions;
pub mod data; pub mod data;
pub mod media_features; pub mod media_features;
pub mod media_queries; pub mod media_queries;
#[cfg(feature = "gecko_profiler")]
pub mod profiler;
pub mod pseudo_element; pub mod pseudo_element;
pub mod restyle_damage; pub mod restyle_damage;
pub mod rules;
pub mod selector_parser; pub mod selector_parser;
pub mod snapshot; pub mod snapshot;
pub mod snapshot_helpers; pub mod snapshot_helpers;

View file

@ -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
}

View file

@ -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()),
}
}
}

View file

@ -310,13 +310,13 @@ impl ToComputedValue for SpecifiedImageUrl {
type ComputedValue = ComputedImageUrl; type ComputedValue = ComputedImageUrl;
#[inline] #[inline]
fn to_computed_value(&self, _: &Context) -> Self::ComputedValue { fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
ComputedImageUrl(self.clone()) ComputedImageUrl(self.0.to_computed_value(context))
} }
#[inline] #[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self { 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()`. /// The computed value of a CSS image `url()`.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
pub struct ComputedImageUrl(pub SpecifiedImageUrl); pub struct ComputedImageUrl(pub ComputedUrl);
impl ToCss for ComputedImageUrl { impl ToCss for ComputedImageUrl {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
@ -395,22 +395,17 @@ impl ComputedImageUrl {
/// Convert from nsStyleImageReques to ComputedImageUrl. /// Convert from nsStyleImageReques to ComputedImageUrl.
pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self { pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
let url_value = image_request.mImageValue.to_safe(); let url_value = image_request.mImageValue.to_safe();
let css_url = &*url_value.mCssUrl.mRawPtr; ComputedImageUrl(ComputedUrl::from_url_value(url_value))
let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc());
ComputedImageUrl(SpecifiedImageUrl(SpecifiedUrl {
url,
url_value: Box::new(URLValueSource::URLValue(url_value)),
}))
} }
/// Clone a new, strong reference to the Gecko URLValue. /// Clone a new, strong reference to the Gecko URLValue.
pub fn clone_url_value(&self) -> RefPtr<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. /// Get a raw pointer to the URLValue held by this ComputedImageUrl, for FFI.
pub fn url_value_ptr(&self) -> *mut URLValue { pub fn url_value_ptr(&self) -> *mut URLValue {
(self.0).0.url_value_ptr() self.0.url_value_ptr()
} }
} }

View file

@ -12,7 +12,6 @@ use crate::gecko_bindings::structs::{nsStyleCoord, CounterStylePtr};
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
use crate::values::computed::{Angle, Length, LengthPercentage}; use crate::values::computed::{Angle, Length, LengthPercentage};
use crate::values::computed::{Number, NumberOrPercentage, Percentage}; use crate::values::computed::{Number, NumberOrPercentage, Percentage};
use crate::values::generics::gecko::ScrollSnapPoint;
use crate::values::generics::grid::{TrackBreadth, TrackKeyword}; use crate::values::generics::grid::{TrackBreadth, TrackKeyword};
use crate::values::generics::length::LengthPercentageOrAuto; use crate::values::generics::length::LengthPercentageOrAuto;
use crate::values::generics::{CounterStyleOrNone, NonNegative}; 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`. /// Convert a given RGBA value to `nscolor`.
pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 { pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
((rgba.alpha as u32) << 24) | ((rgba.alpha as u32) << 24) |
@ -288,7 +266,7 @@ impl CounterStyleOrNone {
.0 .0
.iter() .iter()
.map(|symbol| match *symbol { .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()"), Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"),
}) })
.collect(); .collect();
@ -333,7 +311,7 @@ impl CounterStyleOrNone {
let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32); let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32);
let symbols = symbols let symbols = symbols
.iter() .iter()
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string())) .map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into()))
.collect(); .collect();
Either::First(CounterStyleOrNone::Symbols(symbol_type, Symbols(symbols))) Either::First(CounterStyleOrNone::Symbols(symbol_type, Symbols(symbols)))
} }

View file

@ -1098,7 +1098,7 @@ impl<'le> TElement for GeckoElement<'le> {
type TraversalChildrenIterator = GeckoChildrenIterator<'le>; type TraversalChildrenIterator = GeckoChildrenIterator<'le>;
fn inheritance_parent(&self) -> Option<Self> { fn inheritance_parent(&self) -> Option<Self> {
if self.implemented_pseudo_element().is_some() { if self.is_pseudo_element() {
return self.pseudo_element_originating_element(); return self.pseudo_element_originating_element();
} }
@ -1405,7 +1405,7 @@ impl<'le> TElement for GeckoElement<'le> {
#[inline] #[inline]
fn matches_user_and_author_rules(&self) -> bool { fn matches_user_and_author_rules(&self) -> bool {
!self.rule_hash_target().is_in_native_anonymous_subtree() !self.is_in_native_anonymous_subtree()
} }
#[inline] #[inline]
@ -1471,7 +1471,7 @@ impl<'le> TElement for GeckoElement<'le> {
#[inline] #[inline]
fn skip_item_display_fixup(&self) -> bool { fn skip_item_display_fixup(&self) -> bool {
debug_assert!( 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" "Just don't call me if I'm a pseudo, you should know the answer already"
); );
self.is_root_of_native_anonymous_subtree() self.is_root_of_native_anonymous_subtree()
@ -1918,9 +1918,14 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
Some(shadow.host()) Some(shadow.host())
} }
#[inline]
fn is_pseudo_element(&self) -> bool {
self.implemented_pseudo_element().is_some()
}
#[inline] #[inline]
fn pseudo_element_originating_element(&self) -> Option<Self> { 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()?; let parent = self.closest_anon_subtree_root_parent()?;
// FIXME(emilio): Special-case for <input type="number">s // FIXME(emilio): Special-case for <input type="number">s

View file

@ -6,9 +6,6 @@
mod ns_com_ptr; mod ns_com_ptr;
mod ns_compatibility; mod ns_compatibility;
mod ns_css_shadow_array;
mod ns_css_shadow_item;
pub mod ns_css_value;
mod ns_style_auto_array; mod ns_style_auto_array;
pub mod ns_style_coord; pub mod ns_style_coord;
mod ns_t_array; mod ns_t_array;

View file

@ -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,
)
}
}
}
}

View file

@ -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()
}
}

View file

@ -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
}
}

View file

@ -289,11 +289,6 @@ impl_threadsafe_refcount!(
bindings::Gecko_AddRefURLExtraDataArbitraryThread, bindings::Gecko_AddRefURLExtraDataArbitraryThread,
bindings::Gecko_ReleaseURLExtraDataArbitraryThread bindings::Gecko_ReleaseURLExtraDataArbitraryThread
); );
impl_threadsafe_refcount!(
structs::nsCSSValueSharedList,
bindings::Gecko_AddRefCSSValueSharedListArbitraryThread,
bindings::Gecko_ReleaseCSSValueSharedListArbitraryThread
);
impl_threadsafe_refcount!( impl_threadsafe_refcount!(
structs::mozilla::css::URLValue, structs::mozilla::css::URLValue,
bindings::Gecko_AddRefCSSURLValueArbitraryThread, bindings::Gecko_AddRefCSSURLValueArbitraryThread,

View file

@ -53,6 +53,7 @@ macro_rules! local_name {
/// This is either a strong reference to a dynamic atom (an nsAtom pointer), /// This is either a strong reference to a dynamic atom (an nsAtom pointer),
/// or an offset from gGkAtoms to the nsStaticAtom object. /// or an offset from gGkAtoms to the nsStaticAtom object.
#[derive(Eq, PartialEq)] #[derive(Eq, PartialEq)]
#[repr(C)]
pub struct Atom(usize); pub struct Atom(usize);
/// An atom *without* a strong reference. /// An atom *without* a strong reference.

View file

@ -366,6 +366,10 @@ where
self.element.is_root() self.element.is_root()
} }
fn is_pseudo_element(&self) -> bool {
self.element.is_pseudo_element()
}
fn pseudo_element_originating_element(&self) -> Option<Self> { fn pseudo_element_originating_element(&self) -> Option<Self> {
self.element self.element
.pseudo_element_originating_element() .pseudo_element_originating_element()

View file

@ -190,6 +190,7 @@ pub use servo_atoms::Atom;
pub use style_traits::arc_slice::ArcSlice; pub use style_traits::arc_slice::ArcSlice;
pub use style_traits::owned_slice::OwnedSlice; pub use style_traits::owned_slice::OwnedSlice;
pub use style_traits::owned_str::OwnedStr;
/// The CSS properties supported by the style system. /// The CSS properties supported by the style system.
/// Generated from the properties.mako.rs template by build.rs /// Generated from the properties.mako.rs template by build.rs

View file

@ -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) => {};
}

View file

@ -277,6 +277,7 @@ pub fn traverse_nodes<'a, 'scope, E, D, I>(
top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls); top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls);
} else { } else {
scope.spawn(move |scope| { scope.spawn(move |scope| {
profiler_label!(Style);
let work = work; let work = work;
top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls); 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 nodes: WorkUnit<E::ConcreteNode> = chunk.collect();
let traversal_data_copy = traversal_data.clone(); let traversal_data_copy = traversal_data.clone();
scope.spawn(move |scope| { scope.spawn(move |scope| {
profiler_label!(Style);
let n = nodes; let n = nodes;
top_down_dom(&*n, root, traversal_data_copy, scope, pool, traversal, tls) top_down_dom(&*n, root, traversal_data_copy, scope, pool, traversal, tls)
}); });

View file

@ -628,10 +628,6 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
#[cfg(feature = "gecko")] #[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() { if let Some(bg) = builder.get_background_if_mutated() {
bg.fill_arrays(); bg.fill_arrays();
} }

View file

@ -172,8 +172,9 @@ class Longhand(object):
gecko_ffi_name=None, gecko_ffi_name=None,
allowed_in_keyframe_block=True, cast_type='u8', allowed_in_keyframe_block=True, cast_type='u8',
logical=False, logical_group=None, alias=None, extra_prefixes=None, boxed=False, 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, ignored_when_colors_disabled=False,
simple_vector_bindings=False,
vector=False, servo_restyle_damage="repaint"): vector=False, servo_restyle_damage="repaint"):
self.name = name self.name = name
if not spec: if not spec:
@ -210,6 +211,7 @@ class Longhand(object):
self.allow_quirks = allow_quirks self.allow_quirks = allow_quirks
self.ignored_when_colors_disabled = ignored_when_colors_disabled self.ignored_when_colors_disabled = ignored_when_colors_disabled
self.is_vector = vector self.is_vector = vector
self.simple_vector_bindings = simple_vector_bindings
# https://drafts.csswg.org/css-animations/#keyframes # https://drafts.csswg.org/css-animations/#keyframes
# > The <declaration-list> inside of <keyframe-block> accepts any CSS property # > The <declaration-list> inside of <keyframe-block> accepts any CSS property
@ -323,12 +325,14 @@ class Longhand(object):
"JustifyContent", "JustifyContent",
"JustifyItems", "JustifyItems",
"JustifySelf", "JustifySelf",
"LineBreak",
"MozForceBrokenImageIcon", "MozForceBrokenImageIcon",
"MozListReversed", "MozListReversed",
"MozScriptLevel", "MozScriptLevel",
"MozScriptMinSize", "MozScriptMinSize",
"MozScriptSizeMultiplier", "MozScriptSizeMultiplier",
"NonNegativeNumber", "NonNegativeNumber",
"OffsetRotate",
"Opacity", "Opacity",
"OutlineStyle", "OutlineStyle",
"Overflow", "Overflow",

View file

@ -1301,11 +1301,9 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
Ok(id) => id, Ok(id) => id,
Err(..) => { Err(..) => {
self.last_parsed_property_id = None; self.last_parsed_property_id = None;
return Err(input.new_custom_error(if is_non_mozilla_vendor_identifier(&name) { return Err(input.new_custom_error(
StyleParseErrorKind::UnknownVendorProperty
} else {
StyleParseErrorKind::UnknownProperty(name) StyleParseErrorKind::UnknownProperty(name)
})); ));
} }
}; };
if self.context.error_reporting_enabled() { 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]>; 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] #[cold]
fn report_one_css_error<'i>( fn report_one_css_error<'i>(
context: &ParserContext, context: &ParserContext,
@ -1352,10 +1357,22 @@ fn report_one_css_error<'i>(
} }
} }
// If the unrecognized property looks like a vendor-specific property, if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty(ref name)) = error.kind {
// silently ignore it instead of polluting the error output. if is_non_mozilla_vendor_identifier(name) {
if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownVendorProperty) = error.kind { // If the unrecognized property looks like a vendor-specific property,
return; // 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 { if let Some(ref property) = property {

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@
<%def name="predefined_type(name, type, initial_value, parse_method='parse', <%def name="predefined_type(name, type, initial_value, parse_method='parse',
needs_context=True, vector=False, needs_context=True, vector=False,
computed_type=None, initial_specified_value=None, 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)"> <%def name="predefined_type_inner(name, type, initial_value, parse_method)">
#[allow(unused_imports)] #[allow(unused_imports)]
use app_units::Au; use app_units::Au;
@ -42,8 +42,8 @@
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<SpecifiedValue, ParseError<'i>> { ) -> Result<SpecifiedValue, ParseError<'i>> {
% if allow_quirks: % if allow_quirks != "No":
specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes) specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::${allow_quirks})
% elif needs_context: % elif needs_context:
specified::${type}::${parse_method}(context, input) specified::${type}::${parse_method}(context, input)
% else: % else:
@ -80,12 +80,26 @@
We assume that the default/initial value is an empty vector for these. We assume that the default/initial value is an empty vector for these.
`initial_value` need not be defined for these. `initial_value` need not be defined for these.
</%doc> </%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, <%def name="vector_longhand(name, animation_value_type=None,
vector_animation_type=None, allow_empty=False, vector_animation_type=None, allow_empty=False,
simple_vector_bindings=False,
separator='Comma', separator='Comma',
**kwargs)"> **kwargs)">
<%call expr="longhand(name, animation_value_type=animation_value_type, vector=True, <%call expr="longhand(name, animation_value_type=animation_value_type, vector=True,
**kwargs)"> simple_vector_bindings=simple_vector_bindings, **kwargs)">
#[allow(unused_imports)] #[allow(unused_imports)]
use smallvec::SmallVec; use smallvec::SmallVec;
@ -111,16 +125,46 @@
/// The definition of the computed value for ${name}. /// The definition of the computed value for ${name}.
pub mod computed_value { 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 super::single_value::computed_value as single_value;
pub use self::single_value::T as SingleComputedValue; pub use self::single_value::T as SingleComputedValue;
% if allow_empty and allow_empty != "NotInitial": % if not allow_empty or allow_empty == "NotInitial":
use std::vec::IntoIter; use smallvec::SmallVec;
% else:
use smallvec::{IntoIter, SmallVec};
% endif % endif
use crate::values::computed::ComputedVecIter; 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 /// Making this type generic allows the compiler to figure out the
/// animated value for us, instead of having to implement it /// animated value for us, instead of having to implement it
@ -137,34 +181,115 @@
ToResolvedValue, ToResolvedValue,
ToCss, ToCss,
)] )]
pub struct List<T>( pub struct OwnedList<T>(
% if not allow_empty: % if not allow_empty:
#[css(iterable)] #[css(iterable)]
% else: % else:
#[css(if_empty = "none", iterable)] #[css(if_empty = "none", iterable)]
% endif % endif
% if allow_empty and allow_empty != "NotInitial": pub UnderlyingOwnedList<T>,
pub Vec<T>,
% else:
pub SmallVec<[T; 1]>,
% endif
); );
/// 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:
#[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 vector_animation_type:
% if not animation_value_type: % if not animation_value_type:
Sorry, this is stupid but needed for now. Sorry, this is stupid but needed for now.
% endif % endif
use crate::properties::animated_properties::ListAnimation; 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}; use crate::values::distance::{SquaredDistance, ComputeSquaredDistance};
// FIXME(emilio): For some reason rust thinks that this alias is // FIXME(emilio): For some reason rust thinks that this alias is
// unused, even though it's clearly used below? // unused, even though it's clearly used below?
#[allow(unused)] #[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 { impl ToAnimatedZero for AnimatedList {
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
@ -176,7 +301,7 @@
other: &Self, other: &Self,
procedure: Procedure, procedure: Procedure,
) -> Result<Self, ()> { ) -> Result<Self, ()> {
Ok(List( Ok(OwnedList(
self.0.animate_${vector_animation_type}(&other.0, procedure)? self.0.animate_${vector_animation_type}(&other.0, procedure)?
)) ))
} }
@ -191,21 +316,10 @@
} }
% endif % 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>; 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}. /// The specified value of ${name}.
@ -219,12 +333,12 @@
% else: % else:
#[css(if_empty = "none", iterable)] #[css(if_empty = "none", iterable)]
% endif % endif
pub Vec<single_value::SpecifiedValue>, pub crate::OwnedSlice<single_value::SpecifiedValue>,
); );
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
% if allow_empty and allow_empty != "NotInitial": % if allow_empty and allow_empty != "NotInitial":
computed_value::List(vec![]) computed_value::List(Default::default())
% else: % else:
let mut v = SmallVec::new(); let mut v = SmallVec::new();
v.push(single_value::get_initial_value()); v.push(single_value::get_initial_value());
@ -239,40 +353,47 @@
use style_traits::Separator; use style_traits::Separator;
% if allow_empty: % if allow_empty:
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(Vec::new())) return Ok(SpecifiedValue(Default::default()))
} }
% endif % endif
style_traits::${separator}::parse(input, |parser| { let v = style_traits::${separator}::parse(input, |parser| {
single_value::parse(context, parser) single_value::parse(context, parser)
}).map(SpecifiedValue) })?;
Ok(SpecifiedValue(v.into()))
} }
pub use self::single_value::SpecifiedValue as SingleSpecifiedValue; pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;
% if not simple_vector_bindings and product == "gecko":
impl SpecifiedValue { impl SpecifiedValue {
pub fn compute_iter<'a, 'cx, 'cx_a>( fn compute_iter<'a, 'cx, 'cx_a>(
&'a self, &'a self,
context: &'cx Context<'cx_a>, context: &'cx Context<'cx_a>,
) -> computed_value::Iter<'a, 'cx, 'cx_a> { ) -> computed_value::Iter<'a, 'cx, 'cx_a> {
computed_value::Iter::new(context, &self.0) computed_value::Iter::new(context, &self.0)
} }
} }
% endif
impl ToComputedValue for SpecifiedValue { impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T; type ComputedValue = computed_value::T;
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T { 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] #[inline]
fn from_computed_value(computed: &computed_value::T) -> Self { fn from_computed_value(computed: &computed_value::T) -> Self {
SpecifiedValue(computed.0.iter() let iter = computed.0.iter().map(ToComputedValue::from_computed_value);
.map(ToComputedValue::from_computed_value) SpecifiedValue(iter.collect())
.collect())
} }
} }
</%call> </%call>
@ -375,7 +496,7 @@
.set_writing_mode_dependency(context.builder.writing_mode); .set_writing_mode_dependency(context.builder.writing_mode);
% endif % 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 // In the case of a vector property we want to pass down an
// iterator so that this can be computed without allocation. // iterator so that this can be computed without allocation.
// //
@ -405,8 +526,8 @@
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<PropertyDeclaration, ParseError<'i>> { ) -> Result<PropertyDeclaration, ParseError<'i>> {
% if property.allow_quirks: % if property.allow_quirks != "No":
parse_quirky(context, input, specified::AllowQuirks::Yes) parse_quirky(context, input, specified::AllowQuirks::${property.allow_quirks})
% else: % else:
parse(context, input) parse(context, input)
% endif % endif
@ -868,7 +989,7 @@
</%def> </%def>
<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function, <%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) %> <% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %>
<%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)"> <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)">
#[allow(unused_imports)] #[allow(unused_imports)]
@ -881,8 +1002,8 @@
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> { ) -> Result<Longhands, ParseError<'i>> {
let rect = Rect::parse_with(context, input, |_c, i| { let rect = Rect::parse_with(context, input, |_c, i| {
% if allow_quirks: % if allow_quirks != "No":
${parser_function}_quirky(_c, i, specified::AllowQuirks::Yes) ${parser_function}_quirky(_c, i, specified::AllowQuirks::${allow_quirks})
% elif needs_context: % elif needs_context:
${parser_function}(_c, i) ${parser_function}(_c, i)
% else: % else:

View file

@ -9,9 +9,7 @@
from itertools import groupby 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::structs::nsCSSPropertyID;
#[cfg(feature = "gecko")] use crate::gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI};
use itertools::{EitherOrBoth, Itertools}; use itertools::{EitherOrBoth, Itertools};
use crate::properties::{CSSWideKeyword, PropertyDeclaration}; use crate::properties::{CSSWideKeyword, PropertyDeclaration};
use crate::properties::longhands; use crate::properties::longhands;
@ -190,13 +188,6 @@ impl AnimatedProperty {
/// composed for each TransitionProperty. /// composed for each TransitionProperty.
pub type AnimationValueMap = FxHashMap<LonghandId, AnimationValue>; 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 /// An enum to represent a single computed value belonging to an animated
/// property in order to be interpolated with another one. When interpolating, /// property in order to be interpolated with another one. When interpolating,
/// both values need to belong to the same property. /// 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 SmallVec<[T; 1]>);
animated_list_impl!(<T> for Vec<T>); animated_list_impl!(<T> for Vec<T>);

View file

@ -14,7 +14,7 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-backgrounds/#background-color", spec="https://drafts.csswg.org/css-backgrounds/#background-color",
animation_value_type="AnimatedColor", animation_value_type="AnimatedColor",
ignored_when_colors_disabled=True, ignored_when_colors_disabled=True,
allow_quirks=True, allow_quirks="Yes",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER \ flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER \
CAN_ANIMATE_ON_COMPOSITOR", CAN_ANIMATE_ON_COMPOSITOR",
)} )}

View file

@ -28,7 +28,7 @@
animation_value_type="AnimatedColor", animation_value_type="AnimatedColor",
logical=is_logical, logical=is_logical,
logical_group="border-color", logical_group="border-color",
allow_quirks=not is_logical, allow_quirks="No" if is_logical else "Yes",
flags="APPLIES_TO_FIRST_LETTER", flags="APPLIES_TO_FIRST_LETTER",
ignored_when_colors_disabled=True, ignored_when_colors_disabled=True,
)} )}
@ -56,7 +56,7 @@
logical=is_logical, logical=is_logical,
logical_group="border-width", logical_group="border-width",
flags="APPLIES_TO_FIRST_LETTER GETCS_NEEDS_LAYOUT_FLUSH", 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" servo_restyle_damage="reflow rebuild_and_reflow_inline"
)} )}
% endfor % endfor
@ -159,60 +159,3 @@ ${helpers.predefined_type(
flags="APPLIES_TO_FIRST_LETTER", flags="APPLIES_TO_FIRST_LETTER",
boxed=True, 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
)
)
}
}

View file

@ -309,41 +309,6 @@ ${helpers.predefined_type(
allowed_in_keyframe_block=False, 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" %> <% transform_extra_prefixes = "moz:layout.css.prefixes.transforms webkit" %>
${helpers.predefined_type( ${helpers.predefined_type(
@ -352,7 +317,6 @@ ${helpers.predefined_type(
"generics::transform::Transform::none()", "generics::transform::Transform::none()",
extra_prefixes=transform_extra_prefixes, extra_prefixes=transform_extra_prefixes,
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
gecko_ffi_name="mSpecifiedTransform",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB \ flags="CREATES_STACKING_CONTEXT FIXPOS_CB \
GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR", GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.csswg.org/css-transforms/#propdef-transform", spec="https://drafts.csswg.org/css-transforms/#propdef-transform",
@ -405,6 +369,31 @@ ${helpers.predefined_type(
gecko_pref="layout.css.motion-path.enabled", gecko_pref="layout.css.motion-path.enabled",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB", flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
spec="https://drafts.fxtf.org/motion-1/#offset-path-property", 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 // CSSOM View Module

View file

@ -35,6 +35,7 @@ pub mod system_colors {
-moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext -moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext
-moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight -moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight
-moz-html-cellhighlighttext -moz-mac-buttonactivetext -moz-html-cellhighlighttext -moz-mac-buttonactivetext
-moz-gtk-buttonactivetext
-moz-mac-chrome-active -moz-mac-chrome-inactive -moz-mac-chrome-active -moz-mac-chrome-inactive
-moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect -moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect
-moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect -moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect

View file

@ -23,6 +23,7 @@ ${helpers.predefined_type(
"BoxShadow", "BoxShadow",
None, None,
vector=True, vector=True,
simple_vector_bindings=True,
animation_value_type="AnimatedBoxShadowList", animation_value_type="AnimatedBoxShadowList",
vector_animation_type="with_zero", vector_animation_type="with_zero",
extra_prefixes="webkit", extra_prefixes="webkit",
@ -37,7 +38,7 @@ ${helpers.predefined_type(
"computed::ClipRectOrAuto::auto()", "computed::ClipRectOrAuto::auto()",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
boxed=True, boxed=True,
allow_quirks=True, allow_quirks="Yes",
spec="https://drafts.fxtf.org/css-masking/#clip-property", spec="https://drafts.fxtf.org/css-masking/#clip-property",
)} )}

View file

@ -64,7 +64,7 @@ ${helpers.predefined_type(
initial_value="computed::FontSize::medium()", initial_value="computed::FontSize::medium()",
initial_specified_value="specified::FontSize::medium()", initial_specified_value="specified::FontSize::medium()",
animation_value_type="NonNegativeLength", animation_value_type="NonNegativeLength",
allow_quirks=True, allow_quirks="Yes",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size", spec="https://drafts.csswg.org/css-fonts/#propdef-font-size",
servo_restyle_damage="rebuild_and_reflow", servo_restyle_damage="rebuild_and_reflow",

View file

@ -194,11 +194,8 @@ ${helpers.predefined_type(
${helpers.predefined_type( ${helpers.predefined_type(
"-moz-context-properties", "-moz-context-properties",
"MozContextProperties", "MozContextProperties",
initial_value=None, "computed::MozContextProperties::default()",
vector=True,
need_index=True,
animation_value_type="none",
products="gecko", products="gecko",
animation_value_type="none",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)",
allow_empty=True,
)} )}

View file

@ -56,7 +56,7 @@ ${helpers.predefined_type(
"computed::LengthPercentage::zero()", "computed::LengthPercentage::zero()",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-text/#propdef-text-indent", spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
allow_quirks=True, allow_quirks="Yes",
servo_restyle_damage = "reflow", servo_restyle_damage = "reflow",
)} )}
@ -218,6 +218,7 @@ ${helpers.predefined_type(
vector_animation_type="with_zero", vector_animation_type="with_zero",
animation_value_type="AnimatedTextShadowList", animation_value_type="AnimatedTextShadowList",
ignored_when_colors_disabled=True, ignored_when_colors_disabled=True,
simple_vector_bindings=True,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property", 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", 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 // CSS Compatibility
// https://compat.spec.whatwg.org // https://compat.spec.whatwg.org
${helpers.predefined_type( ${helpers.predefined_type(

View file

@ -17,7 +17,7 @@
"LengthPercentageOrAuto", "LengthPercentageOrAuto",
"computed::LengthPercentageOrAuto::zero()", "computed::LengthPercentageOrAuto::zero()",
alias=maybe_moz_logical_alias(product, side, "-moz-margin-%s"), 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", animation_value_type="ComputedValue",
logical=side[1], logical=side[1],
logical_group="margin", logical_group="margin",

View file

@ -24,7 +24,7 @@
logical_group="padding", logical_group="padding",
spec=spec, spec=spec,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH", 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" servo_restyle_damage="reflow rebuild_and_reflow_inline"
)} )}
% endfor % endfor

View file

@ -17,7 +17,7 @@
spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side, spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
flags="GETCS_NEEDS_LAYOUT_FLUSH", flags="GETCS_NEEDS_LAYOUT_FLUSH",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
allow_quirks=True, allow_quirks="Yes",
servo_restyle_damage="reflow_out_of_flow", servo_restyle_damage="reflow_out_of_flow",
logical_group="inset", logical_group="inset",
)} )}
@ -253,7 +253,7 @@ ${helpers.predefined_type(
"computed::Size::auto()", "computed::Size::auto()",
logical=logical, logical=logical,
logical_group="size", logical_group="size",
allow_quirks=not logical, allow_quirks="No" if logical else "Yes",
spec=spec % size, spec=spec % size,
animation_value_type="Size", animation_value_type="Size",
flags="GETCS_NEEDS_LAYOUT_FLUSH", flags="GETCS_NEEDS_LAYOUT_FLUSH",
@ -266,7 +266,7 @@ ${helpers.predefined_type(
"computed::Size::auto()", "computed::Size::auto()",
logical=logical, logical=logical,
logical_group="min-size", logical_group="min-size",
allow_quirks=not logical, allow_quirks="No" if logical else "Yes",
spec=spec % size, spec=spec % size,
animation_value_type="Size", animation_value_type="Size",
servo_restyle_damage="reflow", servo_restyle_damage="reflow",
@ -277,7 +277,7 @@ ${helpers.predefined_type(
"computed::MaxSize::none()", "computed::MaxSize::none()",
logical=logical, logical=logical,
logical_group="max-size", logical_group="max-size",
allow_quirks=not logical, allow_quirks="No" if logical else "Yes",
spec=spec % size, spec=spec % size,
animation_value_type="MaxSize", animation_value_type="MaxSize",
servo_restyle_damage="reflow", servo_restyle_damage="reflow",

View file

@ -191,3 +191,66 @@ ${helpers.predefined_type(
animation_value_type="discrete", animation_value_type="discrete",
flags="CREATES_STACKING_CONTEXT", 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",
)}

View file

@ -32,12 +32,11 @@ ${helpers.single_keyword(
)} )}
${helpers.predefined_type( ${helpers.predefined_type(
"-moz-user-select", "user-select",
"UserSelect", "UserSelect",
"computed::UserSelect::Auto", "computed::UserSelect::Auto",
products="gecko", products="gecko",
gecko_ffi_name="mUserSelect", extra_prefixes="moz webkit",
alias="-webkit-user-select",
animation_value_type="discrete", animation_value_type="discrete",
needs_context=False, needs_context=False,
spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select", spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select",
@ -81,7 +80,6 @@ ${helpers.predefined_type(
"Transform", "Transform",
"generics::transform::Transform::none()", "generics::transform::Transform::none()",
products="gecko", products="gecko",
gecko_ffi_name="mSpecifiedWindowTransform",
flags="GETCS_NEEDS_LAYOUT_FLUSH", flags="GETCS_NEEDS_LAYOUT_FLUSH",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
spec="None (Nonstandard internal property)", spec="None (Nonstandard internal property)",

View file

@ -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. /// Similar to Vec::drain: leaves this empty when the return value is dropped.
pub fn drain(&mut self) -> SourcePropertyDeclarationDrain { pub fn drain(&mut self) -> SourcePropertyDeclarationDrain {
SourcePropertyDeclarationDrain { SourcePropertyDeclarationDrain {
@ -2474,20 +2482,7 @@ pub mod style_structs {
% if longhand.logical: % if longhand.logical:
${helpers.logical_setter(name=longhand.name)} ${helpers.logical_setter(name=longhand.name)}
% else: % else:
% if longhand.is_vector: % if longhand.ident == "display":
/// 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":
/// Set `display`. /// Set `display`.
/// ///
/// We need to keep track of the original display for hypothetical boxes, /// 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 { pub fn transform_requires_layer(&self) -> bool {
use crate::values::generics::transform::TransformOperation; use crate::values::generics::transform::TransformOperation;
// Check if the transform matrix is 2D or 3D // 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 { match *transform {
TransformOperation::Perspective(..) => { TransformOperation::Perspective(..) => {
return true; return true;
@ -3444,7 +3439,7 @@ impl<'a> StyleBuilder<'a> {
} }
% endif % 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`. /// Set the `${property.ident}` to the computed value `value`.
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn set_${property.ident}( pub fn set_${property.ident}(

View file

@ -40,11 +40,11 @@
let mut background_color = None; let mut background_color = None;
% for name in "image position_x position_y repeat size attachment origin clip".split(): % 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 // Vec grows from 0 to 4 by default on first push(). So allocate with
// with capacity 1, so in the common case of only one item we don't // capacity 1, so in the common case of only one item we don't way
// way overallocate. Note that we always push at least one item if // overallocate, then shrink. Note that we always push at least one
// parsing succeeds. // item if parsing succeeds.
let mut background_${name} = background_${name}::SpecifiedValue(Vec::with_capacity(1)); let mut background_${name} = Vec::with_capacity(1);
% endfor % endfor
input.parse_comma_separated(|input| { input.parse_comma_separated(|input| {
// background-color can only be in the last element, so if it // background-color can only be in the last element, so if it
@ -99,17 +99,17 @@
any = any || background_color.is_some(); any = any || background_color.is_some();
if any { if any {
if let Some(position) = position { if let Some(position) = position {
background_position_x.0.push(position.horizontal); background_position_x.push(position.horizontal);
background_position_y.0.push(position.vertical); background_position_y.push(position.vertical);
} else { } else {
background_position_x.0.push(PositionComponent::zero()); background_position_x.push(PositionComponent::zero());
background_position_y.0.push(PositionComponent::zero()); background_position_y.push(PositionComponent::zero());
} }
% for name in "image repeat size attachment origin clip".split(): % for name in "image repeat size attachment origin clip".split():
if let Some(bg_${name}) = ${name} { if let Some(bg_${name}) = ${name} {
background_${name}.0.push(bg_${name}); background_${name}.push(bg_${name});
} else { } else {
background_${name}.0.push(background_${name}::single_value background_${name}.push(background_${name}::single_value
::get_initial_specified_value()); ::get_initial_specified_value());
} }
% endfor % endfor
@ -121,14 +121,9 @@
Ok(expanded! { Ok(expanded! {
background_color: background_color.unwrap_or(Color::transparent()), background_color: background_color.unwrap_or(Color::transparent()),
background_image: background_image, % for name in "image position_x position_y repeat size attachment origin clip".split():
background_position_x: background_position_x, background_${name}: background_${name}::SpecifiedValue(background_${name}.into()),
background_position_y: background_position_y, % endfor
background_repeat: background_repeat,
background_attachment: background_attachment,
background_size: background_size,
background_origin: background_origin,
background_clip: background_clip,
}) })
} }
@ -209,16 +204,16 @@
) -> Result<Longhands, ParseError<'i>> { ) -> Result<Longhands, ParseError<'i>> {
// Vec grows from 0 to 4 by default on first push(). So allocate with // 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 // 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 // overallocate, then shrink. Note that we always push at least one
// succeeds. // item if parsing succeeds.
let mut position_x = background_position_x::SpecifiedValue(Vec::with_capacity(1)); let mut position_x = Vec::with_capacity(1);
let mut position_y = background_position_y::SpecifiedValue(Vec::with_capacity(1)); let mut position_y = Vec::with_capacity(1);
let mut any = false; let mut any = false;
input.parse_comma_separated(|input| { input.parse_comma_separated(|input| {
let value = Position::parse_quirky(context, input, AllowQuirks::Yes)?; let value = Position::parse_quirky(context, input, AllowQuirks::Yes)?;
position_x.0.push(value.horizontal); position_x.push(value.horizontal);
position_y.0.push(value.vertical); position_y.push(value.vertical);
any = true; any = true;
Ok(()) Ok(())
})?; })?;
@ -227,8 +222,8 @@
} }
Ok(expanded! { Ok(expanded! {
background_position_x: position_x, background_position_x: background_position_x::SpecifiedValue(position_x.into()),
background_position_y: position_y, background_position_y: background_position_y::SpecifiedValue(position_y.into()),
}) })
} }

View file

@ -7,7 +7,7 @@
${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::Color::parse", ${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::Color::parse",
spec="https://drafts.csswg.org/css-backgrounds/#border-color", spec="https://drafts.csswg.org/css-backgrounds/#border-color",
allow_quirks=True)} allow_quirks="Yes")}
${helpers.four_sides_shorthand( ${helpers.four_sides_shorthand(
"border-style", "border-style",

View file

@ -137,7 +137,7 @@ macro_rules! try_parse_one {
Ok(expanded! { Ok(expanded! {
% for prop in "property duration timing_function delay".split(): % 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 % endfor
}) })
} }
@ -266,7 +266,7 @@ macro_rules! try_parse_one {
Ok(expanded! { Ok(expanded! {
% for prop in props: % for prop in props:
animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s), animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s.into()),
% endfor % endfor
}) })
} }

View file

@ -10,7 +10,7 @@ ${helpers.four_sides_shorthand(
"specified::LengthPercentageOrAuto::parse", "specified::LengthPercentageOrAuto::parse",
spec="https://drafts.csswg.org/css-box/#propdef-margin", spec="https://drafts.csswg.org/css-box/#propdef-margin",
allowed_in_page_rule=True, allowed_in_page_rule=True,
allow_quirks=True, allow_quirks="Yes",
)} )}
${helpers.two_properties_shorthand( ${helpers.two_properties_shorthand(

View file

@ -9,7 +9,7 @@ ${helpers.four_sides_shorthand(
"padding-%s", "padding-%s",
"specified::NonNegativeLengthPercentage::parse", "specified::NonNegativeLengthPercentage::parse",
spec="https://drafts.csswg.org/css-box-3/#propdef-padding", spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
allow_quirks=True, allow_quirks="Yes",
)} )}
${helpers.two_properties_shorthand( ${helpers.two_properties_shorthand(

View file

@ -768,7 +768,7 @@ ${helpers.four_sides_shorthand(
"%s", "%s",
"specified::LengthPercentageOrAuto::parse", "specified::LengthPercentageOrAuto::parse",
spec="https://drafts.csswg.org/css-logical/#propdef-inset", spec="https://drafts.csswg.org/css-logical/#propdef-inset",
allow_quirks=False, allow_quirks="No",
)} )}
${helpers.two_properties_shorthand( ${helpers.two_properties_shorthand(

View file

@ -42,11 +42,11 @@
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> { ) -> Result<Longhands, ParseError<'i>> {
% for name in "image mode position_x position_y size repeat origin clip composite".split(): % 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 // Vec grows from 0 to 4 by default on first push(). So allocate with
// with capacity 1, so in the common case of only one item we don't // capacity 1, so in the common case of only one item we don't way
// way overallocate. Note that we always push at least one item if // overallocate, then shrink. Note that we always push at least one
// parsing succeeds. // item if parsing succeeds.
let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::with_capacity(1)); let mut mask_${name} = Vec::with_capacity(1);
% endfor % endfor
input.parse_comma_separated(|input| { input.parse_comma_separated(|input| {
@ -96,17 +96,17 @@
% endfor % endfor
if any { if any {
if let Some(position) = position { if let Some(position) = position {
mask_position_x.0.push(position.horizontal); mask_position_x.push(position.horizontal);
mask_position_y.0.push(position.vertical); mask_position_y.push(position.vertical);
} else { } else {
mask_position_x.0.push(PositionComponent::zero()); mask_position_x.push(PositionComponent::zero());
mask_position_y.0.push(PositionComponent::zero()); mask_position_y.push(PositionComponent::zero());
} }
% for name in "image mode size repeat origin clip composite".split(): % for name in "image mode size repeat origin clip composite".split():
if let Some(m_${name}) = ${name} { if let Some(m_${name}) = ${name} {
mask_${name}.0.push(m_${name}); mask_${name}.push(m_${name});
} else { } else {
mask_${name}.0.push(mask_${name}::single_value mask_${name}.push(mask_${name}::single_value
::get_initial_specified_value()); ::get_initial_specified_value());
} }
% endfor % endfor
@ -118,7 +118,7 @@
Ok(expanded! { Ok(expanded! {
% for name in "image mode position_x position_y size repeat origin clip composite".split(): % 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 % endfor
}) })
} }
@ -209,16 +209,16 @@
) -> Result<Longhands, ParseError<'i>> { ) -> Result<Longhands, ParseError<'i>> {
// Vec grows from 0 to 4 by default on first push(). So allocate with // 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 // 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 // overallocate, then shrink. Note that we always push at least one
// succeeds. // item if parsing succeeds.
let mut position_x = mask_position_x::SpecifiedValue(Vec::with_capacity(1)); let mut position_x = Vec::with_capacity(1);
let mut position_y = mask_position_y::SpecifiedValue(Vec::with_capacity(1)); let mut position_y = Vec::with_capacity(1);
let mut any = false; let mut any = false;
input.parse_comma_separated(|input| { input.parse_comma_separated(|input| {
let value = Position::parse(context, input)?; let value = Position::parse(context, input)?;
position_x.0.push(value.horizontal); position_x.push(value.horizontal);
position_y.0.push(value.vertical); position_y.push(value.vertical);
any = true; any = true;
Ok(()) Ok(())
})?; })?;
@ -227,9 +227,10 @@
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }
Ok(expanded! { Ok(expanded! {
mask_position_x: position_x, mask_position_x: mask_position_x::SpecifiedValue(position_x.into()),
mask_position_y: position_y, mask_position_y: mask_position_y::SpecifiedValue(position_y.into()),
}) })
} }

View file

@ -13,7 +13,7 @@ use crate::selector_parser::PseudoElement;
use crate::shared_lock::Locked; use crate::shared_lock::Locked;
use crate::stylesheets::Origin; use crate::stylesheets::Origin;
use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist}; use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist};
use selectors::matching::{ElementSelectorFlags, MatchingContext}; use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
use servo_arc::ArcBorrow; use servo_arc::ArcBorrow;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -97,8 +97,15 @@ where
context: &'a mut MatchingContext<'b, E::Impl>, context: &'a mut MatchingContext<'b, E::Impl>,
flags_setter: &'a mut F, flags_setter: &'a mut F,
) -> Self { ) -> Self {
let rule_hash_target = element.rule_hash_target(); // When we're matching with matching_mode =
let matches_user_and_author_rules = element.matches_user_and_author_rules(); // `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 // Gecko definitely has pseudo-elements with style attributes, like
// ::-moz-color-swatch. // ::-moz-color-swatch.
@ -120,8 +127,8 @@ where
context, context,
flags_setter, flags_setter,
rules, rules,
matches_user_and_author_rules,
shadow_cascade_order: 0, shadow_cascade_order: 0,
matches_user_and_author_rules,
matches_document_author_rules: matches_user_and_author_rules, matches_document_author_rules: matches_user_and_author_rules,
} }
} }

View file

@ -734,10 +734,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
E: TElement, E: TElement,
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
if element if element.map_or(false, |e| e.is_pseudo_element()) {
.and_then(|e| e.implemented_pseudo_element())
.is_some()
{
// It'd be nice to assert `self.style.pseudo == Some(&pseudo)`, // It'd be nice to assert `self.style.pseudo == Some(&pseudo)`,
// but we do resolve ::-moz-list pseudos on ::before / ::after // but we do resolve ::-moz-list pseudos on ::before / ::after
// content, sigh. // content, sigh.

View file

@ -233,7 +233,7 @@ where
let mut pseudo_styles = EagerPseudoStyles::default(); 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() { let layout_parent_style_for_pseudo = if primary_style.style().is_display_contents() {
layout_parent_style layout_parent_style
} else { } else {
@ -293,10 +293,6 @@ where
layout_parent_style: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>,
pseudo: Option<&PseudoElement>, pseudo: Option<&PseudoElement>,
) -> ResolvedStyle { ) -> 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())); debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
let implemented_pseudo = self.element.implemented_pseudo_element(); let implemented_pseudo = self.element.implemented_pseudo_element();
@ -477,8 +473,8 @@ where
); );
debug_assert!(pseudo_element.is_eager()); debug_assert!(pseudo_element.is_eager());
debug_assert!( debug_assert!(
self.element.implemented_pseudo_element().is_none(), !self.element.is_pseudo_element(),
"Element pseudos can't have any other pseudo." "Element pseudos can't have any other eager pseudo."
); );
let mut applicable_declarations = ApplicableDeclarationList::new(); let mut applicable_declarations = ApplicableDeclarationList::new();

View file

@ -1195,6 +1195,10 @@ impl Stylist {
// See [3] for the bug to implement whatever gets resolved, and related // See [3] for the bug to implement whatever gets resolved, and related
// bugs for a bit more context. // 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/ // [1]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/
// core/css/resolver/style_resolver.cc?l=1267&rcl=90f9f8680ebb4a87d177f3b0833372ae4e0c88d8 // core/css/resolver/style_resolver.cc?l=1267&rcl=90f9f8680ebb4a87d177f3b0833372ae4e0c88d8
// [2]: https://github.com/w3c/csswg-drafts/issues/1995 // [2]: https://github.com/w3c/csswg-drafts/issues/1995

View file

@ -9,22 +9,18 @@ use crate::values::computed::length::Length;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::computed::url::ComputedUrl; use crate::values::computed::url::ComputedUrl;
use crate::values::computed::{Angle, Number}; 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::Filter as GenericFilter;
use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow; use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow;
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
use crate::values::Impossible; use crate::values::Impossible;
/// An animated value for a single `box-shadow`. /// An animated value for the `drop-shadow()` filter.
pub type BoxShadow = GenericBoxShadow<Color, Length, Length, Length>; pub type AnimatedSimpleShadow = GenericSimpleShadow<Color, Length, Length>;
/// An animated value for a single `filter`. /// An animated value for a single `filter`.
#[cfg(feature = "gecko")] #[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`. /// An animated value for a single `filter`.
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>; pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
/// An animated value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Color, Length, Length>;

View file

@ -861,7 +861,7 @@ impl Animate for ComputedTransform {
// animation procedures so we treat it separately here rather than // animation procedures so we treat it separately here rather than
// handling it in TransformOperation. // handling it in TransformOperation.
if procedure == Procedure::Add { 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)); return Ok(Transform(result));
} }
@ -898,15 +898,15 @@ impl Animate for ComputedTransform {
}, },
Procedure::Interpolate { progress } => { Procedure::Interpolate { progress } => {
result.push(TransformOperation::InterpolateMatrix { result.push(TransformOperation::InterpolateMatrix {
from_list: Transform(this_remainder.to_vec()), from_list: Transform(this_remainder.to_vec().into()),
to_list: Transform(other_remainder.to_vec()), to_list: Transform(other_remainder.to_vec().into()),
progress: Percentage(progress as f32), progress: Percentage(progress as f32),
}); });
}, },
Procedure::Accumulate { count } => { Procedure::Accumulate { count } => {
result.push(TransformOperation::AccumulateMatrix { result.push(TransformOperation::AccumulateMatrix {
from_list: Transform(this_remainder.to_vec()), from_list: Transform(this_remainder.to_vec().into()),
to_list: Transform(other_remainder.to_vec()), to_list: Transform(other_remainder.to_vec().into()),
count: cmp::min(count, i32::max_value() as u64) as i32, 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. // matrix. Instead we need to wrap it in another ___Matrix type.
TransformOperation::AccumulateMatrix { .. } | TransformOperation::AccumulateMatrix { .. } |
TransformOperation::InterpolateMatrix { .. } => { TransformOperation::InterpolateMatrix { .. } => {
let transform_list = Transform(vec![transform.clone()]); let transform_list = Transform(vec![transform.clone()].into());
let identity_list = Transform(vec![identity]); let identity_list = Transform(vec![identity].into());
let (from_list, to_list) = if fill_right { let (from_list, to_list) = if fill_right {
(transform_list, identity_list) (transform_list, identity_list)
} else { } else {
@ -970,7 +970,7 @@ impl Animate for ComputedTransform {
(None, None) => {}, (None, None) => {},
} }
Ok(Transform(result)) Ok(Transform(result.into()))
} }
} }

View file

@ -26,6 +26,7 @@ use style_traits::{CssWriter, ToCss};
ToAnimatedZero, ToAnimatedZero,
ToResolvedValue, ToResolvedValue,
)] )]
#[repr(C)]
pub struct Angle(CSSFloat); pub struct Angle(CSSFloat);
impl ToCss for Angle { impl ToCss for Angle {

View file

@ -7,10 +7,10 @@
use crate::values::computed::length::{NonNegativeLength, NonNegativeLengthPercentage}; use crate::values::computed::length::{NonNegativeLength, NonNegativeLengthPercentage};
use crate::values::computed::{NonNegativeNumber, NonNegativeNumberOrPercentage}; use crate::values::computed::{NonNegativeNumber, NonNegativeNumberOrPercentage};
use crate::values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; 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::BorderImageSlice as GenericBorderImageSlice;
use crate::values::generics::border::BorderRadius as GenericBorderRadius; use crate::values::generics::border::BorderRadius as GenericBorderRadius;
use crate::values::generics::border::BorderSpacing as GenericBorderSpacing; use crate::values::generics::border::BorderSpacing as GenericBorderSpacing;
use crate::values::generics::border::GenericBorderImageSideWidth;
use crate::values::generics::rect::Rect; use crate::values::generics::rect::Rect;
use crate::values::generics::size::Size2D; use crate::values::generics::size::Size2D;
use crate::values::generics::NonNegative; use crate::values::generics::NonNegative;

View file

@ -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>;

View file

@ -9,21 +9,19 @@ pub use crate::values::specified::list::ListStyleType;
pub use crate::values::specified::list::MozListReversed; pub use crate::values::specified::list::MozListReversed;
pub use crate::values::specified::list::{QuotePair, Quotes}; pub use crate::values::specified::list::{QuotePair, Quotes};
use servo_arc::Arc;
lazy_static! { lazy_static! {
static ref INITIAL_QUOTES: Arc<Box<[QuotePair]>> = Arc::new( static ref INITIAL_QUOTES: crate::ArcSlice<QuotePair> = crate::ArcSlice::from_iter(
vec![ vec![
QuotePair { QuotePair {
opening: "\u{201c}".to_owned().into_boxed_str(), opening: "\u{201c}".to_owned().into(),
closing: "\u{201d}".to_owned().into_boxed_str(), closing: "\u{201d}".to_owned().into(),
}, },
QuotePair { QuotePair {
opening: "\u{2018}".to_owned().into_boxed_str(), opening: "\u{2018}".to_owned().into(),
closing: "\u{2019}".to_owned().into_boxed_str(), closing: "\u{2019}".to_owned().into(),
}, },
] ]
.into_boxed_slice() .into_iter()
); );
} }

View file

@ -56,8 +56,6 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis};
pub use self::font::{FontVariantAlternates, FontWeight}; pub use self::font::{FontVariantAlternates, FontWeight};
pub use self::font::{FontVariantEastAsian, FontVariationSettings}; pub use self::font::{FontVariantEastAsian, FontVariationSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; 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::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength}; pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber}; 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::ListStyleType;
pub use self::list::MozListReversed; pub use self::list::MozListReversed;
pub use self::list::{QuotePair, Quotes}; 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::outline::OutlineStyle;
pub use self::percentage::{NonNegativePercentage, Percentage}; pub use self::percentage::{NonNegativePercentage, Percentage};
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex}; 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::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::table::XSpan; 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::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle}; pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
pub use self::time::Time; pub use self::time::Time;
@ -106,8 +104,6 @@ pub mod easing;
pub mod effects; pub mod effects;
pub mod flex; pub mod flex;
pub mod font; pub mod font;
#[cfg(feature = "gecko")]
pub mod gecko;
pub mod image; pub mod image;
pub mod length; pub mod length;
pub mod list; pub mod list;
@ -454,17 +450,12 @@ where
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
self.iter() self.iter()
.map(|item| item.to_computed_value(context)) .map(|item| item.to_computed_value(context))
.collect::<Vec<_>>() .collect()
.into()
} }
#[inline] #[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self { fn from_computed_value(computed: &Self::ComputedValue) -> Self {
computed computed.iter().map(T::from_computed_value).collect()
.iter()
.map(T::from_computed_value)
.collect::<Vec<_>>()
.into()
} }
} }

View file

@ -4,7 +4,41 @@
//! Computed types for CSS values that are related to motion path. //! 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. /// A computed offset-path. The computed value is as specified value.
/// ///
/// https://drafts.fxtf.org/motion-1/#offset-path-property /// https://drafts.fxtf.org/motion-1/#offset-path-property
pub use crate::values::specified::motion::OffsetPath; 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(),
}
}
}

View file

@ -20,7 +20,7 @@ use style_traits::{CssWriter, ToCss};
pub use crate::values::specified::TextAlignKeyword as TextAlign; pub use crate::values::specified::TextAlignKeyword as TextAlign;
pub use crate::values::specified::TextTransform; 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}; pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
/// A computed value for the `initial-letter` property. /// A computed value for the `initial-letter` property.
@ -105,6 +105,7 @@ impl ToComputedValue for specified::WordSpacing {
pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLength>; pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLength>;
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToResolvedValue)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToResolvedValue)]
#[repr(C)]
/// text-overflow. /// text-overflow.
/// When the specified value only has one side, that's the "second" /// When the specified value only has one side, that's the "second"
/// side, and the sides are logical, so "second" means "end". The /// side, and the sides are logical, so "second" means "end". The

View file

@ -16,9 +16,9 @@ pub use crate::values::generics::transform::TransformStyle;
/// A single operation in a computed CSS `transform` /// A single operation in a computed CSS `transform`
pub type TransformOperation = pub type TransformOperation =
generic::TransformOperation<Angle, Number, Length, Integer, LengthPercentage>; generic::GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>;
/// A computed CSS `transform` /// A computed CSS `transform`
pub type Transform = generic::Transform<TransformOperation>; pub type Transform = generic::GenericTransform<TransformOperation>;
/// The computed value of a CSS `<transform-origin>` /// The computed value of a CSS `<transform-origin>`
pub type TransformOrigin = pub type TransformOrigin =
@ -540,88 +540,16 @@ impl ToAnimatedZero for Transform {
self.0 self.0
.iter() .iter()
.map(|op| op.to_animated_zero()) .map(|op| op.to_animated_zero())
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<crate::OwnedSlice<_>, _>>()?,
)) ))
} }
} }
/// A computed CSS `rotate` /// A computed CSS `rotate`
pub type Rotate = generic::Rotate<Number, Angle>; pub type Rotate = generic::GenericRotate<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"),
}
}
}
/// A computed CSS `translate` /// A computed CSS `translate`
pub type Translate = generic::Translate<LengthPercentage, Length>; pub type Translate = generic::GenericTranslate<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"),
}
}
}
/// A computed CSS `scale` /// A computed CSS `scale`
pub type Scale = generic::Scale<Number>; pub type Scale = generic::GenericScale<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"),
}
}
}

View file

@ -23,15 +23,18 @@ use style_traits::{CssWriter, ToCss};
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub enum BorderImageSideWidth<LengthPercentage, Number> { #[repr(C, u8)]
pub enum GenericBorderImageSideWidth<LP, N> {
/// `<length-or-percentage>` /// `<length-or-percentage>`
Length(LengthPercentage), LengthPercentage(LP),
/// `<number>` /// `<number>`
Number(Number), Number(N),
/// `auto` /// `auto`
Auto, Auto,
} }
pub use self::GenericBorderImageSideWidth as BorderImageSideWidth;
/// A generic value for the `border-image-slice` property. /// A generic value for the `border-image-slice` property.
#[derive( #[derive(
Clone, Clone,

View file

@ -19,9 +19,10 @@
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> { #[repr(C)]
pub struct GenericBoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
/// The base shadow. /// The base shadow.
pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>, pub base: GenericSimpleShadow<Color, SizeLength, BlurShapeLength>,
/// The spread radius. /// The spread radius.
pub spread: ShapeLength, pub spread: ShapeLength,
/// Whether this is an inset box shadow. /// Whether this is an inset box shadow.
@ -30,6 +31,8 @@ pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
pub inset: bool, pub inset: bool,
} }
pub use self::GenericBoxShadow as BoxShadow;
/// A generic value for a single `filter`. /// A generic value for a single `filter`.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[animation(no_bound(Url))] #[animation(no_bound(Url))]
@ -100,7 +103,8 @@ pub enum Filter<Angle, Factor, Length, DropShadow, Url> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub struct SimpleShadow<Color, SizeLength, ShapeLength> { #[repr(C)]
pub struct GenericSimpleShadow<Color, SizeLength, ShapeLength> {
/// Color. /// Color.
pub color: Color, pub color: Color,
/// Horizontal radius. /// Horizontal radius.
@ -110,3 +114,5 @@ pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
/// Blur radius. /// Blur radius.
pub blur: ShapeLength, pub blur: ShapeLength,
} }
pub use self::GenericSimpleShadow as SimpleShadow;

View file

@ -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),
}
}
}

View file

@ -26,8 +26,6 @@ pub mod easing;
pub mod effects; pub mod effects;
pub mod flex; pub mod flex;
pub mod font; pub mod font;
#[cfg(feature = "gecko")]
pub mod gecko;
pub mod grid; pub mod grid;
pub mod image; pub mod image;
pub mod length; pub mod length;

View file

@ -30,8 +30,9 @@ use style_traits::{CssWriter, ToCss};
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[css(comma, function)] #[css(comma, function = "matrix")]
pub struct Matrix<T> { #[repr(C)]
pub struct GenericMatrix<T> {
pub a: T, pub a: T,
pub b: T, pub b: T,
pub c: T, pub c: T,
@ -40,6 +41,8 @@ pub struct Matrix<T> {
pub f: T, pub f: T,
} }
pub use self::GenericMatrix as Matrix;
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(rustfmt, rustfmt_skip)] #[cfg_attr(rustfmt, rustfmt_skip)]
#[css(comma, function = "matrix3d")] #[css(comma, function = "matrix3d")]
@ -55,13 +58,16 @@ pub struct Matrix<T> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub struct Matrix3D<T> { #[repr(C)]
pub struct GenericMatrix3D<T> {
pub m11: T, pub m12: T, pub m13: T, pub m14: 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 m21: T, pub m22: T, pub m23: T, pub m24: T,
pub m31: T, pub m32: T, pub m33: T, pub m34: 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 m41: T, pub m42: T, pub m43: T, pub m44: T,
} }
pub use self::GenericMatrix3D as Matrix3D;
#[cfg_attr(rustfmt, rustfmt_skip)] #[cfg_attr(rustfmt, rustfmt_skip)]
impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> { impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> {
#[inline] #[inline]
@ -142,17 +148,19 @@ fn is_same<N: PartialEq>(x: &N, y: &N) -> bool {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C, u8)]
/// A single operation in the list of a `transform` value /// 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 where
Angle: Zero, Angle: Zero,
LengthPercentage: Zero, LengthPercentage: Zero,
Number: PartialEq, Number: PartialEq,
{ {
/// Represents a 2D 2x3 matrix. /// Represents a 2D 2x3 matrix.
Matrix(Matrix<Number>), Matrix(GenericMatrix<Number>),
/// Represents a 3D 4x4 matrix. /// Represents a 3D 4x4 matrix.
Matrix3D(Matrix3D<Number>), Matrix3D(GenericMatrix3D<Number>),
/// A 2D skew. /// A 2D skew.
/// ///
/// If the second angle is not provided it is assumed zero. /// If the second angle is not provided it is assumed zero.
@ -232,20 +240,30 @@ where
#[allow(missing_docs)] #[allow(missing_docs)]
#[css(comma, function = "interpolatematrix")] #[css(comma, function = "interpolatematrix")]
InterpolateMatrix { InterpolateMatrix {
from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, from_list: GenericTransform<
to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
>,
to_list: GenericTransform<
GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
>,
progress: computed::Percentage, progress: computed::Percentage,
}, },
/// A intermediate type for accumulation of mismatched transform lists. /// A intermediate type for accumulation of mismatched transform lists.
#[allow(missing_docs)] #[allow(missing_docs)]
#[css(comma, function = "accumulatematrix")] #[css(comma, function = "accumulatematrix")]
AccumulateMatrix { AccumulateMatrix {
from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, from_list: GenericTransform<
to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
>,
to_list: GenericTransform<
GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
>,
count: Integer, count: Integer,
}, },
} }
pub use self::GenericTransformOperation as TransformOperation;
#[derive( #[derive(
Clone, Clone,
Debug, Debug,
@ -257,8 +275,11 @@ where
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C)]
/// A value of the `transform` property /// 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> impl<Angle, Number, Length, Integer, LengthPercentage>
TransformOperation<Angle, Number, Length, Integer, LengthPercentage> TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
@ -497,7 +518,7 @@ where
impl<T> Transform<T> { impl<T> Transform<T> {
/// `none` /// `none`
pub fn none() -> Self { 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 transform = Transform3D::<f64>::identity();
let mut contain_3d = false; let mut contain_3d = false;
for operation in &self.0 { for operation in &*self.0 {
let matrix = operation.to_3d_matrix(reference_box)?; let matrix = operation.to_3d_matrix(reference_box)?;
contain_3d |= operation.is_3d(); contain_3d |= operation.is_3d();
transform = transform.pre_mul(&matrix); transform = transform.pre_mul(&matrix);
@ -589,10 +610,11 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C, u8)]
/// A value of the `Rotate` property /// A value of the `Rotate` property
/// ///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
pub enum Rotate<Number, Angle> { pub enum GenericRotate<Number, Angle> {
/// 'none' /// 'none'
None, None,
/// '<angle>' /// '<angle>'
@ -601,6 +623,8 @@ pub enum Rotate<Number, Angle> {
Rotate3D(Number, Number, 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. /// A trait to check if the current 3D vector is parallel to the DirectionVector.
/// This is especially for serialization on Rotate. /// This is especially for serialization on Rotate.
pub trait IsParallelTo { pub trait IsParallelTo {
@ -660,10 +684,11 @@ where
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C, u8)]
/// A value of the `Scale` property /// A value of the `Scale` property
/// ///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
pub enum Scale<Number> { pub enum GenericScale<Number> {
/// 'none' /// 'none'
None, None,
/// '<number>{1,2}' /// '<number>{1,2}'
@ -672,6 +697,8 @@ pub enum Scale<Number> {
Scale3D(Number, Number, Number), Scale3D(Number, Number, Number),
} }
pub use self::GenericScale as Scale;
impl<Number: ToCss + PartialEq> ToCss for Scale<Number> { impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where where
@ -710,6 +737,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C, u8)]
/// A value of the `translate` property /// A value of the `translate` property
/// ///
/// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization: /// 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 /// related spec issue is https://github.com/w3c/csswg-drafts/issues/3305
/// ///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
pub enum Translate<LengthPercentage, Length> pub enum GenericTranslate<LengthPercentage, Length>
where where
LengthPercentage: Zero, LengthPercentage: Zero,
{ {
@ -739,6 +767,8 @@ where
Translate3D(LengthPercentage, LengthPercentage, Length), Translate3D(LengthPercentage, LengthPercentage, Length),
} }
pub use self::GenericTranslate as Translate;
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive( #[derive(
Clone, Clone,

View file

@ -174,6 +174,7 @@ impl<A: Debug, B: Debug> Debug for Either<A, B> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C)]
pub struct CustomIdent(pub Atom); pub struct CustomIdent(pub Atom);
impl CustomIdent { impl CustomIdent {

View file

@ -183,7 +183,7 @@ impl Parse for BorderImageSideWidth {
} }
if let Ok(len) = input.try(|i| NonNegativeLengthPercentage::parse(context, i)) { 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)?; let num = NonNegativeNumber::parse(context, input)?;

View file

@ -642,6 +642,7 @@ pub enum OverflowClipBox {
#[derive( #[derive(
Clone, Clone,
Debug, Debug,
Default,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
@ -650,38 +651,38 @@ pub enum OverflowClipBox {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
/// Provides a rendering hint to the user agent, #[css(comma)]
/// stating what kinds of changes the author expects #[repr(C)]
/// to perform on the element /// 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> /// <https://drafts.csswg.org/css-will-change/#will-change>
pub enum WillChange { pub struct WillChange {
/// Expresses no particular intent /// The features that are supposed to change.
Auto, ///
/// <custom-ident> /// TODO(emilio): Consider using ArcSlice since we just clone them from the
#[css(comma)] /// specified value? That'd save an allocation, which could be worth it.
AnimateableFeatures { #[css(iterable, if_empty = "auto")]
/// The features that are supposed to change. features: crate::OwnedSlice<CustomIdent>,
#[css(iterable)] /// A bitfield with the kind of change that the value will create, based
features: Box<[CustomIdent]>, /// on the above field.
/// A bitfield with the kind of change that the value will create, based #[css(skip)]
/// on the above field. bits: WillChangeBits,
#[css(skip)]
bits: WillChangeBits,
},
} }
impl WillChange { impl WillChange {
#[inline] #[inline]
/// Get default value of `will-change` as `auto` /// Get default value of `will-change` as `auto`
pub fn auto() -> WillChange { pub fn auto() -> Self {
WillChange::Auto Self::default()
} }
} }
bitflags! { bitflags! {
/// The change bits that we care about. /// The change bits that we care about.
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)] #[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
#[repr(C)] #[repr(C)]
pub struct WillChangeBits: u8 { pub struct WillChangeBits: u8 {
/// Whether the stacking context will change. /// Whether the stacking context will change.
@ -746,7 +747,7 @@ impl Parse for WillChange {
.try(|input| input.expect_ident_matching("auto")) .try(|input| input.expect_ident_matching("auto"))
.is_ok() .is_ok()
{ {
return Ok(WillChange::Auto); return Ok(Self::default());
} }
let mut bits = WillChangeBits::empty(); let mut bits = WillChangeBits::empty();
@ -767,8 +768,8 @@ impl Parse for WillChange {
Ok(ident) Ok(ident)
})?; })?;
Ok(WillChange::AnimateableFeatures { Ok(Self {
features: custom_idents.into_boxed_slice(), features: custom_idents.into(),
bits, bits,
}) })
} }

View file

@ -17,7 +17,7 @@ use crate::values::specified::color::Color;
use crate::values::specified::length::{Length, NonNegativeLength}; use crate::values::specified::length::{Length, NonNegativeLength};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::specified::url::SpecifiedUrl; use crate::values::specified::url::SpecifiedUrl;
use crate::values::specified::{Angle, NumberOrPercentage}; use crate::values::specified::{Angle, Number, NumberOrPercentage};
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
use crate::values::Impossible; use crate::values::Impossible;
use crate::Zero; use crate::Zero;
@ -62,6 +62,10 @@ impl Factor {
}, },
} }
} }
fn one() -> Self {
Factor(NumberOrPercentage::Number(Number::new(1.0)))
}
} }
impl Parse for Factor { impl Parse for Factor {
@ -209,34 +213,61 @@ impl Parse for Filter {
}; };
input.parse_nested_block(|i| { input.parse_nested_block(|i| {
match_ignore_ascii_case! { &*function, match_ignore_ascii_case! { &*function,
"blur" => Ok(GenericFilter::Blur((Length::parse_non_negative(context, i)?).into())), "blur" => Ok(GenericFilter::Blur(
"brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)), i.try(|i| NonNegativeLength::parse(context, i))
"contrast" => Ok(GenericFilter::Contrast(Factor::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" => { "grayscale" => {
// Values of amount over 100% are allowed but UAs must clamp the values to 1. // Values of amount over 100% are allowed but UAs must clamp the values to 1.
// https://drafts.fxtf.org/filter-effects/#funcdef-filter-grayscale // 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" => { "hue-rotate" => {
// We allow unitless zero here, see: // We allow unitless zero here, see:
// https://github.com/w3c/fxtf-drafts/issues/228 // 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" => { "invert" => {
// Values of amount over 100% are allowed but UAs must clamp the values to 1. // Values of amount over 100% are allowed but UAs must clamp the values to 1.
// https://drafts.fxtf.org/filter-effects/#funcdef-filter-invert // 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" => { "opacity" => {
// Values of amount over 100% are allowed but UAs must clamp the values to 1. // Values of amount over 100% are allowed but UAs must clamp the values to 1.
// https://drafts.fxtf.org/filter-effects/#funcdef-filter-opacity // 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" => { "sepia" => {
// Values of amount over 100% are allowed but UAs must clamp the values to 1. // Values of amount over 100% are allowed but UAs must clamp the values to 1.
// https://drafts.fxtf.org/filter-effects/#funcdef-filter-sepia // 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)?)), "drop-shadow" => Ok(GenericFilter::DropShadow(Parse::parse(context, i)?)),
_ => Err(location.new_custom_error( _ => Err(location.new_custom_error(

View file

@ -7,33 +7,12 @@
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::values::computed::length::CSSPixelLength; use crate::values::computed::length::CSSPixelLength;
use crate::values::computed::{self, LengthPercentage}; use crate::values::computed::{self, LengthPercentage};
use crate::values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint;
use crate::values::generics::rect::Rect; use crate::values::generics::rect::Rect;
use crate::values::specified::length::LengthPercentage as SpecifiedLengthPercentage;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use std::fmt; use std::fmt;
use style_traits::values::SequenceWriter; use style_traits::values::SequenceWriter;
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; 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>( fn parse_pixel_or_percent<'i, 't>(
_context: &ParserContext, _context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,

View file

@ -10,7 +10,6 @@ use crate::values::generics::CounterStyleOrNone;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::CustomIdent; use crate::values::CustomIdent;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use servo_arc::Arc;
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, StyleParseErrorKind};
/// Specified and computed `list-style-type` property. /// Specified and computed `list-style-type` property.
@ -96,18 +95,20 @@ impl Parse for ListStyleType {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C)]
pub struct QuotePair { pub struct QuotePair {
/// The opening quote. /// The opening quote.
pub opening: Box<str>, pub opening: crate::OwnedStr,
/// The closing quote. /// The closing quote.
pub closing: Box<str>, pub closing: crate::OwnedStr,
} }
/// Specified and computed `quotes` property. /// Specified and computed `quotes` property.
#[derive( #[derive(
Clone, Clone,
Debug, Debug,
Default,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
@ -116,10 +117,11 @@ pub struct QuotePair {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C)]
pub struct Quotes( pub struct Quotes(
#[css(iterable, if_empty = "none")] #[css(iterable, if_empty = "none")]
#[ignore_malloc_size_of = "Arc"] #[ignore_malloc_size_of = "Arc"]
pub Arc<Box<[QuotePair]>>, pub crate::ArcSlice<QuotePair>,
); );
impl Parse for Quotes { impl Parse for Quotes {
@ -131,24 +133,24 @@ impl Parse for Quotes {
.try(|input| input.expect_ident_matching("none")) .try(|input| input.expect_ident_matching("none"))
.is_ok() .is_ok()
{ {
return Ok(Quotes(Arc::new(Box::new([])))); return Ok(Self::default());
} }
let mut quotes = Vec::new(); let mut quotes = Vec::new();
loop { loop {
let location = input.current_source_location(); let location = input.current_source_location();
let opening = match input.next() { 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())), Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
Err(_) => break, 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 }); quotes.push(QuotePair { opening, closing });
} }
if !quotes.is_empty() { if !quotes.is_empty() {
Ok(Quotes(Arc::new(quotes.into_boxed_slice()))) Ok(Quotes(crate::ArcSlice::from_iter(quotes.into_iter())))
} else { } else {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
} }

View file

@ -54,8 +54,6 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis};
pub use self::font::{FontVariantAlternates, FontWeight}; pub use self::font::{FontVariantAlternates, FontWeight};
pub use self::font::{FontVariantEastAsian, FontVariationSettings}; pub use self::font::{FontVariantEastAsian, FontVariationSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; 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::{ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect}; pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect};
pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth}; 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::ListStyleType;
pub use self::list::MozListReversed; pub use self::list::MozListReversed;
pub use self::list::{QuotePair, Quotes}; 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::outline::OutlineStyle;
pub use self::percentage::Percentage; pub use self::percentage::Percentage;
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position}; 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::svg_path::SVGPathData;
pub use self::table::XSpan; pub use self::table::XSpan;
pub use self::text::TextTransform; 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::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
pub use self::time::Time; pub use self::time::Time;

View file

@ -5,13 +5,17 @@
//! Specified types for CSS values that are related to motion path. //! Specified types for CSS values that are related to motion path.
use crate::parser::{Parse, ParserContext}; 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 cssparser::Parser;
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, StyleParseErrorKind};
/// The offset-path value. /// The offset-path value.
/// ///
/// https://drafts.fxtf.org/motion-1/#offset-path-property /// https://drafts.fxtf.org/motion-1/#offset-path-property
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Animate, Animate,
Clone, Clone,
@ -26,6 +30,7 @@ use style_traits::{ParseError, StyleParseErrorKind};
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C, u8)]
pub enum OffsetPath { pub enum OffsetPath {
// We could merge SVGPathData into ShapeSource, so we could reuse them. However, // 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. // 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),
}
}
}

View file

@ -12,7 +12,7 @@ use crate::values::specified::AllowQuirks;
use crate::values::specified::LengthPercentage; use crate::values::specified::LengthPercentage;
use crate::values::specified::{NonNegativeLengthPercentage, Opacity}; use crate::values::specified::{NonNegativeLengthPercentage, Opacity};
use crate::values::CustomIdent; use crate::values::CustomIdent;
use cssparser::Parser; use cssparser::{Parser, Token};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CommaWithSpace, CssWriter, ParseError, Separator}; use style_traits::{CommaWithSpace, CssWriter, ParseError, Separator};
use style_traits::{StyleParseErrorKind, ToCss}; 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. /// Specified MozContextProperties value.
/// Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties) /// Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)
#[derive( #[derive(
Clone, Clone,
Debug, Debug,
Default,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
@ -256,19 +273,61 @@ impl ToCss for SVGPaintOrder {
ToResolvedValue, ToResolvedValue,
ToShmem, 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 { impl Parse for MozContextProperties {
fn parse<'i, 't>( fn parse<'i, 't>(
_context: &ParserContext, _context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<MozContextProperties, ParseError<'i>> { ) -> Result<MozContextProperties, ParseError<'i>> {
let location = input.current_source_location(); let mut values = vec![];
let i = input.expect_ident()?; let mut bits = ContextPropertyBits::empty();
Ok(MozContextProperties(CustomIdent::from_ident( loop {
location, {
i, let location = input.current_source_location();
&["all", "none", "auto"], 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,
})
} }
} }

View file

@ -134,14 +134,16 @@ impl ToComputedValue for LineHeight {
} }
/// A generic value for the `text-overflow` property. /// A generic value for the `text-overflow` property.
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
#[repr(C, u8)]
pub enum TextOverflowSide { pub enum TextOverflowSide {
/// Clip inline content. /// Clip inline content.
Clip, Clip,
/// Render ellipsis to represent clipped inline content. /// Render ellipsis to represent clipped inline content.
Ellipsis, Ellipsis,
/// Render a given string to represent clipped inline content. /// Render a given string to represent clipped inline content.
String(Box<str>), String(crate::OwnedStr),
} }
impl Parse for TextOverflowSide { impl Parse for TextOverflowSide {
@ -160,9 +162,9 @@ impl Parse for TextOverflowSide {
)) ))
} }
}, },
Token::QuotedString(ref v) => Ok(TextOverflowSide::String( Token::QuotedString(ref v) => {
v.as_ref().to_owned().into_boxed_str(), Ok(TextOverflowSide::String(v.as_ref().to_owned().into()))
)), },
ref t => Err(location.new_unexpected_token_error(t.clone())), ref t => Err(location.new_unexpected_token_error(t.clone())),
} }
} }
@ -1005,6 +1007,31 @@ pub enum WordBreak {
BreakWord, 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. /// Values for the `overflow-wrap` property.
#[repr(u8)] #[repr(u8)]
#[derive( #[derive(

View file

@ -42,183 +42,187 @@ impl Transform {
.try(|input| input.expect_ident_matching("none")) .try(|input| input.expect_ident_matching("none"))
.is_ok() .is_ok()
{ {
return Ok(generic::Transform(Vec::new())); return Ok(generic::Transform::none());
} }
Ok(generic::Transform(Space::parse(input, |input| { Ok(generic::Transform(
let function = input.expect_function()?.clone(); Space::parse(input, |input| {
input.parse_nested_block(|input| { let function = input.expect_function()?.clone();
let location = input.current_source_location(); input.parse_nested_block(|input| {
let result = match_ignore_ascii_case! { &function, let location = input.current_source_location();
"matrix" => { let result = match_ignore_ascii_case! { &function,
let a = Number::parse(context, input)?; "matrix" => {
input.expect_comma()?; let a = Number::parse(context, input)?;
let b = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let b = Number::parse(context, input)?;
let c = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let c = Number::parse(context, input)?;
let d = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let d = Number::parse(context, input)?;
// Standard matrix parsing. input.expect_comma()?;
let e = Number::parse(context, input)?; // Standard matrix parsing.
input.expect_comma()?; let e = Number::parse(context, input)?;
let f = Number::parse(context, input)?; input.expect_comma()?;
Ok(generic::TransformOperation::Matrix(Matrix { a, b, c, d, e, f })) let f = Number::parse(context, input)?;
}, Ok(generic::TransformOperation::Matrix(Matrix { a, b, c, d, e, f }))
"matrix3d" => { },
let m11 = Number::parse(context, input)?; "matrix3d" => {
input.expect_comma()?; let m11 = Number::parse(context, input)?;
let m12 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m12 = Number::parse(context, input)?;
let m13 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m13 = Number::parse(context, input)?;
let m14 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m14 = Number::parse(context, input)?;
let m21 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m21 = Number::parse(context, input)?;
let m22 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m22 = Number::parse(context, input)?;
let m23 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m23 = Number::parse(context, input)?;
let m24 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m24 = Number::parse(context, input)?;
let m31 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m31 = Number::parse(context, input)?;
let m32 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m32 = Number::parse(context, input)?;
let m33 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m33 = Number::parse(context, input)?;
let m34 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m34 = Number::parse(context, input)?;
// Standard matrix3d parsing. input.expect_comma()?;
let m41 = Number::parse(context, input)?; // Standard matrix3d parsing.
input.expect_comma()?; let m41 = Number::parse(context, input)?;
let m42 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m42 = Number::parse(context, input)?;
let m43 = Number::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let m43 = Number::parse(context, input)?;
let m44 = Number::parse(context, input)?; input.expect_comma()?;
Ok(generic::TransformOperation::Matrix3D(Matrix3D { let m44 = Number::parse(context, input)?;
m11, m12, m13, m14, Ok(generic::TransformOperation::Matrix3D(Matrix3D {
m21, m22, m23, m24, m11, m12, m13, m14,
m31, m32, m33, m34, m21, m22, m23, m24,
m41, m42, m43, m44, m31, m32, m33, m34,
})) m41, m42, m43, m44,
}, }))
"translate" => { },
let sx = specified::LengthPercentage::parse(context, input)?; "translate" => {
if input.try(|input| input.expect_comma()).is_ok() { let sx = specified::LengthPercentage::parse(context, input)?;
let sy = specified::LengthPercentage::parse(context, input)?; if input.try(|input| input.expect_comma()).is_ok() {
Ok(generic::TransformOperation::Translate(sx, sy)) let sy = specified::LengthPercentage::parse(context, input)?;
} else { Ok(generic::TransformOperation::Translate(sx, sy))
Ok(generic::TransformOperation::Translate(sx, Zero::zero())) } else {
} Ok(generic::TransformOperation::Translate(sx, Zero::zero()))
}, }
"translatex" => { },
let tx = specified::LengthPercentage::parse(context, input)?; "translatex" => {
Ok(generic::TransformOperation::TranslateX(tx)) let tx = specified::LengthPercentage::parse(context, input)?;
}, Ok(generic::TransformOperation::TranslateX(tx))
"translatey" => { },
let ty = specified::LengthPercentage::parse(context, input)?; "translatey" => {
Ok(generic::TransformOperation::TranslateY(ty)) let ty = specified::LengthPercentage::parse(context, input)?;
}, Ok(generic::TransformOperation::TranslateY(ty))
"translatez" => { },
let tz = specified::Length::parse(context, input)?; "translatez" => {
Ok(generic::TransformOperation::TranslateZ(tz)) let tz = specified::Length::parse(context, input)?;
}, Ok(generic::TransformOperation::TranslateZ(tz))
"translate3d" => { },
let tx = specified::LengthPercentage::parse(context, input)?; "translate3d" => {
input.expect_comma()?; let tx = specified::LengthPercentage::parse(context, input)?;
let ty = specified::LengthPercentage::parse(context, input)?; input.expect_comma()?;
input.expect_comma()?; let ty = specified::LengthPercentage::parse(context, input)?;
let tz = specified::Length::parse(context, input)?; input.expect_comma()?;
Ok(generic::TransformOperation::Translate3D(tx, ty, tz)) let tz = specified::Length::parse(context, input)?;
}, Ok(generic::TransformOperation::Translate3D(tx, ty, tz))
"scale" => { },
let sx = Number::parse(context, input)?; "scale" => {
if input.try(|input| input.expect_comma()).is_ok() { 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)?; let sy = Number::parse(context, input)?;
Ok(generic::TransformOperation::Scale(sx, sy)) Ok(generic::TransformOperation::ScaleY(sy))
} else { },
Ok(generic::TransformOperation::Scale(sx, sx)) "scalez" => {
} let sz = Number::parse(context, input)?;
}, Ok(generic::TransformOperation::ScaleZ(sz))
"scalex" => { },
let sx = Number::parse(context, input)?; "scale3d" => {
Ok(generic::TransformOperation::ScaleX(sx)) let sx = Number::parse(context, input)?;
}, input.expect_comma()?;
"scaley" => { let sy = Number::parse(context, input)?;
let sy = Number::parse(context, input)?; input.expect_comma()?;
Ok(generic::TransformOperation::ScaleY(sy)) let sz = Number::parse(context, input)?;
}, Ok(generic::TransformOperation::Scale3D(sx, sy, sz))
"scalez" => { },
let sz = Number::parse(context, input)?; "rotate" => {
Ok(generic::TransformOperation::ScaleZ(sz)) let theta = specified::Angle::parse_with_unitless(context, input)?;
}, Ok(generic::TransformOperation::Rotate(theta))
"scale3d" => { },
let sx = Number::parse(context, input)?; "rotatex" => {
input.expect_comma()?; let theta = specified::Angle::parse_with_unitless(context, input)?;
let sy = Number::parse(context, input)?; Ok(generic::TransformOperation::RotateX(theta))
input.expect_comma()?; },
let sz = Number::parse(context, input)?; "rotatey" => {
Ok(generic::TransformOperation::Scale3D(sx, sy, sz)) let theta = specified::Angle::parse_with_unitless(context, input)?;
}, Ok(generic::TransformOperation::RotateY(theta))
"rotate" => { },
let theta = specified::Angle::parse_with_unitless(context, input)?; "rotatez" => {
Ok(generic::TransformOperation::Rotate(theta)) let theta = specified::Angle::parse_with_unitless(context, input)?;
}, Ok(generic::TransformOperation::RotateZ(theta))
"rotatex" => { },
let theta = specified::Angle::parse_with_unitless(context, input)?; "rotate3d" => {
Ok(generic::TransformOperation::RotateX(theta)) let ax = Number::parse(context, input)?;
}, input.expect_comma()?;
"rotatey" => { let ay = Number::parse(context, input)?;
let theta = specified::Angle::parse_with_unitless(context, input)?; input.expect_comma()?;
Ok(generic::TransformOperation::RotateY(theta)) let az = Number::parse(context, input)?;
}, input.expect_comma()?;
"rotatez" => { let theta = specified::Angle::parse_with_unitless(context, input)?;
let theta = specified::Angle::parse_with_unitless(context, input)?; // TODO(gw): Check that the axis can be normalized.
Ok(generic::TransformOperation::RotateZ(theta)) Ok(generic::TransformOperation::Rotate3D(ax, ay, az, theta))
}, },
"rotate3d" => { "skew" => {
let ax = Number::parse(context, input)?; let ax = specified::Angle::parse_with_unitless(context, input)?;
input.expect_comma()?; if input.try(|input| input.expect_comma()).is_ok() {
let ay = Number::parse(context, input)?; let ay = specified::Angle::parse_with_unitless(context, input)?;
input.expect_comma()?; Ok(generic::TransformOperation::Skew(ax, ay))
let az = Number::parse(context, input)?; } else {
input.expect_comma()?; Ok(generic::TransformOperation::Skew(ax, Zero::zero()))
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)) "skewx" => {
}, let theta = specified::Angle::parse_with_unitless(context, input)?;
"skew" => { Ok(generic::TransformOperation::SkewX(theta))
let ax = specified::Angle::parse_with_unitless(context, input)?; },
if input.try(|input| input.expect_comma()).is_ok() { "skewy" => {
let ay = specified::Angle::parse_with_unitless(context, input)?; let theta = specified::Angle::parse_with_unitless(context, input)?;
Ok(generic::TransformOperation::Skew(ax, ay)) Ok(generic::TransformOperation::SkewY(theta))
} else { },
Ok(generic::TransformOperation::Skew(ax, Zero::zero())) "perspective" => {
} let d = specified::Length::parse_non_negative(context, input)?;
}, Ok(generic::TransformOperation::Perspective(d))
"skewx" => { },
let theta = specified::Angle::parse_with_unitless(context, input)?; _ => Err(()),
Ok(generic::TransformOperation::SkewX(theta)) };
}, result.map_err(|()| {
"skewy" => { location.new_custom_error(StyleParseErrorKind::UnexpectedFunction(
let theta = specified::Angle::parse_with_unitless(context, input)?; function.clone(),
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(),
))
} }
} }

View file

@ -18,6 +18,7 @@ app_units = "0.7"
cssparser = "0.25" cssparser = "0.25"
bitflags = "1.0" bitflags = "1.0"
euclid = "0.19" euclid = "0.19"
lazy_static = "1"
malloc_size_of = { path = "../malloc_size_of" } malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = "0.1" malloc_size_of_derive = "0.1"
selectors = { path = "../selectors" } selectors = { path = "../selectors" }

View file

@ -5,16 +5,19 @@
//! A thin atomically-reference-counted slice. //! A thin atomically-reference-counted slice.
use servo_arc::ThinArc; use servo_arc::ThinArc;
use std::mem;
use std::ops::Deref; use std::ops::Deref;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::{iter, mem};
/// A canary that we stash in ArcSlices. /// A canary that we stash in ArcSlices.
/// ///
/// Given we cannot use a zero-sized-type for the header, since well, C++ /// 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 /// doesn't have zsts, and we want to use cbindgen for this type, we may as well
/// assert some sanity at runtime. /// 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. /// A wrapper type for a refcounted slice using ThinArc.
/// ///
@ -22,7 +25,7 @@ const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3;
/// cbindgen:derive-neq=false /// cbindgen:derive-neq=false
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, Eq, PartialEq, ToShmem)] #[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> { impl<T> Deref for ArcSlice<T> {
type Target = [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. lazy_static! {
/// The type of the pointer is a bit of a lie, we just want to preserve the type // ThinArc doesn't support alignments greater than align_of::<u64>.
/// but these pointers cannot be constructed outside of this crate, so we're static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
/// good. ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty()))
#[repr(C)] };
pub struct ForgottenArcSlicePtr<T>(NonNull<T>); }
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> { impl<T> ArcSlice<T> {
/// Creates an Arc for a slice using the given iterator to generate the /// Creates an Arc for a slice using the given iterator to generate the
@ -49,6 +68,9 @@ impl<T> ArcSlice<T> {
where where
I: Iterator<Item = T> + ExactSizeIterator, I: Iterator<Item = T> + ExactSizeIterator,
{ {
if items.len() == 0 {
return Self::default();
}
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items)) ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
} }
@ -63,4 +85,21 @@ impl<T> ArcSlice<T> {
mem::forget(self); mem::forget(self);
ret 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>);

View file

@ -16,6 +16,8 @@ extern crate bitflags;
#[macro_use] #[macro_use]
extern crate cssparser; extern crate cssparser;
extern crate euclid; extern crate euclid;
#[macro_use]
extern crate lazy_static;
extern crate malloc_size_of; extern crate malloc_size_of;
#[macro_use] #[macro_use]
extern crate malloc_size_of_derive; extern crate malloc_size_of_derive;
@ -91,6 +93,7 @@ pub mod values;
#[macro_use] #[macro_use]
pub mod viewport; pub mod viewport;
pub mod owned_slice; pub mod owned_slice;
pub mod owned_str;
pub use crate::specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo}; pub use crate::specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo};
pub use crate::values::{ pub use crate::values::{
@ -149,8 +152,6 @@ pub enum StyleParseErrorKind<'i> {
/// The property declaration was for an unknown property. /// The property declaration was for an unknown property.
UnknownProperty(CowRcStr<'i>), UnknownProperty(CowRcStr<'i>),
/// An unknown vendor-specific identifier was encountered.
UnknownVendorProperty,
/// The property declaration was for a disabled experimental property. /// The property declaration was for a disabled experimental property.
ExperimentalProperty, ExperimentalProperty,
/// The property declaration contained an invalid color value. /// The property declaration contained an invalid color value.

View file

@ -10,7 +10,7 @@ use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::ptr::NonNull; use std::ptr::NonNull;
use std::{fmt, mem, slice}; use std::{fmt, iter, mem, slice};
use to_shmem::{SharedMemoryBuilder, ToShmem}; use to_shmem::{SharedMemoryBuilder, ToShmem};
/// A struct that basically replaces a `Box<[T]>`, but which cbindgen can /// 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. /// Iterate over all the elements in the slice taking ownership of them.
#[inline] #[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() 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()
}
}

View file

@ -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())
}
}

View file

@ -5,6 +5,7 @@
//! Value information for devtools. //! Value information for devtools.
use crate::arc_slice::ArcSlice; use crate::arc_slice::ArcSlice;
use crate::owned_slice::OwnedSlice;
use servo_arc::Arc; use servo_arc::Arc;
use std::ops::Range; use std::ops::Range;
use std::sync::Arc as StdArc; use std::sync::Arc as StdArc;
@ -83,6 +84,7 @@ impl SpecifiedValueInfo for u16 {}
impl SpecifiedValueInfo for u32 {} impl SpecifiedValueInfo for u32 {}
impl SpecifiedValueInfo for str {} impl SpecifiedValueInfo for str {}
impl SpecifiedValueInfo for String {} impl SpecifiedValueInfo for String {}
impl SpecifiedValueInfo for crate::owned_str::OwnedStr {}
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
impl SpecifiedValueInfo for ::servo_atoms::Atom {} 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!(Option<T>);
impl_generic_specified_value_info!(OwnedSlice<T>);
impl_generic_specified_value_info!(Vec<T>); impl_generic_specified_value_info!(Vec<T>);
impl_generic_specified_value_info!(Arc<T>); impl_generic_specified_value_info!(Arc<T>);
impl_generic_specified_value_info!(StdArc<T>); impl_generic_specified_value_info!(StdArc<T>);

View file

@ -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 { impl ToCss for str {
#[inline] #[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result

View file

@ -4,7 +4,6 @@
use cssparser::RGBA; use cssparser::RGBA;
use style::values::animated::{Animate, Procedure, ToAnimatedValue}; use style::values::animated::{Animate, Procedure, ToAnimatedValue};
use style::values::generics::transform::{Transform, TransformOperation};
fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA { fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
let from = from.to_animated_value(); 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) 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)])
);
}

View file

@ -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());
}

Some files were not shown because too many files have changed in this diff Show more