mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
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:
commit
b4fb2cda08
105 changed files with 1455 additions and 2515 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4562,6 +4562,7 @@ dependencies = [
|
|||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.25.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.21.0",
|
||||
|
|
|
@ -30,6 +30,8 @@ error
|
|||
fantasy
|
||||
fetch
|
||||
file
|
||||
fill
|
||||
fill-opacity
|
||||
formdata
|
||||
fullscreenchange
|
||||
fullscreenerror
|
||||
|
@ -100,6 +102,8 @@ serif
|
|||
signalingstatechange
|
||||
srclang
|
||||
statechange
|
||||
stroke
|
||||
stroke-opacity
|
||||
storage
|
||||
submit
|
||||
suspend
|
||||
|
|
|
@ -159,7 +159,7 @@ fn side_image_width(
|
|||
total_length: Au,
|
||||
) -> f32 {
|
||||
match border_image_width {
|
||||
BorderImageSideWidth::Length(v) => v.to_used_value(total_length).to_f32_px(),
|
||||
BorderImageSideWidth::LengthPercentage(v) => v.to_used_value(total_length).to_f32_px(),
|
||||
BorderImageSideWidth::Number(x) => border_width * x.0,
|
||||
BorderImageSideWidth::Auto => border_width,
|
||||
}
|
||||
|
|
|
@ -2793,7 +2793,7 @@ impl Fragment {
|
|||
let mut overflow = Overflow::from_rect(&border_box);
|
||||
|
||||
// Box shadows cause us to draw outside our border box.
|
||||
for box_shadow in &self.style().get_effects().box_shadow.0 {
|
||||
for box_shadow in &*self.style().get_effects().box_shadow.0 {
|
||||
let offset = Vector2D::new(
|
||||
Au::from(box_shadow.base.horizontal),
|
||||
Au::from(box_shadow.base.vertical),
|
||||
|
|
|
@ -888,6 +888,10 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
|||
self.element.namespace()
|
||||
}
|
||||
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn match_pseudo_element(
|
||||
&self,
|
||||
_pseudo: &PseudoElement,
|
||||
|
@ -1394,6 +1398,10 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
|||
::selectors::OpaqueElement::new(unsafe { &*(self.as_node().opaque().0 as *const ()) })
|
||||
}
|
||||
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn parent_element(&self) -> Option<Self> {
|
||||
warn!("ServoThreadSafeLayoutElement::parent_element called");
|
||||
None
|
||||
|
|
|
@ -685,9 +685,9 @@ impl LayoutElementHelpers for LayoutDom<Element> {
|
|||
if let Some(url) = background {
|
||||
hints.push(from_declaration(
|
||||
shared_lock,
|
||||
PropertyDeclaration::BackgroundImage(background_image::SpecifiedValue(vec![
|
||||
Either::Second(specified::Image::for_cascade(url.into())),
|
||||
])),
|
||||
PropertyDeclaration::BackgroundImage(background_image::SpecifiedValue(
|
||||
vec![Either::Second(specified::Image::for_cascade(url.into()))].into(),
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -2945,6 +2945,10 @@ impl<'a> SelectorsElement for DomRoot<Element> {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn match_pseudo_element(
|
||||
&self,
|
||||
_pseudo: &PseudoElement,
|
||||
|
|
|
@ -84,12 +84,6 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
|
|||
self.current_len = 0;
|
||||
}
|
||||
|
||||
/// Returns true if no simple selectors have ever been pushed to this builder.
|
||||
#[inline(always)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.simple_selectors.is_empty()
|
||||
}
|
||||
|
||||
/// Returns true if combinators have ever been pushed to this builder.
|
||||
#[inline(always)]
|
||||
pub fn has_combinators(&self) -> bool {
|
||||
|
|
|
@ -331,11 +331,9 @@ where
|
|||
return false;
|
||||
}
|
||||
|
||||
// Advance to the non-pseudo-element part of the selector, but let the
|
||||
// context note that .
|
||||
if iter.next_sequence().is_none() {
|
||||
return true;
|
||||
}
|
||||
// Advance to the non-pseudo-element part of the selector.
|
||||
let next_sequence = iter.next_sequence().unwrap();
|
||||
debug_assert_eq!(next_sequence, Combinator::PseudoElement);
|
||||
}
|
||||
|
||||
let result =
|
||||
|
@ -452,10 +450,6 @@ where
|
|||
},
|
||||
Combinator::Part => element.containing_shadow_host(),
|
||||
Combinator::SlotAssignment => {
|
||||
debug_assert!(
|
||||
context.current_host.is_some(),
|
||||
"Should not be trying to match slotted rules in a non-shadow-tree context"
|
||||
);
|
||||
debug_assert!(element
|
||||
.assigned_slot()
|
||||
.map_or(true, |s| s.is_html_slot_element()));
|
||||
|
@ -677,7 +671,6 @@ where
|
|||
Component::Slotted(ref selector) => {
|
||||
// <slots> are never flattened tree slottables.
|
||||
!element.is_html_slot_element() &&
|
||||
element.assigned_slot().is_some() &&
|
||||
context.shared.nest(|context| {
|
||||
matches_complex_selector(selector.iter(), element, context, flags_setter)
|
||||
})
|
||||
|
|
|
@ -2002,9 +2002,7 @@ where
|
|||
},
|
||||
SimpleSelectorParseResult::SlottedPseudo(selector) => {
|
||||
state.insert(SelectorParsingState::AFTER_SLOTTED);
|
||||
if !builder.is_empty() {
|
||||
builder.push_combinator(Combinator::SlotAssignment);
|
||||
}
|
||||
builder.push_combinator(Combinator::SlotAssignment);
|
||||
builder.push_simple_selector(Component::Slotted(selector));
|
||||
},
|
||||
SimpleSelectorParseResult::PseudoElement(p) => {
|
||||
|
@ -2012,9 +2010,7 @@ where
|
|||
if !p.accepts_state_pseudo_classes() {
|
||||
state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
|
||||
}
|
||||
if !builder.is_empty() {
|
||||
builder.push_combinator(Combinator::PseudoElement);
|
||||
}
|
||||
builder.push_combinator(Combinator::PseudoElement);
|
||||
builder.push_simple_selector(Component::PseudoElement(p));
|
||||
},
|
||||
}
|
||||
|
@ -2828,7 +2824,10 @@ pub mod tests {
|
|||
assert_eq!(
|
||||
parse("::before"),
|
||||
Ok(SelectorList::from_vec(vec![Selector::from_vec(
|
||||
vec![Component::PseudoElement(PseudoElement::Before)],
|
||||
vec![
|
||||
Component::Combinator(Combinator::PseudoElement),
|
||||
Component::PseudoElement(PseudoElement::Before),
|
||||
],
|
||||
specificity(0, 0, 1) | HAS_PSEUDO_BIT,
|
||||
)]))
|
||||
);
|
||||
|
@ -2836,6 +2835,7 @@ pub mod tests {
|
|||
parse("::before:hover"),
|
||||
Ok(SelectorList::from_vec(vec![Selector::from_vec(
|
||||
vec![
|
||||
Component::Combinator(Combinator::PseudoElement),
|
||||
Component::PseudoElement(PseudoElement::Before),
|
||||
Component::NonTSPseudoClass(PseudoClass::Hover),
|
||||
],
|
||||
|
@ -2846,6 +2846,7 @@ pub mod tests {
|
|||
parse("::before:hover:hover"),
|
||||
Ok(SelectorList::from_vec(vec![Selector::from_vec(
|
||||
vec![
|
||||
Component::Combinator(Combinator::PseudoElement),
|
||||
Component::PseudoElement(PseudoElement::Before),
|
||||
Component::NonTSPseudoClass(PseudoClass::Hover),
|
||||
Component::NonTSPseudoClass(PseudoClass::Hover),
|
||||
|
@ -2958,6 +2959,7 @@ pub mod tests {
|
|||
specificity(0, 0, 0),
|
||||
)]))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
parse_ns(":not(svg|*)", &parser),
|
||||
Ok(SelectorList::from_vec(vec![Selector::from_vec(
|
||||
|
@ -3032,6 +3034,8 @@ pub mod tests {
|
|||
Some(&Component::PseudoElement(PseudoElement::Before))
|
||||
);
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.next_sequence(), None);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,9 +47,13 @@ pub trait Element: Sized + Clone + Debug {
|
|||
///
|
||||
/// This is guaranteed to be called in a pseudo-element.
|
||||
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
||||
debug_assert!(self.is_pseudo_element());
|
||||
self.parent_element()
|
||||
}
|
||||
|
||||
/// Whether we're matching on a pseudo-element.
|
||||
fn is_pseudo_element(&self) -> bool;
|
||||
|
||||
/// Skips non-element nodes
|
||||
fn prev_sibling_element(&self) -> Option<Self>;
|
||||
|
||||
|
|
|
@ -612,16 +612,15 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
|||
use std::mem::{align_of, size_of};
|
||||
assert_ne!(size_of::<T>(), 0, "Need to think about ZST");
|
||||
|
||||
let inner_align = align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>();
|
||||
debug_assert!(inner_align >= align_of::<T>());
|
||||
|
||||
// Compute the required size for the allocation.
|
||||
let num_items = items.len();
|
||||
let size = {
|
||||
// First, determine the alignment of a hypothetical pointer to a
|
||||
// HeaderSlice.
|
||||
let fake_slice_ptr_align: usize = mem::align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>();
|
||||
|
||||
// Next, synthesize a totally garbage (but properly aligned) pointer
|
||||
// to a sequence of T.
|
||||
let fake_slice_ptr = fake_slice_ptr_align as *const T;
|
||||
let fake_slice_ptr = inner_align as *const T;
|
||||
|
||||
// Convert that sequence to a fat pointer. The address component of
|
||||
// the fat pointer will be garbage, but the length will be correct.
|
||||
|
@ -641,13 +640,13 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
|||
let ptr: *mut ArcInner<HeaderSlice<H, [T]>>;
|
||||
unsafe {
|
||||
// Allocate the buffer.
|
||||
let layout = if mem::align_of::<T>() <= mem::align_of::<usize>() {
|
||||
Layout::from_size_align_unchecked(size, mem::align_of::<usize>())
|
||||
} else if mem::align_of::<T>() <= mem::align_of::<u64>() {
|
||||
// On 32-bit platforms <T> may have 8 byte alignment while usize has 4 byte aligment.
|
||||
// Use u64 to avoid over-alignment.
|
||||
let layout = if inner_align <= align_of::<usize>() {
|
||||
Layout::from_size_align_unchecked(size, align_of::<usize>())
|
||||
} else if inner_align <= align_of::<u64>() {
|
||||
// On 32-bit platforms <T> may have 8 byte alignment while usize
|
||||
// has 4 byte aligment. Use u64 to avoid over-alignment.
|
||||
// This branch will compile away in optimized builds.
|
||||
Layout::from_size_align_unchecked(size, mem::align_of::<u64>())
|
||||
Layout::from_size_align_unchecked(size, align_of::<u64>())
|
||||
} else {
|
||||
panic!("Over-aligned type not handled");
|
||||
};
|
||||
|
@ -689,7 +688,7 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
|||
// for some padding from the alignment.
|
||||
debug_assert!(
|
||||
(buffer.offset(size as isize) as usize - current as *mut u8 as usize) <
|
||||
align_of::<Self>()
|
||||
inner_align
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
|
|
|
@ -22,6 +22,7 @@ servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5eve
|
|||
"cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union",
|
||||
"servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"]
|
||||
gecko_debug = []
|
||||
gecko_profiler = []
|
||||
|
||||
[dependencies]
|
||||
app_units = "0.7"
|
||||
|
@ -79,7 +80,7 @@ void = "1.0.2"
|
|||
[build-dependencies]
|
||||
lazy_static = "1"
|
||||
log = "0.4"
|
||||
bindgen = { version = "0.49", optional = true, default-features = false }
|
||||
bindgen = {version = "0.49", optional = true, default-features = false}
|
||||
regex = {version = "1.1", optional = true}
|
||||
walkdir = "2.1.4"
|
||||
toml = {version = "0.4.5", optional = true, default-features = false}
|
||||
|
|
|
@ -19,7 +19,6 @@ use selectors::parser::SelectorParseErrorKind;
|
|||
use std::fmt::{self, Write};
|
||||
use std::mem;
|
||||
use std::num::Wrapping;
|
||||
use std::ops::Range;
|
||||
use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError};
|
||||
use style_traits::{StyleParseErrorKind, ToCss};
|
||||
|
||||
|
@ -261,7 +260,7 @@ counter_style_descriptors! {
|
|||
"suffix" suffix / set_suffix [_]: Symbol,
|
||||
|
||||
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-range>
|
||||
"range" range / set_range [_]: Ranges,
|
||||
"range" range / set_range [_]: CounterRanges,
|
||||
|
||||
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-pad>
|
||||
"pad" pad / set_pad [_]: Pad,
|
||||
|
@ -371,7 +370,7 @@ impl Parse for System {
|
|||
"additive" => Ok(System::Additive),
|
||||
"fixed" => {
|
||||
let first_symbol_value = input.try(|i| Integer::parse(context, i)).ok();
|
||||
Ok(System::Fixed { first_symbol_value: first_symbol_value })
|
||||
Ok(System::Fixed { first_symbol_value })
|
||||
}
|
||||
"extends" => {
|
||||
let other = parse_counter_style_name(input)?;
|
||||
|
@ -409,11 +408,10 @@ impl ToCss for System {
|
|||
}
|
||||
|
||||
/// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol>
|
||||
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)]
|
||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
|
||||
pub enum Symbol {
|
||||
/// <string>
|
||||
String(String),
|
||||
String(crate::OwnedStr),
|
||||
/// <custom-ident>
|
||||
Ident(CustomIdent),
|
||||
// Not implemented:
|
||||
|
@ -428,7 +426,7 @@ impl Parse for Symbol {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
let location = input.current_source_location();
|
||||
match *input.next()? {
|
||||
Token::QuotedString(ref s) => Ok(Symbol::String(s.as_ref().to_owned())),
|
||||
Token::QuotedString(ref s) => Ok(Symbol::String(s.as_ref().to_owned().into())),
|
||||
Token::Ident(ref s) => Ok(Symbol::Ident(CustomIdent::from_ident(location, s, &[])?)),
|
||||
ref t => Err(location.new_unexpected_token_error(t.clone())),
|
||||
}
|
||||
|
@ -463,12 +461,22 @@ impl Parse for Negative {
|
|||
}
|
||||
|
||||
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-range>
|
||||
///
|
||||
/// Empty Vec represents 'auto'
|
||||
#[derive(Clone, Debug, ToShmem)]
|
||||
pub struct Ranges(pub Vec<Range<CounterBound>>);
|
||||
#[derive(Clone, Debug, ToCss, ToShmem)]
|
||||
pub struct CounterRange {
|
||||
/// The start of the range.
|
||||
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)]
|
||||
pub enum CounterBound {
|
||||
/// An integer bound.
|
||||
|
@ -477,7 +485,7 @@ pub enum CounterBound {
|
|||
Infinite,
|
||||
}
|
||||
|
||||
impl Parse for Ranges {
|
||||
impl Parse for CounterRanges {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
|
@ -486,25 +494,21 @@ impl Parse for Ranges {
|
|||
.try(|input| input.expect_ident_matching("auto"))
|
||||
.is_ok()
|
||||
{
|
||||
Ok(Ranges(Vec::new()))
|
||||
} else {
|
||||
input
|
||||
.parse_comma_separated(|input| {
|
||||
let opt_start = parse_bound(context, input)?;
|
||||
let opt_end = parse_bound(context, input)?;
|
||||
if let (CounterBound::Integer(start), CounterBound::Integer(end)) =
|
||||
(opt_start, opt_end)
|
||||
{
|
||||
if start > end {
|
||||
return Err(
|
||||
input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(opt_start..opt_end)
|
||||
})
|
||||
.map(Ranges)
|
||||
return Ok(CounterRanges(Default::default()));
|
||||
}
|
||||
|
||||
let ranges = input.parse_comma_separated(|input| {
|
||||
let start = parse_bound(context, input)?;
|
||||
let end = parse_bound(context, input)?;
|
||||
if let (CounterBound::Integer(start), CounterBound::Integer(end)) = (start, end) {
|
||||
if start > end {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
}
|
||||
Ok(CounterRange { start, end })
|
||||
})?;
|
||||
|
||||
Ok(CounterRanges(ranges.into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,34 +523,6 @@ fn parse_bound<'i, 't>(
|
|||
Ok(CounterBound::Infinite)
|
||||
}
|
||||
|
||||
impl ToCss for Ranges {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
let mut iter = self.0.iter();
|
||||
if let Some(first) = iter.next() {
|
||||
range_to_css(first, dest)?;
|
||||
for item in iter {
|
||||
dest.write_str(", ")?;
|
||||
range_to_css(item, dest)?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
dest.write_str("auto")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn range_to_css<W>(range: &Range<CounterBound>, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
range.start.to_css(dest)?;
|
||||
dest.write_char(' ')?;
|
||||
range.end.to_css(dest)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-pad>
|
||||
#[derive(Clone, Debug, ToCss, ToShmem)]
|
||||
pub struct Pad(pub Integer, pub Symbol);
|
||||
|
@ -572,14 +548,13 @@ impl Parse for Fallback {
|
|||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
parse_counter_style_name(input).map(Fallback)
|
||||
Ok(Fallback(parse_counter_style_name(input)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols>
|
||||
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)]
|
||||
pub struct Symbols(#[css(iterable)] pub Vec<Symbol>);
|
||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
|
||||
pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>);
|
||||
|
||||
impl Parse for Symbols {
|
||||
fn parse<'i, 't>(
|
||||
|
@ -587,23 +562,20 @@ impl Parse for Symbols {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut symbols = Vec::new();
|
||||
loop {
|
||||
if let Ok(s) = input.try(|input| Symbol::parse(context, input)) {
|
||||
symbols.push(s)
|
||||
} else {
|
||||
if symbols.is_empty() {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
} else {
|
||||
return Ok(Symbols(symbols));
|
||||
}
|
||||
}
|
||||
while let Ok(s) = input.try(|input| Symbol::parse(context, input)) {
|
||||
symbols.push(s);
|
||||
}
|
||||
if symbols.is_empty() {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
Ok(Symbols(symbols.into()))
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-additive-symbols>
|
||||
#[derive(Clone, Debug, ToCss, ToShmem)]
|
||||
pub struct AdditiveSymbols(pub Vec<AdditiveTuple>);
|
||||
#[css(comma)]
|
||||
pub struct AdditiveSymbols(#[css(iterable)] pub crate::OwnedSlice<AdditiveTuple>);
|
||||
|
||||
impl Parse for AdditiveSymbols {
|
||||
fn parse<'i, 't>(
|
||||
|
@ -618,7 +590,7 @@ impl Parse for AdditiveSymbols {
|
|||
{
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
Ok(AdditiveSymbols(tuples))
|
||||
Ok(AdditiveSymbols(tuples.into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -643,10 +615,7 @@ impl Parse for AdditiveTuple {
|
|||
let symbol = input.try(|input| Symbol::parse(context, input));
|
||||
let weight = Integer::parse_non_negative(context, input)?;
|
||||
let symbol = symbol.or_else(|_| Symbol::parse(context, input))?;
|
||||
Ok(AdditiveTuple {
|
||||
weight: weight,
|
||||
symbol: symbol,
|
||||
})
|
||||
Ok(Self { weight, symbol })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -779,7 +779,7 @@ pub trait TElement:
|
|||
/// element-backed pseudo-element, in which case we return the originating
|
||||
/// element.
|
||||
fn rule_hash_target(&self) -> Self {
|
||||
if self.implemented_pseudo_element().is_some() {
|
||||
if self.is_pseudo_element() {
|
||||
self.pseudo_element_originating_element()
|
||||
.expect("Trying to collect rules for a detached pseudo-element")
|
||||
} else {
|
||||
|
@ -801,24 +801,29 @@ pub trait TElement:
|
|||
{
|
||||
use rule_collector::containing_shadow_ignoring_svg_use;
|
||||
|
||||
let mut doc_rules_apply = self.matches_user_and_author_rules();
|
||||
let target = self.rule_hash_target();
|
||||
if !target.matches_user_and_author_rules() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut doc_rules_apply = true;
|
||||
|
||||
// Use the same rules to look for the containing host as we do for rule
|
||||
// collection.
|
||||
if let Some(shadow) = containing_shadow_ignoring_svg_use(*self) {
|
||||
if let Some(shadow) = containing_shadow_ignoring_svg_use(target) {
|
||||
doc_rules_apply = false;
|
||||
if let Some(data) = shadow.style_data() {
|
||||
f(data, shadow.host());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(shadow) = self.shadow_root() {
|
||||
if let Some(shadow) = target.shadow_root() {
|
||||
if let Some(data) = shadow.style_data() {
|
||||
f(data, shadow.host());
|
||||
}
|
||||
}
|
||||
|
||||
let mut current = self.assigned_slot();
|
||||
let mut current = target.assigned_slot();
|
||||
while let Some(slot) = current {
|
||||
// Slots can only have assigned nodes when in a shadow tree.
|
||||
let shadow = slot.containing_shadow().unwrap();
|
||||
|
|
|
@ -134,6 +134,7 @@ pub fn traverse_dom<E, D>(
|
|||
let drain = discovered.drain(..);
|
||||
pool.install(|| {
|
||||
rayon::scope(|scope| {
|
||||
profiler_label!(Style);
|
||||
parallel::traverse_nodes(
|
||||
drain,
|
||||
DispatchMode::TailCall,
|
||||
|
|
|
@ -23,7 +23,6 @@ use crate::gecko_bindings::structs::RawServoMediaRule;
|
|||
use crate::gecko_bindings::structs::RawServoMozDocumentRule;
|
||||
use crate::gecko_bindings::structs::RawServoNamespaceRule;
|
||||
use crate::gecko_bindings::structs::RawServoPageRule;
|
||||
use crate::gecko_bindings::structs::RawServoQuotes;
|
||||
use crate::gecko_bindings::structs::RawServoStyleRule;
|
||||
use crate::gecko_bindings::structs::RawServoStyleSheetContents;
|
||||
use crate::gecko_bindings::structs::RawServoSupportsRule;
|
||||
|
@ -40,7 +39,6 @@ use crate::stylesheets::{NamespaceRule, PageRule};
|
|||
use crate::stylesheets::{StyleRule, StylesheetContents, SupportsRule};
|
||||
use servo_arc::{Arc, ArcBorrow};
|
||||
use std::{mem, ptr};
|
||||
use values::computed::QuotePair;
|
||||
|
||||
macro_rules! impl_arc_ffi {
|
||||
($servo_type:ty => $gecko_type:ty[$addref:ident, $release:ident]) => {
|
||||
|
@ -115,9 +113,6 @@ impl_arc_ffi!(Locked<CounterStyleRule> => RawServoCounterStyleRule
|
|||
impl_arc_ffi!(CssUrlData => RawServoCssUrlData
|
||||
[Servo_CssUrlData_AddRef, Servo_CssUrlData_Release]);
|
||||
|
||||
impl_arc_ffi!(Box<[QuotePair]> => RawServoQuotes
|
||||
[Servo_Quotes_AddRef, Servo_Quotes_Release]);
|
||||
|
||||
// ComputedStyle is not an opaque type on any side of FFI.
|
||||
// This means that doing the HasArcFFI type trick is actually unsound,
|
||||
// since it gives us a way to construct an Arc<ComputedStyle> from
|
||||
|
|
|
@ -5,12 +5,22 @@
|
|||
//! FFI implementations for types listed in ServoBoxedTypeList.h.
|
||||
|
||||
use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
|
||||
use crate::properties::animated_properties::AnimationValueMap;
|
||||
use to_shmem::SharedMemoryBuilder;
|
||||
|
||||
// TODO(heycam): The FFI impls for most of the types in ServoBoxedTypeList.h are spread across
|
||||
// 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.
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
unsafe impl HasFFI for AnimationValueMap {
|
||||
type FFIType = crate::gecko_bindings::bindings::RawServoAnimationValueMap;
|
||||
}
|
||||
#[cfg(feature = "gecko")]
|
||||
unsafe impl HasSimpleFFI for AnimationValueMap {}
|
||||
#[cfg(feature = "gecko")]
|
||||
unsafe impl HasBoxFFI for AnimationValueMap {}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
unsafe impl HasFFI for SharedMemoryBuilder {
|
||||
type FFIType = crate::gecko_bindings::bindings::RawServoSharedMemoryBuilder;
|
||||
|
|
|
@ -383,7 +383,6 @@ impl nsStyleImage {
|
|||
let atom = bindings::Gecko_GetImageElement(self);
|
||||
Some(GenericImage::Element(Atom::from_raw(atom)))
|
||||
},
|
||||
_ => panic!("Unexpected image type"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,10 +534,8 @@ pub mod basic_shape {
|
|||
use crate::gecko_bindings::structs::{
|
||||
StyleGeometryBox, StyleShapeSource, StyleShapeSourceType,
|
||||
};
|
||||
use crate::gecko_bindings::sugar::refptr::RefPtr;
|
||||
use crate::values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape};
|
||||
use crate::values::computed::motion::OffsetPath;
|
||||
use crate::values::computed::url::ComputedUrl;
|
||||
use crate::values::generics::basic_shape::{GeometryBox, Path, ShapeBox, ShapeSource};
|
||||
use crate::values::specified::SVGPathData;
|
||||
|
||||
|
@ -564,7 +561,7 @@ pub mod basic_shape {
|
|||
};
|
||||
Some(ShapeSource::Shape(shape, reference_box))
|
||||
},
|
||||
StyleShapeSourceType::URL | StyleShapeSourceType::Image => None,
|
||||
StyleShapeSourceType::Image => None,
|
||||
StyleShapeSourceType::Path => {
|
||||
let path = self.to_svg_path().expect("expect an SVGPathData");
|
||||
let fill = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }.mFillRule;
|
||||
|
@ -587,16 +584,15 @@ pub mod basic_shape {
|
|||
|
||||
impl<'a> From<&'a StyleShapeSource> for ClippingShape {
|
||||
fn from(other: &'a StyleShapeSource) -> Self {
|
||||
use crate::values::generics::image::Image as GenericImage;
|
||||
match other.mType {
|
||||
StyleShapeSourceType::URL => unsafe {
|
||||
StyleShapeSourceType::Image => unsafe {
|
||||
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
|
||||
let other_url =
|
||||
RefPtr::new(*shape_image.__bindgen_anon_1.mURLValue.as_ref() as *mut _);
|
||||
let url = ComputedUrl::from_url_value(other_url);
|
||||
ShapeSource::ImageOrUrl(url)
|
||||
},
|
||||
StyleShapeSourceType::Image => {
|
||||
unreachable!("ClippingShape doesn't support Image!");
|
||||
let image = shape_image.into_image().expect("Cannot convert to Image");
|
||||
match image {
|
||||
GenericImage::Url(url) => ShapeSource::ImageOrUrl(url.0),
|
||||
_ => panic!("ClippingShape doesn't support non-url images"),
|
||||
}
|
||||
},
|
||||
_ => other
|
||||
.into_shape_source()
|
||||
|
@ -608,9 +604,6 @@ pub mod basic_shape {
|
|||
impl<'a> From<&'a StyleShapeSource> for FloatAreaShape {
|
||||
fn from(other: &'a StyleShapeSource) -> Self {
|
||||
match other.mType {
|
||||
StyleShapeSourceType::URL => {
|
||||
unreachable!("FloatAreaShape doesn't support URL!");
|
||||
},
|
||||
StyleShapeSourceType::Image => unsafe {
|
||||
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
|
||||
let image = shape_image.into_image().expect("Cannot convert to Image");
|
||||
|
@ -632,7 +625,6 @@ pub mod basic_shape {
|
|||
StyleShapeSourceType::None => OffsetPath::none(),
|
||||
StyleShapeSourceType::Shape |
|
||||
StyleShapeSourceType::Box |
|
||||
StyleShapeSourceType::URL |
|
||||
StyleShapeSourceType::Image => unreachable!("Unsupported offset-path type"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,10 @@ pub mod conversions;
|
|||
pub mod data;
|
||||
pub mod media_features;
|
||||
pub mod media_queries;
|
||||
#[cfg(feature = "gecko_profiler")]
|
||||
pub mod profiler;
|
||||
pub mod pseudo_element;
|
||||
pub mod restyle_damage;
|
||||
pub mod rules;
|
||||
pub mod selector_parser;
|
||||
pub mod snapshot;
|
||||
pub mod snapshot_helpers;
|
||||
|
|
75
components/style/gecko/profiler.rs
Normal file
75
components/style/gecko/profiler.rs
Normal 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
|
||||
}
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -310,13 +310,13 @@ impl ToComputedValue for SpecifiedImageUrl {
|
|||
type ComputedValue = ComputedImageUrl;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
|
||||
ComputedImageUrl(self.clone())
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
ComputedImageUrl(self.0.to_computed_value(context))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
computed.0.clone()
|
||||
SpecifiedImageUrl(ToComputedValue::from_computed_value(&computed.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +378,7 @@ impl ComputedUrl {
|
|||
|
||||
/// The computed value of a CSS image `url()`.
|
||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
|
||||
pub struct ComputedImageUrl(pub SpecifiedImageUrl);
|
||||
pub struct ComputedImageUrl(pub ComputedUrl);
|
||||
|
||||
impl ToCss for ComputedImageUrl {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
|
@ -395,22 +395,17 @@ impl ComputedImageUrl {
|
|||
/// Convert from nsStyleImageReques to ComputedImageUrl.
|
||||
pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
|
||||
let url_value = image_request.mImageValue.to_safe();
|
||||
let css_url = &*url_value.mCssUrl.mRawPtr;
|
||||
let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc());
|
||||
ComputedImageUrl(SpecifiedImageUrl(SpecifiedUrl {
|
||||
url,
|
||||
url_value: Box::new(URLValueSource::URLValue(url_value)),
|
||||
}))
|
||||
ComputedImageUrl(ComputedUrl::from_url_value(url_value))
|
||||
}
|
||||
|
||||
/// Clone a new, strong reference to the Gecko URLValue.
|
||||
pub fn clone_url_value(&self) -> RefPtr<URLValue> {
|
||||
(self.0).0.clone_url_value()
|
||||
self.0.clone_url_value()
|
||||
}
|
||||
|
||||
/// Get a raw pointer to the URLValue held by this ComputedImageUrl, for FFI.
|
||||
pub fn url_value_ptr(&self) -> *mut URLValue {
|
||||
(self.0).0.url_value_ptr()
|
||||
self.0.url_value_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ use crate::gecko_bindings::structs::{nsStyleCoord, CounterStylePtr};
|
|||
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
||||
use crate::values::computed::{Angle, Length, LengthPercentage};
|
||||
use crate::values::computed::{Number, NumberOrPercentage, Percentage};
|
||||
use crate::values::generics::gecko::ScrollSnapPoint;
|
||||
use crate::values::generics::grid::{TrackBreadth, TrackKeyword};
|
||||
use crate::values::generics::length::LengthPercentageOrAuto;
|
||||
use crate::values::generics::{CounterStyleOrNone, NonNegative};
|
||||
|
@ -217,27 +216,6 @@ impl GeckoStyleCoordConvertible for Angle {
|
|||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for ScrollSnapPoint<LengthPercentage> {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
match self.repeated() {
|
||||
None => coord.set_value(CoordDataValue::None),
|
||||
Some(l) => l.to_gecko_style_coord(coord),
|
||||
};
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
use crate::gecko_bindings::structs::root::nsStyleUnit;
|
||||
|
||||
Some(match coord.unit() {
|
||||
nsStyleUnit::eStyleUnit_None => ScrollSnapPoint::None,
|
||||
_ => ScrollSnapPoint::Repeat(
|
||||
LengthPercentage::from_gecko_style_coord(coord)
|
||||
.expect("coord could not convert to LengthPercentage"),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a given RGBA value to `nscolor`.
|
||||
pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
|
||||
((rgba.alpha as u32) << 24) |
|
||||
|
@ -288,7 +266,7 @@ impl CounterStyleOrNone {
|
|||
.0
|
||||
.iter()
|
||||
.map(|symbol| match *symbol {
|
||||
Symbol::String(ref s) => nsCStr::from(s),
|
||||
Symbol::String(ref s) => nsCStr::from(&**s),
|
||||
Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"),
|
||||
})
|
||||
.collect();
|
||||
|
@ -333,7 +311,7 @@ impl CounterStyleOrNone {
|
|||
let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32);
|
||||
let symbols = symbols
|
||||
.iter()
|
||||
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string()))
|
||||
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into()))
|
||||
.collect();
|
||||
Either::First(CounterStyleOrNone::Symbols(symbol_type, Symbols(symbols)))
|
||||
}
|
||||
|
|
|
@ -1098,7 +1098,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
type TraversalChildrenIterator = GeckoChildrenIterator<'le>;
|
||||
|
||||
fn inheritance_parent(&self) -> Option<Self> {
|
||||
if self.implemented_pseudo_element().is_some() {
|
||||
if self.is_pseudo_element() {
|
||||
return self.pseudo_element_originating_element();
|
||||
}
|
||||
|
||||
|
@ -1405,7 +1405,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
|
||||
#[inline]
|
||||
fn matches_user_and_author_rules(&self) -> bool {
|
||||
!self.rule_hash_target().is_in_native_anonymous_subtree()
|
||||
!self.is_in_native_anonymous_subtree()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -1471,7 +1471,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
#[inline]
|
||||
fn skip_item_display_fixup(&self) -> bool {
|
||||
debug_assert!(
|
||||
self.implemented_pseudo_element().is_none(),
|
||||
!self.is_pseudo_element(),
|
||||
"Just don't call me if I'm a pseudo, you should know the answer already"
|
||||
);
|
||||
self.is_root_of_native_anonymous_subtree()
|
||||
|
@ -1918,9 +1918,14 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
|||
Some(shadow.host())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
self.implemented_pseudo_element().is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
||||
debug_assert!(self.implemented_pseudo_element().is_some());
|
||||
debug_assert!(self.is_pseudo_element());
|
||||
let parent = self.closest_anon_subtree_root_parent()?;
|
||||
|
||||
// FIXME(emilio): Special-case for <input type="number">s
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
|
||||
mod ns_com_ptr;
|
||||
mod ns_compatibility;
|
||||
mod ns_css_shadow_array;
|
||||
mod ns_css_shadow_item;
|
||||
pub mod ns_css_value;
|
||||
mod ns_style_auto_array;
|
||||
pub mod ns_style_coord;
|
||||
mod ns_t_array;
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -289,11 +289,6 @@ impl_threadsafe_refcount!(
|
|||
bindings::Gecko_AddRefURLExtraDataArbitraryThread,
|
||||
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
|
||||
);
|
||||
impl_threadsafe_refcount!(
|
||||
structs::nsCSSValueSharedList,
|
||||
bindings::Gecko_AddRefCSSValueSharedListArbitraryThread,
|
||||
bindings::Gecko_ReleaseCSSValueSharedListArbitraryThread
|
||||
);
|
||||
impl_threadsafe_refcount!(
|
||||
structs::mozilla::css::URLValue,
|
||||
bindings::Gecko_AddRefCSSURLValueArbitraryThread,
|
||||
|
|
|
@ -53,6 +53,7 @@ macro_rules! local_name {
|
|||
/// This is either a strong reference to a dynamic atom (an nsAtom pointer),
|
||||
/// or an offset from gGkAtoms to the nsStaticAtom object.
|
||||
#[derive(Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct Atom(usize);
|
||||
|
||||
/// An atom *without* a strong reference.
|
||||
|
|
|
@ -366,6 +366,10 @@ where
|
|||
self.element.is_root()
|
||||
}
|
||||
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
self.element.is_pseudo_element()
|
||||
}
|
||||
|
||||
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
||||
self.element
|
||||
.pseudo_element_originating_element()
|
||||
|
|
|
@ -190,6 +190,7 @@ pub use servo_atoms::Atom;
|
|||
|
||||
pub use style_traits::arc_slice::ArcSlice;
|
||||
pub use style_traits::owned_slice::OwnedSlice;
|
||||
pub use style_traits::owned_str::OwnedStr;
|
||||
|
||||
/// The CSS properties supported by the style system.
|
||||
/// Generated from the properties.mako.rs template by build.rs
|
||||
|
|
|
@ -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) => {};
|
||||
}
|
||||
|
|
|
@ -277,6 +277,7 @@ pub fn traverse_nodes<'a, 'scope, E, D, I>(
|
|||
top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls);
|
||||
} else {
|
||||
scope.spawn(move |scope| {
|
||||
profiler_label!(Style);
|
||||
let work = work;
|
||||
top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls);
|
||||
});
|
||||
|
@ -286,6 +287,7 @@ pub fn traverse_nodes<'a, 'scope, E, D, I>(
|
|||
let nodes: WorkUnit<E::ConcreteNode> = chunk.collect();
|
||||
let traversal_data_copy = traversal_data.clone();
|
||||
scope.spawn(move |scope| {
|
||||
profiler_label!(Style);
|
||||
let n = nodes;
|
||||
top_down_dom(&*n, root, traversal_data_copy, scope, pool, traversal, tls)
|
||||
});
|
||||
|
|
|
@ -628,10 +628,6 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
|||
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
if let Some(display) = builder.get_box_if_mutated() {
|
||||
display.generate_combined_transform();
|
||||
}
|
||||
|
||||
if let Some(bg) = builder.get_background_if_mutated() {
|
||||
bg.fill_arrays();
|
||||
}
|
||||
|
|
|
@ -172,8 +172,9 @@ class Longhand(object):
|
|||
gecko_ffi_name=None,
|
||||
allowed_in_keyframe_block=True, cast_type='u8',
|
||||
logical=False, logical_group=None, alias=None, extra_prefixes=None, boxed=False,
|
||||
flags=None, allowed_in_page_rule=False, allow_quirks=False,
|
||||
flags=None, allowed_in_page_rule=False, allow_quirks="No",
|
||||
ignored_when_colors_disabled=False,
|
||||
simple_vector_bindings=False,
|
||||
vector=False, servo_restyle_damage="repaint"):
|
||||
self.name = name
|
||||
if not spec:
|
||||
|
@ -210,6 +211,7 @@ class Longhand(object):
|
|||
self.allow_quirks = allow_quirks
|
||||
self.ignored_when_colors_disabled = ignored_when_colors_disabled
|
||||
self.is_vector = vector
|
||||
self.simple_vector_bindings = simple_vector_bindings
|
||||
|
||||
# https://drafts.csswg.org/css-animations/#keyframes
|
||||
# > The <declaration-list> inside of <keyframe-block> accepts any CSS property
|
||||
|
@ -323,12 +325,14 @@ class Longhand(object):
|
|||
"JustifyContent",
|
||||
"JustifyItems",
|
||||
"JustifySelf",
|
||||
"LineBreak",
|
||||
"MozForceBrokenImageIcon",
|
||||
"MozListReversed",
|
||||
"MozScriptLevel",
|
||||
"MozScriptMinSize",
|
||||
"MozScriptSizeMultiplier",
|
||||
"NonNegativeNumber",
|
||||
"OffsetRotate",
|
||||
"Opacity",
|
||||
"OutlineStyle",
|
||||
"Overflow",
|
||||
|
|
|
@ -1301,11 +1301,9 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
|
|||
Ok(id) => id,
|
||||
Err(..) => {
|
||||
self.last_parsed_property_id = None;
|
||||
return Err(input.new_custom_error(if is_non_mozilla_vendor_identifier(&name) {
|
||||
StyleParseErrorKind::UnknownVendorProperty
|
||||
} else {
|
||||
return Err(input.new_custom_error(
|
||||
StyleParseErrorKind::UnknownProperty(name)
|
||||
}));
|
||||
));
|
||||
}
|
||||
};
|
||||
if self.context.error_reporting_enabled() {
|
||||
|
@ -1326,6 +1324,13 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
|
|||
|
||||
type SmallParseErrorVec<'i> = SmallVec<[(ParseError<'i>, &'i str, Option<PropertyId>); 2]>;
|
||||
|
||||
fn alias_of_known_property(name: &str) -> Option<PropertyId> {
|
||||
let mut prefixed = String::with_capacity(name.len() + 5);
|
||||
prefixed.push_str("-moz-");
|
||||
prefixed.push_str(name);
|
||||
PropertyId::parse_enabled_for_all_content(&prefixed).ok()
|
||||
}
|
||||
|
||||
#[cold]
|
||||
fn report_one_css_error<'i>(
|
||||
context: &ParserContext,
|
||||
|
@ -1352,10 +1357,22 @@ fn report_one_css_error<'i>(
|
|||
}
|
||||
}
|
||||
|
||||
// If the unrecognized property looks like a vendor-specific property,
|
||||
// silently ignore it instead of polluting the error output.
|
||||
if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownVendorProperty) = error.kind {
|
||||
return;
|
||||
if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty(ref name)) = error.kind {
|
||||
if is_non_mozilla_vendor_identifier(name) {
|
||||
// If the unrecognized property looks like a vendor-specific property,
|
||||
// silently ignore it instead of polluting the error output.
|
||||
return;
|
||||
}
|
||||
if let Some(alias) = alias_of_known_property(name) {
|
||||
// This is an unknown property, but its -moz-* version is known.
|
||||
// We don't want to report error if the -moz-* version is already
|
||||
// specified.
|
||||
if let Some(block) = block {
|
||||
if all_properties_in_block(block, &alias) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref property) = property {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,7 @@
|
|||
<%def name="predefined_type(name, type, initial_value, parse_method='parse',
|
||||
needs_context=True, vector=False,
|
||||
computed_type=None, initial_specified_value=None,
|
||||
allow_quirks=False, allow_empty=False, **kwargs)">
|
||||
allow_quirks='No', allow_empty=False, **kwargs)">
|
||||
<%def name="predefined_type_inner(name, type, initial_value, parse_method)">
|
||||
#[allow(unused_imports)]
|
||||
use app_units::Au;
|
||||
|
@ -42,8 +42,8 @@
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<SpecifiedValue, ParseError<'i>> {
|
||||
% if allow_quirks:
|
||||
specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes)
|
||||
% if allow_quirks != "No":
|
||||
specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::${allow_quirks})
|
||||
% elif needs_context:
|
||||
specified::${type}::${parse_method}(context, input)
|
||||
% else:
|
||||
|
@ -80,12 +80,26 @@
|
|||
We assume that the default/initial value is an empty vector for these.
|
||||
`initial_value` need not be defined for these.
|
||||
</%doc>
|
||||
|
||||
// The setup here is roughly:
|
||||
//
|
||||
// * UnderlyingList is the list that is stored in the computed value. This may
|
||||
// be a shared ArcSlice if the property is inherited.
|
||||
// * UnderlyingOwnedList is the list that is used for animation.
|
||||
// * Specified values always use OwnedSlice, since it's more compact.
|
||||
// * computed_value::List is just a convenient alias that you can use for the
|
||||
// computed value list, since this is in the computed_value module.
|
||||
//
|
||||
// If simple_vector_bindings is true, then we don't use the complex iterator
|
||||
// machinery and set_foo_from, and just compute the value like any other
|
||||
// longhand.
|
||||
<%def name="vector_longhand(name, animation_value_type=None,
|
||||
vector_animation_type=None, allow_empty=False,
|
||||
simple_vector_bindings=False,
|
||||
separator='Comma',
|
||||
**kwargs)">
|
||||
<%call expr="longhand(name, animation_value_type=animation_value_type, vector=True,
|
||||
**kwargs)">
|
||||
simple_vector_bindings=simple_vector_bindings, **kwargs)">
|
||||
#[allow(unused_imports)]
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
@ -111,16 +125,46 @@
|
|||
|
||||
/// The definition of the computed value for ${name}.
|
||||
pub mod computed_value {
|
||||
#[allow(unused_imports)]
|
||||
use crate::values::animated::ToAnimatedValue;
|
||||
#[allow(unused_imports)]
|
||||
use crate::values::resolved::ToResolvedValue;
|
||||
pub use super::single_value::computed_value as single_value;
|
||||
pub use self::single_value::T as SingleComputedValue;
|
||||
% if allow_empty and allow_empty != "NotInitial":
|
||||
use std::vec::IntoIter;
|
||||
% else:
|
||||
use smallvec::{IntoIter, SmallVec};
|
||||
% if not allow_empty or allow_empty == "NotInitial":
|
||||
use smallvec::SmallVec;
|
||||
% endif
|
||||
use crate::values::computed::ComputedVecIter;
|
||||
|
||||
/// The generic type defining the value for this property.
|
||||
<%
|
||||
is_shared_list = allow_empty and allow_empty != "NotInitial" and \
|
||||
data.longhands_by_name[name].style_struct.inherited
|
||||
%>
|
||||
|
||||
// FIXME(emilio): Add an OwnedNonEmptySlice type, and figure out
|
||||
// something for transition-name, which is the only remaining user
|
||||
// of NotInitial.
|
||||
pub type UnderlyingList<T> =
|
||||
% if allow_empty and allow_empty != "NotInitial":
|
||||
% if data.longhands_by_name[name].style_struct.inherited:
|
||||
crate::ArcSlice<T>;
|
||||
% else:
|
||||
crate::OwnedSlice<T>;
|
||||
% endif
|
||||
% else:
|
||||
SmallVec<[T; 1]>;
|
||||
% endif
|
||||
|
||||
pub type UnderlyingOwnedList<T> =
|
||||
% if allow_empty and allow_empty != "NotInitial":
|
||||
crate::OwnedSlice<T>;
|
||||
% else:
|
||||
SmallVec<[T; 1]>;
|
||||
% endif
|
||||
|
||||
|
||||
/// The generic type defining the animated and resolved values for
|
||||
/// this property.
|
||||
///
|
||||
/// Making this type generic allows the compiler to figure out the
|
||||
/// animated value for us, instead of having to implement it
|
||||
|
@ -137,34 +181,115 @@
|
|||
ToResolvedValue,
|
||||
ToCss,
|
||||
)]
|
||||
pub struct List<T>(
|
||||
pub struct OwnedList<T>(
|
||||
% if not allow_empty:
|
||||
#[css(iterable)]
|
||||
% else:
|
||||
#[css(if_empty = "none", iterable)]
|
||||
% endif
|
||||
% if allow_empty and allow_empty != "NotInitial":
|
||||
pub Vec<T>,
|
||||
% else:
|
||||
pub SmallVec<[T; 1]>,
|
||||
% endif
|
||||
pub UnderlyingOwnedList<T>,
|
||||
);
|
||||
|
||||
/// The computed value for this property.
|
||||
% if not is_shared_list:
|
||||
pub type ComputedList = OwnedList<single_value::T>;
|
||||
pub use self::OwnedList as List;
|
||||
% else:
|
||||
pub use self::ComputedList as List;
|
||||
|
||||
% if separator == "Comma":
|
||||
#[css(comma)]
|
||||
% endif
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
ToCss,
|
||||
)]
|
||||
pub struct ComputedList(
|
||||
% if not allow_empty:
|
||||
#[css(iterable)]
|
||||
% else:
|
||||
#[css(if_empty = "none", iterable)]
|
||||
% endif
|
||||
% if is_shared_list:
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
% endif
|
||||
pub UnderlyingList<single_value::T>,
|
||||
);
|
||||
|
||||
type ResolvedList = OwnedList<<single_value::T as ToResolvedValue>::ResolvedValue>;
|
||||
impl ToResolvedValue for ComputedList {
|
||||
type ResolvedValue = ResolvedList;
|
||||
|
||||
fn to_resolved_value(self, context: &crate::values::resolved::Context) -> Self::ResolvedValue {
|
||||
OwnedList(
|
||||
self.0
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|v| v.to_resolved_value(context))
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
||||
% if not is_shared_list:
|
||||
use std::iter::FromIterator;
|
||||
% endif
|
||||
let iter =
|
||||
resolved.0.into_iter().map(ToResolvedValue::from_resolved_value);
|
||||
ComputedList(UnderlyingList::from_iter(iter))
|
||||
}
|
||||
}
|
||||
% endif
|
||||
|
||||
% if simple_vector_bindings:
|
||||
impl From<ComputedList> for UnderlyingList<single_value::T> {
|
||||
#[inline]
|
||||
fn from(l: ComputedList) -> Self {
|
||||
l.0
|
||||
}
|
||||
}
|
||||
impl From<UnderlyingList<single_value::T>> for ComputedList {
|
||||
#[inline]
|
||||
fn from(l: UnderlyingList<single_value::T>) -> Self {
|
||||
List(l)
|
||||
}
|
||||
}
|
||||
% endif
|
||||
|
||||
/// The computed value, effectively a list of single values.
|
||||
% if vector_animation_type:
|
||||
% if not animation_value_type:
|
||||
Sorry, this is stupid but needed for now.
|
||||
% endif
|
||||
|
||||
use crate::properties::animated_properties::ListAnimation;
|
||||
use crate::values::animated::{Animate, ToAnimatedValue, ToAnimatedZero, Procedure};
|
||||
use crate::values::animated::{Animate, ToAnimatedZero, Procedure};
|
||||
use crate::values::distance::{SquaredDistance, ComputeSquaredDistance};
|
||||
|
||||
// FIXME(emilio): For some reason rust thinks that this alias is
|
||||
// unused, even though it's clearly used below?
|
||||
#[allow(unused)]
|
||||
type AnimatedList = <List<single_value::T> as ToAnimatedValue>::AnimatedValue;
|
||||
type AnimatedList = OwnedList<<single_value::T as ToAnimatedValue>::AnimatedValue>;
|
||||
|
||||
% if is_shared_list:
|
||||
impl ToAnimatedValue for ComputedList {
|
||||
type AnimatedValue = AnimatedList;
|
||||
|
||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||
OwnedList(
|
||||
self.0.iter().map(|v| v.clone().to_animated_value()).collect()
|
||||
)
|
||||
}
|
||||
|
||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||
let iter =
|
||||
animated.0.into_iter().map(ToAnimatedValue::from_animated_value);
|
||||
ComputedList(UnderlyingList::from_iter(iter))
|
||||
}
|
||||
}
|
||||
% endif
|
||||
|
||||
impl ToAnimatedZero for AnimatedList {
|
||||
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
|
||||
|
@ -176,7 +301,7 @@
|
|||
other: &Self,
|
||||
procedure: Procedure,
|
||||
) -> Result<Self, ()> {
|
||||
Ok(List(
|
||||
Ok(OwnedList(
|
||||
self.0.animate_${vector_animation_type}(&other.0, procedure)?
|
||||
))
|
||||
}
|
||||
|
@ -191,21 +316,10 @@
|
|||
}
|
||||
% endif
|
||||
|
||||
pub type T = List<single_value::T>;
|
||||
/// The computed value, effectively a list of single values.
|
||||
pub use self::ComputedList as T;
|
||||
|
||||
pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
|
||||
|
||||
impl IntoIterator for T {
|
||||
type Item = single_value::T;
|
||||
% if allow_empty and allow_empty != "NotInitial":
|
||||
type IntoIter = IntoIter<single_value::T>;
|
||||
% else:
|
||||
type IntoIter = IntoIter<[single_value::T; 1]>;
|
||||
% endif
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The specified value of ${name}.
|
||||
|
@ -219,12 +333,12 @@
|
|||
% else:
|
||||
#[css(if_empty = "none", iterable)]
|
||||
% endif
|
||||
pub Vec<single_value::SpecifiedValue>,
|
||||
pub crate::OwnedSlice<single_value::SpecifiedValue>,
|
||||
);
|
||||
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
% if allow_empty and allow_empty != "NotInitial":
|
||||
computed_value::List(vec![])
|
||||
computed_value::List(Default::default())
|
||||
% else:
|
||||
let mut v = SmallVec::new();
|
||||
v.push(single_value::get_initial_value());
|
||||
|
@ -239,40 +353,47 @@
|
|||
use style_traits::Separator;
|
||||
|
||||
% if allow_empty:
|
||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(SpecifiedValue(Vec::new()))
|
||||
}
|
||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(SpecifiedValue(Default::default()))
|
||||
}
|
||||
% endif
|
||||
|
||||
style_traits::${separator}::parse(input, |parser| {
|
||||
let v = style_traits::${separator}::parse(input, |parser| {
|
||||
single_value::parse(context, parser)
|
||||
}).map(SpecifiedValue)
|
||||
})?;
|
||||
Ok(SpecifiedValue(v.into()))
|
||||
}
|
||||
|
||||
pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;
|
||||
|
||||
% if not simple_vector_bindings and product == "gecko":
|
||||
impl SpecifiedValue {
|
||||
pub fn compute_iter<'a, 'cx, 'cx_a>(
|
||||
fn compute_iter<'a, 'cx, 'cx_a>(
|
||||
&'a self,
|
||||
context: &'cx Context<'cx_a>,
|
||||
) -> computed_value::Iter<'a, 'cx, 'cx_a> {
|
||||
computed_value::Iter::new(context, &self.0)
|
||||
}
|
||||
}
|
||||
% endif
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
type ComputedValue = computed_value::T;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||
computed_value::List(self.compute_iter(context).collect())
|
||||
% if not is_shared_list:
|
||||
use std::iter::FromIterator;
|
||||
% endif
|
||||
computed_value::List(computed_value::UnderlyingList::from_iter(
|
||||
self.0.iter().map(|i| i.to_computed_value(context))
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
||||
SpecifiedValue(computed.0.iter()
|
||||
.map(ToComputedValue::from_computed_value)
|
||||
.collect())
|
||||
let iter = computed.0.iter().map(ToComputedValue::from_computed_value);
|
||||
SpecifiedValue(iter.collect())
|
||||
}
|
||||
}
|
||||
</%call>
|
||||
|
@ -375,7 +496,7 @@
|
|||
.set_writing_mode_dependency(context.builder.writing_mode);
|
||||
% endif
|
||||
|
||||
% if property.is_vector:
|
||||
% if property.is_vector and not property.simple_vector_bindings and product == "gecko":
|
||||
// In the case of a vector property we want to pass down an
|
||||
// iterator so that this can be computed without allocation.
|
||||
//
|
||||
|
@ -405,8 +526,8 @@
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<PropertyDeclaration, ParseError<'i>> {
|
||||
% if property.allow_quirks:
|
||||
parse_quirky(context, input, specified::AllowQuirks::Yes)
|
||||
% if property.allow_quirks != "No":
|
||||
parse_quirky(context, input, specified::AllowQuirks::${property.allow_quirks})
|
||||
% else:
|
||||
parse(context, input)
|
||||
% endif
|
||||
|
@ -868,7 +989,7 @@
|
|||
</%def>
|
||||
|
||||
<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function,
|
||||
needs_context=True, allow_quirks=False, **kwargs)">
|
||||
needs_context=True, allow_quirks='No', **kwargs)">
|
||||
<% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %>
|
||||
<%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)">
|
||||
#[allow(unused_imports)]
|
||||
|
@ -881,8 +1002,8 @@
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Longhands, ParseError<'i>> {
|
||||
let rect = Rect::parse_with(context, input, |_c, i| {
|
||||
% if allow_quirks:
|
||||
${parser_function}_quirky(_c, i, specified::AllowQuirks::Yes)
|
||||
% if allow_quirks != "No":
|
||||
${parser_function}_quirky(_c, i, specified::AllowQuirks::${allow_quirks})
|
||||
% elif needs_context:
|
||||
${parser_function}(_c, i)
|
||||
% else:
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
from itertools import groupby
|
||||
%>
|
||||
|
||||
#[cfg(feature = "gecko")] use crate::gecko_bindings::structs::RawServoAnimationValueMap;
|
||||
#[cfg(feature = "gecko")] use crate::gecko_bindings::structs::nsCSSPropertyID;
|
||||
#[cfg(feature = "gecko")] use crate::gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI};
|
||||
use itertools::{EitherOrBoth, Itertools};
|
||||
use crate::properties::{CSSWideKeyword, PropertyDeclaration};
|
||||
use crate::properties::longhands;
|
||||
|
@ -190,13 +188,6 @@ impl AnimatedProperty {
|
|||
/// composed for each TransitionProperty.
|
||||
pub type AnimationValueMap = FxHashMap<LonghandId, AnimationValue>;
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
unsafe impl HasFFI for AnimationValueMap {
|
||||
type FFIType = RawServoAnimationValueMap;
|
||||
}
|
||||
#[cfg(feature = "gecko")]
|
||||
unsafe impl HasSimpleFFI for AnimationValueMap {}
|
||||
|
||||
/// An enum to represent a single computed value belonging to an animated
|
||||
/// property in order to be interpolated with another one. When interpolating,
|
||||
/// both values need to belong to the same property.
|
||||
|
@ -773,6 +764,7 @@ macro_rules! animated_list_impl {
|
|||
}
|
||||
}
|
||||
|
||||
animated_list_impl!(<T> for crate::OwnedSlice<T>);
|
||||
animated_list_impl!(<T> for SmallVec<[T; 1]>);
|
||||
animated_list_impl!(<T> for Vec<T>);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ ${helpers.predefined_type(
|
|||
spec="https://drafts.csswg.org/css-backgrounds/#background-color",
|
||||
animation_value_type="AnimatedColor",
|
||||
ignored_when_colors_disabled=True,
|
||||
allow_quirks=True,
|
||||
allow_quirks="Yes",
|
||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER \
|
||||
CAN_ANIMATE_ON_COMPOSITOR",
|
||||
)}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
animation_value_type="AnimatedColor",
|
||||
logical=is_logical,
|
||||
logical_group="border-color",
|
||||
allow_quirks=not is_logical,
|
||||
allow_quirks="No" if is_logical else "Yes",
|
||||
flags="APPLIES_TO_FIRST_LETTER",
|
||||
ignored_when_colors_disabled=True,
|
||||
)}
|
||||
|
@ -56,7 +56,7 @@
|
|||
logical=is_logical,
|
||||
logical_group="border-width",
|
||||
flags="APPLIES_TO_FIRST_LETTER GETCS_NEEDS_LAYOUT_FLUSH",
|
||||
allow_quirks=not is_logical,
|
||||
allow_quirks="No" if is_logical else "Yes",
|
||||
servo_restyle_damage="reflow rebuild_and_reflow_inline"
|
||||
)}
|
||||
% endfor
|
||||
|
@ -159,60 +159,3 @@ ${helpers.predefined_type(
|
|||
flags="APPLIES_TO_FIRST_LETTER",
|
||||
boxed=True,
|
||||
)}
|
||||
|
||||
// FIXME(emilio): Why does this live here? ;_;
|
||||
#[cfg(feature = "gecko")]
|
||||
impl crate::values::computed::BorderImageWidth {
|
||||
pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) {
|
||||
use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
|
||||
use crate::gecko::values::GeckoStyleCoordConvertible;
|
||||
use crate::values::generics::border::BorderImageSideWidth;
|
||||
|
||||
% for i in range(0, 4):
|
||||
match self.${i} {
|
||||
BorderImageSideWidth::Auto => {
|
||||
sides.data_at_mut(${i}).set_value(CoordDataValue::Auto)
|
||||
},
|
||||
BorderImageSideWidth::Length(l) => {
|
||||
l.to_gecko_style_coord(&mut sides.data_at_mut(${i}))
|
||||
},
|
||||
BorderImageSideWidth::Number(n) => {
|
||||
sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n.0))
|
||||
},
|
||||
}
|
||||
% endfor
|
||||
}
|
||||
|
||||
pub fn from_gecko_rect(
|
||||
sides: &crate::gecko_bindings::structs::nsStyleSides,
|
||||
) -> Option<crate::values::computed::BorderImageWidth> {
|
||||
use crate::gecko_bindings::structs::nsStyleUnit::{eStyleUnit_Factor, eStyleUnit_Auto};
|
||||
use crate::gecko_bindings::sugar::ns_style_coord::CoordData;
|
||||
use crate::gecko::values::GeckoStyleCoordConvertible;
|
||||
use crate::values::computed::{LengthPercentage, Number};
|
||||
use crate::values::generics::border::BorderImageSideWidth;
|
||||
use crate::values::generics::NonNegative;
|
||||
|
||||
Some(
|
||||
crate::values::computed::BorderImageWidth::new(
|
||||
% for i in range(0, 4):
|
||||
match sides.data_at(${i}).unit() {
|
||||
eStyleUnit_Auto => {
|
||||
BorderImageSideWidth::Auto
|
||||
},
|
||||
eStyleUnit_Factor => {
|
||||
BorderImageSideWidth::Number(
|
||||
NonNegative(Number::from_gecko_style_coord(&sides.data_at(${i}))
|
||||
.expect("sides[${i}] could not convert to Number")))
|
||||
},
|
||||
_ => {
|
||||
BorderImageSideWidth::Length(
|
||||
NonNegative(LengthPercentage::from_gecko_style_coord(&sides.data_at(${i}))
|
||||
.expect("sides[${i}] could not convert to LengthPercentage")))
|
||||
},
|
||||
},
|
||||
% endfor
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -309,41 +309,6 @@ ${helpers.predefined_type(
|
|||
allowed_in_keyframe_block=False,
|
||||
)}
|
||||
|
||||
% for axis in ["x", "y"]:
|
||||
${helpers.predefined_type(
|
||||
"scroll-snap-points-" + axis,
|
||||
"ScrollSnapPoint",
|
||||
"computed::ScrollSnapPoint::none()",
|
||||
animation_value_type="discrete",
|
||||
gecko_pref="layout.css.scroll-snap.enabled",
|
||||
products="gecko",
|
||||
spec="Nonstandard (https://www.w3.org/TR/2015/WD-css-snappoints-1-20150326/#scroll-snap-points)",
|
||||
)}
|
||||
% endfor
|
||||
|
||||
${helpers.predefined_type(
|
||||
"scroll-snap-destination",
|
||||
"Position",
|
||||
"computed::Position::zero()",
|
||||
products="gecko",
|
||||
gecko_pref="layout.css.scroll-snap.enabled",
|
||||
boxed=True,
|
||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
|
||||
animation_value_type="discrete",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"scroll-snap-coordinate",
|
||||
"Position",
|
||||
"computed::Position::zero()",
|
||||
vector=True,
|
||||
allow_empty=True,
|
||||
products="gecko",
|
||||
gecko_pref="layout.css.scroll-snap.enabled",
|
||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
|
||||
animation_value_type="discrete",
|
||||
)}
|
||||
|
||||
<% transform_extra_prefixes = "moz:layout.css.prefixes.transforms webkit" %>
|
||||
|
||||
${helpers.predefined_type(
|
||||
|
@ -352,7 +317,6 @@ ${helpers.predefined_type(
|
|||
"generics::transform::Transform::none()",
|
||||
extra_prefixes=transform_extra_prefixes,
|
||||
animation_value_type="ComputedValue",
|
||||
gecko_ffi_name="mSpecifiedTransform",
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB \
|
||||
GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR",
|
||||
spec="https://drafts.csswg.org/css-transforms/#propdef-transform",
|
||||
|
@ -405,6 +369,31 @@ ${helpers.predefined_type(
|
|||
gecko_pref="layout.css.motion-path.enabled",
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||
spec="https://drafts.fxtf.org/motion-1/#offset-path-property",
|
||||
servo_restyle_damage="reflow_out_of_flow"
|
||||
)}
|
||||
|
||||
// Motion Path Module Level 1
|
||||
${helpers.predefined_type(
|
||||
"offset-distance",
|
||||
"LengthPercentage",
|
||||
"computed::LengthPercentage::zero()",
|
||||
products="gecko",
|
||||
animation_value_type="ComputedValue",
|
||||
gecko_pref="layout.css.motion-path.enabled",
|
||||
spec="https://drafts.fxtf.org/motion-1/#offset-distance-property",
|
||||
servo_restyle_damage="reflow_out_of_flow"
|
||||
)}
|
||||
|
||||
// Motion Path Module Level 1
|
||||
${helpers.predefined_type(
|
||||
"offset-rotate",
|
||||
"OffsetRotate",
|
||||
"computed::OffsetRotate::auto()",
|
||||
products="gecko",
|
||||
animation_value_type="none",
|
||||
gecko_pref="layout.css.motion-path.enabled",
|
||||
spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property",
|
||||
servo_restyle_damage="reflow_out_of_flow"
|
||||
)}
|
||||
|
||||
// CSSOM View Module
|
||||
|
|
|
@ -35,6 +35,7 @@ pub mod system_colors {
|
|||
-moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext
|
||||
-moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight
|
||||
-moz-html-cellhighlighttext -moz-mac-buttonactivetext
|
||||
-moz-gtk-buttonactivetext
|
||||
-moz-mac-chrome-active -moz-mac-chrome-inactive
|
||||
-moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect
|
||||
-moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect
|
||||
|
|
|
@ -23,6 +23,7 @@ ${helpers.predefined_type(
|
|||
"BoxShadow",
|
||||
None,
|
||||
vector=True,
|
||||
simple_vector_bindings=True,
|
||||
animation_value_type="AnimatedBoxShadowList",
|
||||
vector_animation_type="with_zero",
|
||||
extra_prefixes="webkit",
|
||||
|
@ -37,7 +38,7 @@ ${helpers.predefined_type(
|
|||
"computed::ClipRectOrAuto::auto()",
|
||||
animation_value_type="ComputedValue",
|
||||
boxed=True,
|
||||
allow_quirks=True,
|
||||
allow_quirks="Yes",
|
||||
spec="https://drafts.fxtf.org/css-masking/#clip-property",
|
||||
)}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ ${helpers.predefined_type(
|
|||
initial_value="computed::FontSize::medium()",
|
||||
initial_specified_value="specified::FontSize::medium()",
|
||||
animation_value_type="NonNegativeLength",
|
||||
allow_quirks=True,
|
||||
allow_quirks="Yes",
|
||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
||||
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size",
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
|
|
|
@ -194,11 +194,8 @@ ${helpers.predefined_type(
|
|||
${helpers.predefined_type(
|
||||
"-moz-context-properties",
|
||||
"MozContextProperties",
|
||||
initial_value=None,
|
||||
vector=True,
|
||||
need_index=True,
|
||||
animation_value_type="none",
|
||||
"computed::MozContextProperties::default()",
|
||||
products="gecko",
|
||||
animation_value_type="none",
|
||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)",
|
||||
allow_empty=True,
|
||||
)}
|
||||
|
|
|
@ -56,7 +56,7 @@ ${helpers.predefined_type(
|
|||
"computed::LengthPercentage::zero()",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
|
||||
allow_quirks=True,
|
||||
allow_quirks="Yes",
|
||||
servo_restyle_damage = "reflow",
|
||||
)}
|
||||
|
||||
|
@ -218,6 +218,7 @@ ${helpers.predefined_type(
|
|||
vector_animation_type="with_zero",
|
||||
animation_value_type="AnimatedTextShadowList",
|
||||
ignored_when_colors_disabled=True,
|
||||
simple_vector_bindings=True,
|
||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
||||
spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
|
||||
)}
|
||||
|
@ -263,6 +264,16 @@ ${helpers.predefined_type(
|
|||
spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"line-break",
|
||||
"LineBreak",
|
||||
"computed::LineBreak::Auto",
|
||||
products="gecko",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-text-3/#line-break-property",
|
||||
needs_context=False,
|
||||
)}
|
||||
|
||||
// CSS Compatibility
|
||||
// https://compat.spec.whatwg.org
|
||||
${helpers.predefined_type(
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
"LengthPercentageOrAuto",
|
||||
"computed::LengthPercentageOrAuto::zero()",
|
||||
alias=maybe_moz_logical_alias(product, side, "-moz-margin-%s"),
|
||||
allow_quirks=not side[1],
|
||||
allow_quirks="No" if side[1] else "Yes",
|
||||
animation_value_type="ComputedValue",
|
||||
logical=side[1],
|
||||
logical_group="margin",
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
logical_group="padding",
|
||||
spec=spec,
|
||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH",
|
||||
allow_quirks=not side[1],
|
||||
allow_quirks="No" if side[1] else "Yes",
|
||||
servo_restyle_damage="reflow rebuild_and_reflow_inline"
|
||||
)}
|
||||
% endfor
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
|
||||
flags="GETCS_NEEDS_LAYOUT_FLUSH",
|
||||
animation_value_type="ComputedValue",
|
||||
allow_quirks=True,
|
||||
allow_quirks="Yes",
|
||||
servo_restyle_damage="reflow_out_of_flow",
|
||||
logical_group="inset",
|
||||
)}
|
||||
|
@ -253,7 +253,7 @@ ${helpers.predefined_type(
|
|||
"computed::Size::auto()",
|
||||
logical=logical,
|
||||
logical_group="size",
|
||||
allow_quirks=not logical,
|
||||
allow_quirks="No" if logical else "Yes",
|
||||
spec=spec % size,
|
||||
animation_value_type="Size",
|
||||
flags="GETCS_NEEDS_LAYOUT_FLUSH",
|
||||
|
@ -266,7 +266,7 @@ ${helpers.predefined_type(
|
|||
"computed::Size::auto()",
|
||||
logical=logical,
|
||||
logical_group="min-size",
|
||||
allow_quirks=not logical,
|
||||
allow_quirks="No" if logical else "Yes",
|
||||
spec=spec % size,
|
||||
animation_value_type="Size",
|
||||
servo_restyle_damage="reflow",
|
||||
|
@ -277,7 +277,7 @@ ${helpers.predefined_type(
|
|||
"computed::MaxSize::none()",
|
||||
logical=logical,
|
||||
logical_group="max-size",
|
||||
allow_quirks=not logical,
|
||||
allow_quirks="No" if logical else "Yes",
|
||||
spec=spec % size,
|
||||
animation_value_type="MaxSize",
|
||||
servo_restyle_damage="reflow",
|
||||
|
|
|
@ -191,3 +191,66 @@ ${helpers.predefined_type(
|
|||
animation_value_type="discrete",
|
||||
flags="CREATES_STACKING_CONTEXT",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"x",
|
||||
"LengthPercentage",
|
||||
"computed::LengthPercentage::zero()",
|
||||
products="gecko",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://svgwg.org/svg2-draft/geometry.html#X",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"y",
|
||||
"LengthPercentage",
|
||||
"computed::LengthPercentage::zero()",
|
||||
products="gecko",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://svgwg.org/svg2-draft/geometry.html#Y",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"cx",
|
||||
"LengthPercentage",
|
||||
"computed::LengthPercentage::zero()",
|
||||
products="gecko",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://svgwg.org/svg2-draft/geometry.html#CX",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"cy",
|
||||
"LengthPercentage",
|
||||
"computed::LengthPercentage::zero()",
|
||||
products="gecko",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://svgwg.org/svg2-draft/geometry.html#CY",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"rx",
|
||||
"NonNegativeLengthPercentageOrAuto",
|
||||
"computed::NonNegativeLengthPercentageOrAuto::auto()",
|
||||
products="gecko",
|
||||
animation_value_type="LengthPercentageOrAuto",
|
||||
spec="https://svgwg.org/svg2-draft/geometry.html#RX",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"ry",
|
||||
"NonNegativeLengthPercentageOrAuto",
|
||||
"computed::NonNegativeLengthPercentageOrAuto::auto()",
|
||||
products="gecko",
|
||||
animation_value_type="LengthPercentageOrAuto",
|
||||
spec="https://svgwg.org/svg2-draft/geometry.html#RY",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"r",
|
||||
"NonNegativeLengthPercentage",
|
||||
"computed::NonNegativeLengthPercentage::zero()",
|
||||
products="gecko",
|
||||
animation_value_type="LengthPercentage",
|
||||
spec="https://svgwg.org/svg2-draft/geometry.html#R",
|
||||
)}
|
||||
|
|
|
@ -32,12 +32,11 @@ ${helpers.single_keyword(
|
|||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"-moz-user-select",
|
||||
"user-select",
|
||||
"UserSelect",
|
||||
"computed::UserSelect::Auto",
|
||||
products="gecko",
|
||||
gecko_ffi_name="mUserSelect",
|
||||
alias="-webkit-user-select",
|
||||
extra_prefixes="moz webkit",
|
||||
animation_value_type="discrete",
|
||||
needs_context=False,
|
||||
spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select",
|
||||
|
@ -81,7 +80,6 @@ ${helpers.predefined_type(
|
|||
"Transform",
|
||||
"generics::transform::Transform::none()",
|
||||
products="gecko",
|
||||
gecko_ffi_name="mSpecifiedWindowTransform",
|
||||
flags="GETCS_NEEDS_LAYOUT_FLUSH",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="None (Nonstandard internal property)",
|
||||
|
|
|
@ -2337,6 +2337,14 @@ impl SourcePropertyDeclaration {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create one with a single PropertyDeclaration.
|
||||
#[inline]
|
||||
pub fn with_one(decl: PropertyDeclaration) -> Self {
|
||||
let mut result = Self::new();
|
||||
result.declarations.push(decl);
|
||||
result
|
||||
}
|
||||
|
||||
/// Similar to Vec::drain: leaves this empty when the return value is dropped.
|
||||
pub fn drain(&mut self) -> SourcePropertyDeclarationDrain {
|
||||
SourcePropertyDeclarationDrain {
|
||||
|
@ -2474,20 +2482,7 @@ pub mod style_structs {
|
|||
% if longhand.logical:
|
||||
${helpers.logical_setter(name=longhand.name)}
|
||||
% else:
|
||||
% if longhand.is_vector:
|
||||
/// Set ${longhand.name}.
|
||||
#[allow(non_snake_case)]
|
||||
#[inline]
|
||||
pub fn set_${longhand.ident}<I>(&mut self, v: I)
|
||||
where
|
||||
I: IntoIterator<Item = longhands::${longhand.ident}
|
||||
::computed_value::single_value::T>,
|
||||
I::IntoIter: ExactSizeIterator
|
||||
{
|
||||
self.${longhand.ident} = longhands::${longhand.ident}::computed_value
|
||||
::List(v.into_iter().collect());
|
||||
}
|
||||
% elif longhand.ident == "display":
|
||||
% if longhand.ident == "display":
|
||||
/// Set `display`.
|
||||
///
|
||||
/// We need to keep track of the original display for hypothetical boxes,
|
||||
|
@ -3101,7 +3096,7 @@ impl ComputedValuesInner {
|
|||
pub fn transform_requires_layer(&self) -> bool {
|
||||
use crate::values::generics::transform::TransformOperation;
|
||||
// Check if the transform matrix is 2D or 3D
|
||||
for transform in &self.get_box().transform.0 {
|
||||
for transform in &*self.get_box().transform.0 {
|
||||
match *transform {
|
||||
TransformOperation::Perspective(..) => {
|
||||
return true;
|
||||
|
@ -3444,7 +3439,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
}
|
||||
% endif
|
||||
|
||||
% if not property.is_vector:
|
||||
% if not property.is_vector or property.simple_vector_bindings or product != "gecko":
|
||||
/// Set the `${property.ident}` to the computed value `value`.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn set_${property.ident}(
|
||||
|
|
|
@ -40,11 +40,11 @@
|
|||
let mut background_color = None;
|
||||
|
||||
% for name in "image position_x position_y repeat size attachment origin clip".split():
|
||||
// Vec grows from 0 to 4 by default on first push(). So allocate
|
||||
// with capacity 1, so in the common case of only one item we don't
|
||||
// way overallocate. Note that we always push at least one item if
|
||||
// parsing succeeds.
|
||||
let mut background_${name} = background_${name}::SpecifiedValue(Vec::with_capacity(1));
|
||||
// Vec grows from 0 to 4 by default on first push(). So allocate with
|
||||
// capacity 1, so in the common case of only one item we don't way
|
||||
// overallocate, then shrink. Note that we always push at least one
|
||||
// item if parsing succeeds.
|
||||
let mut background_${name} = Vec::with_capacity(1);
|
||||
% endfor
|
||||
input.parse_comma_separated(|input| {
|
||||
// background-color can only be in the last element, so if it
|
||||
|
@ -99,17 +99,17 @@
|
|||
any = any || background_color.is_some();
|
||||
if any {
|
||||
if let Some(position) = position {
|
||||
background_position_x.0.push(position.horizontal);
|
||||
background_position_y.0.push(position.vertical);
|
||||
background_position_x.push(position.horizontal);
|
||||
background_position_y.push(position.vertical);
|
||||
} else {
|
||||
background_position_x.0.push(PositionComponent::zero());
|
||||
background_position_y.0.push(PositionComponent::zero());
|
||||
background_position_x.push(PositionComponent::zero());
|
||||
background_position_y.push(PositionComponent::zero());
|
||||
}
|
||||
% for name in "image repeat size attachment origin clip".split():
|
||||
if let Some(bg_${name}) = ${name} {
|
||||
background_${name}.0.push(bg_${name});
|
||||
background_${name}.push(bg_${name});
|
||||
} else {
|
||||
background_${name}.0.push(background_${name}::single_value
|
||||
background_${name}.push(background_${name}::single_value
|
||||
::get_initial_specified_value());
|
||||
}
|
||||
% endfor
|
||||
|
@ -121,14 +121,9 @@
|
|||
|
||||
Ok(expanded! {
|
||||
background_color: background_color.unwrap_or(Color::transparent()),
|
||||
background_image: background_image,
|
||||
background_position_x: background_position_x,
|
||||
background_position_y: background_position_y,
|
||||
background_repeat: background_repeat,
|
||||
background_attachment: background_attachment,
|
||||
background_size: background_size,
|
||||
background_origin: background_origin,
|
||||
background_clip: background_clip,
|
||||
% for name in "image position_x position_y repeat size attachment origin clip".split():
|
||||
background_${name}: background_${name}::SpecifiedValue(background_${name}.into()),
|
||||
% endfor
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -209,16 +204,16 @@
|
|||
) -> Result<Longhands, ParseError<'i>> {
|
||||
// Vec grows from 0 to 4 by default on first push(). So allocate with
|
||||
// capacity 1, so in the common case of only one item we don't way
|
||||
// overallocate. Note that we always push at least one item if parsing
|
||||
// succeeds.
|
||||
let mut position_x = background_position_x::SpecifiedValue(Vec::with_capacity(1));
|
||||
let mut position_y = background_position_y::SpecifiedValue(Vec::with_capacity(1));
|
||||
// overallocate, then shrink. Note that we always push at least one
|
||||
// item if parsing succeeds.
|
||||
let mut position_x = Vec::with_capacity(1);
|
||||
let mut position_y = Vec::with_capacity(1);
|
||||
let mut any = false;
|
||||
|
||||
input.parse_comma_separated(|input| {
|
||||
let value = Position::parse_quirky(context, input, AllowQuirks::Yes)?;
|
||||
position_x.0.push(value.horizontal);
|
||||
position_y.0.push(value.vertical);
|
||||
position_x.push(value.horizontal);
|
||||
position_y.push(value.vertical);
|
||||
any = true;
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -227,8 +222,8 @@
|
|||
}
|
||||
|
||||
Ok(expanded! {
|
||||
background_position_x: position_x,
|
||||
background_position_y: position_y,
|
||||
background_position_x: background_position_x::SpecifiedValue(position_x.into()),
|
||||
background_position_y: background_position_y::SpecifiedValue(position_y.into()),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::Color::parse",
|
||||
spec="https://drafts.csswg.org/css-backgrounds/#border-color",
|
||||
allow_quirks=True)}
|
||||
allow_quirks="Yes")}
|
||||
|
||||
${helpers.four_sides_shorthand(
|
||||
"border-style",
|
||||
|
|
|
@ -137,7 +137,7 @@ macro_rules! try_parse_one {
|
|||
|
||||
Ok(expanded! {
|
||||
% for prop in "property duration timing_function delay".split():
|
||||
transition_${prop}: transition_${prop}::SpecifiedValue(${prop}s),
|
||||
transition_${prop}: transition_${prop}::SpecifiedValue(${prop}s.into()),
|
||||
% endfor
|
||||
})
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ macro_rules! try_parse_one {
|
|||
|
||||
Ok(expanded! {
|
||||
% for prop in props:
|
||||
animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s),
|
||||
animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s.into()),
|
||||
% endfor
|
||||
})
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ ${helpers.four_sides_shorthand(
|
|||
"specified::LengthPercentageOrAuto::parse",
|
||||
spec="https://drafts.csswg.org/css-box/#propdef-margin",
|
||||
allowed_in_page_rule=True,
|
||||
allow_quirks=True,
|
||||
allow_quirks="Yes",
|
||||
)}
|
||||
|
||||
${helpers.two_properties_shorthand(
|
||||
|
|
|
@ -9,7 +9,7 @@ ${helpers.four_sides_shorthand(
|
|||
"padding-%s",
|
||||
"specified::NonNegativeLengthPercentage::parse",
|
||||
spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
|
||||
allow_quirks=True,
|
||||
allow_quirks="Yes",
|
||||
)}
|
||||
|
||||
${helpers.two_properties_shorthand(
|
||||
|
|
|
@ -768,7 +768,7 @@ ${helpers.four_sides_shorthand(
|
|||
"%s",
|
||||
"specified::LengthPercentageOrAuto::parse",
|
||||
spec="https://drafts.csswg.org/css-logical/#propdef-inset",
|
||||
allow_quirks=False,
|
||||
allow_quirks="No",
|
||||
)}
|
||||
|
||||
${helpers.two_properties_shorthand(
|
||||
|
|
|
@ -42,11 +42,11 @@
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Longhands, ParseError<'i>> {
|
||||
% for name in "image mode position_x position_y size repeat origin clip composite".split():
|
||||
// Vec grows from 0 to 4 by default on first push(). So allocate
|
||||
// with capacity 1, so in the common case of only one item we don't
|
||||
// way overallocate. Note that we always push at least one item if
|
||||
// parsing succeeds.
|
||||
let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::with_capacity(1));
|
||||
// Vec grows from 0 to 4 by default on first push(). So allocate with
|
||||
// capacity 1, so in the common case of only one item we don't way
|
||||
// overallocate, then shrink. Note that we always push at least one
|
||||
// item if parsing succeeds.
|
||||
let mut mask_${name} = Vec::with_capacity(1);
|
||||
% endfor
|
||||
|
||||
input.parse_comma_separated(|input| {
|
||||
|
@ -96,17 +96,17 @@
|
|||
% endfor
|
||||
if any {
|
||||
if let Some(position) = position {
|
||||
mask_position_x.0.push(position.horizontal);
|
||||
mask_position_y.0.push(position.vertical);
|
||||
mask_position_x.push(position.horizontal);
|
||||
mask_position_y.push(position.vertical);
|
||||
} else {
|
||||
mask_position_x.0.push(PositionComponent::zero());
|
||||
mask_position_y.0.push(PositionComponent::zero());
|
||||
mask_position_x.push(PositionComponent::zero());
|
||||
mask_position_y.push(PositionComponent::zero());
|
||||
}
|
||||
% for name in "image mode size repeat origin clip composite".split():
|
||||
if let Some(m_${name}) = ${name} {
|
||||
mask_${name}.0.push(m_${name});
|
||||
mask_${name}.push(m_${name});
|
||||
} else {
|
||||
mask_${name}.0.push(mask_${name}::single_value
|
||||
mask_${name}.push(mask_${name}::single_value
|
||||
::get_initial_specified_value());
|
||||
}
|
||||
% endfor
|
||||
|
@ -118,7 +118,7 @@
|
|||
|
||||
Ok(expanded! {
|
||||
% for name in "image mode position_x position_y size repeat origin clip composite".split():
|
||||
mask_${name}: mask_${name},
|
||||
mask_${name}: mask_${name}::SpecifiedValue(mask_${name}.into()),
|
||||
% endfor
|
||||
})
|
||||
}
|
||||
|
@ -209,16 +209,16 @@
|
|||
) -> Result<Longhands, ParseError<'i>> {
|
||||
// Vec grows from 0 to 4 by default on first push(). So allocate with
|
||||
// capacity 1, so in the common case of only one item we don't way
|
||||
// overallocate. Note that we always push at least one item if parsing
|
||||
// succeeds.
|
||||
let mut position_x = mask_position_x::SpecifiedValue(Vec::with_capacity(1));
|
||||
let mut position_y = mask_position_y::SpecifiedValue(Vec::with_capacity(1));
|
||||
// overallocate, then shrink. Note that we always push at least one
|
||||
// item if parsing succeeds.
|
||||
let mut position_x = Vec::with_capacity(1);
|
||||
let mut position_y = Vec::with_capacity(1);
|
||||
let mut any = false;
|
||||
|
||||
input.parse_comma_separated(|input| {
|
||||
let value = Position::parse(context, input)?;
|
||||
position_x.0.push(value.horizontal);
|
||||
position_y.0.push(value.vertical);
|
||||
position_x.push(value.horizontal);
|
||||
position_y.push(value.vertical);
|
||||
any = true;
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -227,9 +227,10 @@
|
|||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
|
||||
Ok(expanded! {
|
||||
mask_position_x: position_x,
|
||||
mask_position_y: position_y,
|
||||
mask_position_x: mask_position_x::SpecifiedValue(position_x.into()),
|
||||
mask_position_y: mask_position_y::SpecifiedValue(position_y.into()),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::selector_parser::PseudoElement;
|
|||
use crate::shared_lock::Locked;
|
||||
use crate::stylesheets::Origin;
|
||||
use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||
use servo_arc::ArcBorrow;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
@ -97,8 +97,15 @@ where
|
|||
context: &'a mut MatchingContext<'b, E::Impl>,
|
||||
flags_setter: &'a mut F,
|
||||
) -> Self {
|
||||
let rule_hash_target = element.rule_hash_target();
|
||||
let matches_user_and_author_rules = element.matches_user_and_author_rules();
|
||||
// When we're matching with matching_mode =
|
||||
// `ForStatelessPseudoeElement`, the "target" for the rule hash is the
|
||||
// element itself, since it's what's generating the pseudo-element.
|
||||
let rule_hash_target = match context.matching_mode() {
|
||||
MatchingMode::ForStatelessPseudoElement => element,
|
||||
MatchingMode::Normal => element.rule_hash_target(),
|
||||
};
|
||||
|
||||
let matches_user_and_author_rules = rule_hash_target.matches_user_and_author_rules();
|
||||
|
||||
// Gecko definitely has pseudo-elements with style attributes, like
|
||||
// ::-moz-color-swatch.
|
||||
|
@ -120,8 +127,8 @@ where
|
|||
context,
|
||||
flags_setter,
|
||||
rules,
|
||||
matches_user_and_author_rules,
|
||||
shadow_cascade_order: 0,
|
||||
matches_user_and_author_rules,
|
||||
matches_document_author_rules: matches_user_and_author_rules,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -734,10 +734,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
|||
E: TElement,
|
||||
{
|
||||
if cfg!(debug_assertions) {
|
||||
if element
|
||||
.and_then(|e| e.implemented_pseudo_element())
|
||||
.is_some()
|
||||
{
|
||||
if element.map_or(false, |e| e.is_pseudo_element()) {
|
||||
// It'd be nice to assert `self.style.pseudo == Some(&pseudo)`,
|
||||
// but we do resolve ::-moz-list pseudos on ::before / ::after
|
||||
// content, sigh.
|
||||
|
|
|
@ -233,7 +233,7 @@ where
|
|||
|
||||
let mut pseudo_styles = EagerPseudoStyles::default();
|
||||
|
||||
if self.element.implemented_pseudo_element().is_none() {
|
||||
if !self.element.is_pseudo_element() {
|
||||
let layout_parent_style_for_pseudo = if primary_style.style().is_display_contents() {
|
||||
layout_parent_style
|
||||
} else {
|
||||
|
@ -293,10 +293,6 @@ where
|
|||
layout_parent_style: Option<&ComputedValues>,
|
||||
pseudo: Option<&PseudoElement>,
|
||||
) -> ResolvedStyle {
|
||||
debug_assert!(
|
||||
self.element.implemented_pseudo_element().is_none() || pseudo.is_none(),
|
||||
"Pseudo-elements can't have other pseudos!"
|
||||
);
|
||||
debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
|
||||
|
||||
let implemented_pseudo = self.element.implemented_pseudo_element();
|
||||
|
@ -477,8 +473,8 @@ where
|
|||
);
|
||||
debug_assert!(pseudo_element.is_eager());
|
||||
debug_assert!(
|
||||
self.element.implemented_pseudo_element().is_none(),
|
||||
"Element pseudos can't have any other pseudo."
|
||||
!self.element.is_pseudo_element(),
|
||||
"Element pseudos can't have any other eager pseudo."
|
||||
);
|
||||
|
||||
let mut applicable_declarations = ApplicableDeclarationList::new();
|
||||
|
|
|
@ -1195,6 +1195,10 @@ impl Stylist {
|
|||
// See [3] for the bug to implement whatever gets resolved, and related
|
||||
// bugs for a bit more context.
|
||||
//
|
||||
// FIXME(emilio): This should probably work for pseudo-elements (i.e.,
|
||||
// use rule_hash_target().shadow_root() instead of
|
||||
// element.shadow_root()).
|
||||
//
|
||||
// [1]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/
|
||||
// core/css/resolver/style_resolver.cc?l=1267&rcl=90f9f8680ebb4a87d177f3b0833372ae4e0c88d8
|
||||
// [2]: https://github.com/w3c/csswg-drafts/issues/1995
|
||||
|
|
|
@ -9,22 +9,18 @@ use crate::values::computed::length::Length;
|
|||
#[cfg(feature = "gecko")]
|
||||
use crate::values::computed::url::ComputedUrl;
|
||||
use crate::values::computed::{Angle, Number};
|
||||
use crate::values::generics::effects::BoxShadow as GenericBoxShadow;
|
||||
use crate::values::generics::effects::Filter as GenericFilter;
|
||||
use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow;
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
use crate::values::Impossible;
|
||||
|
||||
/// An animated value for a single `box-shadow`.
|
||||
pub type BoxShadow = GenericBoxShadow<Color, Length, Length, Length>;
|
||||
/// An animated value for the `drop-shadow()` filter.
|
||||
pub type AnimatedSimpleShadow = GenericSimpleShadow<Color, Length, Length>;
|
||||
|
||||
/// An animated value for a single `filter`.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>;
|
||||
pub type Filter = GenericFilter<Angle, Number, Length, AnimatedSimpleShadow, ComputedUrl>;
|
||||
|
||||
/// An animated value for a single `filter`.
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
|
||||
|
||||
/// An animated value for the `drop-shadow()` filter.
|
||||
pub type SimpleShadow = GenericSimpleShadow<Color, Length, Length>;
|
||||
|
|
|
@ -861,7 +861,7 @@ impl Animate for ComputedTransform {
|
|||
// animation procedures so we treat it separately here rather than
|
||||
// handling it in TransformOperation.
|
||||
if procedure == Procedure::Add {
|
||||
let result = self.0.iter().chain(&other.0).cloned().collect::<Vec<_>>();
|
||||
let result = self.0.iter().chain(&*other.0).cloned().collect();
|
||||
return Ok(Transform(result));
|
||||
}
|
||||
|
||||
|
@ -898,15 +898,15 @@ impl Animate for ComputedTransform {
|
|||
},
|
||||
Procedure::Interpolate { progress } => {
|
||||
result.push(TransformOperation::InterpolateMatrix {
|
||||
from_list: Transform(this_remainder.to_vec()),
|
||||
to_list: Transform(other_remainder.to_vec()),
|
||||
from_list: Transform(this_remainder.to_vec().into()),
|
||||
to_list: Transform(other_remainder.to_vec().into()),
|
||||
progress: Percentage(progress as f32),
|
||||
});
|
||||
},
|
||||
Procedure::Accumulate { count } => {
|
||||
result.push(TransformOperation::AccumulateMatrix {
|
||||
from_list: Transform(this_remainder.to_vec()),
|
||||
to_list: Transform(other_remainder.to_vec()),
|
||||
from_list: Transform(this_remainder.to_vec().into()),
|
||||
to_list: Transform(other_remainder.to_vec().into()),
|
||||
count: cmp::min(count, i32::max_value() as u64) as i32,
|
||||
});
|
||||
},
|
||||
|
@ -927,8 +927,8 @@ impl Animate for ComputedTransform {
|
|||
// matrix. Instead we need to wrap it in another ___Matrix type.
|
||||
TransformOperation::AccumulateMatrix { .. } |
|
||||
TransformOperation::InterpolateMatrix { .. } => {
|
||||
let transform_list = Transform(vec![transform.clone()]);
|
||||
let identity_list = Transform(vec![identity]);
|
||||
let transform_list = Transform(vec![transform.clone()].into());
|
||||
let identity_list = Transform(vec![identity].into());
|
||||
let (from_list, to_list) = if fill_right {
|
||||
(transform_list, identity_list)
|
||||
} else {
|
||||
|
@ -970,7 +970,7 @@ impl Animate for ComputedTransform {
|
|||
(None, None) => {},
|
||||
}
|
||||
|
||||
Ok(Transform(result))
|
||||
Ok(Transform(result.into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ use style_traits::{CssWriter, ToCss};
|
|||
ToAnimatedZero,
|
||||
ToResolvedValue,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct Angle(CSSFloat);
|
||||
|
||||
impl ToCss for Angle {
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
use crate::values::computed::length::{NonNegativeLength, NonNegativeLengthPercentage};
|
||||
use crate::values::computed::{NonNegativeNumber, NonNegativeNumberOrPercentage};
|
||||
use crate::values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
|
||||
use crate::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
|
||||
use crate::values::generics::border::BorderImageSlice as GenericBorderImageSlice;
|
||||
use crate::values::generics::border::BorderRadius as GenericBorderRadius;
|
||||
use crate::values::generics::border::BorderSpacing as GenericBorderSpacing;
|
||||
use crate::values::generics::border::GenericBorderImageSideWidth;
|
||||
use crate::values::generics::rect::Rect;
|
||||
use crate::values::generics::size::Size2D;
|
||||
use crate::values::generics::NonNegative;
|
||||
|
|
|
@ -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>;
|
|
@ -9,21 +9,19 @@ pub use crate::values::specified::list::ListStyleType;
|
|||
pub use crate::values::specified::list::MozListReversed;
|
||||
pub use crate::values::specified::list::{QuotePair, Quotes};
|
||||
|
||||
use servo_arc::Arc;
|
||||
|
||||
lazy_static! {
|
||||
static ref INITIAL_QUOTES: Arc<Box<[QuotePair]>> = Arc::new(
|
||||
static ref INITIAL_QUOTES: crate::ArcSlice<QuotePair> = crate::ArcSlice::from_iter(
|
||||
vec![
|
||||
QuotePair {
|
||||
opening: "\u{201c}".to_owned().into_boxed_str(),
|
||||
closing: "\u{201d}".to_owned().into_boxed_str(),
|
||||
opening: "\u{201c}".to_owned().into(),
|
||||
closing: "\u{201d}".to_owned().into(),
|
||||
},
|
||||
QuotePair {
|
||||
opening: "\u{2018}".to_owned().into_boxed_str(),
|
||||
closing: "\u{2019}".to_owned().into_boxed_str(),
|
||||
opening: "\u{2018}".to_owned().into(),
|
||||
closing: "\u{2019}".to_owned().into(),
|
||||
},
|
||||
]
|
||||
.into_boxed_slice()
|
||||
.into_iter()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,8 +56,6 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis};
|
|||
pub use self::font::{FontVariantAlternates, FontWeight};
|
||||
pub use self::font::{FontVariantEastAsian, FontVariationSettings};
|
||||
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::gecko::ScrollSnapPoint;
|
||||
pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
|
||||
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
|
||||
pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
|
||||
|
@ -67,7 +65,7 @@ pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageO
|
|||
pub use self::list::ListStyleType;
|
||||
pub use self::list::MozListReversed;
|
||||
pub use self::list::{QuotePair, Quotes};
|
||||
pub use self::motion::OffsetPath;
|
||||
pub use self::motion::{OffsetPath, OffsetRotate};
|
||||
pub use self::outline::OutlineStyle;
|
||||
pub use self::percentage::{NonNegativePercentage, Percentage};
|
||||
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex};
|
||||
|
@ -77,7 +75,7 @@ pub use self::svg::MozContextProperties;
|
|||
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
|
||||
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
||||
pub use self::table::XSpan;
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight};
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight};
|
||||
pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
|
||||
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
|
||||
pub use self::time::Time;
|
||||
|
@ -106,8 +104,6 @@ pub mod easing;
|
|||
pub mod effects;
|
||||
pub mod flex;
|
||||
pub mod font;
|
||||
#[cfg(feature = "gecko")]
|
||||
pub mod gecko;
|
||||
pub mod image;
|
||||
pub mod length;
|
||||
pub mod list;
|
||||
|
@ -454,17 +450,12 @@ where
|
|||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
self.iter()
|
||||
.map(|item| item.to_computed_value(context))
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
computed
|
||||
.iter()
|
||||
.map(T::from_computed_value)
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
computed.iter().map(T::from_computed_value).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,41 @@
|
|||
|
||||
//! Computed types for CSS values that are related to motion path.
|
||||
|
||||
use crate::values::computed::Angle;
|
||||
use crate::Zero;
|
||||
|
||||
/// A computed offset-path. The computed value is as specified value.
|
||||
///
|
||||
/// https://drafts.fxtf.org/motion-1/#offset-path-property
|
||||
pub use crate::values::specified::motion::OffsetPath;
|
||||
|
||||
#[inline]
|
||||
fn is_auto_zero_angle(auto: &bool, angle: &Angle) -> bool {
|
||||
*auto && angle.is_zero()
|
||||
}
|
||||
|
||||
/// A computed offset-rotate.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)]
|
||||
#[repr(C)]
|
||||
pub struct OffsetRotate {
|
||||
/// If auto is false, this is a fixed angle which indicates a
|
||||
/// constant clockwise rotation transformation applied to it by this
|
||||
/// specified rotation angle. Otherwise, the angle will be added to
|
||||
/// the angle of the direction in layout.
|
||||
#[css(represents_keyword)]
|
||||
pub auto: bool,
|
||||
/// The angle value.
|
||||
#[css(contextual_skip_if = "is_auto_zero_angle")]
|
||||
pub angle: Angle,
|
||||
}
|
||||
|
||||
impl OffsetRotate {
|
||||
/// Returns "auto 0deg".
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
OffsetRotate {
|
||||
auto: true,
|
||||
angle: Zero::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use style_traits::{CssWriter, ToCss};
|
|||
|
||||
pub use crate::values::specified::TextAlignKeyword as TextAlign;
|
||||
pub use crate::values::specified::TextTransform;
|
||||
pub use crate::values::specified::{OverflowWrap, WordBreak};
|
||||
pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak};
|
||||
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
|
||||
|
||||
/// A computed value for the `initial-letter` property.
|
||||
|
@ -105,6 +105,7 @@ impl ToComputedValue for specified::WordSpacing {
|
|||
pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLength>;
|
||||
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToResolvedValue)]
|
||||
#[repr(C)]
|
||||
/// text-overflow.
|
||||
/// When the specified value only has one side, that's the "second"
|
||||
/// side, and the sides are logical, so "second" means "end". The
|
||||
|
|
|
@ -16,9 +16,9 @@ pub use crate::values::generics::transform::TransformStyle;
|
|||
|
||||
/// A single operation in a computed CSS `transform`
|
||||
pub type TransformOperation =
|
||||
generic::TransformOperation<Angle, Number, Length, Integer, LengthPercentage>;
|
||||
generic::GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>;
|
||||
/// A computed CSS `transform`
|
||||
pub type Transform = generic::Transform<TransformOperation>;
|
||||
pub type Transform = generic::GenericTransform<TransformOperation>;
|
||||
|
||||
/// The computed value of a CSS `<transform-origin>`
|
||||
pub type TransformOrigin =
|
||||
|
@ -540,88 +540,16 @@ impl ToAnimatedZero for Transform {
|
|||
self.0
|
||||
.iter()
|
||||
.map(|op| op.to_animated_zero())
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
.collect::<Result<crate::OwnedSlice<_>, _>>()?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// A computed CSS `rotate`
|
||||
pub type Rotate = generic::Rotate<Number, Angle>;
|
||||
|
||||
impl Rotate {
|
||||
/// Convert TransformOperation to Rotate.
|
||||
pub fn to_transform_operation(&self) -> Option<TransformOperation> {
|
||||
match *self {
|
||||
generic::Rotate::None => None,
|
||||
generic::Rotate::Rotate(angle) => Some(generic::TransformOperation::Rotate(angle)),
|
||||
generic::Rotate::Rotate3D(rx, ry, rz, angle) => {
|
||||
Some(generic::TransformOperation::Rotate3D(rx, ry, rz, angle))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert Rotate to TransformOperation.
|
||||
pub fn from_transform_operation(operation: &TransformOperation) -> Rotate {
|
||||
match *operation {
|
||||
generic::TransformOperation::Rotate(angle) => generic::Rotate::Rotate(angle),
|
||||
generic::TransformOperation::Rotate3D(rx, ry, rz, angle) => {
|
||||
generic::Rotate::Rotate3D(rx, ry, rz, angle)
|
||||
},
|
||||
_ => unreachable!("Found unexpected value for rotate property"),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type Rotate = generic::GenericRotate<Number, Angle>;
|
||||
|
||||
/// A computed CSS `translate`
|
||||
pub type Translate = generic::Translate<LengthPercentage, Length>;
|
||||
|
||||
impl Translate {
|
||||
/// Convert TransformOperation to Translate.
|
||||
pub fn to_transform_operation(&self) -> Option<TransformOperation> {
|
||||
match *self {
|
||||
generic::Translate::None => None,
|
||||
generic::Translate::Translate(tx, ty) => {
|
||||
Some(generic::TransformOperation::Translate(tx, ty))
|
||||
},
|
||||
generic::Translate::Translate3D(tx, ty, tz) => {
|
||||
Some(generic::TransformOperation::Translate3D(tx, ty, tz))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert Translate to TransformOperation.
|
||||
pub fn from_transform_operation(operation: &TransformOperation) -> Translate {
|
||||
match *operation {
|
||||
generic::TransformOperation::Translate(tx, ty) => generic::Translate::Translate(tx, ty),
|
||||
generic::TransformOperation::Translate3D(tx, ty, tz) => {
|
||||
generic::Translate::Translate3D(tx, ty, tz)
|
||||
},
|
||||
_ => unreachable!("Found unexpected value for translate"),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type Translate = generic::GenericTranslate<LengthPercentage, Length>;
|
||||
|
||||
/// A computed CSS `scale`
|
||||
pub type Scale = generic::Scale<Number>;
|
||||
|
||||
impl Scale {
|
||||
/// Convert TransformOperation to Scale.
|
||||
pub fn to_transform_operation(&self) -> Option<TransformOperation> {
|
||||
match *self {
|
||||
generic::Scale::None => None,
|
||||
generic::Scale::Scale(sx, sy) => Some(generic::TransformOperation::Scale(sx, sy)),
|
||||
generic::Scale::Scale3D(sx, sy, sz) => {
|
||||
Some(generic::TransformOperation::Scale3D(sx, sy, sz))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert Scale to TransformOperation.
|
||||
pub fn from_transform_operation(operation: &TransformOperation) -> Scale {
|
||||
match *operation {
|
||||
generic::TransformOperation::Scale(sx, sy) => generic::Scale::Scale(sx, sy),
|
||||
generic::TransformOperation::Scale3D(sx, sy, sz) => generic::Scale::Scale3D(sx, sy, sz),
|
||||
_ => unreachable!("Found unexpected value for scale"),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type Scale = generic::GenericScale<Number>;
|
||||
|
|
|
@ -23,15 +23,18 @@ use style_traits::{CssWriter, ToCss};
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
pub enum BorderImageSideWidth<LengthPercentage, Number> {
|
||||
#[repr(C, u8)]
|
||||
pub enum GenericBorderImageSideWidth<LP, N> {
|
||||
/// `<length-or-percentage>`
|
||||
Length(LengthPercentage),
|
||||
LengthPercentage(LP),
|
||||
/// `<number>`
|
||||
Number(Number),
|
||||
Number(N),
|
||||
/// `auto`
|
||||
Auto,
|
||||
}
|
||||
|
||||
pub use self::GenericBorderImageSideWidth as BorderImageSideWidth;
|
||||
|
||||
/// A generic value for the `border-image-slice` property.
|
||||
#[derive(
|
||||
Clone,
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
|
||||
#[repr(C)]
|
||||
pub struct GenericBoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
|
||||
/// The base shadow.
|
||||
pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
|
||||
pub base: GenericSimpleShadow<Color, SizeLength, BlurShapeLength>,
|
||||
/// The spread radius.
|
||||
pub spread: ShapeLength,
|
||||
/// Whether this is an inset box shadow.
|
||||
|
@ -30,6 +31,8 @@ pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
|
|||
pub inset: bool,
|
||||
}
|
||||
|
||||
pub use self::GenericBoxShadow as BoxShadow;
|
||||
|
||||
/// A generic value for a single `filter`.
|
||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||
#[animation(no_bound(Url))]
|
||||
|
@ -100,7 +103,8 @@ pub enum Filter<Angle, Factor, Length, DropShadow, Url> {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
|
||||
#[repr(C)]
|
||||
pub struct GenericSimpleShadow<Color, SizeLength, ShapeLength> {
|
||||
/// Color.
|
||||
pub color: Color,
|
||||
/// Horizontal radius.
|
||||
|
@ -110,3 +114,5 @@ pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
|
|||
/// Blur radius.
|
||||
pub blur: ShapeLength,
|
||||
}
|
||||
|
||||
pub use self::GenericSimpleShadow as SimpleShadow;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,8 +26,6 @@ pub mod easing;
|
|||
pub mod effects;
|
||||
pub mod flex;
|
||||
pub mod font;
|
||||
#[cfg(feature = "gecko")]
|
||||
pub mod gecko;
|
||||
pub mod grid;
|
||||
pub mod image;
|
||||
pub mod length;
|
||||
|
|
|
@ -30,8 +30,9 @@ use style_traits::{CssWriter, ToCss};
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[css(comma, function)]
|
||||
pub struct Matrix<T> {
|
||||
#[css(comma, function = "matrix")]
|
||||
#[repr(C)]
|
||||
pub struct GenericMatrix<T> {
|
||||
pub a: T,
|
||||
pub b: T,
|
||||
pub c: T,
|
||||
|
@ -40,6 +41,8 @@ pub struct Matrix<T> {
|
|||
pub f: T,
|
||||
}
|
||||
|
||||
pub use self::GenericMatrix as Matrix;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#[css(comma, function = "matrix3d")]
|
||||
|
@ -55,13 +58,16 @@ pub struct Matrix<T> {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
pub struct Matrix3D<T> {
|
||||
#[repr(C)]
|
||||
pub struct GenericMatrix3D<T> {
|
||||
pub m11: T, pub m12: T, pub m13: T, pub m14: T,
|
||||
pub m21: T, pub m22: T, pub m23: T, pub m24: T,
|
||||
pub m31: T, pub m32: T, pub m33: T, pub m34: T,
|
||||
pub m41: T, pub m42: T, pub m43: T, pub m44: T,
|
||||
}
|
||||
|
||||
pub use self::GenericMatrix3D as Matrix3D;
|
||||
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> {
|
||||
#[inline]
|
||||
|
@ -142,17 +148,19 @@ fn is_same<N: PartialEq>(x: &N, y: &N) -> bool {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
/// A single operation in the list of a `transform` value
|
||||
pub enum TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
|
||||
/// cbindgen:derive-tagged-enum-copy-constructor=true
|
||||
pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>
|
||||
where
|
||||
Angle: Zero,
|
||||
LengthPercentage: Zero,
|
||||
Number: PartialEq,
|
||||
{
|
||||
/// Represents a 2D 2x3 matrix.
|
||||
Matrix(Matrix<Number>),
|
||||
Matrix(GenericMatrix<Number>),
|
||||
/// Represents a 3D 4x4 matrix.
|
||||
Matrix3D(Matrix3D<Number>),
|
||||
Matrix3D(GenericMatrix3D<Number>),
|
||||
/// A 2D skew.
|
||||
///
|
||||
/// If the second angle is not provided it is assumed zero.
|
||||
|
@ -232,20 +240,30 @@ where
|
|||
#[allow(missing_docs)]
|
||||
#[css(comma, function = "interpolatematrix")]
|
||||
InterpolateMatrix {
|
||||
from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
||||
to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
||||
from_list: GenericTransform<
|
||||
GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
|
||||
>,
|
||||
to_list: GenericTransform<
|
||||
GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
|
||||
>,
|
||||
progress: computed::Percentage,
|
||||
},
|
||||
/// A intermediate type for accumulation of mismatched transform lists.
|
||||
#[allow(missing_docs)]
|
||||
#[css(comma, function = "accumulatematrix")]
|
||||
AccumulateMatrix {
|
||||
from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
||||
to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
|
||||
from_list: GenericTransform<
|
||||
GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
|
||||
>,
|
||||
to_list: GenericTransform<
|
||||
GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>,
|
||||
>,
|
||||
count: Integer,
|
||||
},
|
||||
}
|
||||
|
||||
pub use self::GenericTransformOperation as TransformOperation;
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
|
@ -257,8 +275,11 @@ where
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C)]
|
||||
/// A value of the `transform` property
|
||||
pub struct Transform<T>(#[css(if_empty = "none", iterable)] pub Vec<T>);
|
||||
pub struct GenericTransform<T>(#[css(if_empty = "none", iterable)] pub crate::OwnedSlice<T>);
|
||||
|
||||
pub use self::GenericTransform as Transform;
|
||||
|
||||
impl<Angle, Number, Length, Integer, LengthPercentage>
|
||||
TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
|
||||
|
@ -497,7 +518,7 @@ where
|
|||
impl<T> Transform<T> {
|
||||
/// `none`
|
||||
pub fn none() -> Self {
|
||||
Transform(vec![])
|
||||
Transform(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,7 +550,7 @@ impl<T: ToMatrix> Transform<T> {
|
|||
let mut transform = Transform3D::<f64>::identity();
|
||||
let mut contain_3d = false;
|
||||
|
||||
for operation in &self.0 {
|
||||
for operation in &*self.0 {
|
||||
let matrix = operation.to_3d_matrix(reference_box)?;
|
||||
contain_3d |= operation.is_3d();
|
||||
transform = transform.pre_mul(&matrix);
|
||||
|
@ -589,10 +610,11 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
/// A value of the `Rotate` property
|
||||
///
|
||||
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
||||
pub enum Rotate<Number, Angle> {
|
||||
pub enum GenericRotate<Number, Angle> {
|
||||
/// 'none'
|
||||
None,
|
||||
/// '<angle>'
|
||||
|
@ -601,6 +623,8 @@ pub enum Rotate<Number, Angle> {
|
|||
Rotate3D(Number, Number, Number, Angle),
|
||||
}
|
||||
|
||||
pub use self::GenericRotate as Rotate;
|
||||
|
||||
/// A trait to check if the current 3D vector is parallel to the DirectionVector.
|
||||
/// This is especially for serialization on Rotate.
|
||||
pub trait IsParallelTo {
|
||||
|
@ -660,10 +684,11 @@ where
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
/// A value of the `Scale` property
|
||||
///
|
||||
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
||||
pub enum Scale<Number> {
|
||||
pub enum GenericScale<Number> {
|
||||
/// 'none'
|
||||
None,
|
||||
/// '<number>{1,2}'
|
||||
|
@ -672,6 +697,8 @@ pub enum Scale<Number> {
|
|||
Scale3D(Number, Number, Number),
|
||||
}
|
||||
|
||||
pub use self::GenericScale as Scale;
|
||||
|
||||
impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
|
@ -710,6 +737,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
/// A value of the `translate` property
|
||||
///
|
||||
/// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization:
|
||||
|
@ -724,7 +752,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
|||
/// related spec issue is https://github.com/w3c/csswg-drafts/issues/3305
|
||||
///
|
||||
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
||||
pub enum Translate<LengthPercentage, Length>
|
||||
pub enum GenericTranslate<LengthPercentage, Length>
|
||||
where
|
||||
LengthPercentage: Zero,
|
||||
{
|
||||
|
@ -739,6 +767,8 @@ where
|
|||
Translate3D(LengthPercentage, LengthPercentage, Length),
|
||||
}
|
||||
|
||||
pub use self::GenericTranslate as Translate;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[derive(
|
||||
Clone,
|
||||
|
|
|
@ -174,6 +174,7 @@ impl<A: Debug, B: Debug> Debug for Either<A, B> {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct CustomIdent(pub Atom);
|
||||
|
||||
impl CustomIdent {
|
||||
|
|
|
@ -183,7 +183,7 @@ impl Parse for BorderImageSideWidth {
|
|||
}
|
||||
|
||||
if let Ok(len) = input.try(|i| NonNegativeLengthPercentage::parse(context, i)) {
|
||||
return Ok(GenericBorderImageSideWidth::Length(len));
|
||||
return Ok(GenericBorderImageSideWidth::LengthPercentage(len));
|
||||
}
|
||||
|
||||
let num = NonNegativeNumber::parse(context, input)?;
|
||||
|
|
|
@ -642,6 +642,7 @@ pub enum OverflowClipBox {
|
|||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
Default,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
|
@ -650,38 +651,38 @@ pub enum OverflowClipBox {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
/// Provides a rendering hint to the user agent,
|
||||
/// stating what kinds of changes the author expects
|
||||
/// to perform on the element
|
||||
#[css(comma)]
|
||||
#[repr(C)]
|
||||
/// Provides a rendering hint to the user agent, stating what kinds of changes
|
||||
/// the author expects to perform on the element.
|
||||
///
|
||||
/// `auto` is represented by an empty `features` list.
|
||||
///
|
||||
/// <https://drafts.csswg.org/css-will-change/#will-change>
|
||||
pub enum WillChange {
|
||||
/// Expresses no particular intent
|
||||
Auto,
|
||||
/// <custom-ident>
|
||||
#[css(comma)]
|
||||
AnimateableFeatures {
|
||||
/// The features that are supposed to change.
|
||||
#[css(iterable)]
|
||||
features: Box<[CustomIdent]>,
|
||||
/// A bitfield with the kind of change that the value will create, based
|
||||
/// on the above field.
|
||||
#[css(skip)]
|
||||
bits: WillChangeBits,
|
||||
},
|
||||
pub struct WillChange {
|
||||
/// The features that are supposed to change.
|
||||
///
|
||||
/// TODO(emilio): Consider using ArcSlice since we just clone them from the
|
||||
/// specified value? That'd save an allocation, which could be worth it.
|
||||
#[css(iterable, if_empty = "auto")]
|
||||
features: crate::OwnedSlice<CustomIdent>,
|
||||
/// A bitfield with the kind of change that the value will create, based
|
||||
/// on the above field.
|
||||
#[css(skip)]
|
||||
bits: WillChangeBits,
|
||||
}
|
||||
|
||||
impl WillChange {
|
||||
#[inline]
|
||||
/// Get default value of `will-change` as `auto`
|
||||
pub fn auto() -> WillChange {
|
||||
WillChange::Auto
|
||||
pub fn auto() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// The change bits that we care about.
|
||||
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||
#[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||
#[repr(C)]
|
||||
pub struct WillChangeBits: u8 {
|
||||
/// Whether the stacking context will change.
|
||||
|
@ -746,7 +747,7 @@ impl Parse for WillChange {
|
|||
.try(|input| input.expect_ident_matching("auto"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(WillChange::Auto);
|
||||
return Ok(Self::default());
|
||||
}
|
||||
|
||||
let mut bits = WillChangeBits::empty();
|
||||
|
@ -767,8 +768,8 @@ impl Parse for WillChange {
|
|||
Ok(ident)
|
||||
})?;
|
||||
|
||||
Ok(WillChange::AnimateableFeatures {
|
||||
features: custom_idents.into_boxed_slice(),
|
||||
Ok(Self {
|
||||
features: custom_idents.into(),
|
||||
bits,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::values::specified::color::Color;
|
|||
use crate::values::specified::length::{Length, NonNegativeLength};
|
||||
#[cfg(feature = "gecko")]
|
||||
use crate::values::specified::url::SpecifiedUrl;
|
||||
use crate::values::specified::{Angle, NumberOrPercentage};
|
||||
use crate::values::specified::{Angle, Number, NumberOrPercentage};
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
use crate::values::Impossible;
|
||||
use crate::Zero;
|
||||
|
@ -62,6 +62,10 @@ impl Factor {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
Factor(NumberOrPercentage::Number(Number::new(1.0)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Factor {
|
||||
|
@ -209,34 +213,61 @@ impl Parse for Filter {
|
|||
};
|
||||
input.parse_nested_block(|i| {
|
||||
match_ignore_ascii_case! { &*function,
|
||||
"blur" => Ok(GenericFilter::Blur((Length::parse_non_negative(context, i)?).into())),
|
||||
"brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)),
|
||||
"contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)),
|
||||
"blur" => Ok(GenericFilter::Blur(
|
||||
i.try(|i| NonNegativeLength::parse(context, i))
|
||||
.unwrap_or(Zero::zero()),
|
||||
)),
|
||||
"brightness" => Ok(GenericFilter::Brightness(
|
||||
i.try(|i| Factor::parse(context, i))
|
||||
.unwrap_or(Factor::one()),
|
||||
)),
|
||||
"contrast" => Ok(GenericFilter::Contrast(
|
||||
i.try(|i| Factor::parse(context, i))
|
||||
.unwrap_or(Factor::one()),
|
||||
)),
|
||||
"grayscale" => {
|
||||
// Values of amount over 100% are allowed but UAs must clamp the values to 1.
|
||||
// https://drafts.fxtf.org/filter-effects/#funcdef-filter-grayscale
|
||||
Ok(GenericFilter::Grayscale(Factor::parse_with_clamping_to_one(context, i)?))
|
||||
Ok(GenericFilter::Grayscale(
|
||||
i.try(|i| Factor::parse_with_clamping_to_one(context, i))
|
||||
.unwrap_or(Factor::one()),
|
||||
))
|
||||
},
|
||||
"hue-rotate" => {
|
||||
// We allow unitless zero here, see:
|
||||
// https://github.com/w3c/fxtf-drafts/issues/228
|
||||
Ok(GenericFilter::HueRotate(Angle::parse_with_unitless(context, i)?))
|
||||
Ok(GenericFilter::HueRotate(
|
||||
i.try(|i| Angle::parse_with_unitless(context, i))
|
||||
.unwrap_or(Zero::zero()),
|
||||
))
|
||||
},
|
||||
"invert" => {
|
||||
// Values of amount over 100% are allowed but UAs must clamp the values to 1.
|
||||
// https://drafts.fxtf.org/filter-effects/#funcdef-filter-invert
|
||||
Ok(GenericFilter::Invert(Factor::parse_with_clamping_to_one(context, i)?))
|
||||
Ok(GenericFilter::Invert(
|
||||
i.try(|i| Factor::parse_with_clamping_to_one(context, i))
|
||||
.unwrap_or(Factor::one()),
|
||||
))
|
||||
},
|
||||
"opacity" => {
|
||||
// Values of amount over 100% are allowed but UAs must clamp the values to 1.
|
||||
// https://drafts.fxtf.org/filter-effects/#funcdef-filter-opacity
|
||||
Ok(GenericFilter::Opacity(Factor::parse_with_clamping_to_one(context, i)?))
|
||||
Ok(GenericFilter::Opacity(
|
||||
i.try(|i| Factor::parse_with_clamping_to_one(context, i))
|
||||
.unwrap_or(Factor::one()),
|
||||
))
|
||||
},
|
||||
"saturate" => Ok(GenericFilter::Saturate(Factor::parse(context, i)?)),
|
||||
"saturate" => Ok(GenericFilter::Saturate(
|
||||
i.try(|i| Factor::parse(context, i))
|
||||
.unwrap_or(Factor::one()),
|
||||
)),
|
||||
"sepia" => {
|
||||
// Values of amount over 100% are allowed but UAs must clamp the values to 1.
|
||||
// https://drafts.fxtf.org/filter-effects/#funcdef-filter-sepia
|
||||
Ok(GenericFilter::Sepia(Factor::parse_with_clamping_to_one(context, i)?))
|
||||
Ok(GenericFilter::Sepia(
|
||||
i.try(|i| Factor::parse_with_clamping_to_one(context, i))
|
||||
.unwrap_or(Factor::one()),
|
||||
))
|
||||
},
|
||||
"drop-shadow" => Ok(GenericFilter::DropShadow(Parse::parse(context, i)?)),
|
||||
_ => Err(location.new_custom_error(
|
||||
|
|
|
@ -7,33 +7,12 @@
|
|||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::computed::length::CSSPixelLength;
|
||||
use crate::values::computed::{self, LengthPercentage};
|
||||
use crate::values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint;
|
||||
use crate::values::generics::rect::Rect;
|
||||
use crate::values::specified::length::LengthPercentage as SpecifiedLengthPercentage;
|
||||
use cssparser::{Parser, Token};
|
||||
use std::fmt;
|
||||
use style_traits::values::SequenceWriter;
|
||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
||||
|
||||
/// A specified type for scroll snap points.
|
||||
pub type ScrollSnapPoint = GenericScrollSnapPoint<SpecifiedLengthPercentage>;
|
||||
|
||||
impl Parse for ScrollSnapPoint {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(GenericScrollSnapPoint::None);
|
||||
}
|
||||
input.expect_function_matching("repeat")?;
|
||||
// FIXME(emilio): This won't clamp properly when animating.
|
||||
let length = input
|
||||
.parse_nested_block(|i| SpecifiedLengthPercentage::parse_non_negative(context, i))?;
|
||||
Ok(GenericScrollSnapPoint::Repeat(length))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_pixel_or_percent<'i, 't>(
|
||||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
|
|
|
@ -10,7 +10,6 @@ use crate::values::generics::CounterStyleOrNone;
|
|||
#[cfg(feature = "gecko")]
|
||||
use crate::values::CustomIdent;
|
||||
use cssparser::{Parser, Token};
|
||||
use servo_arc::Arc;
|
||||
use style_traits::{ParseError, StyleParseErrorKind};
|
||||
|
||||
/// Specified and computed `list-style-type` property.
|
||||
|
@ -96,18 +95,20 @@ impl Parse for ListStyleType {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct QuotePair {
|
||||
/// The opening quote.
|
||||
pub opening: Box<str>,
|
||||
pub opening: crate::OwnedStr,
|
||||
|
||||
/// The closing quote.
|
||||
pub closing: Box<str>,
|
||||
pub closing: crate::OwnedStr,
|
||||
}
|
||||
|
||||
/// Specified and computed `quotes` property.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
Default,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
|
@ -116,10 +117,11 @@ pub struct QuotePair {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct Quotes(
|
||||
#[css(iterable, if_empty = "none")]
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
pub Arc<Box<[QuotePair]>>,
|
||||
pub crate::ArcSlice<QuotePair>,
|
||||
);
|
||||
|
||||
impl Parse for Quotes {
|
||||
|
@ -131,24 +133,24 @@ impl Parse for Quotes {
|
|||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(Quotes(Arc::new(Box::new([]))));
|
||||
return Ok(Self::default());
|
||||
}
|
||||
|
||||
let mut quotes = Vec::new();
|
||||
loop {
|
||||
let location = input.current_source_location();
|
||||
let opening = match input.next() {
|
||||
Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into_boxed_str(),
|
||||
Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into(),
|
||||
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
let closing = input.expect_string()?.as_ref().to_owned().into_boxed_str();
|
||||
let closing = input.expect_string()?.as_ref().to_owned().into();
|
||||
quotes.push(QuotePair { opening, closing });
|
||||
}
|
||||
|
||||
if !quotes.is_empty() {
|
||||
Ok(Quotes(Arc::new(quotes.into_boxed_slice())))
|
||||
Ok(Quotes(crate::ArcSlice::from_iter(quotes.into_iter())))
|
||||
} else {
|
||||
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
}
|
||||
|
|
|
@ -54,8 +54,6 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis};
|
|||
pub use self::font::{FontVariantAlternates, FontWeight};
|
||||
pub use self::font::{FontVariantEastAsian, FontVariationSettings};
|
||||
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::gecko::ScrollSnapPoint;
|
||||
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
|
||||
pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect};
|
||||
pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth};
|
||||
|
@ -68,7 +66,7 @@ pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageO
|
|||
pub use self::list::ListStyleType;
|
||||
pub use self::list::MozListReversed;
|
||||
pub use self::list::{QuotePair, Quotes};
|
||||
pub use self::motion::OffsetPath;
|
||||
pub use self::motion::{OffsetPath, OffsetRotate};
|
||||
pub use self::outline::OutlineStyle;
|
||||
pub use self::percentage::Percentage;
|
||||
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position};
|
||||
|
@ -81,7 +79,7 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
|||
pub use self::svg_path::SVGPathData;
|
||||
pub use self::table::XSpan;
|
||||
pub use self::text::TextTransform;
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextAlign};
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign};
|
||||
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
|
||||
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
|
||||
pub use self::time::Time;
|
||||
|
|
|
@ -5,13 +5,17 @@
|
|||
//! Specified types for CSS values that are related to motion path.
|
||||
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::specified::SVGPathData;
|
||||
use crate::values::computed::motion::OffsetRotate as ComputedOffsetRotate;
|
||||
use crate::values::computed::{Context, ToComputedValue};
|
||||
use crate::values::specified::{Angle, SVGPathData};
|
||||
use crate::Zero;
|
||||
use cssparser::Parser;
|
||||
use style_traits::{ParseError, StyleParseErrorKind};
|
||||
|
||||
/// The offset-path value.
|
||||
///
|
||||
/// https://drafts.fxtf.org/motion-1/#offset-path-property
|
||||
/// cbindgen:derive-tagged-enum-copy-constructor=true
|
||||
#[derive(
|
||||
Animate,
|
||||
Clone,
|
||||
|
@ -26,6 +30,7 @@ use style_traits::{ParseError, StyleParseErrorKind};
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
pub enum OffsetPath {
|
||||
// We could merge SVGPathData into ShapeSource, so we could reuse them. However,
|
||||
// we don't want to support other value for offset-path, so use SVGPathData only for now.
|
||||
|
@ -73,3 +78,104 @@ impl Parse for OffsetPath {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// The direction of offset-rotate.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||
#[repr(u8)]
|
||||
pub enum OffsetRotateDirection {
|
||||
/// Unspecified direction keyword.
|
||||
#[css(skip)]
|
||||
None,
|
||||
/// 0deg offset (face forward).
|
||||
Auto,
|
||||
/// 180deg offset (face backward).
|
||||
Reverse,
|
||||
}
|
||||
|
||||
impl OffsetRotateDirection {
|
||||
/// Returns true if it is none (i.e. the keyword is not specified).
|
||||
#[inline]
|
||||
fn is_none(&self) -> bool {
|
||||
*self == OffsetRotateDirection::None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn direction_specified_and_angle_is_zero(direction: &OffsetRotateDirection, angle: &Angle) -> bool {
|
||||
!direction.is_none() && angle.is_zero()
|
||||
}
|
||||
|
||||
/// The specified offset-rotate.
|
||||
/// The syntax is: "[ auto | reverse ] || <angle>"
|
||||
///
|
||||
/// https://drafts.fxtf.org/motion-1/#offset-rotate-property
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||
pub struct OffsetRotate {
|
||||
/// [auto | reverse].
|
||||
#[css(skip_if = "OffsetRotateDirection::is_none")]
|
||||
direction: OffsetRotateDirection,
|
||||
/// <angle>.
|
||||
/// If direction is None, this is a fixed angle which indicates a
|
||||
/// constant clockwise rotation transformation applied to it by this
|
||||
/// specified rotation angle. Otherwise, the angle will be added to
|
||||
/// the angle of the direction in layout.
|
||||
#[css(contextual_skip_if = "direction_specified_and_angle_is_zero")]
|
||||
angle: Angle,
|
||||
}
|
||||
|
||||
impl Parse for OffsetRotate {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let location = input.current_source_location();
|
||||
let mut direction = input.try(OffsetRotateDirection::parse);
|
||||
let angle = input.try(|i| Angle::parse(context, i));
|
||||
if direction.is_err() {
|
||||
// The direction and angle could be any order, so give it a change to parse
|
||||
// direction again.
|
||||
direction = input.try(OffsetRotateDirection::parse);
|
||||
}
|
||||
|
||||
if direction.is_err() && angle.is_err() {
|
||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
Ok(OffsetRotate {
|
||||
direction: direction.unwrap_or(OffsetRotateDirection::None),
|
||||
angle: angle.unwrap_or(Zero::zero()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for OffsetRotate {
|
||||
type ComputedValue = ComputedOffsetRotate;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
use crate::values::computed::Angle as ComputedAngle;
|
||||
|
||||
ComputedOffsetRotate {
|
||||
auto: !self.direction.is_none(),
|
||||
angle: if self.direction == OffsetRotateDirection::Reverse {
|
||||
// The computed value should always convert "reverse" into "auto".
|
||||
// e.g. "reverse calc(20deg + 10deg)" => "auto 210deg"
|
||||
self.angle.to_computed_value(context) + ComputedAngle::from_degrees(180.0)
|
||||
} else {
|
||||
self.angle.to_computed_value(context)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
OffsetRotate {
|
||||
direction: if computed.auto {
|
||||
OffsetRotateDirection::Auto
|
||||
} else {
|
||||
OffsetRotateDirection::None
|
||||
},
|
||||
angle: ToComputedValue::from_computed_value(&computed.angle),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::values::specified::AllowQuirks;
|
|||
use crate::values::specified::LengthPercentage;
|
||||
use crate::values::specified::{NonNegativeLengthPercentage, Opacity};
|
||||
use crate::values::CustomIdent;
|
||||
use cssparser::Parser;
|
||||
use cssparser::{Parser, Token};
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CommaWithSpace, CssWriter, ParseError, Separator};
|
||||
use style_traits::{StyleParseErrorKind, ToCss};
|
||||
|
@ -243,11 +243,28 @@ impl ToCss for SVGPaintOrder {
|
|||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// The context properties we understand.
|
||||
#[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||
#[repr(C)]
|
||||
pub struct ContextPropertyBits: u8 {
|
||||
/// `fill`
|
||||
const FILL = 1 << 0;
|
||||
/// `stroke`
|
||||
const STROKE = 1 << 1;
|
||||
/// `fill-opacity`
|
||||
const FILL_OPACITY = 1 << 2;
|
||||
/// `stroke-opacity`
|
||||
const STROKE_OPACITY = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
/// Specified MozContextProperties value.
|
||||
/// Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
Default,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
|
@ -256,19 +273,61 @@ impl ToCss for SVGPaintOrder {
|
|||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
pub struct MozContextProperties(pub CustomIdent);
|
||||
#[repr(C)]
|
||||
pub struct MozContextProperties {
|
||||
#[css(iterable, if_empty = "none")]
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
idents: crate::ArcSlice<CustomIdent>,
|
||||
#[css(skip)]
|
||||
bits: ContextPropertyBits,
|
||||
}
|
||||
|
||||
impl Parse for MozContextProperties {
|
||||
fn parse<'i, 't>(
|
||||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<MozContextProperties, ParseError<'i>> {
|
||||
let location = input.current_source_location();
|
||||
let i = input.expect_ident()?;
|
||||
Ok(MozContextProperties(CustomIdent::from_ident(
|
||||
location,
|
||||
i,
|
||||
&["all", "none", "auto"],
|
||||
)?))
|
||||
let mut values = vec![];
|
||||
let mut bits = ContextPropertyBits::empty();
|
||||
loop {
|
||||
{
|
||||
let location = input.current_source_location();
|
||||
let ident = input.expect_ident()?;
|
||||
|
||||
if ident.eq_ignore_ascii_case("none") && values.is_empty() {
|
||||
return Ok(Self::default());
|
||||
}
|
||||
|
||||
let ident = CustomIdent::from_ident(location, ident, &["all", "none", "auto"])?;
|
||||
|
||||
if ident.0 == atom!("fill") {
|
||||
bits.insert(ContextPropertyBits::FILL);
|
||||
} else if ident.0 == atom!("stroke") {
|
||||
bits.insert(ContextPropertyBits::STROKE);
|
||||
} else if ident.0 == atom!("fill-opacity") {
|
||||
bits.insert(ContextPropertyBits::FILL_OPACITY);
|
||||
} else if ident.0 == atom!("stroke-opacity") {
|
||||
bits.insert(ContextPropertyBits::STROKE_OPACITY);
|
||||
}
|
||||
|
||||
values.push(ident);
|
||||
}
|
||||
|
||||
let location = input.current_source_location();
|
||||
match input.next() {
|
||||
Ok(&Token::Comma) => continue,
|
||||
Err(..) => break,
|
||||
Ok(other) => return Err(location.new_unexpected_token_error(other.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
if values.is_empty() {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
Ok(MozContextProperties {
|
||||
idents: crate::ArcSlice::from_iter(values.into_iter()),
|
||||
bits,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,14 +134,16 @@ impl ToComputedValue for LineHeight {
|
|||
}
|
||||
|
||||
/// A generic value for the `text-overflow` property.
|
||||
/// cbindgen:derive-tagged-enum-copy-constructor=true
|
||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||
#[repr(C, u8)]
|
||||
pub enum TextOverflowSide {
|
||||
/// Clip inline content.
|
||||
Clip,
|
||||
/// Render ellipsis to represent clipped inline content.
|
||||
Ellipsis,
|
||||
/// Render a given string to represent clipped inline content.
|
||||
String(Box<str>),
|
||||
String(crate::OwnedStr),
|
||||
}
|
||||
|
||||
impl Parse for TextOverflowSide {
|
||||
|
@ -160,9 +162,9 @@ impl Parse for TextOverflowSide {
|
|||
))
|
||||
}
|
||||
},
|
||||
Token::QuotedString(ref v) => Ok(TextOverflowSide::String(
|
||||
v.as_ref().to_owned().into_boxed_str(),
|
||||
)),
|
||||
Token::QuotedString(ref v) => {
|
||||
Ok(TextOverflowSide::String(v.as_ref().to_owned().into()))
|
||||
},
|
||||
ref t => Err(location.new_unexpected_token_error(t.clone())),
|
||||
}
|
||||
}
|
||||
|
@ -1005,6 +1007,31 @@ pub enum WordBreak {
|
|||
BreakWord,
|
||||
}
|
||||
|
||||
/// Values for the `line-break` property.
|
||||
#[repr(u8)]
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Eq,
|
||||
MallocSizeOf,
|
||||
Parse,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
ToComputedValue,
|
||||
ToCss,
|
||||
ToResolvedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LineBreak {
|
||||
Auto,
|
||||
Loose,
|
||||
Normal,
|
||||
Strict,
|
||||
Anywhere,
|
||||
}
|
||||
|
||||
/// Values for the `overflow-wrap` property.
|
||||
#[repr(u8)]
|
||||
#[derive(
|
||||
|
|
|
@ -42,183 +42,187 @@ impl Transform {
|
|||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(generic::Transform(Vec::new()));
|
||||
return Ok(generic::Transform::none());
|
||||
}
|
||||
|
||||
Ok(generic::Transform(Space::parse(input, |input| {
|
||||
let function = input.expect_function()?.clone();
|
||||
input.parse_nested_block(|input| {
|
||||
let location = input.current_source_location();
|
||||
let result = match_ignore_ascii_case! { &function,
|
||||
"matrix" => {
|
||||
let a = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let b = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let c = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let d = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
// Standard matrix parsing.
|
||||
let e = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let f = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Matrix(Matrix { a, b, c, d, e, f }))
|
||||
},
|
||||
"matrix3d" => {
|
||||
let m11 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m12 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m13 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m14 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m21 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m22 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m23 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m24 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m31 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m32 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m33 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m34 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
// Standard matrix3d parsing.
|
||||
let m41 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m42 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m43 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m44 = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Matrix3D(Matrix3D {
|
||||
m11, m12, m13, m14,
|
||||
m21, m22, m23, m24,
|
||||
m31, m32, m33, m34,
|
||||
m41, m42, m43, m44,
|
||||
}))
|
||||
},
|
||||
"translate" => {
|
||||
let sx = specified::LengthPercentage::parse(context, input)?;
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
let sy = specified::LengthPercentage::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Translate(sx, sy))
|
||||
} else {
|
||||
Ok(generic::TransformOperation::Translate(sx, Zero::zero()))
|
||||
}
|
||||
},
|
||||
"translatex" => {
|
||||
let tx = specified::LengthPercentage::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::TranslateX(tx))
|
||||
},
|
||||
"translatey" => {
|
||||
let ty = specified::LengthPercentage::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::TranslateY(ty))
|
||||
},
|
||||
"translatez" => {
|
||||
let tz = specified::Length::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::TranslateZ(tz))
|
||||
},
|
||||
"translate3d" => {
|
||||
let tx = specified::LengthPercentage::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let ty = specified::LengthPercentage::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let tz = specified::Length::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Translate3D(tx, ty, tz))
|
||||
},
|
||||
"scale" => {
|
||||
let sx = Number::parse(context, input)?;
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
Ok(generic::Transform(
|
||||
Space::parse(input, |input| {
|
||||
let function = input.expect_function()?.clone();
|
||||
input.parse_nested_block(|input| {
|
||||
let location = input.current_source_location();
|
||||
let result = match_ignore_ascii_case! { &function,
|
||||
"matrix" => {
|
||||
let a = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let b = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let c = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let d = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
// Standard matrix parsing.
|
||||
let e = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let f = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Matrix(Matrix { a, b, c, d, e, f }))
|
||||
},
|
||||
"matrix3d" => {
|
||||
let m11 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m12 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m13 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m14 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m21 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m22 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m23 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m24 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m31 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m32 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m33 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m34 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
// Standard matrix3d parsing.
|
||||
let m41 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m42 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m43 = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let m44 = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Matrix3D(Matrix3D {
|
||||
m11, m12, m13, m14,
|
||||
m21, m22, m23, m24,
|
||||
m31, m32, m33, m34,
|
||||
m41, m42, m43, m44,
|
||||
}))
|
||||
},
|
||||
"translate" => {
|
||||
let sx = specified::LengthPercentage::parse(context, input)?;
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
let sy = specified::LengthPercentage::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Translate(sx, sy))
|
||||
} else {
|
||||
Ok(generic::TransformOperation::Translate(sx, Zero::zero()))
|
||||
}
|
||||
},
|
||||
"translatex" => {
|
||||
let tx = specified::LengthPercentage::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::TranslateX(tx))
|
||||
},
|
||||
"translatey" => {
|
||||
let ty = specified::LengthPercentage::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::TranslateY(ty))
|
||||
},
|
||||
"translatez" => {
|
||||
let tz = specified::Length::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::TranslateZ(tz))
|
||||
},
|
||||
"translate3d" => {
|
||||
let tx = specified::LengthPercentage::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let ty = specified::LengthPercentage::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let tz = specified::Length::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Translate3D(tx, ty, tz))
|
||||
},
|
||||
"scale" => {
|
||||
let sx = Number::parse(context, input)?;
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
let sy = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Scale(sx, sy))
|
||||
} else {
|
||||
Ok(generic::TransformOperation::Scale(sx, sx))
|
||||
}
|
||||
},
|
||||
"scalex" => {
|
||||
let sx = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::ScaleX(sx))
|
||||
},
|
||||
"scaley" => {
|
||||
let sy = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Scale(sx, sy))
|
||||
} else {
|
||||
Ok(generic::TransformOperation::Scale(sx, sx))
|
||||
}
|
||||
},
|
||||
"scalex" => {
|
||||
let sx = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::ScaleX(sx))
|
||||
},
|
||||
"scaley" => {
|
||||
let sy = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::ScaleY(sy))
|
||||
},
|
||||
"scalez" => {
|
||||
let sz = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::ScaleZ(sz))
|
||||
},
|
||||
"scale3d" => {
|
||||
let sx = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let sy = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let sz = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Scale3D(sx, sy, sz))
|
||||
},
|
||||
"rotate" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::Rotate(theta))
|
||||
},
|
||||
"rotatex" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::RotateX(theta))
|
||||
},
|
||||
"rotatey" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::RotateY(theta))
|
||||
},
|
||||
"rotatez" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::RotateZ(theta))
|
||||
},
|
||||
"rotate3d" => {
|
||||
let ax = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let ay = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let az = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
// TODO(gw): Check that the axis can be normalized.
|
||||
Ok(generic::TransformOperation::Rotate3D(ax, ay, az, theta))
|
||||
},
|
||||
"skew" => {
|
||||
let ax = specified::Angle::parse_with_unitless(context, input)?;
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
let ay = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::Skew(ax, ay))
|
||||
} else {
|
||||
Ok(generic::TransformOperation::Skew(ax, Zero::zero()))
|
||||
}
|
||||
},
|
||||
"skewx" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::SkewX(theta))
|
||||
},
|
||||
"skewy" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::SkewY(theta))
|
||||
},
|
||||
"perspective" => {
|
||||
let d = specified::Length::parse_non_negative(context, input)?;
|
||||
Ok(generic::TransformOperation::Perspective(d))
|
||||
},
|
||||
_ => Err(()),
|
||||
};
|
||||
result.map_err(|()| {
|
||||
location
|
||||
.new_custom_error(StyleParseErrorKind::UnexpectedFunction(function.clone()))
|
||||
Ok(generic::TransformOperation::ScaleY(sy))
|
||||
},
|
||||
"scalez" => {
|
||||
let sz = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::ScaleZ(sz))
|
||||
},
|
||||
"scale3d" => {
|
||||
let sx = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let sy = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let sz = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Scale3D(sx, sy, sz))
|
||||
},
|
||||
"rotate" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::Rotate(theta))
|
||||
},
|
||||
"rotatex" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::RotateX(theta))
|
||||
},
|
||||
"rotatey" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::RotateY(theta))
|
||||
},
|
||||
"rotatez" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::RotateZ(theta))
|
||||
},
|
||||
"rotate3d" => {
|
||||
let ax = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let ay = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let az = Number::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
// TODO(gw): Check that the axis can be normalized.
|
||||
Ok(generic::TransformOperation::Rotate3D(ax, ay, az, theta))
|
||||
},
|
||||
"skew" => {
|
||||
let ax = specified::Angle::parse_with_unitless(context, input)?;
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
let ay = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::Skew(ax, ay))
|
||||
} else {
|
||||
Ok(generic::TransformOperation::Skew(ax, Zero::zero()))
|
||||
}
|
||||
},
|
||||
"skewx" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::SkewX(theta))
|
||||
},
|
||||
"skewy" => {
|
||||
let theta = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::SkewY(theta))
|
||||
},
|
||||
"perspective" => {
|
||||
let d = specified::Length::parse_non_negative(context, input)?;
|
||||
Ok(generic::TransformOperation::Perspective(d))
|
||||
},
|
||||
_ => Err(()),
|
||||
};
|
||||
result.map_err(|()| {
|
||||
location.new_custom_error(StyleParseErrorKind::UnexpectedFunction(
|
||||
function.clone(),
|
||||
))
|
||||
})
|
||||
})
|
||||
})
|
||||
})?))
|
||||
})?
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ app_units = "0.7"
|
|||
cssparser = "0.25"
|
||||
bitflags = "1.0"
|
||||
euclid = "0.19"
|
||||
lazy_static = "1"
|
||||
malloc_size_of = { path = "../malloc_size_of" }
|
||||
malloc_size_of_derive = "0.1"
|
||||
selectors = { path = "../selectors" }
|
||||
|
|
|
@ -5,16 +5,19 @@
|
|||
//! A thin atomically-reference-counted slice.
|
||||
|
||||
use servo_arc::ThinArc;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::ptr::NonNull;
|
||||
use std::{iter, mem};
|
||||
|
||||
/// A canary that we stash in ArcSlices.
|
||||
///
|
||||
/// Given we cannot use a zero-sized-type for the header, since well, C++
|
||||
/// doesn't have zsts, and we want to use cbindgen for this type, we may as well
|
||||
/// assert some sanity at runtime.
|
||||
const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3;
|
||||
///
|
||||
/// We use an u64, to guarantee that we can use a single singleton for every
|
||||
/// empty slice, even if the types they hold are aligned differently.
|
||||
const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3;
|
||||
|
||||
/// A wrapper type for a refcounted slice using ThinArc.
|
||||
///
|
||||
|
@ -22,7 +25,7 @@ const ARC_SLICE_CANARY: u32 = 0xf3f3f3f3;
|
|||
/// cbindgen:derive-neq=false
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, ToShmem)]
|
||||
pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u32, T>);
|
||||
pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>);
|
||||
|
||||
impl<T> Deref for ArcSlice<T> {
|
||||
type Target = [T];
|
||||
|
@ -34,12 +37,28 @@ impl<T> Deref for ArcSlice<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The inner pointer of an ArcSlice<T>, to be sent via FFI.
|
||||
/// The type of the pointer is a bit of a lie, we just want to preserve the type
|
||||
/// but these pointers cannot be constructed outside of this crate, so we're
|
||||
/// good.
|
||||
#[repr(C)]
|
||||
pub struct ForgottenArcSlicePtr<T>(NonNull<T>);
|
||||
lazy_static! {
|
||||
// ThinArc doesn't support alignments greater than align_of::<u64>.
|
||||
static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
|
||||
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty()))
|
||||
};
|
||||
}
|
||||
|
||||
impl<T> Default for ArcSlice<T> {
|
||||
#[allow(unsafe_code)]
|
||||
fn default() -> Self {
|
||||
debug_assert!(
|
||||
mem::align_of::<T>() <= mem::align_of::<u64>(),
|
||||
"Need to increase the alignment of EMPTY_ARC_SLICE"
|
||||
);
|
||||
unsafe {
|
||||
let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
|
||||
let empty: Self = mem::transmute(empty);
|
||||
debug_assert_eq!(empty.len(), 0);
|
||||
empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ArcSlice<T> {
|
||||
/// Creates an Arc for a slice using the given iterator to generate the
|
||||
|
@ -49,6 +68,9 @@ impl<T> ArcSlice<T> {
|
|||
where
|
||||
I: Iterator<Item = T> + ExactSizeIterator,
|
||||
{
|
||||
if items.len() == 0 {
|
||||
return Self::default();
|
||||
}
|
||||
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
|
||||
}
|
||||
|
||||
|
@ -63,4 +85,21 @@ impl<T> ArcSlice<T> {
|
|||
mem::forget(self);
|
||||
ret
|
||||
}
|
||||
|
||||
/// Leaks an empty arc slice pointer, and returns it. Only to be used to
|
||||
/// construct ArcSlices from FFI.
|
||||
#[inline]
|
||||
pub fn leaked_empty_ptr() -> *mut std::os::raw::c_void {
|
||||
let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
|
||||
let ptr = empty.0.ptr();
|
||||
std::mem::forget(empty);
|
||||
ptr as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
/// The inner pointer of an ArcSlice<T>, to be sent via FFI.
|
||||
/// The type of the pointer is a bit of a lie, we just want to preserve the type
|
||||
/// but these pointers cannot be constructed outside of this crate, so we're
|
||||
/// good.
|
||||
#[repr(C)]
|
||||
pub struct ForgottenArcSlicePtr<T>(NonNull<T>);
|
||||
|
|
|
@ -16,6 +16,8 @@ extern crate bitflags;
|
|||
#[macro_use]
|
||||
extern crate cssparser;
|
||||
extern crate euclid;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate malloc_size_of;
|
||||
#[macro_use]
|
||||
extern crate malloc_size_of_derive;
|
||||
|
@ -91,6 +93,7 @@ pub mod values;
|
|||
#[macro_use]
|
||||
pub mod viewport;
|
||||
pub mod owned_slice;
|
||||
pub mod owned_str;
|
||||
|
||||
pub use crate::specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo};
|
||||
pub use crate::values::{
|
||||
|
@ -149,8 +152,6 @@ pub enum StyleParseErrorKind<'i> {
|
|||
|
||||
/// The property declaration was for an unknown property.
|
||||
UnknownProperty(CowRcStr<'i>),
|
||||
/// An unknown vendor-specific identifier was encountered.
|
||||
UnknownVendorProperty,
|
||||
/// The property declaration was for a disabled experimental property.
|
||||
ExperimentalProperty,
|
||||
/// The property declaration contained an invalid color value.
|
||||
|
|
|
@ -10,7 +10,7 @@ use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
|
|||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr::NonNull;
|
||||
use std::{fmt, mem, slice};
|
||||
use std::{fmt, iter, mem, slice};
|
||||
use to_shmem::{SharedMemoryBuilder, ToShmem};
|
||||
|
||||
/// A struct that basically replaces a `Box<[T]>`, but which cbindgen can
|
||||
|
@ -93,7 +93,7 @@ impl<T: Sized> OwnedSlice<T> {
|
|||
|
||||
/// Iterate over all the elements in the slice taking ownership of them.
|
||||
#[inline]
|
||||
pub fn into_iter(self) -> impl Iterator<Item = T> {
|
||||
pub fn into_iter(self) -> impl Iterator<Item = T> + ExactSizeIterator {
|
||||
self.into_vec().into_iter()
|
||||
}
|
||||
|
||||
|
@ -164,3 +164,10 @@ impl<T: ToShmem + Sized> ToShmem for OwnedSlice<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> iter::FromIterator<T> for OwnedSlice<T> {
|
||||
#[inline]
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
Vec::from_iter(iter).into()
|
||||
}
|
||||
}
|
||||
|
|
53
components/style_traits/owned_str.rs
Normal file
53
components/style_traits/owned_str.rs
Normal 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())
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
//! Value information for devtools.
|
||||
|
||||
use crate::arc_slice::ArcSlice;
|
||||
use crate::owned_slice::OwnedSlice;
|
||||
use servo_arc::Arc;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc as StdArc;
|
||||
|
@ -83,6 +84,7 @@ impl SpecifiedValueInfo for u16 {}
|
|||
impl SpecifiedValueInfo for u32 {}
|
||||
impl SpecifiedValueInfo for str {}
|
||||
impl SpecifiedValueInfo for String {}
|
||||
impl SpecifiedValueInfo for crate::owned_str::OwnedStr {}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
impl SpecifiedValueInfo for ::servo_atoms::Atom {}
|
||||
|
@ -114,6 +116,7 @@ macro_rules! impl_generic_specified_value_info {
|
|||
};
|
||||
}
|
||||
impl_generic_specified_value_info!(Option<T>);
|
||||
impl_generic_specified_value_info!(OwnedSlice<T>);
|
||||
impl_generic_specified_value_info!(Vec<T>);
|
||||
impl_generic_specified_value_info!(Arc<T>);
|
||||
impl_generic_specified_value_info!(StdArc<T>);
|
||||
|
|
|
@ -75,6 +75,16 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl ToCss for crate::owned_str::OwnedStr {
|
||||
#[inline]
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
serialize_string(self, dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for str {
|
||||
#[inline]
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
use cssparser::RGBA;
|
||||
use style::values::animated::{Animate, Procedure, ToAnimatedValue};
|
||||
use style::values::generics::transform::{Transform, TransformOperation};
|
||||
|
||||
fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
|
||||
let from = from.to_animated_value();
|
||||
|
@ -81,14 +80,3 @@ fn test_rgba_color_interepolation_out_of_range_clamped_2() {
|
|||
RGBA::from_floats(0.0, 0.0, 0.0, 0.0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_interpolation_on_scale() {
|
||||
let from = Transform(vec![TransformOperation::Scale3D(1.0, 2.0, 1.0)]);
|
||||
let to = Transform(vec![TransformOperation::Scale3D(2.0, 4.0, 2.0)]);
|
||||
assert_eq!(
|
||||
from.animate(&to, Procedure::Interpolate { progress: 0.5 })
|
||||
.unwrap(),
|
||||
Transform(vec![TransformOperation::Scale3D(1.5, 3.0, 1.5)])
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue