mirror of
https://github.com/servo/servo.git
synced 2025-10-04 02:29:12 +01:00
I'm _really_ sorry for the size of the patch. I tried to do this in two steps but it was a lot of work and pretty ugly. This patch makes us use cbindgen for grid-template-{rows,columns}, in order to: * Make us preserve repeat() at computed-value time. This is per spec since interpolation needs to know about repeat(). Except for subgrid, which did the repeat expansion at parse-time and was a bit more annoying (plus it doesn't really animate yet so we don't need it to comply with the spec). * Tweaks the WPT tests for interpolation to adopt the resolution at: https://github.com/w3c/csswg-drafts/issues/3503. Trade-off here, as this patch stands, is that this change makes us use less long-living memory, since we expand repeat() during layout, but at the cost of a bit of CPU time during layout (conditional on the property applying though, which wasn't the case before). It should be very easy to store a cached version of the template, should this be too hot (I expect it isn't), or to change the representation in other ways to optimize grid layout code if it's worth it. Another trade-off: I've used SmallPointerArray to handle line-name merging, pointing to the individual arrays in the style data, rather than actually heap-allocating the merged lists. This would also be pretty easy to change should we measure and see that it's not worth it. This patch also opens the gate to potentially improving memory usage in some other ways, by reference-counting line-name lists for example, though I don't have data that suggests it is worth it. In general, this patch makes much easier to tweak the internal representation of the grid style data structures. Overall, I think it's a win, the amount of magic going on in that mako code was a bit huge; it took a bit to wrap my head around it. This patch comments out the style struct size assertions. They will be uncommented in a follow-up patch which contains some improvements for this type, which are worth getting reviewed separately. Also, this patch doesn't remove as much code as I would've hoped for because of I tried not to change most of the dom/grid code for inspector, but I think a fair bit of the nsGridContainerFrame.cpp code that collects information for it can be simplified / de-copy-pasted to some extent. But that was a pre-existing problem and this patch is already quite massive. Differential Revision: https://phabricator.services.mozilla.com/D36598
213 lines
6 KiB
Rust
213 lines
6 KiB
Rust
/* 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/. */
|
|
|
|
//! Resolved values. These are almost always computed values, but in some cases
|
|
//! there are used values.
|
|
|
|
use crate::properties::ComputedValues;
|
|
use cssparser;
|
|
use smallvec::SmallVec;
|
|
|
|
mod color;
|
|
|
|
use crate::values::computed;
|
|
|
|
/// Information needed to resolve a given value.
|
|
pub struct Context<'a> {
|
|
/// The style we're resolving for. This is useful to resolve currentColor.
|
|
pub style: &'a ComputedValues,
|
|
// TODO(emilio): Add layout box information, and maybe property-specific
|
|
// information?
|
|
}
|
|
|
|
/// A trait to represent the conversion between resolved and resolved values.
|
|
///
|
|
/// This trait is derivable with `#[derive(ToResolvedValue)]`.
|
|
///
|
|
/// The deriving code assumes that if the type isn't generic, then the trait can
|
|
/// be implemented as simple move. This means that a manual implementation with
|
|
/// `ResolvedValue = Self` is bogus if it returns anything else than a clone.
|
|
pub trait ToResolvedValue {
|
|
/// The resolved value type we're going to be converted to.
|
|
type ResolvedValue;
|
|
|
|
/// Convert a resolved value to a resolved value.
|
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue;
|
|
|
|
/// Convert a resolved value to resolved value form.
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self;
|
|
}
|
|
|
|
macro_rules! trivial_to_resolved_value {
|
|
($ty:ty) => {
|
|
impl $crate::values::resolved::ToResolvedValue for $ty {
|
|
type ResolvedValue = Self;
|
|
|
|
#[inline]
|
|
fn to_resolved_value(self, _: &Context) -> Self {
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
|
resolved
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
trivial_to_resolved_value!(());
|
|
trivial_to_resolved_value!(bool);
|
|
trivial_to_resolved_value!(f32);
|
|
trivial_to_resolved_value!(i32);
|
|
trivial_to_resolved_value!(u8);
|
|
trivial_to_resolved_value!(i8);
|
|
trivial_to_resolved_value!(u16);
|
|
trivial_to_resolved_value!(u32);
|
|
trivial_to_resolved_value!(usize);
|
|
trivial_to_resolved_value!(String);
|
|
trivial_to_resolved_value!(Box<str>);
|
|
trivial_to_resolved_value!(cssparser::RGBA);
|
|
trivial_to_resolved_value!(crate::Atom);
|
|
trivial_to_resolved_value!(app_units::Au);
|
|
trivial_to_resolved_value!(computed::url::ComputedUrl);
|
|
#[cfg(feature = "gecko")]
|
|
trivial_to_resolved_value!(computed::url::ComputedImageUrl);
|
|
#[cfg(feature = "servo")]
|
|
trivial_to_resolved_value!(html5ever::Prefix);
|
|
|
|
impl<A, B> ToResolvedValue for (A, B)
|
|
where
|
|
A: ToResolvedValue,
|
|
B: ToResolvedValue,
|
|
{
|
|
type ResolvedValue = (
|
|
<A as ToResolvedValue>::ResolvedValue,
|
|
<B as ToResolvedValue>::ResolvedValue,
|
|
);
|
|
|
|
#[inline]
|
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
|
(
|
|
self.0.to_resolved_value(context),
|
|
self.1.to_resolved_value(context),
|
|
)
|
|
}
|
|
|
|
#[inline]
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
|
(
|
|
A::from_resolved_value(resolved.0),
|
|
B::from_resolved_value(resolved.1),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<T> ToResolvedValue for Option<T>
|
|
where
|
|
T: ToResolvedValue,
|
|
{
|
|
type ResolvedValue = Option<<T as ToResolvedValue>::ResolvedValue>;
|
|
|
|
#[inline]
|
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
|
self.map(|item| item.to_resolved_value(context))
|
|
}
|
|
|
|
#[inline]
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
|
resolved.map(T::from_resolved_value)
|
|
}
|
|
}
|
|
|
|
impl<T> ToResolvedValue for SmallVec<[T; 1]>
|
|
where
|
|
T: ToResolvedValue,
|
|
{
|
|
type ResolvedValue = SmallVec<[<T as ToResolvedValue>::ResolvedValue; 1]>;
|
|
|
|
#[inline]
|
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
|
self.into_iter()
|
|
.map(|item| item.to_resolved_value(context))
|
|
.collect()
|
|
}
|
|
|
|
#[inline]
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
|
resolved.into_iter().map(T::from_resolved_value).collect()
|
|
}
|
|
}
|
|
|
|
impl<T> ToResolvedValue for Vec<T>
|
|
where
|
|
T: ToResolvedValue,
|
|
{
|
|
type ResolvedValue = Vec<<T as ToResolvedValue>::ResolvedValue>;
|
|
|
|
#[inline]
|
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
|
self.into_iter()
|
|
.map(|item| item.to_resolved_value(context))
|
|
.collect()
|
|
}
|
|
|
|
#[inline]
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
|
resolved.into_iter().map(T::from_resolved_value).collect()
|
|
}
|
|
}
|
|
|
|
impl<T> ToResolvedValue for Box<T>
|
|
where
|
|
T: ToResolvedValue,
|
|
{
|
|
type ResolvedValue = Box<<T as ToResolvedValue>::ResolvedValue>;
|
|
|
|
#[inline]
|
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
|
Box::new(T::to_resolved_value(*self, context))
|
|
}
|
|
|
|
#[inline]
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
|
Box::new(T::from_resolved_value(*resolved))
|
|
}
|
|
}
|
|
|
|
impl<T> ToResolvedValue for Box<[T]>
|
|
where
|
|
T: ToResolvedValue,
|
|
{
|
|
type ResolvedValue = Box<[<T as ToResolvedValue>::ResolvedValue]>;
|
|
|
|
#[inline]
|
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
|
Vec::from(self)
|
|
.to_resolved_value(context)
|
|
.into_boxed_slice()
|
|
}
|
|
|
|
#[inline]
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
|
Vec::from_resolved_value(Vec::from(resolved)).into_boxed_slice()
|
|
}
|
|
}
|
|
|
|
impl<T> ToResolvedValue for crate::OwnedSlice<T>
|
|
where
|
|
T: ToResolvedValue,
|
|
{
|
|
type ResolvedValue = crate::OwnedSlice<<T as ToResolvedValue>::ResolvedValue>;
|
|
|
|
#[inline]
|
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
|
self.into_box().to_resolved_value(context).into()
|
|
}
|
|
|
|
#[inline]
|
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
|
Self::from(Box::from_resolved_value(resolved.into_box()))
|
|
}
|
|
}
|