Auto merge of #23456 - emilio:gecko-sync, r=emilio

style: Sync changes from mozilla-central.

See each individual commit for details.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23456)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-05-29 16:49:16 -04:00 committed by GitHub
commit b4fb2cda08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
105 changed files with 1455 additions and 2515 deletions

1
Cargo.lock generated
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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!(

View file

@ -22,6 +22,7 @@ servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5eve
"cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union",
"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}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,75 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Gecko profiler support.
//!
//! Use the `profiler_label!` macro from macros.rs.
use crate::gecko_bindings::structs;
/// A label describing a category of work that style threads can perform.
pub enum ProfilerLabel {
/// Style computation.
Style,
/// Style sheet parsing.
Parse,
}
/// RAII object that constructs and destroys a C++ AutoProfilerLabel object
/// pointed to be the specified reference.
#[cfg(feature = "gecko_profiler")]
pub struct AutoProfilerLabel<'a>(&'a mut structs::AutoProfilerLabel);
#[cfg(feature = "gecko_profiler")]
impl<'a> AutoProfilerLabel<'a> {
/// Creates a new AutoProfilerLabel with the specified label type.
///
/// unsafe since the caller must ensure that `label` is allocated on the
/// stack.
#[inline]
pub unsafe fn new(
label: &mut structs::AutoProfilerLabel,
label_type: ProfilerLabel,
) -> AutoProfilerLabel {
let category_pair = match label_type {
ProfilerLabel::Style => structs::JS::ProfilingCategoryPair_LAYOUT_StyleComputation,
ProfilerLabel::Parse => structs::JS::ProfilingCategoryPair_LAYOUT_CSSParsing,
};
structs::Gecko_Construct_AutoProfilerLabel(label, category_pair);
AutoProfilerLabel(label)
}
}
#[cfg(feature = "gecko_profiler")]
impl<'a> Drop for AutoProfilerLabel<'a> {
#[inline]
fn drop(&mut self) {
unsafe {
structs::Gecko_Destroy_AutoProfilerLabel(self.0);
}
}
}
/// Whether the Gecko profiler is currently active.
///
/// This implementation must be kept in sync with
/// `mozilla::profiler::detail::RacyFeatures::IsActive`.
#[cfg(feature = "gecko_profiler")]
#[inline]
pub fn profiler_is_active() -> bool {
use self::structs::profiler::detail;
use std::mem;
use std::sync::atomic::{AtomicU32, Ordering};
let active_and_features: &AtomicU32 =
unsafe { mem::transmute(&detail::RacyFeatures_sActiveAndFeatures) };
(active_and_features.load(Ordering::Relaxed) & detail::RacyFeatures_Active) != 0
}
/// Always false when the Gecko profiler is disabled.
#[cfg(not(feature = "gecko_profiler"))]
#[inline]
pub fn profiler_is_active() -> bool {
false
}

View file

