summaryrefslogtreecommitdiffstats
path: root/servo/components/style/values/resolved
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/values/resolved')
-rw-r--r--servo/components/style/values/resolved/color.rs48
-rw-r--r--servo/components/style/values/resolved/counters.rs51
-rw-r--r--servo/components/style/values/resolved/mod.rs274
3 files changed, 373 insertions, 0 deletions
diff --git a/servo/components/style/values/resolved/color.rs b/servo/components/style/values/resolved/color.rs
new file mode 100644
index 0000000000..79dfd8685f
--- /dev/null
+++ b/servo/components/style/values/resolved/color.rs
@@ -0,0 +1,48 @@
+/* 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 color values.
+
+use super::{Context, ToResolvedValue};
+
+use crate::color::AbsoluteColor;
+use crate::values::computed::color as computed;
+use crate::values::generics::color as generics;
+
+impl ToResolvedValue for computed::Color {
+ // A resolved color value is an rgba color, with currentcolor resolved.
+ type ResolvedValue = AbsoluteColor;
+
+ #[inline]
+ fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+ context.style.resolve_color(self)
+ }
+
+ #[inline]
+ fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+ generics::Color::Absolute(resolved)
+ }
+}
+
+impl ToResolvedValue for computed::CaretColor {
+ // A resolved caret-color value is an rgba color, with auto resolving to
+ // currentcolor.
+ type ResolvedValue = AbsoluteColor;
+
+ #[inline]
+ fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
+ let color = match self.0 {
+ generics::ColorOrAuto::Color(color) => color,
+ generics::ColorOrAuto::Auto => generics::Color::currentcolor(),
+ };
+ color.to_resolved_value(context)
+ }
+
+ #[inline]
+ fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
+ generics::CaretColor(generics::ColorOrAuto::Color(
+ computed::Color::from_resolved_value(resolved),
+ ))
+ }
+}
diff --git a/servo/components/style/values/resolved/counters.rs b/servo/components/style/values/resolved/counters.rs
new file mode 100644
index 0000000000..c1332449ad
--- /dev/null
+++ b/servo/components/style/values/resolved/counters.rs
@@ -0,0 +1,51 @@
+/* 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 for counter properties
+
+use super::{Context, ToResolvedValue};
+use crate::values::computed;
+
+/// https://drafts.csswg.org/css-content/#content-property
+///
+/// We implement this at resolved value time because otherwise it causes us to
+/// allocate a bunch of useless initial structs for ::before / ::after, which is
+/// a bit unfortunate.
+///
+/// Though these should be temporary, mostly, so if this causes complexity in
+/// other places, it should be fine to move to `StyleAdjuster`.
+///
+/// See https://github.com/w3c/csswg-drafts/issues/4632 for where some related
+/// issues are being discussed.
+impl ToResolvedValue for computed::Content {
+ type ResolvedValue = Self;
+
+ #[inline]
+ fn to_resolved_value(self, context: &Context) -> Self {
+ let (is_pseudo, is_before_or_after, is_marker) = match context.style.pseudo() {
+ Some(ref pseudo) => (true, pseudo.is_before_or_after(), pseudo.is_marker()),
+ None => (false, false, false),
+ };
+ match self {
+ Self::Normal if is_before_or_after => Self::None,
+ // For now, make `content: none` compute to `normal` for pseudos
+ // other than ::before, ::after and ::marker, as we don't respect it.
+ // https://github.com/w3c/csswg-drafts/issues/6124
+ // Ditto for non-pseudo elements if the pref is disabled.
+ Self::None
+ if (is_pseudo && !is_before_or_after && !is_marker) ||
+ (!is_pseudo &&
+ !static_prefs::pref!("layout.css.element-content-none.enabled")) =>
+ {
+ Self::Normal
+ },
+ other => other,
+ }
+ }
+
+ #[inline]
+ fn from_resolved_value(resolved: Self) -> Self {
+ resolved
+ }
+}
diff --git a/servo/components/style/values/resolved/mod.rs b/servo/components/style/values/resolved/mod.rs
new file mode 100644
index 0000000000..31ef2de44b
--- /dev/null
+++ b/servo/components/style/values/resolved/mod.rs
@@ -0,0 +1,274 @@
+/* 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::media_queries::Device;
+use crate::properties::ComputedValues;
+use crate::ArcSlice;
+use servo_arc::Arc;
+use smallvec::SmallVec;
+
+mod color;
+mod counters;
+
+use crate::values::computed;
+
+/// Element-specific information needed to resolve property values.
+pub struct ResolvedElementInfo<'a> {
+ /// Element we're resolving line-height against.
+ #[cfg(feature = "gecko")]
+ pub element: crate::gecko::wrapper::GeckoElement<'a>,
+}
+
+/// 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,
+ /// The device / document we're resolving style for. Useful to do font metrics stuff needed for
+ /// line-height.
+ pub device: &'a Device,
+ /// The element-specific information to resolve the value.
+ pub element_info: ResolvedElementInfo<'a>,
+}
+
+/// 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!(u8);
+trivial_to_resolved_value!(i8);
+trivial_to_resolved_value!(u16);
+trivial_to_resolved_value!(i16);
+trivial_to_resolved_value!(u32);
+trivial_to_resolved_value!(i32);
+trivial_to_resolved_value!(usize);
+trivial_to_resolved_value!(String);
+trivial_to_resolved_value!(Box<str>);
+trivial_to_resolved_value!(crate::OwnedStr);
+trivial_to_resolved_value!(crate::color::AbsoluteColor);
+trivial_to_resolved_value!(crate::Atom);
+trivial_to_resolved_value!(crate::values::AtomIdent);
+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!(crate::Namespace);
+#[cfg(feature = "servo")]
+trivial_to_resolved_value!(crate::Prefix);
+trivial_to_resolved_value!(computed::LengthPercentage);
+trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType);
+trivial_to_resolved_value!(computed::TimingFunction);
+
+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()))
+ }
+}
+
+// NOTE(emilio): This is implementable more generically, but it's unlikely what
+// you want there, as it forces you to have an extra allocation.
+//
+// We could do that if needed, ideally with specialization for the case where
+// ResolvedValue = T. But we don't need it for now.
+impl<T> ToResolvedValue for Arc<T>
+where
+ T: ToResolvedValue<ResolvedValue = T>,
+{
+ type ResolvedValue = Self;
+
+ #[inline]
+ fn to_resolved_value(self, _: &Context) -> Self {
+ self
+ }
+
+ #[inline]
+ fn from_resolved_value(resolved: Self) -> Self {
+ resolved
+ }
+}
+
+// Same caveat as above applies.
+impl<T> ToResolvedValue for ArcSlice<T>
+where
+ T: ToResolvedValue<ResolvedValue = T>,
+{
+ type ResolvedValue = Self;
+
+ #[inline]
+ fn to_resolved_value(self, _: &Context) -> Self {
+ self
+ }
+
+ #[inline]
+ fn from_resolved_value(resolved: Self) -> Self {
+ resolved
+ }
+}