mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
style: Introduce Optional<T> to represent optional values in the style system
cross-fade() was kinda doing this in its own way with PercentOrNone, but since now we have more use-cases for this we should probably make this a slightly more general solution. I added some convenience APIs, but they're unused as of this patch so let me know if you want them gone. Differential Revision: https://phabricator.services.mozilla.com/D144831
This commit is contained in:
parent
16cfd01823
commit
819ebc5710
4 changed files with 90 additions and 39 deletions
|
@ -47,8 +47,6 @@ pub type Gradient = generic::GenericGradient<
|
||||||
/// Computed values for CSS cross-fade
|
/// Computed values for CSS cross-fade
|
||||||
/// <https://drafts.csswg.org/css-images-4/#cross-fade-function>
|
/// <https://drafts.csswg.org/css-images-4/#cross-fade-function>
|
||||||
pub type CrossFade = generic::CrossFade<Image, Color, Percentage>;
|
pub type CrossFade = generic::CrossFade<Image, Color, Percentage>;
|
||||||
/// A computed percentage or nothing.
|
|
||||||
pub type PercentOrNone = generic::PercentOrNone<Percentage>;
|
|
||||||
|
|
||||||
/// A computed radial gradient ending shape.
|
/// A computed radial gradient ending shape.
|
||||||
pub type EndingShape = generic::GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>;
|
pub type EndingShape = generic::GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
use crate::custom_properties;
|
use crate::custom_properties;
|
||||||
use crate::values::generics::position::PositionComponent;
|
use crate::values::generics::position::PositionComponent;
|
||||||
|
use crate::values::generics::Optional;
|
||||||
use crate::values::serialize_atom_identifier;
|
use crate::values::serialize_atom_identifier;
|
||||||
use crate::Atom;
|
use crate::Atom;
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
|
@ -71,20 +72,6 @@ pub struct GenericCrossFade<Image, Color, Percentage> {
|
||||||
pub elements: crate::OwnedSlice<GenericCrossFadeElement<Image, Color, Percentage>>,
|
pub elements: crate::OwnedSlice<GenericCrossFadeElement<Image, Color, Percentage>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `<percent> | none` value. Represents optional percentage values
|
|
||||||
/// assosicated with cross-fade images.
|
|
||||||
#[derive(
|
|
||||||
Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, ToCss,
|
|
||||||
)]
|
|
||||||
#[repr(C, u8)]
|
|
||||||
pub enum PercentOrNone<Percentage> {
|
|
||||||
/// `none` variant.
|
|
||||||
#[css(skip)]
|
|
||||||
None,
|
|
||||||
/// A percentage variant.
|
|
||||||
Percent(Percentage),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An optional percent and a cross fade image.
|
/// An optional percent and a cross fade image.
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, ToCss,
|
Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, ToCss,
|
||||||
|
@ -92,7 +79,7 @@ pub enum PercentOrNone<Percentage> {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct GenericCrossFadeElement<Image, Color, Percentage> {
|
pub struct GenericCrossFadeElement<Image, Color, Percentage> {
|
||||||
/// The percent of the final image that `image` will be.
|
/// The percent of the final image that `image` will be.
|
||||||
pub percent: PercentOrNone<Percentage>,
|
pub percent: Optional<Percentage>,
|
||||||
/// A color or image that will be blended when cross-fade is
|
/// A color or image that will be blended when cross-fade is
|
||||||
/// evaluated.
|
/// evaluated.
|
||||||
pub image: GenericCrossFadeImage<Image, Color>,
|
pub image: GenericCrossFadeImage<Image, Color>,
|
||||||
|
|
|
@ -310,3 +310,74 @@ impl<L> ClipRectOrAuto<L> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use page::PageSize;
|
pub use page::PageSize;
|
||||||
|
|
||||||
|
/// An optional value, much like `Option<T>`, but with a defined struct layout
|
||||||
|
/// to be able to use it from C++ as well.
|
||||||
|
///
|
||||||
|
/// Note that this is relatively inefficient, struct-layout-wise, as you have
|
||||||
|
/// one byte for the tag, but padding to the alignment of T. If you have
|
||||||
|
/// multiple optional values and care about struct compactness, you might be
|
||||||
|
/// better off "coalescing" the combinations into a parent enum. But that
|
||||||
|
/// shouldn't matter for most use cases.
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[derive(
|
||||||
|
Animate,
|
||||||
|
Clone,
|
||||||
|
ComputeSquaredDistance,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
MallocSizeOf,
|
||||||
|
Parse,
|
||||||
|
PartialEq,
|
||||||
|
SpecifiedValueInfo,
|
||||||
|
ToAnimatedValue,
|
||||||
|
ToAnimatedZero,
|
||||||
|
ToComputedValue,
|
||||||
|
ToCss,
|
||||||
|
ToResolvedValue,
|
||||||
|
ToShmem,
|
||||||
|
)]
|
||||||
|
#[repr(C, u8)]
|
||||||
|
pub enum Optional<T> {
|
||||||
|
#[css(skip)]
|
||||||
|
None,
|
||||||
|
Some(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Optional<T> {
|
||||||
|
/// Returns whether this value is present.
|
||||||
|
pub fn is_some(&self) -> bool {
|
||||||
|
matches!(*self, Self::Some(..))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this value is not present.
|
||||||
|
pub fn is_none(&self) -> bool {
|
||||||
|
matches!(*self, Self::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Turns this Optional<> into a regular rust Option<>.
|
||||||
|
pub fn into_rust(self) -> Option<T> {
|
||||||
|
match self {
|
||||||
|
Self::Some(v) => Some(v),
|
||||||
|
Self::None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a reference to the containing value, if any, as a plain rust
|
||||||
|
/// Option<>.
|
||||||
|
pub fn as_ref(&self) -> Option<&T> {
|
||||||
|
match *self {
|
||||||
|
Self::Some(ref v) => Some(v),
|
||||||
|
Self::None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Option<T>> for Optional<T> {
|
||||||
|
fn from(rust: Option<T>) -> Self {
|
||||||
|
match rust {
|
||||||
|
Some(t) => Self::Some(t),
|
||||||
|
None => Self::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -60,8 +60,6 @@ pub type CrossFade = generic::CrossFade<Image, Color, Percentage>;
|
||||||
pub type CrossFadeElement = generic::CrossFadeElement<Image, Color, Percentage>;
|
pub type CrossFadeElement = generic::CrossFadeElement<Image, Color, Percentage>;
|
||||||
/// CrossFadeImage = image | color
|
/// CrossFadeImage = image | color
|
||||||
pub type CrossFadeImage = generic::CrossFadeImage<Image, Color>;
|
pub type CrossFadeImage = generic::CrossFadeImage<Image, Color>;
|
||||||
/// A specified percentage or nothing.
|
|
||||||
pub type PercentOrNone = generic::PercentOrNone<Percentage>;
|
|
||||||
|
|
||||||
/// `image-set()`
|
/// `image-set()`
|
||||||
pub type ImageSet = generic::ImageSet<Image, Resolution>;
|
pub type ImageSet = generic::ImageSet<Image, Resolution>;
|
||||||
|
@ -315,6 +313,16 @@ impl CrossFade {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrossFadeElement {
|
impl CrossFadeElement {
|
||||||
|
fn parse_percentage<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Option<Percentage> {
|
||||||
|
// We clamp our values here as this is the way that Safari and Chrome's
|
||||||
|
// implementation handle out-of-bounds percentages but whether or not
|
||||||
|
// this behavior follows the specification is still being discussed.
|
||||||
|
// See: <https://github.com/w3c/csswg-drafts/issues/5333>
|
||||||
|
input.try_parse(|input| Percentage::parse_non_negative(context, input))
|
||||||
|
.ok()
|
||||||
|
.map(|p| p.clamp_to_hundred())
|
||||||
|
}
|
||||||
|
|
||||||
/// <cf-image> = <percentage>? && [ <image> | <color> ]
|
/// <cf-image> = <percentage>? && [ <image> | <color> ]
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
|
@ -322,14 +330,17 @@ impl CrossFadeElement {
|
||||||
cors_mode: CorsMode,
|
cors_mode: CorsMode,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
// Try and parse a leading percent sign.
|
// Try and parse a leading percent sign.
|
||||||
let mut percent = PercentOrNone::parse_or_none(context, input);
|
let mut percent = Self::parse_percentage(context, input);
|
||||||
// Parse the image
|
// Parse the image
|
||||||
let image = CrossFadeImage::parse(context, input, cors_mode)?;
|
let image = CrossFadeImage::parse(context, input, cors_mode)?;
|
||||||
// Try and parse a trailing percent sign.
|
// Try and parse a trailing percent sign.
|
||||||
if percent == PercentOrNone::None {
|
if percent.is_none() {
|
||||||
percent = PercentOrNone::parse_or_none(context, input);
|
percent = Self::parse_percentage(context, input);
|
||||||
}
|
}
|
||||||
Ok(Self { percent, image })
|
Ok(Self {
|
||||||
|
percent: percent.into(),
|
||||||
|
image,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,22 +362,6 @@ impl CrossFadeImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PercentOrNone {
|
|
||||||
fn parse_or_none<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Self {
|
|
||||||
// We clamp our values here as this is the way that Safari and
|
|
||||||
// Chrome's implementation handle out-of-bounds percentages
|
|
||||||
// but whether or not this behavior follows the specification
|
|
||||||
// is still being discussed. See:
|
|
||||||
// <https://github.com/w3c/csswg-drafts/issues/5333>
|
|
||||||
if let Ok(percent) = input.try_parse(|input| Percentage::parse_non_negative(context, input))
|
|
||||||
{
|
|
||||||
Self::Percent(percent.clamp_to_hundred())
|
|
||||||
} else {
|
|
||||||
Self::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImageSet {
|
impl ImageSet {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue