зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1766655 - Introduce Optional<T> to represent optional values in the style system. r=dshin
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:
Родитель
642b5e7837
Коммит
14f8cafbc3
|
@ -47,8 +47,6 @@ pub type Gradient = generic::GenericGradient<
|
|||
/// Computed values for CSS cross-fade
|
||||
/// <https://drafts.csswg.org/css-images-4/#cross-fade-function>
|
||||
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.
|
||||
pub type EndingShape = generic::GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
use crate::custom_properties;
|
||||
use crate::values::generics::position::PositionComponent;
|
||||
use crate::values::generics::Optional;
|
||||
use crate::values::serialize_atom_identifier;
|
||||
use crate::Atom;
|
||||
use crate::Zero;
|
||||
|
@ -71,20 +72,6 @@ pub struct GenericCrossFade<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.
|
||||
#[derive(
|
||||
Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, ToCss,
|
||||
|
@ -92,7 +79,7 @@ pub enum PercentOrNone<Percentage> {
|
|||
#[repr(C)]
|
||||
pub struct GenericCrossFadeElement<Image, Color, Percentage> {
|
||||
/// 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
|
||||
/// evaluated.
|
||||
pub image: GenericCrossFadeImage<Image, Color>,
|
||||
|
|
|
@ -310,3 +310,74 @@ impl<L> ClipRectOrAuto<L> {
|
|||
}
|
||||
|
||||
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>;
|
||||
/// CrossFadeImage = image | color
|
||||
pub type CrossFadeImage = generic::CrossFadeImage<Image, Color>;
|
||||
/// A specified percentage or nothing.
|
||||
pub type PercentOrNone = generic::PercentOrNone<Percentage>;
|
||||
|
||||
/// `image-set()`
|
||||
pub type ImageSet = generic::ImageSet<Image, Resolution>;
|
||||
|
@ -303,6 +301,16 @@ impl CrossFade {
|
|||
}
|
||||
|
||||
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> ]
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
|
@ -310,14 +318,17 @@ impl CrossFadeElement {
|
|||
cors_mode: CorsMode,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
// 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
|
||||
let image = CrossFadeImage::parse(context, input, cors_mode)?;
|
||||
// Try and parse a trailing percent sign.
|
||||
if percent == PercentOrNone::None {
|
||||
percent = PercentOrNone::parse_or_none(context, input);
|
||||
if percent.is_none() {
|
||||
percent = Self::parse_percentage(context, input);
|
||||
}
|
||||
Ok(Self { percent, image })
|
||||
Ok(Self {
|
||||
percent: percent.into(),
|
||||
image,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,22 +350,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 {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
|
|
Загрузка…
Ссылка в новой задаче