@ -1,135 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Bindings for CSS Rule objects
use crate::counter_style::{self, CounterBound};
use crate::gecko_bindings::structs::{self, nsCSSValue};
use crate::gecko_bindings::sugar::ns_css_value::ToNsCssValue;
impl<'a> ToNsCssValue for &'a counter_style::System {
fn convert(self, nscssvalue: &mut nsCSSValue) {
use crate::counter_style::System::*;
match *self {
Cyclic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as i32),
Numeric => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as i32),
Alphabetic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as i32),
Symbolic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32),
Additive => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ADDITIVE as i32),
Fixed {
ref first_symbol_value,
} => {
let mut a = nsCSSValue::null();
let mut b = nsCSSValue::null();
a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_FIXED as i32);
b.set_integer(first_symbol_value.map_or(1, |v| v.value()));
nscssvalue.set_pair(&a, &b);
},
Extends(ref other) => {
let mut a = nsCSSValue::null();
let mut b = nsCSSValue::null();
a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS as i32);
b.set_atom_ident(other.0.clone());
nscssvalue.set_pair(&a, &b);
},
}
}
}
impl<'a> ToNsCssValue for &'a counter_style::Negative {
fn convert(self, nscssvalue: &mut nsCSSValue) {
if let Some(ref second) = self.1 {
let mut a = nsCSSValue::null();
let mut b = nsCSSValue::null();
a.set_from(&self.0);
b.set_from(second);
nscssvalue.set_pair(&a, &b);
} else {
nscssvalue.set_from(&self.0)
}
}
}
impl<'a> ToNsCssValue for &'a counter_style::Symbol {
fn convert(self, nscssvalue: &mut nsCSSValue) {
match *self {
counter_style::Symbol::String(ref s) => nscssvalue.set_string(s),
counter_style::Symbol::Ident(ref s) => nscssvalue.set_ident_from_atom(&s.0),
}
}
}
impl<'a> ToNsCssValue for &'a counter_style::Ranges {
fn convert(self, nscssvalue: &mut nsCSSValue) {
if self.0.is_empty() {
nscssvalue.set_auto();
} else {
nscssvalue.set_pair_list(self.0.iter().map(|range| {
fn set_bound(bound: CounterBound, nscssvalue: &mut nsCSSValue) {
if let CounterBound::Integer(finite) = bound {
nscssvalue.set_integer(finite.value())
} else {
nscssvalue.set_enum(structs::NS_STYLE_COUNTER_RANGE_INFINITE as i32)
}
}
let mut start = nsCSSValue::null();
let mut end = nsCSSValue::null();
set_bound(range.start, &mut start);
set_bound(range.end, &mut end);
(start, end)
}));
}
}
}
impl<'a> ToNsCssValue for &'a counter_style::Pad {
fn convert(self, nscssvalue: &mut nsCSSValue) {
let mut min_length = nsCSSValue::null();
let mut pad_with = nsCSSValue::null();
min_length.set_integer(self.0.value());
pad_with.set_from(&self.1);
nscssvalue.set_pair(&min_length, &pad_with);
}
}
impl<'a> ToNsCssValue for &'a counter_style::Fallback {
fn convert(self, nscssvalue: &mut nsCSSValue) {
nscssvalue.set_atom_ident(self.0 .0.clone())
}
}
impl<'a> ToNsCssValue for &'a counter_style::Symbols {
fn convert(self, nscssvalue: &mut nsCSSValue) {
nscssvalue.set_list(self.0.iter().map(|item| {
let mut value = nsCSSValue::null();
value.set_from(item);
value
}));
}
}
impl<'a> ToNsCssValue for &'a counter_style::AdditiveSymbols {
fn convert(self, nscssvalue: &mut nsCSSValue) {
nscssvalue.set_pair_list(self.0.iter().map(|tuple| {
let mut weight = nsCSSValue::null();
let mut symbol = nsCSSValue::null();
weight.set_integer(tuple.weight.value());
symbol.set_from(&tuple.symbol);
(weight, symbol)
}));
}
}
impl<'a> ToNsCssValue for &'a counter_style::SpeakAs {
fn convert(self, nscssvalue: &mut nsCSSValue) {
use crate::counter_style::SpeakAs::*;
match *self {
Auto => nscssvalue.set_auto(),
Bullets => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_BULLETS as i32),
Numbers => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_NUMBERS as i32),
Words => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_WORDS as i32),
Other(ref other) => nscssvalue.set_atom_ident(other.0.clone()),
}
}
}

View file

@ -310,13 +310,13 @@ impl ToComputedValue for SpecifiedImageUrl {
type ComputedValue = ComputedImageUrl;
#[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()
}
}

View file

@ -12,7 +12,6 @@ use crate::gecko_bindings::structs::{nsStyleCoord, CounterStylePtr};
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
use crate::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)))
}

View file

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

View file

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

View file

@ -1,78 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Rust helpers for Gecko's `nsCSSShadowArray`.
use crate::gecko_bindings::bindings::Gecko_AddRefCSSShadowArrayArbitraryThread;
use crate::gecko_bindings::bindings::Gecko_NewCSSShadowArray;
use crate::gecko_bindings::bindings::Gecko_ReleaseCSSShadowArrayArbitraryThread;
use crate::gecko_bindings::structs::{nsCSSShadowArray, nsCSSShadowItem, RefPtr};
use std::ops::{Deref, DerefMut};
use std::{ptr, slice};
impl RefPtr<nsCSSShadowArray> {
/// Replaces the current `nsCSSShadowArray` with a new one of len `len`.
pub fn replace_with_new(&mut self, len: u32) {
unsafe {
if !self.mRawPtr.is_null() {
Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr);
}
self.mRawPtr = if len == 0 {
ptr::null_mut()
} else {
Gecko_NewCSSShadowArray(len)
}
}
}
/// Sets the value to other `nsCSSShadowArray`, bumping and decreasing
/// refcounts as needed.
///
/// TODO(emilio): Seems like this could move to `refptr.rs`, and be more
/// generic.
pub fn copy_from(&mut self, other: &Self) {
unsafe {
if !self.mRawPtr.is_null() {
Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr);
}
if !other.mRawPtr.is_null() {
Gecko_AddRefCSSShadowArrayArbitraryThread(other.mRawPtr);
}
self.mRawPtr = other.mRawPtr;
}
}
}
impl Deref for RefPtr<nsCSSShadowArray> {
type Target = [nsCSSShadowItem];
fn deref(&self) -> &[nsCSSShadowItem] {
if self.mRawPtr.is_null() {
&[]
} else {
unsafe {
slice::from_raw_parts(
(*self.mRawPtr).mArray.as_ptr(),
(*self.mRawPtr).mLength as usize,
)
}
}
}
}
impl DerefMut for RefPtr<nsCSSShadowArray> {
fn deref_mut(&mut self) -> &mut [nsCSSShadowItem] {
if self.mRawPtr.is_null() {
&mut []
} else {
unsafe {
slice::from_raw_parts_mut(
(*self.mRawPtr).mArray.as_mut_ptr(),
(*self.mRawPtr).mLength as usize,
)
}
}
}
}

View file

@ -1,59 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Rust helpers for Gecko's `nsCSSShadowItem`.
use crate::gecko_bindings::structs::nsCSSShadowItem;
use crate::values::computed::effects::{BoxShadow, SimpleShadow};
use app_units::Au;
impl nsCSSShadowItem {
/// Sets this item from the given box shadow.
#[inline]
pub fn set_from_box_shadow(&mut self, shadow: BoxShadow) {
self.set_from_simple_shadow(shadow.base);
self.mSpread = shadow.spread.to_i32_au();
self.mInset = shadow.inset;
}
/// Returns this item as a box shadow.
#[inline]
pub fn to_box_shadow(&self) -> BoxShadow {
BoxShadow {
base: self.extract_simple_shadow(),
spread: Au(self.mSpread).into(),
inset: self.mInset,
}
}
/// Sets this item from the given simple shadow.
#[inline]
pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) {
self.mXOffset = shadow.horizontal.to_i32_au();
self.mYOffset = shadow.vertical.to_i32_au();
self.mRadius = shadow.blur.0.to_i32_au();
self.mSpread = 0;
self.mInset = false;
self.mColor = shadow.color.into();
}
/// Gets a simple shadow from this item.
#[inline]
fn extract_simple_shadow(&self) -> SimpleShadow {
SimpleShadow {
color: self.mColor.into(),
horizontal: Au(self.mXOffset).into(),
vertical: Au(self.mYOffset).into(),
blur: Au(self.mRadius).into(),
}
}
/// Returns this item as a simple shadow.
#[inline]
pub fn to_simple_shadow(&self) -> SimpleShadow {
debug_assert_eq!(self.mSpread, 0);
debug_assert_eq!(self.mInset, false);
self.extract_simple_shadow()
}
}

View file

@ -1,424 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Little helpers for `nsCSSValue`.
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::{nsCSSUnit, nsCSSValue};
use crate::gecko_bindings::structs::{nsCSSValueList, nsCSSValue_Array};
use crate::gecko_string_cache::Atom;
use crate::values::computed::{Angle, Length, LengthPercentage, Percentage};
use crate::Zero;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Index, IndexMut};
use std::slice;
impl nsCSSValue {
/// Create a CSSValue with null unit, useful to be used as a return value.
#[inline]
pub fn null() -> Self {
unsafe { mem::zeroed() }
}
/// Returns true if this nsCSSValue is none.
#[inline]
pub fn is_none(&self) -> bool {
self.mUnit == nsCSSUnit::eCSSUnit_None
}
/// Returns this nsCSSValue value as an integer, unchecked in release
/// builds.
pub fn integer_unchecked(&self) -> i32 {
debug_assert!(
self.mUnit == nsCSSUnit::eCSSUnit_Integer ||
self.mUnit == nsCSSUnit::eCSSUnit_Enumerated
);
unsafe { *self.mValue.mInt.as_ref() }
}
/// Checks if it is an integer and returns it if so
pub fn integer(&self) -> Option<i32> {
if self.mUnit == nsCSSUnit::eCSSUnit_Integer || self.mUnit == nsCSSUnit::eCSSUnit_Enumerated
{
Some(unsafe { *self.mValue.mInt.as_ref() })
} else {
None
}
}
/// Returns this nsCSSValue value as a floating point value, unchecked in
/// release builds.
pub fn float_unchecked(&self) -> f32 {
debug_assert!(nsCSSUnit::eCSSUnit_Number as u32 <= self.mUnit as u32);
unsafe { *self.mValue.mFloat.as_ref() }
}
/// Returns this nsCSSValue as a nsCSSValue::Array, unchecked in release
/// builds.
pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array {
debug_assert!(
nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 &&
self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Plus as u32
);
let array = *self.mValue.mArray.as_ref();
debug_assert!(!array.is_null());
&*array
}
/// Sets LengthPercentage value to this nsCSSValue.
pub unsafe fn set_length_percentage(&mut self, lp: LengthPercentage) {
if lp.was_calc {
return bindings::Gecko_CSSValue_SetCalc(self, lp.into());
}
debug_assert!(!lp.has_percentage || lp.unclamped_length() == Length::zero());
if lp.has_percentage {
return self.set_percentage(lp.percentage());
}
self.set_px(lp.unclamped_length().px());
}
/// Sets a px value to this nsCSSValue.
pub unsafe fn set_px(&mut self, px: f32) {
bindings::Gecko_CSSValue_SetPixelLength(self, px)
}
/// Sets a percentage value to this nsCSSValue.
pub unsafe fn set_percentage(&mut self, unit_value: f32) {
bindings::Gecko_CSSValue_SetPercentage(self, unit_value)
}
/// Returns LengthPercentage value.
pub unsafe fn get_length_percentage(&self) -> LengthPercentage {
match self.mUnit {
nsCSSUnit::eCSSUnit_Pixel => {
LengthPercentage::new(Length::new(bindings::Gecko_CSSValue_GetNumber(self)), None)
},
nsCSSUnit::eCSSUnit_Percent => LengthPercentage::new_percent(Percentage(
bindings::Gecko_CSSValue_GetPercentage(self),
)),
nsCSSUnit::eCSSUnit_Calc => bindings::Gecko_CSSValue_GetCalc(self).into(),
_ => panic!("Unexpected unit"),
}
}
/// Returns Length value.
pub unsafe fn get_length(&self) -> Length {
match self.mUnit {
nsCSSUnit::eCSSUnit_Pixel => Length::new(bindings::Gecko_CSSValue_GetNumber(self)),
_ => panic!("Unexpected unit"),
}
}
fn set_valueless_unit(&mut self, unit: nsCSSUnit) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
debug_assert!(
unit as u32 <= nsCSSUnit::eCSSUnit_DummyInherit as u32,
"Not a valueless unit"
);
self.mUnit = unit;
}
/// Set to an auto value
///
/// This method requires the current value to be null.
pub fn set_auto(&mut self) {
self.set_valueless_unit(nsCSSUnit::eCSSUnit_Auto);
}
/// Set to a normal value
///
/// This method requires the current value to be null.
pub fn set_normal(&mut self) {
self.set_valueless_unit(nsCSSUnit::eCSSUnit_Normal);
}
fn set_string_internal(&mut self, s: &str, unit: nsCSSUnit) {
unsafe { bindings::Gecko_CSSValue_SetString(self, s.as_ptr(), s.len() as u32, unit) }
}
fn set_string_from_atom_internal(&mut self, s: &Atom, unit: nsCSSUnit) {
unsafe { bindings::Gecko_CSSValue_SetStringFromAtom(self, s.as_ptr(), unit) }
}
/// Set to a string value
pub fn set_string(&mut self, s: &str) {
self.set_string_internal(s, nsCSSUnit::eCSSUnit_String)
}
/// Set to a string value from the given atom
pub fn set_string_from_atom(&mut self, s: &Atom) {
self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_String)
}
/// Set to a ident value from the given atom
pub fn set_ident_from_atom(&mut self, s: &Atom) {
self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_Ident)
}
/// Set to an identifier value
pub fn set_ident(&mut self, s: &str) {
self.set_string_internal(s, nsCSSUnit::eCSSUnit_Ident)
}
/// Set to an atom identifier value
pub fn set_atom_ident(&mut self, s: Atom) {
unsafe { bindings::Gecko_CSSValue_SetAtomIdent(self, s.into_addrefed()) }
}
fn set_int_internal(&mut self, value: i32, unit: nsCSSUnit) {
unsafe { bindings::Gecko_CSSValue_SetInt(self, value, unit) }
}
/// Set to an integer value
pub fn set_integer(&mut self, value: i32) {
self.set_int_internal(value, nsCSSUnit::eCSSUnit_Integer)
}
/// Set to an enumerated value
pub fn set_enum<T: Into<i32>>(&mut self, value: T) {
self.set_int_internal(value.into(), nsCSSUnit::eCSSUnit_Enumerated);
}
/// Set to a number value
pub fn set_number(&mut self, number: f32) {
unsafe { bindings::Gecko_CSSValue_SetFloat(self, number, nsCSSUnit::eCSSUnit_Number) }
}
/// Set to an array of given length
pub fn set_array(&mut self, len: i32) -> &mut nsCSSValue_Array {
unsafe { bindings::Gecko_CSSValue_SetArray(self, len) }
unsafe { self.mValue.mArray.as_mut().as_mut() }.unwrap()
}
/// Generic set from any value that implements the ToNsCssValue trait.
pub fn set_from<T: ToNsCssValue>(&mut self, value: T) {
value.convert(self)
}
/// Returns an `Angle` value from this `nsCSSValue`.
///
/// Panics if the unit is not `eCSSUnit_Degree`.
#[inline]
pub fn get_angle(&self) -> Angle {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Degree);
Angle::from_degrees(self.float_unchecked())
}
/// Sets Angle value to this nsCSSValue.
pub fn set_angle(&mut self, angle: Angle) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
self.mUnit = nsCSSUnit::eCSSUnit_Degree;
unsafe {
*self.mValue.mFloat.as_mut() = angle.degrees();
}
}
/// Set to a pair value
///
/// This is only supported on the main thread.
pub fn set_pair(&mut self, x: &nsCSSValue, y: &nsCSSValue) {
unsafe { bindings::Gecko_CSSValue_SetPair(self, x, y) }
}
/// Set to a list value
///
/// This is only supported on the main thread.
pub fn set_list<I>(&mut self, values: I)
where
I: ExactSizeIterator<Item = nsCSSValue>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe {
bindings::Gecko_CSSValue_SetList(self, values.len() as u32);
}
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_List);
let list: &mut structs::nsCSSValueList = &mut unsafe {
self.mValue
.mList
.as_ref() // &*nsCSSValueList_heap
.as_mut()
.expect("List pointer should be non-null")
}
._base;
for (item, new_value) in list.into_iter().zip(values) {
*item = new_value;
}
}
/// Set to a pair list value
///
/// This is only supported on the main thread.
pub fn set_pair_list<I>(&mut self, mut values: I)
where
I: ExactSizeIterator<Item = (nsCSSValue, nsCSSValue)>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe {
bindings::Gecko_CSSValue_SetPairList(self, values.len() as u32);
}
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_PairList);
let mut item_ptr = &mut unsafe {
self.mValue
.mPairList
.as_ref() // &*nsCSSValuePairList_heap
.as_mut()
.expect("List pointer should be non-null")
}
._base as *mut structs::nsCSSValuePairList;
while let Some(item) = unsafe { item_ptr.as_mut() } {
let value = values.next().expect("Values shouldn't have been exhausted");
item.mXValue = value.0;
item.mYValue = value.1;
item_ptr = item.mNext;
}
debug_assert!(values.next().is_none(), "Values should have been exhausted");
}
/// Set a shared list
pub fn set_shared_list<I>(&mut self, values: I)
where
I: ExactSizeIterator<Item = nsCSSValue>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe { bindings::Gecko_CSSValue_InitSharedList(self, values.len() as u32) };
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_SharedList);
let list = unsafe {
self.mValue
.mSharedList
.as_ref()
.as_mut()
.expect("List pointer should be non-null")
.mHead
.as_mut()
};
debug_assert!(list.is_some(), "New created shared list shouldn't be null");
for (item, new_value) in list.unwrap().into_iter().zip(values) {
*item = new_value;
}
}
}
impl Drop for nsCSSValue {
fn drop(&mut self) {
unsafe { bindings::Gecko_CSSValue_Drop(self) };
}
}
/// Iterator of nsCSSValueList.
#[allow(non_camel_case_types)]
pub struct nsCSSValueListIterator<'a> {
current: Option<&'a nsCSSValueList>,
}
impl<'a> Iterator for nsCSSValueListIterator<'a> {
type Item = &'a nsCSSValue;
fn next(&mut self) -> Option<Self::Item> {
match self.current {
Some(item) => {
self.current = unsafe { item.mNext.as_ref() };
Some(&item.mValue)
},
None => None,
}
}
}
impl<'a> IntoIterator for &'a nsCSSValueList {
type Item = &'a nsCSSValue;
type IntoIter = nsCSSValueListIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
nsCSSValueListIterator {
current: Some(self),
}
}
}
/// Mutable Iterator of nsCSSValueList.
#[allow(non_camel_case_types)]
pub struct nsCSSValueListMutIterator<'a> {
current: *mut nsCSSValueList,
phantom: PhantomData<&'a mut nsCSSValue>,
}
impl<'a> Iterator for nsCSSValueListMutIterator<'a> {
type Item = &'a mut nsCSSValue;
fn next(&mut self) -> Option<Self::Item> {
match unsafe { self.current.as_mut() } {
Some(item) => {
self.current = item.mNext;
Some(&mut item.mValue)
},
None => None,
}
}
}
impl<'a> IntoIterator for &'a mut nsCSSValueList {
type Item = &'a mut nsCSSValue;
type IntoIter = nsCSSValueListMutIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
nsCSSValueListMutIterator {
current: self as *mut nsCSSValueList,
phantom: PhantomData,
}
}
}
impl nsCSSValue_Array {
/// Return the length of this `nsCSSValue::Array`
#[inline]
pub fn len(&self) -> usize {
self.mCount
}
#[inline]
fn buffer(&self) -> *const nsCSSValue {
self.mArray.as_ptr()
}
/// Get the array as a slice of nsCSSValues.
#[inline]
pub fn as_slice(&self) -> &[nsCSSValue] {
unsafe { slice::from_raw_parts(self.buffer(), self.len()) }
}
/// Get the array as a mutable slice of nsCSSValues.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [nsCSSValue] {
unsafe { slice::from_raw_parts_mut(self.buffer() as *mut _, self.len()) }
}
}
impl Index<usize> for nsCSSValue_Array {
type Output = nsCSSValue;
#[inline]
fn index(&self, i: usize) -> &nsCSSValue {
&self.as_slice()[i]
}
}
impl IndexMut<usize> for nsCSSValue_Array {
#[inline]
fn index_mut(&mut self, i: usize) -> &mut nsCSSValue {
&mut self.as_mut_slice()[i]
}
}
/// Generic conversion to nsCSSValue
pub trait ToNsCssValue {
/// Convert
fn convert(self, nscssvalue: &mut nsCSSValue);
}
impl<T: ToNsCssValue> From<T> for nsCSSValue {
fn from(value: T) -> nsCSSValue {
let mut result = nsCSSValue::null();
value.convert(&mut result);
result
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -104,3 +104,32 @@ macro_rules! define_keyword_type {
}
};
}
/// Place a Gecko profiler label on the stack.
///
/// The `label_type` argument must be the name of a variant of `ProfilerLabel`.
#[cfg(feature = "gecko_profiler")]
#[macro_export]
macro_rules! profiler_label {
($label_type:ident) => {
let mut _profiler_label: $crate::gecko_bindings::structs::AutoProfilerLabel =
unsafe { ::std::mem::uninitialized() };
let _profiler_label = if $crate::gecko::profiler::profiler_is_active() {
unsafe {
Some($crate::gecko::profiler::AutoProfilerLabel::new(
&mut _profiler_label,
$crate::gecko::profiler::ProfilerLabel::$label_type,
))
}
} else {
None
};
};
}
/// No-op when the Gecko profiler is not available.
#[cfg(not(feature = "gecko_profiler"))]
#[macro_export]
macro_rules! profiler_label {
($label_type:ident) => {};
}

View file

@ -277,6 +277,7 @@ pub fn traverse_nodes<'a, 'scope, E, D, I>(
top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls);
} 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)
});

View file

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

View file

@ -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",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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",

View file

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

View file

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

View file

@ -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",

View file

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

View file

@ -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",

View file

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

View file

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

View file

@ -2337,6 +2337,14 @@ impl SourcePropertyDeclaration {
}
}
/// Create one with a single PropertyDeclaration.
#[inline]
pub fn with_one(decl: PropertyDeclaration) -> Self {
let mut result = Self::new();
result.declarations.push(decl);
result
}
/// Similar to Vec::drain: leaves this empty when the return value is dropped.
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}(

View file

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

View file

@ -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",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,11 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Computed types for legacy Gecko-only properties.
use crate::values::computed::length::LengthPercentage;
use crate::values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint;
/// A computed type for scroll snap points.
pub type ScrollSnapPoint = GenericScrollSnapPoint<LengthPercentage>;

View file

@ -9,21 +9,19 @@ pub use crate::values::specified::list::ListStyleType;
pub use crate::values::specified::list::MozListReversed;
pub use crate::values::specified::list::{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()
);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,44 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Generic types for legacy Gecko-only properties that should probably be
//! un-shipped at some point in the future.
/// A generic value for scroll snap points.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(
Clone,
Copy,
Debug,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
pub enum ScrollSnapPoint<LengthPercentage> {
/// `none`
None,
/// `repeat(<length-or-percentage>)`
#[css(function)]
Repeat(LengthPercentage),
}
impl<L> ScrollSnapPoint<L> {
/// Returns `none`.
#[inline]
pub fn none() -> Self {
ScrollSnapPoint::None
}
/// Returns the repeat argument, if any.
#[inline]
pub fn repeated(&self) -> Option<&L> {
match *self {
ScrollSnapPoint::None => None,
ScrollSnapPoint::Repeat(ref length) => Some(length),
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,53 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![allow(unsafe_code)]
//! A replacement for `Box<str>` that has a defined layout for FFI.
use crate::owned_slice::OwnedSlice;
use std::fmt;
use std::ops::{Deref, DerefMut};
/// A struct that basically replaces a Box<str>, but with a defined layout,
/// suitable for FFI.
#[repr(C)]
#[derive(Clone, Default, Eq, MallocSizeOf, PartialEq, ToShmem)]
pub struct OwnedStr(OwnedSlice<u8>);
impl fmt::Debug for OwnedStr {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.deref().fmt(formatter)
}
}
impl Deref for OwnedStr {
type Target = str;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { std::str::from_utf8_unchecked(&*self.0) }
}
}
impl DerefMut for OwnedStr {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::str::from_utf8_unchecked_mut(&mut *self.0) }
}
}
impl From<Box<str>> for OwnedStr {
#[inline]
fn from(b: Box<str>) -> Self {
Self::from(b.into_string())
}
}
impl From<String> for OwnedStr {
#[inline]
fn from(s: String) -> Self {
OwnedStr(s.into_bytes().into())
}
}

