style: Use an ArcSlice as the computed value representation of inherited list properties.

This adds a bit of complexity, which I think will pay off in the end. Removals
incoming.

Differential Revision: https://phabricator.services.mozilla.com/D30544
This commit is contained in:
Emilio Cobos Álvarez 2019-05-16 23:03:27 +00:00
parent 5e4fdf647d
commit 2bc4c42d45
4 changed files with 135 additions and 28 deletions

View file

@ -3811,9 +3811,10 @@ fn static_assert() {
self.copy_text_shadow_from(other) self.copy_text_shadow_from(other)
} }
// FIXME(emilio): Remove by sharing representation.
pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T { pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
let buf = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow()).collect::<Vec<_>>(); let iter = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow());
longhands::text_shadow::computed_value::List(buf.into()) longhands::text_shadow::computed_value::List(crate::ArcSlice::from_iter(iter))
} }
fn clear_text_emphasis_style_if_string(&mut self) { fn clear_text_emphasis_style_if_string(&mut self) {
@ -4185,16 +4186,14 @@ clip-path
self.gecko.mContextProps.len() self.gecko.mContextProps.len()
} }
// FIXME(emilio): Remove by sharing representation.
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn _moz_context_properties_at( pub fn clone__moz_context_properties(&self) -> longhands::_moz_context_properties::computed_value::T {
&self, use crate::values::specified::svg::MozContextProperties;
index: usize, let buf = self.gecko.mContextProps.iter().map(|v| {
) -> longhands::_moz_context_properties::computed_value::single_value::T { MozContextProperties(CustomIdent(unsafe { Atom::from_raw(v.mRawPtr) }))
longhands::_moz_context_properties::computed_value::single_value::T( }).collect::<Vec<_>>();
CustomIdent(unsafe { longhands::_moz_context_properties::computed_value::List(crate::ArcSlice::from_iter(buf.into_iter()))
Atom::from_raw(self.gecko.mContextProps[index].mRawPtr)
})
)
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]

View file

@ -80,6 +80,16 @@
We assume that the default/initial value is an empty vector for these. We assume that the default/initial value is an empty vector for these.
`initial_value` need not be defined for these. `initial_value` need not be defined for these.
</%doc> </%doc>
// The setup here is roughly:
//
// * UnderlyingList is the list that is stored in the computed value. This may
// be a shared ArcSlice if the property is inherited.
// * UnderlyingOwnedList is the list that is used for animation.
// * Specified values always use OwnedSlice, since it's more compact.
// * computed_value::List is just a convenient alias that you can use for the
// computed value list, since this is in the computed_value module.
//
<%def name="vector_longhand(name, animation_value_type=None, <%def name="vector_longhand(name, animation_value_type=None,
vector_animation_type=None, allow_empty=False, vector_animation_type=None, allow_empty=False,
separator='Comma', separator='Comma',
@ -111,6 +121,10 @@
/// The definition of the computed value for ${name}. /// The definition of the computed value for ${name}.
pub mod computed_value { pub mod computed_value {
#[allow(unused_imports)]
use crate::values::animated::ToAnimatedValue;
#[allow(unused_imports)]
use crate::values::resolved::ToResolvedValue;
pub use super::single_value::computed_value as single_value; pub use super::single_value::computed_value as single_value;
pub use self::single_value::T as SingleComputedValue; pub use self::single_value::T as SingleComputedValue;
% if not allow_empty or allow_empty == "NotInitial": % if not allow_empty or allow_empty == "NotInitial":
@ -118,7 +132,32 @@
% endif % endif
use crate::values::computed::ComputedVecIter; use crate::values::computed::ComputedVecIter;
/// The generic type defining the value for this property. <% is_shared_list = allow_empty and allow_empty != "NotInitial" and data.longhands_by_name[name].style_struct.inherited %>
// FIXME(emilio): Add an OwnedNonEmptySlice type, and figure out
// something for transition-name, which is the only remaining user
// of NotInitial.
pub type UnderlyingList<T> =
% if allow_empty and allow_empty != "NotInitial":
% if data.longhands_by_name[name].style_struct.inherited:
crate::ArcSlice<T>;
% else:
crate::OwnedSlice<T>;
% endif
% else:
SmallVec<[T; 1]>;
% endif
pub type UnderlyingOwnedList<T> =
% if allow_empty and allow_empty != "NotInitial":
crate::OwnedSlice<T>;
% else:
SmallVec<[T; 1]>;
% endif
/// The generic type defining the animated and resolved values for
/// this property.
/// ///
/// Making this type generic allows the compiler to figure out the /// Making this type generic allows the compiler to figure out the
/// animated value for us, instead of having to implement it /// animated value for us, instead of having to implement it
@ -135,22 +174,69 @@
ToResolvedValue, ToResolvedValue,
ToCss, ToCss,
)] )]
pub struct List<T>( pub struct OwnedList<T>(
% if not allow_empty: % if not allow_empty:
#[css(iterable)] #[css(iterable)]
% else: % else:
#[css(if_empty = "none", iterable)] #[css(if_empty = "none", iterable)]
% endif % endif
% if allow_empty and allow_empty != "NotInitial": pub UnderlyingOwnedList<T>,
pub crate::OwnedSlice<T>,
% else:
// FIXME(emilio): Add an OwnedNonEmptySlice type, and figure out
// something for transition-name, which is the only remaining
// user of NotInitial.
pub SmallVec<[T; 1]>,
% endif
); );
/// The computed value for this property.
% if not is_shared_list:
pub type ComputedList = OwnedList<single_value::T>;
pub use self::OwnedList as List;
% else:
pub use self::ComputedList as List;
% if separator == "Comma":
#[css(comma)]
% endif
#[derive(
Clone,
Debug,
MallocSizeOf,
PartialEq,
ToCss,
)]
pub struct ComputedList(
% if not allow_empty:
#[css(iterable)]
% else:
#[css(if_empty = "none", iterable)]
% endif
% if is_shared_list:
#[ignore_malloc_size_of = "Arc"]
% endif
pub UnderlyingList<single_value::T>,
);
type ResolvedList = OwnedList<<single_value::T as ToResolvedValue>::ResolvedValue>;
impl ToResolvedValue for ComputedList {
type ResolvedValue = ResolvedList;
fn to_resolved_value(self, context: &crate::values::resolved::Context) -> Self::ResolvedValue {
OwnedList(
self.0
.iter()
.cloned()
.map(|v| v.to_resolved_value(context))
.collect()
)
}
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
% if not is_shared_list:
use std::iter::FromIterator;
% endif
let iter =
resolved.0.into_iter().map(ToResolvedValue::from_resolved_value);
ComputedList(UnderlyingList::from_iter(iter))
}
}
% endif
% if vector_animation_type: % if vector_animation_type:
% if not animation_value_type: % if not animation_value_type:
@ -158,13 +244,31 @@
% endif % endif
use crate::properties::animated_properties::ListAnimation; use crate::properties::animated_properties::ListAnimation;
use crate::values::animated::{Animate, ToAnimatedValue, ToAnimatedZero, Procedure}; use crate::values::animated::{Animate, ToAnimatedZero, Procedure};
use crate::values::distance::{SquaredDistance, ComputeSquaredDistance}; use crate::values::distance::{SquaredDistance, ComputeSquaredDistance};
// FIXME(emilio): For some reason rust thinks that this alias is // FIXME(emilio): For some reason rust thinks that this alias is
// unused, even though it's clearly used below? // unused, even though it's clearly used below?
#[allow(unused)] #[allow(unused)]
type AnimatedList = <List<single_value::T> as ToAnimatedValue>::AnimatedValue; type AnimatedList = OwnedList<<single_value::T as ToAnimatedValue>::AnimatedValue>;
% if is_shared_list:
impl ToAnimatedValue for ComputedList {
type AnimatedValue = AnimatedList;
fn to_animated_value(self) -> Self::AnimatedValue {
OwnedList(
self.0.iter().map(|v| v.clone().to_animated_value()).collect()
)
}
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
let iter =
animated.0.into_iter().map(ToAnimatedValue::from_animated_value);
ComputedList(UnderlyingList::from_iter(iter))
}
}
% endif
impl ToAnimatedZero for AnimatedList { impl ToAnimatedZero for AnimatedList {
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
@ -176,7 +280,7 @@
other: &Self, other: &Self,
procedure: Procedure, procedure: Procedure,
) -> Result<Self, ()> { ) -> Result<Self, ()> {
Ok(List( Ok(OwnedList(
self.0.animate_${vector_animation_type}(&other.0, procedure)? self.0.animate_${vector_animation_type}(&other.0, procedure)?
)) ))
} }
@ -192,7 +296,7 @@
% endif % endif
/// The computed value, effectively a list of single values. /// The computed value, effectively a list of single values.
pub type T = List<single_value::T>; pub use self::ComputedList as T;
pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>; pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
} }
@ -255,7 +359,12 @@
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T { fn to_computed_value(&self, context: &Context) -> computed_value::T {
computed_value::List(self.0.iter().map(|i| i.to_computed_value(context)).collect()) % if not is_shared_list:
use std::iter::FromIterator;
% endif
computed_value::List(computed_value::UnderlyingList::from_iter(
self.0.iter().map(|i| i.to_computed_value(context))
))
} }
#[inline] #[inline]

View file

@ -196,7 +196,6 @@ ${helpers.predefined_type(
"MozContextProperties", "MozContextProperties",
initial_value=None, initial_value=None,
vector=True, vector=True,
need_index=True,
animation_value_type="none", animation_value_type="none",
products="gecko", products="gecko",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)",

View file

@ -93,7 +93,7 @@ impl<T: Sized> OwnedSlice<T> {
/// Iterate over all the elements in the slice taking ownership of them. /// Iterate over all the elements in the slice taking ownership of them.
#[inline] #[inline]
pub fn into_iter(self) -> impl Iterator<Item = T> { pub fn into_iter(self) -> impl Iterator<Item = T> + ExactSizeIterator {
self.into_vec().into_iter() self.into_vec().into_iter()
} }