View file

@ -5,6 +5,7 @@
//! Value information for devtools.
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>);

View file

@ -75,6 +75,16 @@ where
}
}
impl ToCss for crate::owned_str::OwnedStr {
#[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
serialize_string(self, dest)
}
}
impl ToCss for str {
#[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result

View file

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

View file

@ -1,43 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::parsing::parse;
use servo_atoms::Atom;
use style::parser::Parse;
use style::properties::longhands::animation_name;
use style::values::specified::AnimationIterationCount;
use style::values::{CustomIdent, KeyframesName};
use style_traits::ToCss;
#[test]
fn test_animation_name() {
use self::animation_name::single_value::SpecifiedValue as SingleValue;
let other_name = Atom::from("other-name");
assert_eq!(
parse_longhand!(animation_name, "none"),
animation_name::SpecifiedValue(vec![SingleValue(None)])
);
assert_eq!(
parse_longhand!(
animation_name,
"other-name, none, 'other-name', \"other-name\""
),
animation_name::SpecifiedValue(vec![
SingleValue(Some(KeyframesName::Ident(CustomIdent(other_name.clone())))),
SingleValue(None),
SingleValue(Some(KeyframesName::QuotedString(other_name.clone()))),
SingleValue(Some(KeyframesName::QuotedString(other_name.clone())))
])
);
}
#[test]
fn test_animation_iteration() {
assert_roundtrip_with_context!(AnimationIterationCount::parse, "0", "0");
assert_roundtrip_with_context!(AnimationIterationCount::parse, "0.1", "0.1");
assert_roundtrip_with_context!(AnimationIterationCount::parse, "infinite", "infinite");
// Negative numbers are invalid
assert!(parse(AnimationIterationCount::parse, "-1").is_err());
}

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