Auto merge of #22930 - emilio:gecko-sync, r=emilio

style: Sync changes from mozilla-central.

See individual commits for details.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/22930)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-02-24 08:31:08 -05:00 committed by GitHub
commit 427003210b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 846 additions and 1175 deletions

View file

@ -2,8 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// FIXME(rust-lang/rust#26264): Remove GenericBackgroundSize.
use crate::display_list::border; use crate::display_list::border;
use app_units::Au; use app_units::Au;
use euclid::{Point2D, Rect, SideOffsets2D, Size2D}; use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
@ -12,7 +10,6 @@ use style::computed_values::background_clip::single_value::T as BackgroundClip;
use style::computed_values::background_origin::single_value::T as BackgroundOrigin; use style::computed_values::background_origin::single_value::T as BackgroundOrigin;
use style::properties::style_structs::Background; use style::properties::style_structs::Background;
use style::values::computed::{BackgroundSize, NonNegativeLengthPercentageOrAuto}; use style::values::computed::{BackgroundSize, NonNegativeLengthPercentageOrAuto};
use style::values::generics::background::BackgroundSize as GenericBackgroundSize;
use style::values::specified::background::BackgroundRepeatKeyword; use style::values::specified::background::BackgroundRepeatKeyword;
use webrender_api::BorderRadius; use webrender_api::BorderRadius;
@ -56,8 +53,8 @@ fn compute_background_image_size(
) -> Size2D<Au> { ) -> Size2D<Au> {
match intrinsic_size { match intrinsic_size {
None => match bg_size { None => match bg_size {
GenericBackgroundSize::Cover | GenericBackgroundSize::Contain => bounds_size, BackgroundSize::Cover | BackgroundSize::Contain => bounds_size,
GenericBackgroundSize::Explicit { width, height } => Size2D::new( BackgroundSize::ExplicitSize { width, height } => Size2D::new(
width width
.to_used_value(bounds_size.width) .to_used_value(bounds_size.width)
.unwrap_or(bounds_size.width), .unwrap_or(bounds_size.width),
@ -73,20 +70,16 @@ fn compute_background_image_size(
let bounds_aspect_ratio = let bounds_aspect_ratio =
bounds_size.width.to_f32_px() / bounds_size.height.to_f32_px(); bounds_size.width.to_f32_px() / bounds_size.height.to_f32_px();
match (bg_size, image_aspect_ratio < bounds_aspect_ratio) { match (bg_size, image_aspect_ratio < bounds_aspect_ratio) {
(GenericBackgroundSize::Contain, false) | (GenericBackgroundSize::Cover, true) => { (BackgroundSize::Contain, false) | (BackgroundSize::Cover, true) => Size2D::new(
Size2D::new( bounds_size.width,
bounds_size.width, bounds_size.width.scale_by(image_aspect_ratio.recip()),
bounds_size.width.scale_by(image_aspect_ratio.recip()), ),
) (BackgroundSize::Contain, true) | (BackgroundSize::Cover, false) => Size2D::new(
}, bounds_size.height.scale_by(image_aspect_ratio),
(GenericBackgroundSize::Contain, true) | (GenericBackgroundSize::Cover, false) => { bounds_size.height,
Size2D::new( ),
bounds_size.height.scale_by(image_aspect_ratio),
bounds_size.height,
)
},
( (
GenericBackgroundSize::Explicit { BackgroundSize::ExplicitSize {
width, width,
height: NonNegativeLengthPercentageOrAuto::Auto, height: NonNegativeLengthPercentageOrAuto::Auto,
}, },
@ -98,7 +91,7 @@ fn compute_background_image_size(
Size2D::new(width, width.scale_by(image_aspect_ratio.recip())) Size2D::new(width, width.scale_by(image_aspect_ratio.recip()))
}, },
( (
GenericBackgroundSize::Explicit { BackgroundSize::ExplicitSize {
width: NonNegativeLengthPercentageOrAuto::Auto, width: NonNegativeLengthPercentageOrAuto::Auto,
height, height,
}, },
@ -109,7 +102,7 @@ fn compute_background_image_size(
.unwrap_or(own_size.height); .unwrap_or(own_size.height);
Size2D::new(height.scale_by(image_aspect_ratio), height) Size2D::new(height.scale_by(image_aspect_ratio), height)
}, },
(GenericBackgroundSize::Explicit { width, height }, _) => Size2D::new( (BackgroundSize::ExplicitSize { width, height }, _) => Size2D::new(
width width
.to_used_value(bounds_size.width) .to_used_value(bounds_size.width)
.unwrap_or(own_size.width), .unwrap_or(own_size.width),

View file

@ -2,8 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// FIXME(rust-lang/rust#26264): Remove GenericBorderImageSideWidth.
use crate::display_list::ToLayout; use crate::display_list::ToLayout;
use app_units::Au; use app_units::Au;
use euclid::{Rect, SideOffsets2D, Size2D}; use euclid::{Rect, SideOffsets2D, Size2D};
@ -11,11 +9,9 @@ use style::computed_values::border_image_outset::T as BorderImageOutset;
use style::properties::style_structs::Border; use style::properties::style_structs::Border;
use style::values::computed::NumberOrPercentage; use style::values::computed::NumberOrPercentage;
use style::values::computed::{BorderCornerRadius, BorderImageWidth}; use style::values::computed::{BorderCornerRadius, BorderImageWidth};
use style::values::computed::{BorderImageSideWidth, LengthOrNumber}; use style::values::computed::{BorderImageSideWidth, NonNegativeLengthOrNumber};
use style::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use style::values::generics::rect::Rect as StyleRect; use style::values::generics::rect::Rect as StyleRect;
use style::values::generics::NonNegative; use style::values::generics::NonNegative;
use style::values::Either;
use webrender_api::{BorderRadius, BorderSide, BorderStyle, ColorF}; use webrender_api::{BorderRadius, BorderSide, BorderStyle, ColorF};
use webrender_api::{LayoutSideOffsets, LayoutSize, NormalBorder}; use webrender_api::{LayoutSideOffsets, LayoutSize, NormalBorder};
@ -140,10 +136,10 @@ pub fn simple(color: ColorF, style: BorderStyle) -> NormalBorder {
} }
} }
fn side_image_outset(outset: LengthOrNumber, border_width: Au) -> Au { fn side_image_outset(outset: NonNegativeLengthOrNumber, border_width: Au) -> Au {
match outset { match outset {
Either::First(length) => length.into(), NonNegativeLengthOrNumber::Length(length) => length.into(),
Either::Second(factor) => border_width.scale_by(factor), NonNegativeLengthOrNumber::Number(factor) => border_width.scale_by(factor.0),
} }
} }
@ -163,9 +159,9 @@ fn side_image_width(
total_length: Au, total_length: Au,
) -> f32 { ) -> f32 {
match border_image_width { match border_image_width {
GenericBorderImageSideWidth::Length(v) => v.to_used_value(total_length).to_f32_px(), BorderImageSideWidth::Length(v) => v.to_used_value(total_length).to_f32_px(),
GenericBorderImageSideWidth::Number(x) => border_width * x.0, BorderImageSideWidth::Number(x) => border_width * x.0,
GenericBorderImageSideWidth::Auto => border_width, BorderImageSideWidth::Auto => border_width,
} }
} }

View file

@ -763,7 +763,7 @@ impl Fragment {
let background_size = let background_size =
get_cyclic(&style.get_background().background_size.0, i).clone(); get_cyclic(&style.get_background().background_size.0, i).clone();
let size = match background_size { let size = match background_size {
BackgroundSize::Explicit { width, height } => Size2D::new( BackgroundSize::ExplicitSize { width, height } => Size2D::new(
width width
.to_used_value(bounding_box_size.width) .to_used_value(bounding_box_size.width)
.unwrap_or(bounding_box_size.width), .unwrap_or(bounding_box_size.width),

View file

@ -30,7 +30,6 @@ use style::properties::ComputedValues;
use style::servo::restyle_damage::ServoRestyleDamage; use style::servo::restyle_damage::ServoRestyleDamage;
use style::values::computed::flex::FlexBasis; use style::values::computed::flex::FlexBasis;
use style::values::computed::{MaxSize, Size}; use style::values::computed::{MaxSize, Size};
use style::values::generics::flex::FlexBasis as GenericFlexBasis;
/// The size of an axis. May be a specified size, a min/max /// The size of an axis. May be a specified size, a min/max
/// constraint, or an unlimited size /// constraint, or an unlimited size
@ -61,8 +60,8 @@ impl AxisSize {
/// is definite after flex size resolving. /// is definite after flex size resolving.
fn from_flex_basis(flex_basis: FlexBasis, main_length: Size, containing_length: Au) -> MaybeAuto { fn from_flex_basis(flex_basis: FlexBasis, main_length: Size, containing_length: Au) -> MaybeAuto {
let width = match flex_basis { let width = match flex_basis {
GenericFlexBasis::Content => return MaybeAuto::Auto, FlexBasis::Content => return MaybeAuto::Auto,
GenericFlexBasis::Width(width) => width, FlexBasis::Size(width) => width,
}; };
let width = match width { let width = match width {

View file

@ -57,6 +57,7 @@ include = [
"CursorKind", "CursorKind",
"Display", "Display",
"DisplayMode", "DisplayMode",
"PrefersColorScheme",
"ExtremumLength", "ExtremumLength",
"FillRule", "FillRule",
"FontDisplay", "FontDisplay",
@ -69,6 +70,7 @@ include = [
"UserSelect", "UserSelect",
"Float", "Float",
"OverscrollBehavior", "OverscrollBehavior",
"ScrollSnapAlign",
"ScrollSnapType", "ScrollSnapType",
"OverflowAnchor", "OverflowAnchor",
"OverflowClipBox", "OverflowClipBox",
@ -77,32 +79,97 @@ include = [
"LengthPercentage", "LengthPercentage",
"NonNegativeLengthPercentage", "NonNegativeLengthPercentage",
"LengthPercentageOrAuto", "LengthPercentageOrAuto",
"NonNegativeLengthPercentageOrAuto",
"Rect", "Rect",
"IntersectionObserverRootMargin", "IntersectionObserverRootMargin",
"Size",
"MaxSize",
"FlexBasis",
"Position",
"BackgroundSize",
"BorderImageSlice",
"NonNegativeLengthOrNumberRect",
"Perspective",
"ZIndex",
"TransformOrigin",
] ]
item_types = ["enums", "structs", "typedefs"] item_types = ["enums", "structs", "typedefs"]
[export.body] [export.body]
"CSSPixelLength" = """
inline nscoord ToAppUnits() const;
"""
"LengthPercentage" = """ "LengthPercentage" = """
// Defined in nsStyleCoord.h // Defined in nsStyleCoord.h
static constexpr inline StyleLengthPercentage Zero(); static constexpr inline StyleLengthPercentage Zero();
static inline StyleLengthPercentage FromAppUnits(nscoord);
static inline StyleLengthPercentage FromPixels(CSSCoord);
static inline StyleLengthPercentage FromPercentage(float);
inline CSSCoord LengthInCSSPixels() const;
inline float Percentage() const;
inline bool HasPercent() const; inline bool HasPercent() const;
inline bool ConvertsToLength() const; inline bool ConvertsToLength() const;
inline nscoord ToLength() const; inline nscoord ToLength() const;
inline bool ConvertsToPercentage() const; inline bool ConvertsToPercentage() const;
inline bool HasLengthAndPercentage() const;
inline float ToPercentage() const; inline float ToPercentage() const;
inline CSSCoord LengthInCSSPixels() const;
inline float Percentage() const;
inline CSSCoord ResolveToCSSPixels(CSSCoord aPercentageBasisInCSSPixels) const; inline CSSCoord ResolveToCSSPixels(CSSCoord aPercentageBasisInCSSPixels) const;
template<typename T> inline CSSCoord ResolveToCSSPixelsWith(T aPercentageGetter) const; template<typename T> inline CSSCoord ResolveToCSSPixelsWith(T aPercentageGetter) const;
template<typename T, typename U>
inline nscoord Resolve(T aPercentageGetter, U aPercentRoundingFunction) const;
template<typename T>
inline nscoord Resolve(nscoord aPercentageBasis, T aPercentRoundingFunction) const;
template<typename T> inline nscoord Resolve(T aPercentageGetter) const;
inline nscoord Resolve(nscoord aPercentageBasis) const; inline nscoord Resolve(nscoord aPercentageBasis) const;
template<typename T> inline nscoord ResolveWith(T aPercentageGetter) const;
""" """
"GenericLengthPercentageOrAuto" = """ "GenericLengthPercentageOrAuto" = """
inline const StyleLengthPercentage& AsLengthPercentage() const; inline const StyleLengthPercentage& AsLengthPercentage() const;
inline bool HasPercent() const;
inline bool ConvertsToLength() const; inline bool ConvertsToLength() const;
inline nscoord ToLength() const;
inline bool ConvertsToPercentage() const;
inline float ToPercentage() const;
inline bool HasPercent() const;
inline bool HasLengthAndPercentage() const;
"""
"GenericSize" = """
inline const StyleLengthPercentage& AsLengthPercentage() const;
inline StyleExtremumLength AsExtremumLength() const;
inline bool ConvertsToLength() const;
inline nscoord ToLength() const;
inline bool ConvertsToPercentage() const;
inline float ToPercentage() const;
inline bool HasPercent() const;
inline bool HasLengthAndPercentage() const;
inline bool BehavesLikeInitialValueOnBlockAxis() const;
"""
"GenericFlexBasis" = """
inline bool IsAuto() const;
inline const StyleSize& AsSize() const;
"""
"GenericMaxSize" = """
inline const StyleLengthPercentage& AsLengthPercentage() const;
inline StyleExtremumLength AsExtremumLength() const;
inline bool ConvertsToLength() const;
inline nscoord ToLength() const;
inline bool ConvertsToPercentage() const;
inline float ToPercentage() const;
inline bool HasPercent() const;
inline bool HasLengthAndPercentage() const;
inline bool BehavesLikeInitialValueOnBlockAxis() const;
"""
"GenericPosition" = """
inline bool DependsOnPositioningAreaSize() const;
static inline StyleGenericPosition FromPercentage(float);
"""
"GenericBackgroundSize" = """
bool IsInitialValue() const;
""" """
"Rect" = """ "Rect" = """

View file

@ -23,13 +23,10 @@ use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::{Angle, Gradient, Image}; use crate::values::computed::{Angle, Gradient, Image};
use crate::values::computed::{Integer, LengthPercentage}; use crate::values::computed::{Integer, LengthPercentage};
use crate::values::computed::{Length, Percentage, TextAlign}; use crate::values::computed::{Length, Percentage, TextAlign};
use crate::values::computed::{LengthPercentageOrAuto, NonNegativeLengthPercentageOrAuto};
use crate::values::generics::box_::VerticalAlign; use crate::values::generics::box_::VerticalAlign;
use crate::values::generics::grid::{TrackListValue, TrackSize}; use crate::values::generics::grid::{TrackListValue, TrackSize};
use crate::values::generics::image::{CompatMode, GradientItem, Image as GenericImage}; use crate::values::generics::image::{CompatMode, GradientItem, Image as GenericImage};
use crate::values::generics::length::LengthPercentageOrAuto as GenericLengthPercentageOrAuto;
use crate::values::generics::rect::Rect; use crate::values::generics::rect::Rect;
use crate::values::generics::NonNegative;
use app_units::Au; use app_units::Au;
use std::f32::consts::PI; use std::f32::consts::PI;
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
@ -62,42 +59,6 @@ impl From<nsStyleCoord_CalcValue> for LengthPercentage {
) )
} }
} }
impl NonNegativeLengthPercentageOrAuto {
/// Convert this value in an appropriate `nsStyleCoord::CalcValue`.
pub fn to_calc_value(&self) -> Option<nsStyleCoord_CalcValue> {
match *self {
GenericLengthPercentageOrAuto::LengthPercentage(ref len) => Some(From::from(len.0)),
GenericLengthPercentageOrAuto::Auto => None,
}
}
}
impl From<nsStyleCoord_CalcValue> for LengthPercentageOrAuto {
fn from(other: nsStyleCoord_CalcValue) -> LengthPercentageOrAuto {
GenericLengthPercentageOrAuto::LengthPercentage(LengthPercentage::from(other))
}
}
// FIXME(emilio): A lot of these impl From should probably become explicit or
// disappear as we move more stuff to cbindgen.
impl From<nsStyleCoord_CalcValue> for NonNegativeLengthPercentageOrAuto {
fn from(other: nsStyleCoord_CalcValue) -> Self {
GenericLengthPercentageOrAuto::LengthPercentage(NonNegative(
LengthPercentage::with_clamping_mode(
Au(other.mLength).into(),
if other.mHasPercent {
Some(Percentage(other.mPercent))
} else {
None
},
AllowedNumericType::NonNegative,
/* was_calc = */ true,
),
))
}
}
impl From<Angle> for CoordDataValue { impl From<Angle> for CoordDataValue {
fn from(reference: Angle) -> Self { fn from(reference: Angle) -> Self {
CoordDataValue::Degree(reference.degrees()) CoordDataValue::Degree(reference.degrees())
@ -614,7 +575,6 @@ pub mod basic_shape {
//! Conversions from and to CSS shape representations. //! Conversions from and to CSS shape representations.
use crate::gecko::values::GeckoStyleCoordConvertible; use crate::gecko::values::GeckoStyleCoordConvertible;
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::{nsStyleCoord, nsStyleCorners}; use crate::gecko_bindings::structs::{nsStyleCoord, nsStyleCorners};
use crate::gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType}; use crate::gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType};
use crate::gecko_bindings::structs::{ use crate::gecko_bindings::structs::{
@ -628,7 +588,6 @@ pub mod basic_shape {
use crate::values::computed::border::{BorderCornerRadius, BorderRadius}; use crate::values::computed::border::{BorderCornerRadius, BorderRadius};
use crate::values::computed::length::LengthPercentage; use crate::values::computed::length::LengthPercentage;
use crate::values::computed::motion::OffsetPath; use crate::values::computed::motion::OffsetPath;
use crate::values::computed::position;
use crate::values::computed::url::ComputedUrl; use crate::values::computed::url::ComputedUrl;
use crate::values::generics::basic_shape::{ use crate::values::generics::basic_shape::{
BasicShape as GenericBasicShape, InsetRect, Polygon, BasicShape as GenericBasicShape, InsetRect, Polygon,
@ -759,12 +718,12 @@ pub mod basic_shape {
}, },
StyleBasicShapeType::Circle => GenericBasicShape::Circle(Circle { StyleBasicShapeType::Circle => GenericBasicShape::Circle(Circle {
radius: (&other.mCoordinates[0]).into(), radius: (&other.mCoordinates[0]).into(),
position: (&other.mPosition).into(), position: other.mPosition,
}), }),
StyleBasicShapeType::Ellipse => GenericBasicShape::Ellipse(Ellipse { StyleBasicShapeType::Ellipse => GenericBasicShape::Ellipse(Ellipse {
semiaxis_x: (&other.mCoordinates[0]).into(), semiaxis_x: (&other.mCoordinates[0]).into(),
semiaxis_y: (&other.mCoordinates[1]).into(), semiaxis_y: (&other.mCoordinates[1]).into(),
position: (&other.mPosition).into(), position: other.mPosition,
}), }),
StyleBasicShapeType::Polygon => { StyleBasicShapeType::Polygon => {
let mut coords = Vec::with_capacity(other.mCoordinates.len() / 2); let mut coords = Vec::with_capacity(other.mCoordinates.len() / 2);
@ -852,17 +811,6 @@ pub mod basic_shape {
} }
} }
// Can't be a From impl since we need to set an existing
// Position, not create a new one
impl From<position::Position> for structs::Position {
fn from(other: position::Position) -> Self {
structs::Position {
mXPosition: other.horizontal.into(),
mYPosition: other.vertical.into(),
}
}
}
impl<'a> From<&'a nsStyleCoord> for ShapeRadius { impl<'a> From<&'a nsStyleCoord> for ShapeRadius {
fn from(other: &'a nsStyleCoord) -> Self { fn from(other: &'a nsStyleCoord) -> Self {
let other = other.borrow(); let other = other.borrow();
@ -871,15 +819,6 @@ pub mod basic_shape {
} }
} }
impl<'a> From<&'a structs::Position> for position::Position {
fn from(other: &'a structs::Position) -> Self {
position::Position {
horizontal: other.mXPosition.into(),
vertical: other.mYPosition.into(),
}
}
}
impl From<ShapeBox> for StyleGeometryBox { impl From<ShapeBox> for StyleGeometryBox {
fn from(reference: ShapeBox) -> Self { fn from(reference: ShapeBox) -> Self {
use crate::gecko_bindings::structs::StyleGeometryBox::*; use crate::gecko_bindings::structs::StyleGeometryBox::*;

View file

@ -280,6 +280,16 @@ enum PrefersReducedMotion {
Reduce, Reduce,
} }
/// Values for the prefers-color-scheme media feature.
#[derive(Clone, Copy, Debug, FromPrimitive, Parse, PartialEq, ToCss)]
#[repr(u8)]
#[allow(missing_docs)]
pub enum PrefersColorScheme {
Light,
Dark,
NoPreference,
}
/// https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-motion /// https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-motion
fn eval_prefers_reduced_motion(device: &Device, query_value: Option<PrefersReducedMotion>) -> bool { fn eval_prefers_reduced_motion(device: &Device, query_value: Option<PrefersReducedMotion>) -> bool {
let prefers_reduced = let prefers_reduced =
@ -348,6 +358,16 @@ fn eval_overflow_inline(device: &Device, query_value: Option<OverflowInline>) ->
} }
} }
/// https://drafts.csswg.org/mediaqueries-5/#prefers-color-scheme
fn eval_prefers_color_scheme(device: &Device, query_value: Option<PrefersColorScheme>) -> bool {
let prefers_color_scheme =
unsafe { bindings::Gecko_MediaFeatures_PrefersColorScheme(device.document()) };
match query_value {
Some(v) => prefers_color_scheme == v,
None => prefers_color_scheme != PrefersColorScheme::NoPreference,
}
}
/// https://drafts.csswg.org/mediaqueries-4/#mf-interaction /// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
bitflags! { bitflags! {
struct PointerCapabilities: u8 { struct PointerCapabilities: u8 {
@ -441,7 +461,7 @@ fn eval_moz_is_glyph(
query_value: Option<bool>, query_value: Option<bool>,
_: Option<RangeOrOperator>, _: Option<RangeOrOperator>,
) -> bool { ) -> bool {
let is_glyph = unsafe { (*device.document()).mIsSVGGlyphsDocument() }; let is_glyph = device.document().mIsSVGGlyphsDocument();
query_value.map_or(is_glyph, |v| v == is_glyph) query_value.map_or(is_glyph, |v| v == is_glyph)
} }
@ -526,7 +546,7 @@ lazy_static! {
/// to support new types in these entries and (2) ensuring that either /// to support new types in these entries and (2) ensuring that either
/// nsPresContext::MediaFeatureValuesChanged is called when the value that /// nsPresContext::MediaFeatureValuesChanged is called when the value that
/// would be returned by the evaluator function could change. /// would be returned by the evaluator function could change.
pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 52] = [ pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 53] = [
feature!( feature!(
atom!("width"), atom!("width"),
AllowsRanges::Yes, AllowsRanges::Yes,
@ -657,6 +677,12 @@ lazy_static! {
keyword_evaluator!(eval_overflow_inline, OverflowInline), keyword_evaluator!(eval_overflow_inline, OverflowInline),
ParsingRequirements::empty(), ParsingRequirements::empty(),
), ),
feature!(
atom!("prefers-color-scheme"),
AllowsRanges::No,
keyword_evaluator!(eval_prefers_color_scheme, PrefersColorScheme),
ParsingRequirements::empty(),
),
feature!( feature!(
atom!("pointer"), atom!("pointer"),
AllowsRanges::No, AllowsRanges::No,

View file

@ -85,7 +85,9 @@ impl Device {
assert!(!pres_context.is_null()); assert!(!pres_context.is_null());
Device { Device {
pres_context, pres_context,
default_values: ComputedValues::default_values(unsafe { &*pres_context }), default_values: ComputedValues::default_values(unsafe {
&*(*pres_context).mDocument.mRawPtr
}),
// FIXME(bz): Seems dubious? // FIXME(bz): Seems dubious?
root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize), root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize),
body_text_color: AtomicUsize::new(unsafe { &*pres_context }.mDefaultColor as usize), body_text_color: AtomicUsize::new(unsafe { &*pres_context }.mDefaultColor as usize),
@ -162,13 +164,13 @@ impl Device {
/// Gets the document pointer. /// Gets the document pointer.
#[inline] #[inline]
pub fn document(&self) -> *mut structs::Document { pub fn document(&self) -> &structs::Document {
self.pres_context().mDocument.mRawPtr unsafe { &*self.pres_context().mDocument.mRawPtr }
} }
/// Recreates the default computed values. /// Recreates the default computed values.
pub fn reset_computed_values(&mut self) { pub fn reset_computed_values(&mut self) {
self.default_values = ComputedValues::default_values(self.pres_context()); self.default_values = ComputedValues::default_values(self.document());
} }
/// Rebuild all the cached data. /// Rebuild all the cached data.

View file

@ -8,7 +8,7 @@
//! `pseudo_element_definition.mako.rs`. If you touch that file, you probably //! `pseudo_element_definition.mako.rs`. If you touch that file, you probably
//! need to update the checked-in files for Servo. //! need to update the checked-in files for Servo.
use crate::gecko_bindings::structs::{self, CSSPseudoElementType}; use crate::gecko_bindings::structs::{self, PseudoStyleType};
use crate::properties::longhands::display::computed_value::T as Display; use crate::properties::longhands::display::computed_value::T as Display;
use crate::properties::{ComputedValues, PropertyFlags}; use crate::properties::{ComputedValues, PropertyFlags};
use crate::selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl}; use crate::selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};

View file

@ -48,17 +48,6 @@ PseudoElement::${pseudo.capitalized_pseudo()}${"({})".format(tree_arg) if pseudo
</%def> </%def>
impl PseudoElement { impl PseudoElement {
/// Get the pseudo-element as an atom.
#[inline]
fn atom(&self) -> Atom {
match *self {
% for pseudo in PSEUDOS:
${pseudo_element_variant(pseudo)} => atom!("${pseudo.value}"),
% endfor
PseudoElement::UnknownWebkit(..) => unreachable!(),
}
}
/// Returns an index of the pseudo-element. /// Returns an index of the pseudo-element.
#[inline] #[inline]
pub fn index(&self) -> usize { pub fn index(&self) -> usize {
@ -138,45 +127,36 @@ impl PseudoElement {
} }
} }
/// Construct a pseudo-element from a `CSSPseudoElementType`. /// Construct a pseudo-element from a `PseudoStyleType`.
#[inline] #[inline]
pub fn from_pseudo_type(type_: CSSPseudoElementType) -> Option<Self> { pub fn from_pseudo_type(type_: PseudoStyleType) -> Option<Self> {
match type_ { match type_ {
% for pseudo in PSEUDOS: % for pseudo in PSEUDOS:
% if not pseudo.is_anon_box(): % if not pseudo.is_tree_pseudo_element():
CSSPseudoElementType::${pseudo.pseudo_ident} => { PseudoStyleType::${pseudo.pseudo_ident} => {
Some(${pseudo_element_variant(pseudo)}) Some(${pseudo_element_variant(pseudo)})
}, },
% endif % endif
% endfor % endfor
_ => None, _ => None,
} }
} }
/// Construct a `CSSPseudoElementType` from a pseudo-element /// Construct a `PseudoStyleType` from a pseudo-element
#[inline] #[inline]
fn pseudo_type(&self) -> CSSPseudoElementType { pub fn pseudo_type(&self) -> PseudoStyleType {
match *self { match *self {
% for pseudo in PSEUDOS: % for pseudo in PSEUDOS:
% if not pseudo.is_anon_box(): % if pseudo.is_tree_pseudo_element():
PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::${pseudo.pseudo_ident}, PseudoElement::${pseudo.capitalized_pseudo()}(..) => PseudoStyleType::XULTree,
% elif pseudo.is_tree_pseudo_element(): % else:
PseudoElement::${pseudo.capitalized_pseudo()}(..) => CSSPseudoElementType::XULTree, PseudoElement::${pseudo.capitalized_pseudo()} => PseudoStyleType::${pseudo.pseudo_ident},
% elif pseudo.is_inheriting_anon_box(): % endif
PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::InheritingAnonBox,
% else:
PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::NonInheritingAnonBox,
% endif
% endfor % endfor
PseudoElement::UnknownWebkit(..) => unreachable!(), PseudoElement::UnknownWebkit(..) => unreachable!(),
} }
} }
/// Get a PseudoInfo for a pseudo
pub fn pseudo_info(&self) -> (*mut structs::nsAtom, CSSPseudoElementType) {
(self.atom().as_ptr(), self.pseudo_type())
}
/// Get the argument list of a tree pseudo-element. /// Get the argument list of a tree pseudo-element.
#[inline] #[inline]
pub fn tree_pseudo_args(&self) -> Option<<&[Atom]> { pub fn tree_pseudo_args(&self) -> Option<<&[Atom]> {
@ -188,45 +168,15 @@ impl PseudoElement {
} }
} }
/// Construct a pseudo-element from an `Atom`.
#[inline]
pub fn from_atom(atom: &Atom) -> Option<Self> {
% for pseudo in PSEUDOS:
% if pseudo.is_tree_pseudo_element():
// We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
% else:
if atom == &atom!("${pseudo.value}") {
return Some(${pseudo_element_variant(pseudo)});
}
% endif
% endfor
None
}
/// Construct a pseudo-element from an anonymous box `Atom`.
#[inline]
pub fn from_anon_box_atom(atom: &Atom) -> Option<Self> {
% for pseudo in PSEUDOS:
% if pseudo.is_tree_pseudo_element():
// We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
% elif pseudo.is_anon_box():
if atom == &atom!("${pseudo.value}") {
return Some(${pseudo_element_variant(pseudo)});
}
% endif
% endfor
None
}
/// Construct a tree pseudo-element from atom and args. /// Construct a tree pseudo-element from atom and args.
#[inline] #[inline]
pub fn from_tree_pseudo_atom(atom: &Atom, args: Box<[Atom]>) -> Option<Self> { pub fn from_tree_pseudo_atom(atom: &Atom, args: Box<[Atom]>) -> Option<Self> {
% for pseudo in PSEUDOS: % for pseudo in PSEUDOS:
% if pseudo.is_tree_pseudo_element(): % if pseudo.is_tree_pseudo_element():
if atom == &atom!("${pseudo.value}") { if atom == &atom!("${pseudo.value}") {
return Some(PseudoElement::${pseudo.capitalized_pseudo()}(args.into())); return Some(PseudoElement::${pseudo.capitalized_pseudo()}(args.into()));
} }
% endif % endif
% endfor % endfor
None None
} }

View file

@ -41,8 +41,10 @@ class Atom:
# The type of atom: "Atom", "PseudoElement", "NonInheritingAnonBox", # The type of atom: "Atom", "PseudoElement", "NonInheritingAnonBox",
# or "InheritingAnonBox". # or "InheritingAnonBox".
self.atom_type = atom_type self.atom_type = atom_type
if self.is_pseudo() or self.is_anon_box():
if self.is_pseudo_element() or self.is_anon_box() or self.is_tree_pseudo_element():
self.pseudo_ident = (ident.split("_", 1))[1] self.pseudo_ident = (ident.split("_", 1))[1]
if self.is_anon_box(): if self.is_anon_box():
assert self.is_inheriting_anon_box() or self.is_non_inheriting_anon_box() assert self.is_inheriting_anon_box() or self.is_non_inheriting_anon_box()
@ -52,16 +54,21 @@ class Atom:
def capitalized_pseudo(self): def capitalized_pseudo(self):
return self.pseudo_ident[0].upper() + self.pseudo_ident[1:] return self.pseudo_ident[0].upper() + self.pseudo_ident[1:]
def is_pseudo(self): def is_pseudo_element(self):
return self.atom_type == "PseudoElementAtom" return self.atom_type == "PseudoElementAtom"
def is_anon_box(self): def is_anon_box(self):
if self.is_tree_pseudo_element():
return False
return self.is_non_inheriting_anon_box() or self.is_inheriting_anon_box() return self.is_non_inheriting_anon_box() or self.is_inheriting_anon_box()
def is_non_inheriting_anon_box(self): def is_non_inheriting_anon_box(self):
assert not self.is_tree_pseudo_element()
return self.atom_type == "NonInheritingAnonBoxAtom" return self.atom_type == "NonInheritingAnonBoxAtom"
def is_inheriting_anon_box(self): def is_inheriting_anon_box(self):
if self.is_tree_pseudo_element():
return False
return self.atom_type == "InheritingAnonBoxAtom" return self.atom_type == "InheritingAnonBoxAtom"
def is_tree_pseudo_element(self): def is_tree_pseudo_element(self):

View file

@ -7,22 +7,16 @@
//! Different kind of helpers to interact with Gecko values. //! Different kind of helpers to interact with Gecko values.
use crate::counter_style::{Symbol, Symbols}; use crate::counter_style::{Symbol, Symbols};
use crate::gecko_bindings::structs::{self, nsStyleCoord, CounterStylePtr}; use crate::gecko_bindings::structs::{nsStyleCoord, CounterStylePtr};
use crate::gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius}; use crate::gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius};
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
use crate::media_queries::Device;
use crate::values::computed::basic_shape::ShapeRadius as ComputedShapeRadius; use crate::values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
use crate::values::computed::FlexBasis as ComputedFlexBasis; use crate::values::computed::{Angle, Length, LengthPercentage};
use crate::values::computed::{Angle, ExtremumLength, Length, LengthPercentage}; use crate::values::computed::{Number, NumberOrPercentage, Percentage};
use crate::values::computed::{MaxSize as ComputedMaxSize, Size as ComputedSize};
use crate::values::computed::{NonNegativeLengthPercentage, Percentage};
use crate::values::computed::{Number, NumberOrPercentage};
use crate::values::generics::basic_shape::ShapeRadius; use crate::values::generics::basic_shape::ShapeRadius;
use crate::values::generics::box_::Perspective;
use crate::values::generics::flex::FlexBasis;
use crate::values::generics::gecko::ScrollSnapPoint; use crate::values::generics::gecko::ScrollSnapPoint;
use crate::values::generics::grid::{TrackBreadth, TrackKeyword}; use crate::values::generics::grid::{TrackBreadth, TrackKeyword};
use crate::values::generics::length::{LengthPercentageOrAuto, MaxSize, Size}; use crate::values::generics::length::LengthPercentageOrAuto;
use crate::values::generics::{CounterStyleOrNone, NonNegative}; use crate::values::generics::{CounterStyleOrNone, NonNegative};
use crate::values::{Auto, Either, None_, Normal}; use crate::values::{Auto, Either, None_, Normal};
use crate::Atom; use crate::Atom;
@ -80,29 +74,6 @@ where
} }
} }
impl GeckoStyleCoordConvertible for ComputedFlexBasis {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
FlexBasis::Content => coord.set_value(CoordDataValue::Enumerated(
structs::NS_STYLE_FLEX_BASIS_CONTENT,
)),
FlexBasis::Width(ref w) => w.to_gecko_style_coord(coord),
}
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
if let Some(width) = ComputedSize::from_gecko_style_coord(coord) {
return Some(FlexBasis::Width(width));
}
if let CoordDataValue::Enumerated(structs::NS_STYLE_FLEX_BASIS_CONTENT) = coord.as_value() {
return Some(FlexBasis::Content);
}
None
}
}
impl GeckoStyleCoordConvertible for Number { impl GeckoStyleCoordConvertible for Number {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
coord.set_value(CoordDataValue::Factor(*self)); coord.set_value(CoordDataValue::Factor(*self));
@ -336,60 +307,6 @@ impl GeckoStyleCoordConvertible for Normal {
} }
} }
impl GeckoStyleCoordConvertible for ExtremumLength {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
coord.set_value(CoordDataValue::Enumerated(*self as u32));
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
use num_traits::FromPrimitive;
match coord.as_value() {
CoordDataValue::Enumerated(v) => ExtremumLength::from_u32(v),
_ => None,
}
}
}
impl GeckoStyleCoordConvertible for ComputedSize {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
Size::LengthPercentage(ref lpoa) => lpoa.to_gecko_style_coord(coord),
Size::Auto => coord.set_value(CoordDataValue::Auto),
Size::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
}
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
if let CoordDataValue::Auto = coord.as_value() {
return Some(Size::Auto);
}
if let Some(lp) = NonNegativeLengthPercentage::from_gecko_style_coord(coord) {
return Some(Size::LengthPercentage(lp));
}
ExtremumLength::from_gecko_style_coord(coord).map(Size::ExtremumLength)
}
}
impl GeckoStyleCoordConvertible for ComputedMaxSize {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
MaxSize::LengthPercentage(ref lpon) => lpon.to_gecko_style_coord(coord),
MaxSize::None => coord.set_value(CoordDataValue::None),
MaxSize::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
}
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
if let CoordDataValue::None = coord.as_value() {
return Some(MaxSize::None);
}
if let Some(lp) = NonNegativeLengthPercentage::from_gecko_style_coord(coord) {
return Some(MaxSize::LengthPercentage(lp));
}
ExtremumLength::from_gecko_style_coord(coord).map(MaxSize::ExtremumLength)
}
}
impl GeckoStyleCoordConvertible for ScrollSnapPoint<LengthPercentage> { impl GeckoStyleCoordConvertible for ScrollSnapPoint<LengthPercentage> {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match self.repeated() { match self.repeated() {
@ -412,27 +329,6 @@ impl GeckoStyleCoordConvertible for ScrollSnapPoint<LengthPercentage> {
} }
} }
impl<L> GeckoStyleCoordConvertible for Perspective<L>
where
L: GeckoStyleCoordConvertible,
{
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
Perspective::None => coord.set_value(CoordDataValue::None),
Perspective::Length(ref l) => l.to_gecko_style_coord(coord),
};
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
use crate::gecko_bindings::structs::root::nsStyleUnit;
if coord.unit() == nsStyleUnit::eStyleUnit_None {
return Some(Perspective::None);
}
Some(Perspective::Length(L::from_gecko_style_coord(coord)?))
}
}
/// Convert a given RGBA value to `nscolor`. /// Convert a given RGBA value to `nscolor`.
pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 { pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
((rgba.alpha as u32) << 24) | ((rgba.alpha as u32) << 24) |
@ -468,16 +364,15 @@ pub fn round_border_to_device_pixels(width: Au, au_per_device_px: Au) -> Au {
impl CounterStyleOrNone { impl CounterStyleOrNone {
/// Convert this counter style to a Gecko CounterStylePtr. /// Convert this counter style to a Gecko CounterStylePtr.
pub fn to_gecko_value(self, gecko_value: &mut CounterStylePtr, device: &Device) { pub fn to_gecko_value(self, gecko_value: &mut CounterStylePtr) {
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name; use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name;
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols; use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols;
let pres_context = device.pres_context();
match self { match self {
CounterStyleOrNone::None => unsafe { CounterStyleOrNone::None => unsafe {
set_name(gecko_value, atom!("none").into_addrefed(), pres_context); set_name(gecko_value, atom!("none").into_addrefed());
}, },
CounterStyleOrNone::Name(name) => unsafe { CounterStyleOrNone::Name(name) => unsafe {
set_name(gecko_value, name.0.into_addrefed(), pres_context); set_name(gecko_value, name.0.into_addrefed());
}, },
CounterStyleOrNone::Symbols(symbols_type, symbols) => { CounterStyleOrNone::Symbols(symbols_type, symbols) => {
let symbols: Vec<_> = symbols let symbols: Vec<_> = symbols

View file

@ -7,10 +7,10 @@
use crate::gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; use crate::gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use crate::gecko_bindings::structs::StyleComplexColor; use crate::gecko_bindings::structs::StyleComplexColor;
use crate::gecko_bindings::structs::StyleComplexColor_Tag as Tag; use crate::gecko_bindings::structs::StyleComplexColor_Tag as Tag;
use crate::values::computed::ui::ColorOrAuto; use crate::values::computed::{Color as ComputedColor, ColorOrAuto, RGBAColor as ComputedRGBA};
use crate::values::computed::{Color as ComputedColor, RGBAColor as ComputedRGBA}; use crate::values::generics::color::{
use crate::values::generics::color::{Color as GenericColor, ComplexColorRatios}; Color as GenericColor, ColorOrAuto as GenericColorOrAuto, ComplexColorRatios,
use crate::values::{Auto, Either}; };
impl StyleComplexColor { impl StyleComplexColor {
/// Create a `StyleComplexColor` value that represents `currentColor`. /// Create a `StyleComplexColor` value that represents `currentColor`.
@ -94,8 +94,8 @@ impl From<StyleComplexColor> for ComputedColor {
impl From<ColorOrAuto> for StyleComplexColor { impl From<ColorOrAuto> for StyleComplexColor {
fn from(other: ColorOrAuto) -> Self { fn from(other: ColorOrAuto) -> Self {
match other { match other {
Either::First(color) => color.into(), GenericColorOrAuto::Color(color) => color.into(),
Either::Second(_) => StyleComplexColor::auto(), GenericColorOrAuto::Auto => StyleComplexColor::auto(),
} }
} }
} }
@ -103,9 +103,9 @@ impl From<ColorOrAuto> for StyleComplexColor {
impl From<StyleComplexColor> for ColorOrAuto { impl From<StyleComplexColor> for ColorOrAuto {
fn from(other: StyleComplexColor) -> Self { fn from(other: StyleComplexColor) -> Self {
if other.mTag != Tag::eAuto { if other.mTag != Tag::eAuto {
Either::First(other.into()) GenericColorOrAuto::Color(other.into())
} else { } else {
Either::Second(Auto) GenericColorOrAuto::Auto
} }
} }
} }

View file

@ -236,7 +236,7 @@ where
parent_style.unwrap(), parent_style.unwrap(),
parent_style_ignoring_first_line.unwrap() parent_style_ignoring_first_line.unwrap()
) || ) ||
parent_style.unwrap().pseudo() == Some(PseudoElement::FirstLine) parent_style.unwrap().is_first_line_style()
); );
let inherited_style = parent_style.unwrap_or(device.default_computed_values()); let inherited_style = parent_style.unwrap_or(device.default_computed_values());
@ -745,13 +745,13 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
// FIXME(emilio): Why both setting the generic and passing it // FIXME(emilio): Why both setting the generic and passing it
// down? // down?
let pres_context = self.context.builder.device.pres_context(); let doc = self.context.builder.device.document();
let gecko_font = self.context.builder.mutate_font().gecko_mut(); let gecko_font = self.context.builder.mutate_font().gecko_mut();
gecko_font.mGenericID = generic; gecko_font.mGenericID = generic;
unsafe { unsafe {
crate::gecko_bindings::bindings::Gecko_nsStyleFont_PrefillDefaultForGeneric( crate::gecko_bindings::bindings::Gecko_nsStyleFont_PrefillDefaultForGeneric(
gecko_font, gecko_font,
pres_context, doc,
generic, generic,
); );
} }

View file

@ -339,6 +339,7 @@ class Longhand(object):
"Resize", "Resize",
"SVGOpacity", "SVGOpacity",
"SVGPaintOrder", "SVGPaintOrder",
"ScrollSnapAlign",
"ScrollSnapType", "ScrollSnapType",
"TextAlign", "TextAlign",
"TextDecorationLine", "TextDecorationLine",

View file

@ -35,10 +35,9 @@ use crate::gecko_bindings::bindings::Gecko_SetListStyleImageNone;
use crate::gecko_bindings::bindings::Gecko_SetListStyleImageImageValue; use crate::gecko_bindings::bindings::Gecko_SetListStyleImageImageValue;
use crate::gecko_bindings::bindings::Gecko_SetNullImageValue; use crate::gecko_bindings::bindings::Gecko_SetNullImageValue;
use crate::gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom}; use crate::gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom};
use crate::gecko_bindings::bindings::RawGeckoPresContextBorrowed;
use crate::gecko_bindings::structs; use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsCSSPropertyID; use crate::gecko_bindings::structs::nsCSSPropertyID;
use crate::gecko_bindings::structs::mozilla::CSSPseudoElementType; use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut}; use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
use crate::gecko_bindings::sugar::refptr::RefPtr; use crate::gecko_bindings::sugar::refptr::RefPtr;
use crate::gecko::values::convert_nscolor_to_rgba; use crate::gecko::values::convert_nscolor_to_rgba;
@ -61,8 +60,6 @@ use crate::values::computed::BorderStyle;
use crate::values::computed::font::FontSize; use crate::values::computed::font::FontSize;
use crate::values::computed::effects::{BoxShadow, Filter, SimpleShadow}; use crate::values::computed::effects::{BoxShadow, Filter, SimpleShadow};
use crate::values::generics::column::ColumnCount; use crate::values::generics::column::ColumnCount;
use crate::values::generics::position::ZIndex;
use crate::values::generics::text::MozTabSize;
use crate::values::generics::transform::TransformStyle; use crate::values::generics::transform::TransformStyle;
use crate::values::generics::url::UrlOrNone; use crate::values::generics::url::UrlOrNone;
@ -102,7 +99,7 @@ impl ComputedValues {
).to_outer(pseudo) ).to_outer(pseudo)
} }
pub fn default_values(pres_context: RawGeckoPresContextBorrowed) -> Arc<Self> { pub fn default_values(doc: &structs::Document) -> Arc<Self> {
ComputedValuesInner::new( ComputedValuesInner::new(
/* custom_properties = */ None, /* custom_properties = */ None,
/* writing_mode = */ WritingMode::empty(), // FIXME(bz): This seems dubious /* writing_mode = */ WritingMode::empty(), // FIXME(bz): This seems dubious
@ -110,31 +107,22 @@ impl ComputedValues {
/* rules = */ None, /* rules = */ None,
/* visited_style = */ None, /* visited_style = */ None,
% for style_struct in data.style_structs: % for style_struct in data.style_structs:
style_structs::${style_struct.name}::default(pres_context), style_structs::${style_struct.name}::default(doc),
% endfor % endfor
).to_outer(None) ).to_outer(None)
} }
#[inline]
pub fn pseudo(&self) -> Option<PseudoElement> { pub fn pseudo(&self) -> Option<PseudoElement> {
let atom = (self.0).mPseudoTag.mRawPtr; if self.0.mPseudoType == PseudoStyleType::NotPseudo {
if atom.is_null() {
return None; return None;
} }
PseudoElement::from_pseudo_type(self.0.mPseudoType)
let atom = unsafe { Atom::from_raw(atom) };
PseudoElement::from_atom(&atom)
} }
#[inline] #[inline]
fn get_pseudo_type(&self) -> CSSPseudoElementType { pub fn is_first_line_style(&self) -> bool {
self.0.mPseudoType self.pseudo() == Some(PseudoElement::FirstLine)
}
#[inline]
pub fn is_anon_box(&self) -> bool {
let our_type = self.get_pseudo_type();
return our_type == CSSPseudoElementType::InheritingAnonBox ||
our_type == CSSPseudoElementType::NonInheritingAnonBox;
} }
/// Returns true if the display property is changed from 'none' to others. /// Returns true if the display property is changed from 'none' to others.
@ -213,9 +201,9 @@ impl ComputedValuesInner {
self, self,
pseudo: Option<<&PseudoElement>, pseudo: Option<<&PseudoElement>,
) -> Arc<ComputedValues> { ) -> Arc<ComputedValues> {
let (pseudo_tag, pseudo_ty) = match pseudo { let pseudo_ty = match pseudo {
Some(p) => p.pseudo_info(), Some(p) => p.pseudo_type(),
None => (ptr::null_mut(), structs::CSSPseudoElementType::NotPseudo), None => structs::PseudoStyleType::NotPseudo,
}; };
let arc = unsafe { let arc = unsafe {
let arc: Arc<ComputedValues> = Arc::new(uninitialized()); let arc: Arc<ComputedValues> = Arc::new(uninitialized());
@ -223,7 +211,6 @@ impl ComputedValuesInner {
&arc.0 as *const _ as *mut _, &arc.0 as *const _ as *mut _,
&self, &self,
pseudo_ty, pseudo_ty,
pseudo_tag
); );
// We're simulating a move by having C++ do a memcpy and then forgetting // We're simulating a move by having C++ do a memcpy and then forgetting
// it on this end. // it on this end.
@ -453,22 +440,6 @@ def set_gecko_property(ffi_name, expr):
} }
</%def> </%def>
<%def name="impl_position(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.into()")}
${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.into()")}
}
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
longhands::${ident}::computed_value::T {
horizontal: self.gecko.${gecko_ffi_name}.mXPosition.into(),
vertical: self.gecko.${gecko_ffi_name}.mYPosition.into(),
}
}
</%def>
<%def name="impl_color(ident, gecko_ffi_name)"> <%def name="impl_color(ident, gecko_ffi_name)">
<%call expr="impl_color_setter(ident, gecko_ffi_name)"></%call> <%call expr="impl_color_setter(ident, gecko_ffi_name)"></%call>
<%call expr="impl_color_copy(ident, gecko_ffi_name)"></%call> <%call expr="impl_color_copy(ident, gecko_ffi_name)"></%call>
@ -1217,55 +1188,6 @@ pub fn clone_transform_from_list(
} }
</%def> </%def>
<%def name="impl_transform_origin(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: values::computed::TransformOrigin) {
self.gecko.${gecko_ffi_name}[0].set(v.horizontal);
self.gecko.${gecko_ffi_name}[1].set(v.vertical);
// transform-origin supports the third value for depth, while
// -moz-window-transform-origin doesn't. The following code is
// for handling this difference. If we can have more knowledge
// about the type here, we may want to check that the length is
// exactly either 2 or 3 in compile time.
if let Some(third) = self.gecko.${gecko_ffi_name}.get_mut(2) {
third.set(v.depth);
}
}
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name}[0].copy_from(&other.gecko.${gecko_ffi_name}[0]);
self.gecko.${gecko_ffi_name}[1].copy_from(&other.gecko.${gecko_ffi_name}[1]);
if let (Some(self_third), Some(other_third)) =
(self.gecko.${gecko_ffi_name}.get_mut(2), other.gecko.${gecko_ffi_name}.get(2))
{
self_third.copy_from(other_third)
}
}
#[allow(non_snake_case)]
pub fn reset_${ident}(&mut self, other: &Self) {
self.copy_${ident}_from(other)
}
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> values::computed::TransformOrigin {
use crate::values::computed::{Length, LengthPercentage, TransformOrigin};
TransformOrigin {
horizontal: LengthPercentage::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}[0])
.expect("clone for LengthPercentage failed"),
vertical: LengthPercentage::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}[1])
.expect("clone for LengthPercentage failed"),
depth: if let Some(third) = self.gecko.${gecko_ffi_name}.get(2) {
Length::from_gecko_style_coord(third)
.expect("clone for Length failed")
} else {
Length::new(0.)
},
}
}
</%def>
<%def name="impl_logical(name, **kwargs)"> <%def name="impl_logical(name, **kwargs)">
${helpers.logical_setter(name)} ${helpers.logical_setter(name)}
</%def> </%def>
@ -1273,11 +1195,13 @@ pub fn clone_transform_from_list(
<%def name="impl_style_struct(style_struct)"> <%def name="impl_style_struct(style_struct)">
impl ${style_struct.gecko_struct_name} { impl ${style_struct.gecko_struct_name} {
#[allow(dead_code, unused_variables)] #[allow(dead_code, unused_variables)]
pub fn default(pres_context: RawGeckoPresContextBorrowed) -> Arc<Self> { pub fn default(document: &structs::Document) -> Arc<Self> {
let mut result = Arc::new(${style_struct.gecko_struct_name} { gecko: unsafe { zeroed() } }); let mut result = Arc::new(${style_struct.gecko_struct_name} { gecko: unsafe { zeroed() } });
unsafe { unsafe {
Gecko_Construct_Default_${style_struct.gecko_ffi_name}(&mut Arc::get_mut(&mut result).unwrap().gecko, Gecko_Construct_Default_${style_struct.gecko_ffi_name}(
pres_context); &mut Arc::get_mut(&mut result).unwrap().gecko,
document,
);
} }
result result
} }
@ -1370,6 +1294,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
"Appearance": impl_simple, "Appearance": impl_simple,
"OverscrollBehavior": impl_simple, "OverscrollBehavior": impl_simple,
"OverflowClipBox": impl_simple, "OverflowClipBox": impl_simple,
"ScrollSnapAlign": impl_simple,
"ScrollSnapType": impl_simple, "ScrollSnapType": impl_simple,
"Float": impl_simple, "Float": impl_simple,
"Overflow": impl_simple, "Overflow": impl_simple,
@ -1385,32 +1310,36 @@ impl Clone for ${style_struct.gecko_struct_name} {
"length::NonNegativeLengthOrAuto": impl_style_coord, "length::NonNegativeLengthOrAuto": impl_style_coord,
"length::NonNegativeLengthPercentageOrNormal": impl_style_coord, "length::NonNegativeLengthPercentageOrNormal": impl_style_coord,
"FillRule": impl_simple, "FillRule": impl_simple,
"FlexBasis": impl_style_coord, "FlexBasis": impl_simple,
"Length": impl_absolute_length, "Length": impl_absolute_length,
"LengthOrNormal": impl_style_coord, "LengthOrNormal": impl_style_coord,
"LengthPercentage": impl_simple, "LengthPercentage": impl_simple,
"LengthPercentageOrAuto": impl_style_coord, "LengthPercentageOrAuto": impl_style_coord,
"MaxSize": impl_style_coord, "MaxSize": impl_simple,
"Size": impl_style_coord, "Size": impl_simple,
"MozScriptMinSize": impl_absolute_length, "MozScriptMinSize": impl_absolute_length,
"MozScriptSizeMultiplier": impl_simple, "MozScriptSizeMultiplier": impl_simple,
"NonNegativeLengthPercentage": impl_simple, "NonNegativeLengthPercentage": impl_simple,
"NonNegativeLengthOrNumber": impl_simple,
"NonNegativeLengthOrNumberRect": impl_simple,
"BorderImageSlice": impl_simple,
"NonNegativeNumber": impl_simple, "NonNegativeNumber": impl_simple,
"Number": impl_simple, "Number": impl_simple,
"Opacity": impl_simple, "Opacity": impl_simple,
"OverflowWrap": impl_simple, "OverflowWrap": impl_simple,
"OverflowAnchor": impl_simple, "OverflowAnchor": impl_simple,
"Perspective": impl_style_coord, "Perspective": impl_simple,
"Position": impl_position, "Position": impl_simple,
"RGBAColor": impl_rgba_color, "RGBAColor": impl_rgba_color,
"SVGLength": impl_svg_length, "SVGLength": impl_svg_length,
"SVGOpacity": impl_svg_opacity, "SVGOpacity": impl_svg_opacity,
"SVGPaint": impl_svg_paint, "SVGPaint": impl_svg_paint,
"SVGWidth": impl_svg_length, "SVGWidth": impl_svg_length,
"Transform": impl_transform, "Transform": impl_transform,
"TransformOrigin": impl_transform_origin, "TransformOrigin": impl_simple,
"UserSelect": impl_simple, "UserSelect": impl_simple,
"url::UrlOrNone": impl_css_url, "url::UrlOrNone": impl_css_url,
"ZIndex": impl_simple,
} }
def longhand_method(longhand): def longhand_method(longhand):
@ -1500,8 +1429,8 @@ fn static_assert() {
for x in CORNERS]) %> for x in CORNERS]) %>
<%self:impl_trait style_struct_name="Border" <%self:impl_trait style_struct_name="Border"
skip_longhands="${skip_border_longhands} border-image-source border-image-outset skip_longhands="${skip_border_longhands} border-image-source
border-image-repeat border-image-width border-image-slice"> border-image-repeat border-image-width">
% for side in SIDES: % for side in SIDES:
pub fn set_border_${side.ident}_style(&mut self, v: BorderStyle) { pub fn set_border_${side.ident}_style(&mut self, v: BorderStyle) {
self.gecko.mBorderStyle[${side.index}] = v; self.gecko.mBorderStyle[${side.index}] = v;
@ -1602,8 +1531,6 @@ fn static_assert() {
} }
} }
<% impl_style_sides("border_image_outset") %>
<% <%
border_image_repeat_keywords = ["Stretch", "Repeat", "Round", "Space"] border_image_repeat_keywords = ["Stretch", "Repeat", "Round", "Space"]
%> %>
@ -1645,63 +1572,41 @@ fn static_assert() {
} }
<% impl_style_sides("border_image_width") %> <% impl_style_sides("border_image_width") %>
pub fn set_border_image_slice(&mut self, v: longhands::border_image_slice::computed_value::T) {
use crate::gecko_bindings::structs::{NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, NS_STYLE_BORDER_IMAGE_SLICE_FILL};
v.offsets.to_gecko_rect(&mut self.gecko.mBorderImageSlice);
let fill = if v.fill {
NS_STYLE_BORDER_IMAGE_SLICE_FILL
} else {
NS_STYLE_BORDER_IMAGE_SLICE_NOFILL
};
self.gecko.mBorderImageFill = fill as u8;
}
<%self:copy_sides_style_coord ident="border_image_slice">
self.gecko.mBorderImageFill = other.gecko.mBorderImageFill;
</%self:copy_sides_style_coord>
pub fn clone_border_image_slice(&self) -> longhands::border_image_slice::computed_value::T {
use crate::gecko_bindings::structs::NS_STYLE_BORDER_IMAGE_SLICE_FILL;
use crate::values::computed::{BorderImageSlice, NonNegativeNumberOrPercentage};
type NumberOrPercentageRect = crate::values::generics::rect::Rect<NonNegativeNumberOrPercentage>;
BorderImageSlice {
offsets:
NumberOrPercentageRect::from_gecko_rect(&self.gecko.mBorderImageSlice)
.expect("mBorderImageSlice[${side}] could not convert to NumberOrPercentageRect"),
fill: self.gecko.mBorderImageFill as u32 == NS_STYLE_BORDER_IMAGE_SLICE_FILL
}
}
</%self:impl_trait> </%self:impl_trait>
<% skip_scroll_margin_longhands = " ".join(["scroll-margin-%s" % x.ident for x in SIDES]) %>
<% skip_margin_longhands = " ".join(["margin-%s" % x.ident for x in SIDES]) %> <% skip_margin_longhands = " ".join(["margin-%s" % x.ident for x in SIDES]) %>
<%self:impl_trait style_struct_name="Margin" <%self:impl_trait style_struct_name="Margin"
skip_longhands="${skip_margin_longhands}"> skip_longhands="${skip_margin_longhands}
${skip_scroll_margin_longhands}">
% for side in SIDES: % for side in SIDES:
<% impl_split_style_coord("margin_%s" % side.ident, <% impl_split_style_coord("margin_%s" % side.ident,
"mMargin", "mMargin",
side.index) %> side.index) %>
<% impl_split_style_coord("scroll_margin_%s" % side.ident,
"mScrollMargin",
side.index) %>
% endfor % endfor
</%self:impl_trait> </%self:impl_trait>
<% skip_scroll_padding_longhands = " ".join(["scroll-padding-%s" % x.ident for x in SIDES]) %>
<% skip_padding_longhands = " ".join(["padding-%s" % x.ident for x in SIDES]) %> <% skip_padding_longhands = " ".join(["padding-%s" % x.ident for x in SIDES]) %>
<%self:impl_trait style_struct_name="Padding" <%self:impl_trait style_struct_name="Padding"
skip_longhands="${skip_padding_longhands}"> skip_longhands="${skip_padding_longhands}
${skip_scroll_padding_longhands}">
% for side in SIDES: % for side in SIDES:
<% impl_split_style_coord("padding_%s" % side.ident, <% impl_split_style_coord("padding_%s" % side.ident,
"mPadding", "mPadding",
side.index) %> side.index) %>
<% impl_split_style_coord("scroll_padding_%s" % side.ident, "mScrollPadding", side.index) %>
% endfor % endfor
</%self:impl_trait> </%self:impl_trait>
<% skip_position_longhands = " ".join(x.ident for x in SIDES + GRID_LINES) %> <% skip_position_longhands = " ".join(x.ident for x in SIDES + GRID_LINES) %>
<%self:impl_trait style_struct_name="Position" <%self:impl_trait style_struct_name="Position"
skip_longhands="${skip_position_longhands} z-index order skip_longhands="${skip_position_longhands} order
align-content justify-content align-self align-content justify-content align-self
justify-self align-items justify-items justify-self align-items justify-items
grid-auto-rows grid-auto-columns grid-auto-rows grid-auto-columns
@ -1711,38 +1616,6 @@ fn static_assert() {
<% impl_split_style_coord(side.ident, "mOffset", side.index) %> <% impl_split_style_coord(side.ident, "mOffset", side.index) %>
% endfor % endfor
pub fn set_z_index(&mut self, v: longhands::z_index::computed_value::T) {
match v {
ZIndex::Integer(n) => self.gecko.mZIndex.set_value(CoordDataValue::Integer(n)),
ZIndex::Auto => self.gecko.mZIndex.set_value(CoordDataValue::Auto),
}
}
pub fn copy_z_index_from(&mut self, other: &Self) {
use crate::gecko_bindings::structs::nsStyleUnit;
// z-index is never a calc(). If it were, we'd be leaking here, so
// assert that it isn't.
debug_assert_ne!(self.gecko.mZIndex.unit(), nsStyleUnit::eStyleUnit_Calc);
unsafe {
self.gecko.mZIndex.copy_from_unchecked(&other.gecko.mZIndex);
}
}
pub fn reset_z_index(&mut self, other: &Self) {
self.copy_z_index_from(other)
}
pub fn clone_z_index(&self) -> longhands::z_index::computed_value::T {
return match self.gecko.mZIndex.as_value() {
CoordDataValue::Integer(n) => ZIndex::Integer(n),
CoordDataValue::Auto => ZIndex::Auto,
_ => {
debug_assert!(false);
ZIndex::Integer(0)
}
}
}
% for kind in ["align", "justify"]: % for kind in ["align", "justify"]:
${impl_simple_type_with_conversion(kind + "_content")} ${impl_simple_type_with_conversion(kind + "_content")}
${impl_simple_type_with_conversion(kind + "_self")} ${impl_simple_type_with_conversion(kind + "_self")}
@ -2216,7 +2089,7 @@ fn static_assert() {
pub fn fixup_none_generic(&mut self, device: &Device) { pub fn fixup_none_generic(&mut self, device: &Device) {
self.gecko.mFont.systemFont = false; self.gecko.mFont.systemFont = false;
unsafe { unsafe {
bindings::Gecko_nsStyleFont_FixupNoneGeneric(&mut self.gecko, device.pres_context()) bindings::Gecko_nsStyleFont_FixupNoneGeneric(&mut self.gecko, device.document())
} }
} }
@ -2332,7 +2205,7 @@ fn static_assert() {
} }
pub fn fixup_font_min_size(&mut self, device: &Device) { pub fn fixup_font_min_size(&mut self, device: &Device) {
unsafe { bindings::Gecko_nsStyleFont_FixupMinFontSize(&mut self.gecko, device.pres_context()) } unsafe { bindings::Gecko_nsStyleFont_FixupMinFontSize(&mut self.gecko, device.document()) }
} }
pub fn apply_unconstrained_font_size(&mut self, v: NonNegativeLength) { pub fn apply_unconstrained_font_size(&mut self, v: NonNegativeLength) {
@ -2654,12 +2527,11 @@ fn static_assert() {
${impl_simple("_moz_script_level", "mScriptLevel")} ${impl_simple("_moz_script_level", "mScriptLevel")}
<% impl_simple_type_with_conversion("font_language_override", "mFont.languageOverride") %> <% impl_simple_type_with_conversion("font_language_override", "mFont.languageOverride") %>
pub fn set_font_variant_alternates(&mut self, pub fn set_font_variant_alternates(
v: values::computed::font::FontVariantAlternates, &mut self,
device: &Device) { v: values::computed::font::FontVariantAlternates,
) {
use crate::gecko_bindings::bindings::{Gecko_ClearAlternateValues, Gecko_AppendAlternateValues}; use crate::gecko_bindings::bindings::{Gecko_ClearAlternateValues, Gecko_AppendAlternateValues};
use crate::gecko_bindings::bindings::Gecko_nsFont_ResetFontFeatureValuesLookup;
use crate::gecko_bindings::bindings::Gecko_nsFont_SetFontFeatureValuesLookup;
% for value in "normal swash stylistic ornaments annotation styleset character_variant historical".split(): % for value in "normal swash stylistic ornaments annotation styleset character_variant historical".split():
use crate::gecko_bindings::structs::NS_FONT_VARIANT_ALTERNATES_${value.upper()}; use crate::gecko_bindings::structs::NS_FONT_VARIANT_ALTERNATES_${value.upper()};
% endfor % endfor
@ -2671,7 +2543,6 @@ fn static_assert() {
if v.0.is_empty() { if v.0.is_empty() {
self.gecko.mFont.variantAlternates = NS_FONT_VARIANT_ALTERNATES_NORMAL as u16; self.gecko.mFont.variantAlternates = NS_FONT_VARIANT_ALTERNATES_NORMAL as u16;
unsafe { Gecko_nsFont_ResetFontFeatureValuesLookup(&mut self.gecko.mFont); }
return; return;
} }
@ -2704,10 +2575,6 @@ fn static_assert() {
} }
} }
} }
unsafe {
Gecko_nsFont_SetFontFeatureValuesLookup(&mut self.gecko.mFont, device.pres_context());
}
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@ -2997,10 +2864,8 @@ fn static_assert() {
clear transition-duration transition-delay clear transition-duration transition-delay
transition-timing-function transition-property transition-timing-function transition-property
rotate scroll-snap-points-x scroll-snap-points-y rotate scroll-snap-points-x scroll-snap-points-y
scroll-snap-coordinate scroll-snap-coordinate -moz-binding will-change
perspective-origin -moz-binding will-change offset-path shape-outside contain touch-action
offset-path perspective-origin -moz-binding
will-change shape-outside contain touch-action
translate scale""" %> translate scale""" %>
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
#[inline] #[inline]
@ -3095,11 +2960,7 @@ fn static_assert() {
where I: IntoIterator<Item = longhands::scroll_snap_coordinate::computed_value::single_value::T>, where I: IntoIterator<Item = longhands::scroll_snap_coordinate::computed_value::single_value::T>,
I::IntoIter: ExactSizeIterator I::IntoIter: ExactSizeIterator
{ {
let iter = v.into_iter().map(|c| structs::mozilla::Position { self.gecko.mScrollSnapCoordinate.assign_from_iter_pod(v.into_iter());
mXPosition: c.horizontal.into(),
mYPosition: c.vertical.into(),
});
self.gecko.mScrollSnapCoordinate.assign_from_iter_pod(iter);
} }
pub fn copy_scroll_snap_coordinate_from(&mut self, other: &Self) { pub fn copy_scroll_snap_coordinate_from(&mut self, other: &Self) {
@ -3112,7 +2973,7 @@ fn static_assert() {
} }
pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T { pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T {
let vec = self.gecko.mScrollSnapCoordinate.iter().map(|f| f.into()).collect(); let vec = self.gecko.mScrollSnapCoordinate.iter().cloned().collect();
longhands::scroll_snap_coordinate::computed_value::List(vec) longhands::scroll_snap_coordinate::computed_value::List(vec)
} }
@ -3356,31 +3217,6 @@ fn static_assert() {
${impl_animation_timing_function()} ${impl_animation_timing_function()}
pub fn set_perspective_origin(&mut self, v: longhands::perspective_origin::computed_value::T) {
self.gecko.mPerspectiveOrigin[0].set(v.horizontal);
self.gecko.mPerspectiveOrigin[1].set(v.vertical);
}
pub fn copy_perspective_origin_from(&mut self, other: &Self) {
self.gecko.mPerspectiveOrigin[0].copy_from(&other.gecko.mPerspectiveOrigin[0]);
self.gecko.mPerspectiveOrigin[1].copy_from(&other.gecko.mPerspectiveOrigin[1]);
}
pub fn reset_perspective_origin(&mut self, other: &Self) {
self.copy_perspective_origin_from(other)
}
pub fn clone_perspective_origin(&self) -> longhands::perspective_origin::computed_value::T {
use crate::properties::longhands::perspective_origin::computed_value::T;
use crate::values::computed::LengthPercentage;
T {
horizontal: LengthPercentage::from_gecko_style_coord(&self.gecko.mPerspectiveOrigin[0])
.expect("Expected length or percentage for horizontal value of perspective-origin"),
vertical: LengthPercentage::from_gecko_style_coord(&self.gecko.mPerspectiveOrigin[1])
.expect("Expected length or percentage for vertical value of perspective-origin"),
}
}
${impl_individual_transform('rotate', 'Rotate', 'mSpecifiedRotate')} ${impl_individual_transform('rotate', 'Rotate', 'mSpecifiedRotate')}
${impl_individual_transform('translate', 'Translate', 'mSpecifiedTranslate')} ${impl_individual_transform('translate', 'Translate', 'mSpecifiedTranslate')}
${impl_individual_transform('scale', 'Scale', 'mSpecifiedScale')} ${impl_individual_transform('scale', 'Scale', 'mSpecifiedScale')}
@ -3759,7 +3595,7 @@ fn static_assert() {
<% impl_simple_image_array_property("clip", shorthand, image_layers_field, "mClip", struct_name) %> <% impl_simple_image_array_property("clip", shorthand, image_layers_field, "mClip", struct_name) %>
<% impl_simple_image_array_property("origin", shorthand, image_layers_field, "mOrigin", struct_name) %> <% impl_simple_image_array_property("origin", shorthand, image_layers_field, "mOrigin", struct_name) %>
% for orientation in ["x", "y"]: % for (orientation, keyword) in [("x", "horizontal"), ("y", "vertical")]:
pub fn copy_${shorthand}_position_${orientation}_from(&mut self, other: &Self) { pub fn copy_${shorthand}_position_${orientation}_from(&mut self, other: &Self) {
use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
@ -3774,8 +3610,7 @@ fn static_assert() {
for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut() for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
.zip(other.gecko.${image_layers_field}.mLayers.iter()) .zip(other.gecko.${image_layers_field}.mLayers.iter())
.take(count as usize) { .take(count as usize) {
layer.mPosition.m${orientation.upper()}Position layer.mPosition.${keyword} = other.mPosition.${keyword};
= other.mPosition.m${orientation.upper()}Position;
} }
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count = count; self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count = count;
} }
@ -3789,7 +3624,7 @@ fn static_assert() {
longhands::${shorthand}_position_${orientation}::computed_value::List( longhands::${shorthand}_position_${orientation}::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter() self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize) .take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize)
.map(|position| position.mPosition.m${orientation.upper()}Position.into()) .map(|position| position.mPosition.${keyword})
.collect() .collect()
) )
} }
@ -3812,86 +3647,18 @@ fn static_assert() {
self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count = v.len() as u32; self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count = v.len() as u32;
for (servo, geckolayer) in v.zip(self.gecko.${image_layers_field} for (servo, geckolayer) in v.zip(self.gecko.${image_layers_field}
.mLayers.iter_mut()) { .mLayers.iter_mut()) {
geckolayer.mPosition.m${orientation[0].upper()}Position = servo.into(); geckolayer.mPosition.${keyword} = servo;
} }
} }
% endfor % endfor
<%self:simple_image_array_property name="size" shorthand="${shorthand}" field_name="mSize"> <%self:simple_image_array_property name="size" shorthand="${shorthand}" field_name="mSize">
use crate::gecko_bindings::structs::nsStyleImageLayers_Size_Dimension; servo
use crate::gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType;
use crate::gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImageLayers_Size};
use crate::values::generics::background::BackgroundSize;
let mut width = nsStyleCoord_CalcValue::new();
let mut height = nsStyleCoord_CalcValue::new();
let (w_type, h_type) = match servo {
BackgroundSize::Explicit { width: explicit_width, height: explicit_height } => {
let mut w_type = nsStyleImageLayers_Size_DimensionType::eAuto;
let mut h_type = nsStyleImageLayers_Size_DimensionType::eAuto;
if let Some(w) = explicit_width.to_calc_value() {
width = w;
w_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
}
if let Some(h) = explicit_height.to_calc_value() {
height = h;
h_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
}
(w_type, h_type)
}
BackgroundSize::Cover => {
(
nsStyleImageLayers_Size_DimensionType::eCover,
nsStyleImageLayers_Size_DimensionType::eCover,
)
},
BackgroundSize::Contain => {
(
nsStyleImageLayers_Size_DimensionType::eContain,
nsStyleImageLayers_Size_DimensionType::eContain,
)
},
};
nsStyleImageLayers_Size {
mWidth: nsStyleImageLayers_Size_Dimension { _base: width },
mHeight: nsStyleImageLayers_Size_Dimension { _base: height },
mWidthType: w_type as u8,
mHeightType: h_type as u8,
}
</%self:simple_image_array_property> </%self:simple_image_array_property>
pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T { pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T {
use crate::gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue;
use crate::gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType;
use crate::values::computed::NonNegativeLengthPercentageOrAuto;
use crate::values::generics::background::BackgroundSize;
fn to_servo(value: CalcValue, ty: u8) -> NonNegativeLengthPercentageOrAuto {
if ty == DimensionType::eAuto as u8 {
NonNegativeLengthPercentageOrAuto::auto()
} else {
debug_assert_eq!(ty, DimensionType::eLengthPercentage as u8);
value.into()
}
}
longhands::${shorthand}_size::computed_value::List( longhands::${shorthand}_size::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter().map(|ref layer| { self.gecko.${image_layers_field}.mLayers.iter().map(|layer| layer.mSize).collect()
if DimensionType::eCover as u8 == layer.mSize.mWidthType {
debug_assert_eq!(layer.mSize.mHeightType, DimensionType::eCover as u8);
return BackgroundSize::Cover
}
if DimensionType::eContain as u8 == layer.mSize.mWidthType {
debug_assert_eq!(layer.mSize.mHeightType, DimensionType::eContain as u8);
return BackgroundSize::Contain
}
BackgroundSize::Explicit {
width: to_servo(layer.mSize.mWidth._base, layer.mSize.mWidthType),
height: to_servo(layer.mSize.mHeight._base, layer.mSize.mHeightType),
}
}).collect()
) )
} }
@ -4043,12 +3810,12 @@ fn static_assert() {
} }
} }
pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T, device: &Device) { pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) {
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToString; use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToString;
use nsstring::{nsACString, nsCStr}; use nsstring::{nsACString, nsCStr};
use self::longhands::list_style_type::computed_value::T; use self::longhands::list_style_type::computed_value::T;
match v { match v {
T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle, device), T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle),
T::String(s) => unsafe { T::String(s) => unsafe {
Gecko_SetCounterStyleToString(&mut self.gecko.mCounterStyle, Gecko_SetCounterStyleToString(&mut self.gecko.mCounterStyle,
&nsCStr::from(&s) as &nsACString) &nsCStr::from(&s) as &nsACString)
@ -4472,7 +4239,7 @@ fn static_assert() {
<%self:impl_trait style_struct_name="InheritedText" <%self:impl_trait style_struct_name="InheritedText"
skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing
-webkit-text-stroke-width text-emphasis-position -moz-tab-size"> -webkit-text-stroke-width text-emphasis-position">
<% text_align_keyword = Keyword("text-align", <% text_align_keyword = Keyword("text-align",
"start end left right center justify -moz-center -moz-left -moz-right char", "start end left right center justify -moz-center -moz-left -moz-right char",
@ -4661,28 +4428,6 @@ fn static_assert() {
${impl_non_negative_length('_webkit_text_stroke_width', ${impl_non_negative_length('_webkit_text_stroke_width',
'mWebkitTextStrokeWidth')} 'mWebkitTextStrokeWidth')}
#[allow(non_snake_case)]
pub fn set__moz_tab_size(&mut self, v: longhands::_moz_tab_size::computed_value::T) {
match v {
MozTabSize::Number(non_negative_number) => {
self.gecko.mTabSize.set_value(CoordDataValue::Factor(non_negative_number.0));
}
MozTabSize::Length(non_negative_length) => {
self.gecko.mTabSize.set(non_negative_length);
}
}
}
#[allow(non_snake_case)]
pub fn clone__moz_tab_size(&self) -> longhands::_moz_tab_size::computed_value::T {
match self.gecko.mTabSize.as_value() {
CoordDataValue::Coord(coord) => MozTabSize::Length(Au(coord).into()),
CoordDataValue::Factor(number) => MozTabSize::Number(From::from(number)),
_ => unreachable!(),
}
}
<%call expr="impl_coord_copy('_moz_tab_size', 'mTabSize')"></%call>
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="Text" <%self:impl_trait style_struct_name="Text"
@ -5290,7 +5035,7 @@ clip-path
self.gecko.mContents.is_empty() self.gecko.mContents.is_empty()
} }
pub fn set_content(&mut self, v: longhands::content::computed_value::T, device: &Device) { pub fn set_content(&mut self, v: longhands::content::computed_value::T) {
use crate::values::CustomIdent; use crate::values::CustomIdent;
use crate::values::generics::counters::{Content, ContentItem}; use crate::values::generics::counters::{Content, ContentItem};
use crate::values::generics::CounterStyleOrNone; use crate::values::generics::CounterStyleOrNone;
@ -5315,7 +5060,6 @@ clip-path
name: &CustomIdent, name: &CustomIdent,
sep: &str, sep: &str,
style: CounterStyleOrNone, style: CounterStyleOrNone,
device: &Device,
) { ) {
debug_assert!(content_type == StyleContentType::Counter || debug_assert!(content_type == StyleContentType::Counter ||
content_type == StyleContentType::Counters); content_type == StyleContentType::Counters);
@ -5326,7 +5070,7 @@ clip-path
if content_type == StyleContentType::Counters { if content_type == StyleContentType::Counters {
counter_func.mSeparator.assign_str(sep); counter_func.mSeparator.assign_str(sep);
} }
style.to_gecko_value(&mut counter_func.mCounterStyle, device); style.to_gecko_value(&mut counter_func.mCounterStyle);
} }
match v { match v {
@ -5401,7 +5145,6 @@ clip-path
&name, &name,
"", "",
style.clone(), style.clone(),
device,
); );
} }
ContentItem::Counters(ref name, ref sep, ref style) => { ContentItem::Counters(ref name, ref sep, ref style) => {
@ -5411,7 +5154,6 @@ clip-path
&name, &name,
&sep, &sep,
style.clone(), style.clone(),
device,
); );
} }
ContentItem::Url(ref url) => { ContentItem::Url(ref url) => {

View file

@ -119,10 +119,9 @@ ${helpers.predefined_type(
${helpers.predefined_type( ${helpers.predefined_type(
"border-image-outset", "border-image-outset",
"LengthOrNumberRect", "NonNegativeLengthOrNumberRect",
parse_method="parse_non_negative", initial_value="generics::rect::Rect::all(computed::NonNegativeLengthOrNumber::zero())",
initial_value="computed::LengthOrNumberRect::all(computed::LengthOrNumber::zero())", initial_specified_value="generics::rect::Rect::all(specified::NonNegativeLengthOrNumber::zero())",
initial_specified_value="specified::LengthOrNumberRect::all(specified::LengthOrNumber::zero())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset", spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
animation_value_type="discrete", animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER", flags="APPLIES_TO_FIRST_LETTER",

View file

@ -417,6 +417,16 @@ ${helpers.single_keyword(
animation_value_type="discrete", animation_value_type="discrete",
)} )}
${helpers.predefined_type(
"scroll-snap-align",
"ScrollSnapAlign",
"computed::ScrollSnapAlign::none()",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-align",
animation_value_type="discrete",
)}
% for axis in ["x", "y"]: % for axis in ["x", "y"]:
${helpers.predefined_type( ${helpers.predefined_type(
"scroll-snap-type-" + axis, "scroll-snap-type-" + axis,

View file

@ -98,7 +98,7 @@ pub mod system_colors {
unsafe { unsafe {
Gecko_GetLookAndFeelSystemColor( Gecko_GetLookAndFeelSystemColor(
*self as i32, *self as i32,
cx.device().pres_context(), cx.device().document(),
) )
} }
} }

View file

@ -396,7 +396,7 @@ ${helpers.predefined_type(
&mut system, &mut system,
id as i32, id as i32,
cx.style().get_font().gecko(), cx.style().get_font().gecko(),
cx.device().pres_context() cx.device().document()
) )
} }
let font_weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight); let font_weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight);

View file

@ -257,10 +257,10 @@ ${helpers.predefined_type(
${helpers.predefined_type( ${helpers.predefined_type(
"-moz-tab-size", "-moz-tab-size",
"MozTabSize", "NonNegativeLengthOrNumber",
"generics::text::MozTabSize::Number(From::from(8.0))", "generics::length::LengthOrNumber::Number(From::from(8.0))",
products="gecko", products="gecko",
animation_value_type="AnimatedMozTabSize", animation_value_type="LengthOrNumber",
spec="https://drafts.csswg.org/css-text-3/#tab-size-property", spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
)} )}
@ -349,8 +349,8 @@ ${helpers.single_keyword(
"-moz-control-character-visibility", "-moz-control-character-visibility",
"hidden visible", "hidden visible",
gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY", gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
gecko_ffi_name="mControlCharacterVisibility",
animation_value_type="none", animation_value_type="none",
gecko_ffi_name="mControlCharacterVisibility",
products="gecko", products="gecko",
spec="Nonstandard", spec="Nonstandard",
)} )}

View file

@ -60,7 +60,7 @@ ${helpers.single_keyword(
${helpers.predefined_type( ${helpers.predefined_type(
"caret-color", "caret-color",
"ColorOrAuto", "ColorOrAuto",
"Either::Second(Auto)", "generics::color::ColorOrAuto::Auto",
spec="https://drafts.csswg.org/css-ui/#caret-color", spec="https://drafts.csswg.org/css-ui/#caret-color",
animation_value_type="AnimatedCaretColor", animation_value_type="AnimatedCaretColor",
ignored_when_colors_disabled=True, ignored_when_colors_disabled=True,

View file

@ -27,3 +27,18 @@
servo_restyle_damage="reflow" servo_restyle_damage="reflow"
)} )}
% endfor % endfor
% for side in ALL_SIDES:
${helpers.predefined_type(
"scroll-margin-%s" % side[0],
"Length",
"computed::Length::zero()",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
logical=side[1],
logical_group="scroll-margin",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-%s" % side[0],
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE",
animation_value_type="ComputedValue",
)}
% endfor

View file

@ -28,3 +28,17 @@
servo_restyle_damage="reflow rebuild_and_reflow_inline" servo_restyle_damage="reflow rebuild_and_reflow_inline"
)} )}
% endfor % endfor
% for side in ALL_SIDES:
${helpers.predefined_type(
"scroll-padding-%s" % side[0],
"NonNegativeLengthPercentageOrAuto",
"computed::NonNegativeLengthPercentageOrAuto::auto()",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
logical=side[1],
logical_group="scroll-padding",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-%s" % side[0],
animation_value_type="ComputedValue",
)}
% endfor

View file

@ -75,6 +75,7 @@ ${helpers.single_keyword(
extra_prefixes="webkit", extra_prefixes="webkit",
animation_value_type="discrete", animation_value_type="discrete",
servo_restyle_damage = "reflow", servo_restyle_damage = "reflow",
gecko_enum_prefix = "StyleFlexDirection",
)} )}
${helpers.single_keyword( ${helpers.single_keyword(
@ -225,7 +226,7 @@ ${helpers.predefined_type(
extra_prefixes="webkit", extra_prefixes="webkit",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-flexbox/#order-property", spec="https://drafts.csswg.org/css-flexbox/#order-property",
servo_restyle_damage = "reflow", servo_restyle_damage="reflow",
)} )}
${helpers.predefined_type( ${helpers.predefined_type(
@ -235,7 +236,8 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property", spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
extra_prefixes="webkit", extra_prefixes="webkit",
animation_value_type="FlexBasis", animation_value_type="FlexBasis",
servo_restyle_damage = "reflow", servo_restyle_damage="reflow",
boxed=True,
)} )}
% for (size, logical) in ALL_SIZES: % for (size, logical) in ALL_SIZES:

View file

@ -96,6 +96,7 @@ ${helpers.predefined_type(
${helpers.single_keyword( ${helpers.single_keyword(
"mask-mode", "mask-mode",
"match-source alpha luminance", "match-source alpha luminance",
gecko_enum_prefix="StyleMaskMode",
vector=True, vector=True,
products="gecko", products="gecko",
animation_value_type="discrete", animation_value_type="discrete",

View file

@ -3358,7 +3358,7 @@ impl<'a> StyleBuilder<'a> {
debug_assert!(parent_style.is_none() || debug_assert!(parent_style.is_none() ||
std::ptr::eq(parent_style.unwrap(), std::ptr::eq(parent_style.unwrap(),
parent_style_ignoring_first_line.unwrap()) || parent_style_ignoring_first_line.unwrap()) ||
parent_style.unwrap().pseudo() == Some(PseudoElement::FirstLine)); parent_style.unwrap().is_first_line_style());
let reset_style = device.default_computed_values(); let reset_style = device.default_computed_values();
let inherited_style = parent_style.unwrap_or(reset_style); let inherited_style = parent_style.unwrap_or(reset_style);
let inherited_style_ignoring_first_line = parent_style_ignoring_first_line.unwrap_or(reset_style); let inherited_style_ignoring_first_line = parent_style_ignoring_first_line.unwrap_or(reset_style);
@ -3402,7 +3402,7 @@ impl<'a> StyleBuilder<'a> {
let inherited_style = parent_style.unwrap_or(reset_style); let inherited_style = parent_style.unwrap_or(reset_style);
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
debug_assert!(parent_style.is_none() || debug_assert!(parent_style.is_none() ||
parent_style.unwrap().pseudo() != Some(PseudoElement::FirstLine)); !parent_style.unwrap().is_first_line_style());
StyleBuilder { StyleBuilder {
device, device,
inherited_style, inherited_style,
@ -3507,14 +3507,11 @@ impl<'a> StyleBuilder<'a> {
self.modified_reset = true; self.modified_reset = true;
% endif % endif
<% props_need_device = ["content", "list_style_type", "font_variant_alternates"] %>
self.${property.style_struct.ident}.mutate() self.${property.style_struct.ident}.mutate()
.set_${property.ident}( .set_${property.ident}(
value, value,
% if property.logical: % if property.logical:
self.writing_mode, self.writing_mode,
% elif product == "gecko" and property.ident in props_need_device:
self.device,
% endif % endif
); );
} }

View file

@ -28,3 +28,32 @@ ${helpers.two_properties_shorthand(
"specified::LengthPercentageOrAuto::parse", "specified::LengthPercentageOrAuto::parse",
spec="https://drafts.csswg.org/css-logical/#propdef-margin-inline" spec="https://drafts.csswg.org/css-logical/#propdef-margin-inline"
)} )}
${helpers.four_sides_shorthand(
"scroll-margin",
"scroll-margin-%s",
"specified::Length::parse",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
)}
${helpers.two_properties_shorthand(
"scroll-margin-block",
"scroll-margin-block-start",
"scroll-margin-block-end",
"specified::Length::parse",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-block",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
)}
${helpers.two_properties_shorthand(
"scroll-margin-inline",
"scroll-margin-inline-start",
"scroll-margin-inline-end",
"specified::Length::parse",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-inline",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
)}

View file

@ -27,3 +27,33 @@ ${helpers.two_properties_shorthand(
"specified::NonNegativeLengthPercentage::parse", "specified::NonNegativeLengthPercentage::parse",
spec="https://drafts.csswg.org/css-logical/#propdef-padding-inline" spec="https://drafts.csswg.org/css-logical/#propdef-padding-inline"
)} )}
${helpers.four_sides_shorthand(
"scroll-padding",
"scroll-padding-%s",
"specified::NonNegativeLengthPercentageOrAuto::parse",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding"
)}
${helpers.two_properties_shorthand(
"scroll-padding-block",
"scroll-padding-block-start",
"scroll-padding-block-end",
"specified::NonNegativeLengthPercentageOrAuto::parse",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-block"
)}
${helpers.two_properties_shorthand(
"scroll-padding-inline",
"scroll-padding-inline-start",
"scroll-padding-inline-end",
"specified::NonNegativeLengthPercentageOrAuto::parse",
products="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-inline"
)}

View file

@ -766,6 +766,11 @@ impl<E: TElement> StyleSharingCache<E> {
return None; return None;
} }
if target.element.has_animations() {
trace!("Miss: Has Animations");
return None;
}
if target.matches_user_and_author_rules() != if target.matches_user_and_author_rules() !=
candidate.element.matches_user_and_author_rules() candidate.element.matches_user_and_author_rules()
{ {

View file

@ -198,7 +198,7 @@ impl DocumentMatchingFunction {
MediaDocumentKind::Video => "video", MediaDocumentKind::Video => "video",
}, },
}); });
unsafe { Gecko_DocumentRule_UseForPresentation(device.pres_context(), &*pattern, func) } unsafe { Gecko_DocumentRule_UseForPresentation(device.document(), &*pattern, func) }
} }
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]

View file

@ -6,19 +6,8 @@
use crate::values::computed::length::NonNegativeLengthPercentage; use crate::values::computed::length::NonNegativeLengthPercentage;
use crate::values::generics::background::BackgroundSize as GenericBackgroundSize; use crate::values::generics::background::BackgroundSize as GenericBackgroundSize;
use crate::values::generics::length::LengthPercentageOrAuto;
pub use crate::values::specified::background::BackgroundRepeat; pub use crate::values::specified::background::BackgroundRepeat;
/// A computed value for the `background-size` property. /// A computed value for the `background-size` property.
pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthPercentage>; pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthPercentage>;
impl BackgroundSize {
/// Returns `auto auto`.
pub fn auto() -> Self {
GenericBackgroundSize::Explicit {
width: LengthPercentageOrAuto::auto(),
height: LengthPercentageOrAuto::auto(),
}
}
}

View file

@ -15,7 +15,7 @@ pub use crate::values::specified::box_::{AnimationName, Appearance, BreakBetween
pub use crate::values::specified::box_::{Clear as SpecifiedClear, Float as SpecifiedFloat}; pub use crate::values::specified::box_::{Clear as SpecifiedClear, Float as SpecifiedFloat};
pub use crate::values::specified::box_::{Contain, Display, Overflow}; pub use crate::values::specified::box_::{Contain, Display, Overflow};
pub use crate::values::specified::box_::{OverflowAnchor, OverflowClipBox}; pub use crate::values::specified::box_::{OverflowAnchor, OverflowClipBox};
pub use crate::values::specified::box_::{OverscrollBehavior, ScrollSnapType}; pub use crate::values::specified::box_::{OverscrollBehavior, ScrollSnapAlign, ScrollSnapType};
pub use crate::values::specified::box_::{TouchAction, TransitionProperty, WillChange}; pub use crate::values::specified::box_::{TouchAction, TransitionProperty, WillChange};
/// A computed value for the `vertical-align` property. /// A computed value for the `vertical-align` property.

View file

@ -6,7 +6,7 @@
use crate::values::animated::color::RGBA as AnimatedRGBA; use crate::values::animated::color::RGBA as AnimatedRGBA;
use crate::values::animated::ToAnimatedValue; use crate::values::animated::ToAnimatedValue;
use crate::values::generics::color::Color as GenericColor; use crate::values::generics::color::{Color as GenericColor, ColorOrAuto as GenericColorOrAuto};
use cssparser::{Color as CSSParserColor, RGBA}; use cssparser::{Color as CSSParserColor, RGBA};
use std::fmt; use std::fmt;
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
@ -101,3 +101,6 @@ impl ToAnimatedValue for RGBA {
RGBA::from_floats(animated.red, animated.green, animated.blue, animated.alpha) RGBA::from_floats(animated.red, animated.green, animated.blue, animated.alpha)
} }
} }
/// auto | <color>
pub type ColorOrAuto = GenericColorOrAuto<Color>;

View file

@ -14,6 +14,6 @@ impl FlexBasis {
/// `auto` /// `auto`
#[inline] #[inline]
pub fn auto() -> Self { pub fn auto() -> Self {
GenericFlexBasis::Width(Size::auto()) GenericFlexBasis::Size(Size::auto())
} }
} }

View file

@ -6,9 +6,12 @@
use super::{Context, Number, Percentage, ToComputedValue}; use super::{Context, Number, Percentage, ToComputedValue};
use crate::values::animated::ToAnimatedValue; use crate::values::animated::ToAnimatedValue;
use crate::values::computed::NonNegativeNumber;
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
use crate::values::generics::length as generics; use crate::values::generics::length as generics;
use crate::values::generics::length::{MaxSize as GenericMaxSize, Size as GenericSize}; use crate::values::generics::length::{
GenericLengthOrNumber, MaxSize as GenericMaxSize, Size as GenericSize,
};
use crate::values::generics::transform::IsZeroLength; use crate::values::generics::transform::IsZeroLength;
use crate::values::generics::NonNegative; use crate::values::generics::NonNegative;
use crate::values::specified::length::ViewportPercentageLength; use crate::values::specified::length::ViewportPercentageLength;
@ -503,7 +506,7 @@ impl LengthPercentageOrAuto {
/// A wrapper of LengthPercentageOrAuto, whose value must be >= 0. /// A wrapper of LengthPercentageOrAuto, whose value must be >= 0.
pub type NonNegativeLengthPercentageOrAuto = pub type NonNegativeLengthPercentageOrAuto =
generics::LengthPercentageOrAuto<NonNegativeLengthPercentage>; generics::GenericLengthPercentageOrAuto<NonNegativeLengthPercentage>;
impl NonNegativeLengthPercentageOrAuto { impl NonNegativeLengthPercentageOrAuto {
computed_length_percentage_or_auto!(NonNegativeLengthPercentage); computed_length_percentage_or_auto!(NonNegativeLengthPercentage);
@ -678,6 +681,15 @@ impl ToCss for CSSPixelLength {
} }
} }
impl Add for CSSPixelLength {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
Self::new(self.px() + other.px())
}
}
impl Neg for CSSPixelLength { impl Neg for CSSPixelLength {
type Output = Self; type Output = Self;
@ -708,15 +720,7 @@ pub type Length = CSSPixelLength;
pub type LengthOrAuto = Either<Length, Auto>; pub type LengthOrAuto = Either<Length, Auto>;
/// Either a computed `<length>` or a `<number>` value. /// Either a computed `<length>` or a `<number>` value.
pub type LengthOrNumber = Either<Length, Number>; pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
impl LengthOrNumber {
/// Returns `0`.
#[inline]
pub fn zero() -> Self {
Either::Second(0.)
}
}
/// Either a computed `<length>` or the `normal` keyword. /// Either a computed `<length>` or the `normal` keyword.
pub type LengthOrNormal = Either<Length, Normal>; pub type LengthOrNormal = Either<Length, Normal>;
@ -776,13 +780,6 @@ impl NonNegativeLength {
} }
} }
impl Add<NonNegativeLength> for NonNegativeLength {
type Output = Self;
fn add(self, other: Self) -> Self {
NonNegativeLength::new(self.px() + other.px())
}
}
impl From<Length> for NonNegativeLength { impl From<Length> for NonNegativeLength {
#[inline] #[inline]
fn from(len: Length) -> Self { fn from(len: Length) -> Self {
@ -813,6 +810,9 @@ pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
/// Either a computed NonNegativeLengthPercentage or the `normal` keyword. /// Either a computed NonNegativeLengthPercentage or the `normal` keyword.
pub type NonNegativeLengthPercentageOrNormal = Either<NonNegativeLengthPercentage, Normal>; pub type NonNegativeLengthPercentageOrNormal = Either<NonNegativeLengthPercentage, Normal>;
/// Either a non-negative `<length>` or a `<number>`.
pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
/// A type for possible values for min- and max- flavors of width, height, /// A type for possible values for min- and max- flavors of width, height,
/// block-size, and inline-size. /// block-size, and inline-size.
#[allow(missing_docs)] #[allow(missing_docs)]

View file

@ -44,8 +44,8 @@ pub use self::box_::{AnimationIterationCount, AnimationName, Contain};
pub use self::box_::{Appearance, BreakBetween, BreakWithin, Clear, Float}; pub use self::box_::{Appearance, BreakBetween, BreakWithin, Clear, Float};
pub use self::box_::{Display, Overflow, OverflowAnchor, TransitionProperty}; pub use self::box_::{Display, Overflow, OverflowAnchor, TransitionProperty};
pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize}; pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize};
pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange}; pub use self::box_::{ScrollSnapAlign, ScrollSnapType, TouchAction, VerticalAlign, WillChange};
pub use self::color::{Color, ColorPropertyValue, RGBAColor}; pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor};
pub use self::column::ColumnCount; pub use self::column::ColumnCount;
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset}; pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
pub use self::easing::TimingFunction; pub use self::easing::TimingFunction;
@ -61,7 +61,7 @@ pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier,
pub use self::gecko::ScrollSnapPoint; pub use self::gecko::ScrollSnapPoint;
pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect}; pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength}; pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
pub use self::length::{Length, LengthOrNumber, LengthPercentage}; pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
pub use self::length::{LengthPercentageOrAuto, MaxSize, Size}; pub use self::length::{LengthPercentageOrAuto, MaxSize, Size};
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto}; pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -71,13 +71,13 @@ pub use self::motion::OffsetPath;
pub use self::outline::OutlineStyle; pub use self::outline::OutlineStyle;
pub use self::percentage::{NonNegativePercentage, Percentage}; pub use self::percentage::{NonNegativePercentage, Percentage};
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex}; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex};
pub use self::rect::LengthOrNumberRect; pub use self::rect::NonNegativeLengthOrNumberRect;
pub use self::resolution::Resolution; pub use self::resolution::Resolution;
pub use self::svg::MozContextProperties; pub use self::svg::MozContextProperties;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::table::XSpan; pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize}; pub use self::text::{InitialLetter, LetterSpacing, LineHeight};
pub use self::text::{OverflowWrap, TextOverflow, WordSpacing}; pub use self::text::{OverflowWrap, TextOverflow, WordSpacing};
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle}; pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
pub use self::time::Time; pub use self::time::Time;
@ -85,7 +85,7 @@ pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
pub use self::transform::{TransformOrigin, TransformStyle, Translate}; pub use self::transform::{TransformOrigin, TransformStyle, Translate};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub use self::ui::CursorImage; pub use self::ui::CursorImage;
pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon, UserSelect}; pub use self::ui::{Cursor, MozForceBrokenImageIcon, UserSelect};
pub use super::specified::{BorderStyle, TextDecorationLine}; pub use super::specified::{BorderStyle, TextDecorationLine};
pub use super::{Auto, Either, None_}; pub use super::{Auto, Either, None_};
pub use app_units::Au; pub use app_units::Au;
@ -536,6 +536,7 @@ impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)]
#[repr(C, u8)]
pub enum NumberOrPercentage { pub enum NumberOrPercentage {
Percentage(Percentage), Percentage(Percentage),
Number(Number), Number(Number),

View file

@ -4,8 +4,8 @@
//! Computed types for CSS borders. //! Computed types for CSS borders.
use crate::values::computed::length::LengthOrNumber; use crate::values::computed::length::NonNegativeLengthOrNumber;
use crate::values::generics::rect::Rect; use crate::values::generics::rect::Rect;
/// A specified rectangle made of four `<length-or-number>` values. /// A specified rectangle made of four `<length-or-number>` values.
pub type LengthOrNumberRect = Rect<LengthOrNumber>; pub type NonNegativeLengthOrNumberRect = Rect<NonNegativeLengthOrNumber>;

View file

@ -10,7 +10,6 @@ use crate::values::computed::length::{Length, LengthPercentage};
use crate::values::computed::{NonNegativeLength, NonNegativeNumber}; use crate::values::computed::{NonNegativeLength, NonNegativeNumber};
use crate::values::generics::text::InitialLetter as GenericInitialLetter; use crate::values::generics::text::InitialLetter as GenericInitialLetter;
use crate::values::generics::text::LineHeight as GenericLineHeight; use crate::values::generics::text::LineHeight as GenericLineHeight;
use crate::values::generics::text::MozTabSize as GenericMozTabSize;
use crate::values::generics::text::Spacing; use crate::values::generics::text::Spacing;
use crate::values::specified::text::TextOverflowSide; use crate::values::specified::text::TextOverflowSide;
use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword}; use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword};
@ -124,9 +123,6 @@ impl TextDecorationsInEffect {
} }
} }
/// A specified value for the `-moz-tab-size` property.
pub type MozTabSize = GenericMozTabSize<NonNegativeNumber, NonNegativeLength>;
/// computed value for the text-emphasis-style property /// computed value for the text-emphasis-style property
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
pub enum TextEmphasisStyle { pub enum TextEmphasisStyle {

View file

@ -21,7 +21,8 @@ pub type TransformOperation =
pub type Transform = generic::Transform<TransformOperation>; pub type Transform = generic::Transform<TransformOperation>;
/// The computed value of a CSS `<transform-origin>` /// The computed value of a CSS `<transform-origin>`
pub type TransformOrigin = generic::TransformOrigin<LengthPercentage, LengthPercentage, Length>; pub type TransformOrigin =
generic::GenericTransformOrigin<LengthPercentage, LengthPercentage, Length>;
/// A vector to represent the direction vector (rotate axis) for Rotate3D. /// A vector to represent the direction vector (rotate axis) for Rotate3D.
pub type DirectionVector = Vector3D<CSSFloat>; pub type DirectionVector = Vector3D<CSSFloat>;

View file

@ -8,14 +8,10 @@ use crate::values::computed::color::Color;
use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::Number; use crate::values::computed::Number;
use crate::values::generics::ui as generics; use crate::values::generics::ui as generics;
use crate::values::{Auto, Either};
pub use crate::values::specified::ui::CursorKind; pub use crate::values::specified::ui::CursorKind;
pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect}; pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect};
/// auto | <color>
pub type ColorOrAuto = Either<Color, Auto>;
/// A computed value for the `cursor` property. /// A computed value for the `cursor` property.
pub type Cursor = generics::Cursor<CursorImage>; pub type Cursor = generics::Cursor<CursorImage>;

View file

@ -4,7 +4,7 @@
//! Generic types for CSS values related to backgrounds. //! Generic types for CSS values related to backgrounds.
use crate::values::generics::length::LengthPercentageOrAuto; use crate::values::generics::length::{GenericLengthPercentageOrAuto, LengthPercentageOrAuto};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
@ -22,13 +22,14 @@ use style_traits::{CssWriter, ToCss};
ToAnimatedZero, ToAnimatedZero,
ToComputedValue, ToComputedValue,
)] )]
pub enum BackgroundSize<LengthPercentage> { #[repr(C, u8)]
pub enum GenericBackgroundSize<LengthPercent> {
/// `<width> <height>` /// `<width> <height>`
Explicit { ExplicitSize {
/// Explicit width. /// Explicit width.
width: LengthPercentageOrAuto<LengthPercentage>, width: GenericLengthPercentageOrAuto<LengthPercent>,
/// Explicit height. /// Explicit height.
height: LengthPercentageOrAuto<LengthPercentage>, height: GenericLengthPercentageOrAuto<LengthPercent>,
}, },
/// `cover` /// `cover`
#[animation(error)] #[animation(error)]
@ -38,6 +39,8 @@ pub enum BackgroundSize<LengthPercentage> {
Contain, Contain,
} }
pub use self::GenericBackgroundSize as BackgroundSize;
impl<LengthPercentage> ToCss for BackgroundSize<LengthPercentage> impl<LengthPercentage> ToCss for BackgroundSize<LengthPercentage>
where where
LengthPercentage: ToCss, LengthPercentage: ToCss,
@ -47,7 +50,7 @@ where
W: Write, W: Write,
{ {
match self { match self {
BackgroundSize::Explicit { width, height } => { BackgroundSize::ExplicitSize { width, height } => {
width.to_css(dest)?; width.to_css(dest)?;
// NOTE(emilio): We should probably simplify all these in case // NOTE(emilio): We should probably simplify all these in case
// `width == `height`, but all other browsers agree on only // `width == `height`, but all other browsers agree on only
@ -63,3 +66,13 @@ where
} }
} }
} }
impl<LengthPercentage> BackgroundSize<LengthPercentage> {
/// Returns `auto auto`.
pub fn auto() -> Self {
GenericBackgroundSize::ExplicitSize {
width: LengthPercentageOrAuto::Auto,
height: LengthPercentageOrAuto::Auto,
}
}
}

View file

@ -26,7 +26,8 @@ pub enum BorderImageSideWidth<LengthPercentage, Number> {
#[derive( #[derive(
Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
)] )]
pub struct BorderImageSlice<NumberOrPercentage> { #[repr(C)]
pub struct GenericBorderImageSlice<NumberOrPercentage> {
/// The offsets. /// The offsets.
#[css(field_bound)] #[css(field_bound)]
pub offsets: Rect<NumberOrPercentage>, pub offsets: Rect<NumberOrPercentage>,
@ -35,6 +36,8 @@ pub struct BorderImageSlice<NumberOrPercentage> {
pub fill: bool, pub fill: bool,
} }
pub use self::GenericBorderImageSlice as BorderImageSlice;
/// A generic value for the `border-*-radius` longhand properties. /// A generic value for the `border-*-radius` longhand properties.
#[derive( #[derive(
Animate, Animate,

View file

@ -74,6 +74,7 @@ pub enum AnimationIterationCount<Number> {
Copy, Copy,
Debug, Debug,
MallocSizeOf, MallocSizeOf,
Parse,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
@ -81,13 +82,16 @@ pub enum AnimationIterationCount<Number> {
ToComputedValue, ToComputedValue,
ToCss, ToCss,
)] )]
pub enum Perspective<NonNegativeLength> { #[repr(C, u8)]
pub enum GenericPerspective<NonNegativeLength> {
/// A non-negative length. /// A non-negative length.
Length(NonNegativeLength), Length(NonNegativeLength),
/// The keyword `none`. /// The keyword `none`.
None, None,
} }
pub use self::GenericPerspective as Perspective;
impl<L> Perspective<L> { impl<L> Perspective<L> {
/// Returns `none`. /// Returns `none`.
#[inline] #[inline]

View file

@ -74,3 +74,26 @@ impl<RGBA> From<RGBA> for Color<RGBA> {
Self::rgba(color) Self::rgba(color)
} }
} }
/// Either `<color>` or `auto`.
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
Parse,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToCss,
)]
pub enum ColorOrAuto<C> {
/// A `<color>
Color(C),
/// `auto`
Auto,
}

View file

@ -12,6 +12,7 @@
Copy, Copy,
Debug, Debug,
MallocSizeOf, MallocSizeOf,
Parse,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,

View file

@ -12,6 +12,7 @@
ComputeSquaredDistance, ComputeSquaredDistance,
Copy, Copy,
Debug, Debug,
Parse,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
@ -19,9 +20,12 @@
ToComputedValue, ToComputedValue,
ToCss, ToCss,
)] )]
pub enum FlexBasis<Width> { #[repr(C)]
pub enum GenericFlexBasis<S> {
/// `content` /// `content`
Content, Content,
/// `<width>` /// `<width>`
Width(Width), Size(S),
} }
pub use self::GenericFlexBasis as FlexBasis;

View file

@ -192,10 +192,7 @@ impl<L> TrackBreadth<L> {
/// <https://drafts.csswg.org/css-grid/#typedef-fixed-breadth> /// <https://drafts.csswg.org/css-grid/#typedef-fixed-breadth>
#[inline] #[inline]
pub fn is_fixed(&self) -> bool { pub fn is_fixed(&self) -> bool {
match *self { matches!(*self, TrackBreadth::Breadth(..))
TrackBreadth::Breadth(ref _lp) => true,
_ => false,
}
} }
} }

View file

@ -8,6 +8,7 @@ use crate::parser::{Parse, ParserContext};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::computed::ExtremumLength; use crate::values::computed::ExtremumLength;
use cssparser::Parser; use cssparser::Parser;
use num_traits::Zero;
use style_traits::ParseError; use style_traits::ParseError;
/// A `<length-percentage> | auto` value. /// A `<length-percentage> | auto` value.
@ -96,14 +97,17 @@ impl<LengthPercentage: Parse> Parse for LengthPercentageOrAuto<LengthPercentage>
ToComputedValue, ToComputedValue,
ToCss, ToCss,
)] )]
pub enum Size<LengthPercentage> { #[repr(C, u8)]
LengthPercentage(LengthPercentage), pub enum GenericSize<LengthPercent> {
LengthPercentage(LengthPercent),
Auto, Auto,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[animation(error)] #[animation(error)]
ExtremumLength(ExtremumLength), ExtremumLength(ExtremumLength),
} }
pub use self::GenericSize as Size;
impl<LengthPercentage> Size<LengthPercentage> { impl<LengthPercentage> Size<LengthPercentage> {
/// `auto` value. /// `auto` value.
#[inline] #[inline]
@ -134,14 +138,17 @@ impl<LengthPercentage> Size<LengthPercentage> {
ToComputedValue, ToComputedValue,
ToCss, ToCss,
)] )]
pub enum MaxSize<LengthPercentage> { #[repr(C, u8)]
LengthPercentage(LengthPercentage), pub enum GenericMaxSize<LengthPercent> {
LengthPercentage(LengthPercent),
None, None,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[animation(error)] #[animation(error)]
ExtremumLength(ExtremumLength), ExtremumLength(ExtremumLength),
} }
pub use self::GenericMaxSize as MaxSize;
impl<LengthPercentage> MaxSize<LengthPercentage> { impl<LengthPercentage> MaxSize<LengthPercentage> {
/// `none` value. /// `none` value.
#[inline] #[inline]
@ -149,3 +156,42 @@ impl<LengthPercentage> MaxSize<LengthPercentage> {
MaxSize::None MaxSize::None
} }
} }
/// A generic `<length>` | `<number>` value for the `-moz-tab-size` property.
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToCss,
)]
#[repr(C, u8)]
pub enum GenericLengthOrNumber<L, N> {
/// A number.
///
/// NOTE: Numbers need to be before lengths, in order to parse them
/// first, since `0` should be a number, not the `0px` length.
Number(N),
/// A length.
Length(L),
}
pub use self::GenericLengthOrNumber as LengthOrNumber;
impl<L, N> LengthOrNumber<L, N> {
/// Returns `0`.
pub fn zero() -> Self
where
N: Zero,
{
LengthOrNumber::Number(num_traits::Zero::zero())
}
}

View file

@ -9,6 +9,8 @@ use super::CustomIdent;
use crate::counter_style::{parse_counter_style_name, Symbols}; use crate::counter_style::{parse_counter_style_name, Symbols};
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use cssparser::Parser; use cssparser::Parser;
use num_traits::Zero;
use std::ops::Add;
use style_traits::{KeywordsCollectFn, ParseError}; use style_traits::{KeywordsCollectFn, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind}; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind};
@ -117,27 +119,25 @@ impl Parse for CounterStyleOrNone {
if input.try(|i| i.expect_ident_matching("none")).is_ok() { if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(CounterStyleOrNone::None); return Ok(CounterStyleOrNone::None);
} }
if input.try(|i| i.expect_function_matching("symbols")).is_ok() { input.expect_function_matching("symbols")?;
return input.parse_nested_block(|input| { input.parse_nested_block(|input| {
let symbols_type = input let symbols_type = input
.try(|i| SymbolsType::parse(i)) .try(SymbolsType::parse)
.unwrap_or(SymbolsType::Symbolic); .unwrap_or(SymbolsType::Symbolic);
let symbols = Symbols::parse(context, input)?; let symbols = Symbols::parse(context, input)?;
// There must be at least two symbols for alphabetic or // There must be at least two symbols for alphabetic or
// numeric system. // numeric system.
if (symbols_type == SymbolsType::Alphabetic || if (symbols_type == SymbolsType::Alphabetic || symbols_type == SymbolsType::Numeric) &&
symbols_type == SymbolsType::Numeric) && symbols.0.len() < 2 symbols.0.len() < 2
{ {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }
// Identifier is not allowed in symbols() function. // Identifier is not allowed in symbols() function.
if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) { if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }
Ok(CounterStyleOrNone::Symbols(symbols_type, symbols)) Ok(CounterStyleOrNone::Symbols(symbols_type, symbols))
}); })
}
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
} }
} }
@ -177,6 +177,24 @@ impl SpecifiedValueInfo for CounterStyleOrNone {
#[repr(transparent)] #[repr(transparent)]
pub struct NonNegative<T>(pub T); pub struct NonNegative<T>(pub T);
impl<T: Add<Output = T>> Add<NonNegative<T>> for NonNegative<T> {
type Output = Self;
fn add(self, other: Self) -> Self {
NonNegative(self.0 + other.0)
}
}
impl<T: Zero> Zero for NonNegative<T> {
fn is_zero(&self) -> bool {
self.0.is_zero()
}
fn zero() -> Self {
NonNegative(T::zero())
}
}
/// A wrapper of greater-than-or-equal-to-one values. /// A wrapper of greater-than-or-equal-to-one values.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive( #[derive(

View file

@ -19,19 +19,22 @@
ToAnimatedZero, ToAnimatedZero,
ToComputedValue, ToComputedValue,
)] )]
pub struct Position<H, V> { #[repr(C)]
pub struct GenericPosition<H, V> {
/// The horizontal component of position. /// The horizontal component of position.
pub horizontal: H, pub horizontal: H,
/// The vertical component of position. /// The vertical component of position.
pub vertical: V, pub vertical: V,
} }
pub use self::GenericPosition as Position;
impl<H, V> Position<H, V> { impl<H, V> Position<H, V> {
/// Returns a new position. /// Returns a new position.
pub fn new(horizontal: H, vertical: V) -> Self { pub fn new(horizontal: H, vertical: V) -> Self {
Self { Self {
horizontal: horizontal, horizontal,
vertical: vertical, vertical,
} }
} }
} }
@ -45,18 +48,22 @@ impl<H, V> Position<H, V> {
Debug, Debug,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
Parse,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue, ToComputedValue,
ToCss, ToCss,
)] )]
pub enum ZIndex<Integer> { #[repr(C, u8)]
pub enum GenericZIndex<I> {
/// An integer value. /// An integer value.
Integer(Integer), Integer(I),
/// The keyword `auto`. /// The keyword `auto`.
Auto, Auto,
} }
pub use self::GenericZIndex as ZIndex;
impl<Integer> ZIndex<Integer> { impl<Integer> ZIndex<Integer> {
/// Returns `auto` /// Returns `auto`
#[inline] #[inline]

View file

@ -136,6 +136,7 @@ impl<ColorType: Parse, UrlPaintServer: Parse> Parse for SVGPaint<ColorType, UrlP
Debug, Debug,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
Parse,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,
@ -143,28 +144,26 @@ impl<ColorType: Parse, UrlPaintServer: Parse> Parse for SVGPaint<ColorType, UrlP
ToCss, ToCss,
)] )]
pub enum SvgLengthPercentageOrNumber<LengthPercentage, Number> { pub enum SvgLengthPercentageOrNumber<LengthPercentage, Number> {
/// <number>
///
/// Note that this needs to be before, so it gets parsed before the length,
/// to handle `0` correctly as a number instead of a `<length>`.
Number(Number),
/// <length> | <percentage> /// <length> | <percentage>
LengthPercentage(LengthPercentage), LengthPercentage(LengthPercentage),
/// <number>
Number(Number),
} }
/// Parsing the SvgLengthPercentageOrNumber. At first, we need to parse number /// Whether the `context-value` value is enabled.
/// since prevent converting to the length. #[cfg(feature = "gecko")]
impl<LengthPercentageType: Parse, NumberType: Parse> Parse pub fn is_context_value_enabled(_: &ParserContext) -> bool {
for SvgLengthPercentageOrNumber<LengthPercentageType, NumberType> use crate::gecko_bindings::structs::mozilla;
{ unsafe { mozilla::StaticPrefs_sVarCache_gfx_font_rendering_opentype_svg_enabled }
fn parse<'i, 't>( }
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(num) = input.try(|i| NumberType::parse(context, i)) {
return Ok(SvgLengthPercentageOrNumber::Number(num));
}
let lp = LengthPercentageType::parse(context, input)?; /// Whether the `context-value` value is enabled.
Ok(SvgLengthPercentageOrNumber::LengthPercentage(lp)) #[cfg(not(feature = "gecko"))]
} pub fn is_context_value_enabled(_: &ParserContext) -> bool {
false
} }
/// An SVG length value supports `context-value` in addition to length. /// An SVG length value supports `context-value` in addition to length.
@ -175,6 +174,7 @@ impl<LengthPercentageType: Parse, NumberType: Parse> Parse
Debug, Debug,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
Parse,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,
@ -185,6 +185,7 @@ pub enum SVGLength<LengthType> {
/// `<length> | <percentage> | <number>` /// `<length> | <percentage> | <number>`
Length(LengthType), Length(LengthType),
/// `context-value` /// `context-value`
#[parse(condition = "is_context_value_enabled")]
ContextValue, ContextValue,
} }
@ -216,6 +217,7 @@ pub enum SVGStrokeDashArray<LengthType> {
Debug, Debug,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
Parse,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue, ToComputedValue,

View file

@ -149,25 +149,3 @@ impl<N, L> LineHeight<N, L> {
LineHeight::Normal LineHeight::Normal
} }
} }
/// A generic value for the `-moz-tab-size` property.
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToCss,
)]
pub enum MozTabSize<Number, Length> {
/// A number.
Number(Number),
/// A length.
Length(Length),
}

View file

@ -83,7 +83,8 @@ impl<T: Into<f64>> From<Matrix3D<T>> for Transform3D<f64> {
ToComputedValue, ToComputedValue,
ToCss, ToCss,
)] )]
pub struct TransformOrigin<H, V, Depth> { #[repr(C)]
pub struct GenericTransformOrigin<H, V, Depth> {
/// The horizontal origin. /// The horizontal origin.
pub horizontal: H, pub horizontal: H,
/// The vertical origin. /// The vertical origin.
@ -92,13 +93,15 @@ pub struct TransformOrigin<H, V, Depth> {
pub depth: Depth, pub depth: Depth,
} }
pub use self::GenericTransformOrigin as TransformOrigin;
impl<H, V, D> TransformOrigin<H, V, D> { impl<H, V, D> TransformOrigin<H, V, D> {
/// Returns a new transform origin. /// Returns a new transform origin.
pub fn new(horizontal: H, vertical: V, depth: D) -> Self { pub fn new(horizontal: H, vertical: V, depth: D) -> Self {
Self { Self {
horizontal: horizontal, horizontal,
vertical: vertical, vertical,
depth: depth, depth,
} }
} }
} }

View file

@ -4,10 +4,6 @@
//! Generic types for url properties. //! Generic types for url properties.
use crate::parser::{Parse, ParserContext};
use cssparser::Parser;
use style_traits::ParseError;
/// An image url or none, used for example in list-style-image /// An image url or none, used for example in list-style-image
#[derive( #[derive(
Animate, Animate,
@ -16,6 +12,7 @@ use style_traits::ParseError;
Debug, Debug,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
Parse,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,
@ -35,19 +32,3 @@ impl<Url> UrlOrNone<Url> {
UrlOrNone::None UrlOrNone::None
} }
} }
impl<Url> Parse for UrlOrNone<Url>
where
Url: Parse,
{
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<UrlOrNone<Url>, ParseError<'i>> {
if let Ok(url) = input.try(|input| Url::parse(context, input)) {
return Ok(UrlOrNone::Url(url));
}
input.expect_ident_matching("none")?;
Ok(UrlOrNone::None)
}
}

View file

@ -125,6 +125,7 @@ impl Parse for Impossible {
Copy, Copy,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
Parse,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,
@ -147,19 +148,6 @@ impl<A: Debug, B: Debug> Debug for Either<A, B> {
} }
} }
impl<A: Parse, B: Parse> Parse for Either<A, B> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Either<A, B>, ParseError<'i>> {
if let Ok(v) = input.try(|i| A::parse(context, i)) {
Ok(Either::First(v))
} else {
B::parse(context, input).map(Either::Second)
}
}
}
/// <https://drafts.csswg.org/css-values-4/#custom-idents> /// <https://drafts.csswg.org/css-values-4/#custom-idents>
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)]
pub struct CustomIdent(pub Atom); pub struct CustomIdent(pub Atom);

View file

@ -26,7 +26,7 @@ impl Parse for BackgroundSize {
let height = input let height = input
.try(|i| NonNegativeLengthPercentageOrAuto::parse(context, i)) .try(|i| NonNegativeLengthPercentageOrAuto::parse(context, i))
.unwrap_or(NonNegativeLengthPercentageOrAuto::auto()); .unwrap_or(NonNegativeLengthPercentageOrAuto::auto());
return Ok(GenericBackgroundSize::Explicit { width, height }); return Ok(GenericBackgroundSize::ExplicitSize { width, height });
} }
Ok(try_match_ident_ignore_ascii_case! { input, Ok(try_match_ident_ignore_ascii_case! { input,
"cover" => GenericBackgroundSize::Cover, "cover" => GenericBackgroundSize::Cover,
@ -35,16 +35,6 @@ impl Parse for BackgroundSize {
} }
} }
impl BackgroundSize {
/// Returns `auto auto`.
pub fn auto() -> Self {
GenericBackgroundSize::Explicit {
width: NonNegativeLengthPercentageOrAuto::auto(),
height: NonNegativeLengthPercentageOrAuto::auto(),
}
}
}
/// One of the keywords for `background-repeat`. /// One of the keywords for `background-repeat`.
#[derive( #[derive(
Clone, Clone,

View file

@ -392,6 +392,76 @@ pub enum ScrollSnapType {
Proximity, Proximity,
} }
/// Specified value of scroll-snap-align keyword value.
#[allow(missing_docs)]
#[derive(
Clone,
Copy,
Debug,
Eq,
FromPrimitive,
Hash,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
)]
#[repr(u8)]
pub enum ScrollSnapAlignKeyword {
None,
Start,
End,
Center,
}
/// https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-align
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)]
#[repr(C)]
pub struct ScrollSnapAlign {
block: ScrollSnapAlignKeyword,
inline: ScrollSnapAlignKeyword,
}
impl ScrollSnapAlign {
/// Returns `none`.
#[inline]
pub fn none() -> Self {
ScrollSnapAlign {
block: ScrollSnapAlignKeyword::None,
inline: ScrollSnapAlignKeyword::None,
}
}
}
impl Parse for ScrollSnapAlign {
/// [ none | start | end | center ]{1,2}
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<ScrollSnapAlign, ParseError<'i>> {
let block = ScrollSnapAlignKeyword::parse(input)?;
let inline = input.try(ScrollSnapAlignKeyword::parse).unwrap_or(block);
Ok(ScrollSnapAlign { block, inline })
}
}
impl ToCss for ScrollSnapAlign {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.block.to_css(dest)?;
if self.block != self.inline {
dest.write_str(" ")?;
self.inline.to_css(dest)?;
}
Ok(())
}
}
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive( #[derive(
@ -782,20 +852,6 @@ impl Parse for Contain {
/// A specified value for the `perspective` property. /// A specified value for the `perspective` property.
pub type Perspective = GenericPerspective<NonNegativeLength>; pub type Perspective = GenericPerspective<NonNegativeLength>;
impl Parse for Perspective {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(GenericPerspective::None);
}
Ok(GenericPerspective::Length(NonNegativeLength::parse(
context, input,
)?))
}
}
/// A given transition property, that is either `All`, a longhand or shorthand /// A given transition property, that is either `All`, a longhand or shorthand
/// property, or an unsupported or custom property. /// property, or an unsupported or custom property.
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue)]

View file

@ -11,7 +11,7 @@ use crate::parser::{Parse, ParserContext};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::properties::longhands::system_colors::SystemColor; use crate::properties::longhands::system_colors::SystemColor;
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue}; use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
use crate::values::generics::color::Color as GenericColor; use crate::values::generics::color::{Color as GenericColor, ColorOrAuto as GenericColorOrAuto};
use crate::values::specified::calc::CalcNode; use crate::values::specified::calc::CalcNode;
use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token, RGBA}; use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token, RGBA};
use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind}; use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind};
@ -469,3 +469,6 @@ impl Parse for ColorPropertyValue {
Color::parse_quirky(context, input, AllowQuirks::Yes).map(ColorPropertyValue) Color::parse_quirky(context, input, AllowQuirks::Yes).map(ColorPropertyValue)
} }
} }
/// auto | <color>
pub type ColorOrAuto = GenericColorOrAuto<Color>;

View file

@ -4,25 +4,8 @@
//! Specified types for the column properties. //! Specified types for the column properties.
use crate::parser::{Parse, ParserContext};
use crate::values::generics::column::ColumnCount as GenericColumnCount; use crate::values::generics::column::ColumnCount as GenericColumnCount;
use crate::values::specified::PositiveInteger; use crate::values::specified::PositiveInteger;
use cssparser::Parser;
use style_traits::ParseError;
/// A specified type for `column-count` values. /// A specified type for `column-count` values.
pub type ColumnCount = GenericColumnCount<PositiveInteger>; pub type ColumnCount = GenericColumnCount<PositiveInteger>;
impl Parse for ColumnCount {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
return Ok(GenericColumnCount::Auto);
}
Ok(GenericColumnCount::Integer(PositiveInteger::parse(
context, input,
)?))
}
}

View file

@ -4,39 +4,22 @@
//! Specified types for CSS values related to flexbox. //! Specified types for CSS values related to flexbox.
use crate::parser::{Parse, ParserContext};
use crate::values::generics::flex::FlexBasis as GenericFlexBasis; use crate::values::generics::flex::FlexBasis as GenericFlexBasis;
use crate::values::specified::Size; use crate::values::specified::Size;
use cssparser::Parser;
use style_traits::ParseError;
/// A specified value for the `flex-basis` property. /// A specified value for the `flex-basis` property.
pub type FlexBasis = GenericFlexBasis<Size>; pub type FlexBasis = GenericFlexBasis<Size>;
impl Parse for FlexBasis {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(width) = input.try(|i| Size::parse(context, i)) {
return Ok(GenericFlexBasis::Width(width));
}
try_match_ident_ignore_ascii_case! { input,
"content" => Ok(GenericFlexBasis::Content),
}
}
}
impl FlexBasis { impl FlexBasis {
/// `auto` /// `auto`
#[inline] #[inline]
pub fn auto() -> Self { pub fn auto() -> Self {
GenericFlexBasis::Width(Size::auto()) GenericFlexBasis::Size(Size::auto())
} }
/// `0%` /// `0%`
#[inline] #[inline]
pub fn zero_percent() -> Self { pub fn zero_percent() -> Self {
GenericFlexBasis::Width(Size::zero_percent()) GenericFlexBasis::Size(Size::zero_percent())
} }
} }

View file

@ -17,7 +17,7 @@ use crate::values::generics::font::{KeywordSize, VariationValue};
use crate::values::generics::NonNegative; use crate::values::generics::NonNegative;
use crate::values::specified::length::{FontBaseSize, AU_PER_PT, AU_PER_PX}; use crate::values::specified::length::{FontBaseSize, AU_PER_PT, AU_PER_PX};
use crate::values::specified::{AllowQuirks, Angle, Integer, LengthPercentage}; use crate::values::specified::{AllowQuirks, Angle, Integer, LengthPercentage};
use crate::values::specified::{NoCalcLength, Number, Percentage}; use crate::values::specified::{NoCalcLength, NonNegativeNumber, Number, Percentage};
use crate::values::CustomIdent; use crate::values::CustomIdent;
use crate::Atom; use crate::Atom;
use app_units::Au; use app_units::Au;
@ -81,7 +81,7 @@ pub const MAX_FONT_WEIGHT: f32 = 1000.;
/// A specified font-weight value. /// A specified font-weight value.
/// ///
/// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight /// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum FontWeight { pub enum FontWeight {
/// `<font-weight-absolute>` /// `<font-weight-absolute>`
Absolute(AbsoluteFontWeight), Absolute(AbsoluteFontWeight),
@ -111,22 +111,6 @@ impl FontWeight {
} }
} }
impl Parse for FontWeight {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<FontWeight, ParseError<'i>> {
if let Ok(absolute) = input.try(|input| AbsoluteFontWeight::parse(context, input)) {
return Ok(FontWeight::Absolute(absolute));
}
Ok(try_match_ident_ignore_ascii_case! { input,
"bolder" => FontWeight::Bolder,
"lighter" => FontWeight::Lighter,
})
}
}
impl ToComputedValue for FontWeight { impl ToComputedValue for FontWeight {
type ComputedValue = computed::FontWeight; type ComputedValue = computed::FontWeight;
@ -335,7 +319,7 @@ impl SpecifiedFontStyle {
} }
/// The specified value of the `font-style` property. /// The specified value of the `font-style` property.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum FontStyle { pub enum FontStyle {
Specified(SpecifiedFontStyle), Specified(SpecifiedFontStyle),
@ -368,20 +352,11 @@ impl ToComputedValue for FontStyle {
} }
} }
impl Parse for FontStyle {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(FontStyle::Specified(SpecifiedFontStyle::parse(
context, input,
)?))
}
}
/// A value for the `font-stretch` property. /// A value for the `font-stretch` property.
/// ///
/// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop /// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop
///
/// TODO(emilio): We could derive Parse if we had NonNegativePercentage.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
#[repr(u8)] #[repr(u8)]
@ -628,13 +603,13 @@ impl Parse for FamilyName {
} }
} }
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)]
/// Preserve the readability of text when font fallback occurs /// Preserve the readability of text when font fallback occurs
pub enum FontSizeAdjust { pub enum FontSizeAdjust {
/// None variant /// None variant
None, None,
/// Number variant /// Number variant
Number(Number), Number(NonNegativeNumber),
/// system font /// system font
#[css(skip)] #[css(skip)]
System(SystemFont), System(SystemFont),
@ -657,7 +632,9 @@ impl ToComputedValue for FontSizeAdjust {
match *self { match *self {
FontSizeAdjust::None => computed::FontSizeAdjust::None, FontSizeAdjust::None => computed::FontSizeAdjust::None,
FontSizeAdjust::Number(ref n) => { FontSizeAdjust::Number(ref n) => {
computed::FontSizeAdjust::Number(n.to_computed_value(context)) // The computed version handles clamping of animated values
// itself.
computed::FontSizeAdjust::Number(n.to_computed_value(context).0)
}, },
FontSizeAdjust::System(_) => self.compute_system(context), FontSizeAdjust::System(_) => self.compute_system(context),
} }
@ -666,32 +643,13 @@ impl ToComputedValue for FontSizeAdjust {
fn from_computed_value(computed: &computed::FontSizeAdjust) -> Self { fn from_computed_value(computed: &computed::FontSizeAdjust) -> Self {
match *computed { match *computed {
computed::FontSizeAdjust::None => FontSizeAdjust::None, computed::FontSizeAdjust::None => FontSizeAdjust::None,
computed::FontSizeAdjust::Number(ref v) => { computed::FontSizeAdjust::Number(v) => {
FontSizeAdjust::Number(Number::from_computed_value(v)) FontSizeAdjust::Number(NonNegativeNumber::from_computed_value(&v.into()))
}, },
} }
} }
} }
impl Parse for FontSizeAdjust {
/// none | <number>
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<FontSizeAdjust, ParseError<'i>> {
if input
.try(|input| input.expect_ident_matching("none"))
.is_ok()
{
return Ok(FontSizeAdjust::None);
}
Ok(FontSizeAdjust::Number(Number::parse_non_negative(
context, input,
)?))
}
}
/// Additional information for specified keyword-derived font sizes. /// Additional information for specified keyword-derived font sizes.
pub type KeywordInfo = generics::KeywordInfo<NonNegativeLength>; pub type KeywordInfo = generics::KeywordInfo<NonNegativeLength>;

View file

@ -305,7 +305,7 @@ impl Gradient {
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
type Point = GenericPosition<Component<X>, Component<Y>>; type Point = GenericPosition<Component<X>, Component<Y>>;
#[derive(Clone, Copy)] #[derive(Clone, Copy, Parse)]
enum Component<S> { enum Component<S> {
Center, Center,
Number(NumberOrPercentage), Number(NumberOrPercentage),
@ -408,22 +408,6 @@ impl Gradient {
} }
} }
impl<S: Parse> Parse for Component<S> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(side) = input.try(|i| S::parse(context, i)) {
return Ok(Component::Side(side));
}
if let Ok(number) = input.try(|i| NumberOrPercentage::parse(context, i)) {
return Ok(Component::Number(number));
}
input.try(|i| i.expect_ident_matching("center"))?;
Ok(Component::Center)
}
}
let ident = input.expect_ident_cloned()?; let ident = input.expect_ident_cloned()?;
input.expect_comma()?; input.expect_comma()?;

View file

@ -11,10 +11,13 @@ use crate::font_metrics::FontMetricsQueryResult;
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::values::computed::{self, CSSPixelLength, Context}; use crate::values::computed::{self, CSSPixelLength, Context};
use crate::values::generics::length as generics; use crate::values::generics::length as generics;
use crate::values::generics::length::{MaxSize as GenericMaxSize, Size as GenericSize}; use crate::values::generics::length::{
GenericLengthOrNumber, MaxSize as GenericMaxSize, Size as GenericSize,
};
use crate::values::generics::transform::IsZeroLength; use crate::values::generics::transform::IsZeroLength;
use crate::values::generics::NonNegative; use crate::values::generics::NonNegative;
use crate::values::specified::calc::CalcNode; use crate::values::specified::calc::CalcNode;
use crate::values::specified::NonNegativeNumber;
use crate::values::{Auto, CSSFloat, Either, Normal}; use crate::values::{Auto, CSSFloat, Either, Normal};
use app_units::Au; use app_units::Au;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
@ -1023,30 +1026,7 @@ pub type LengthOrNormal = Either<Length, Normal>;
pub type LengthOrAuto = Either<Length, Auto>; pub type LengthOrAuto = Either<Length, Auto>;
/// Either a `<length>` or a `<number>`. /// Either a `<length>` or a `<number>`.
pub type LengthOrNumber = Either<Length, Number>; pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
impl LengthOrNumber {
/// Parse a non-negative LengthOrNumber.
pub fn parse_non_negative<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
// We try to parse as a Number first because, for cases like
// LengthOrNumber, we want "0" to be parsed as a plain Number rather
// than a Length (0px); this matches the behaviour of all major browsers
if let Ok(v) = input.try(|i| Number::parse_non_negative(context, i)) {
return Ok(Either::Second(v));
}
Length::parse_non_negative(context, input).map(Either::First)
}
/// Returns `0`.
#[inline]
pub fn zero() -> Self {
Either::Second(Number::new(0.))
}
}
/// A specified value for `min-width`, `min-height`, `width` or `height` property. /// A specified value for `min-width`, `min-height`, `width` or `height` property.
pub type Size = GenericSize<NonNegativeLengthPercentage>; pub type Size = GenericSize<NonNegativeLengthPercentage>;
@ -1123,3 +1103,6 @@ impl MaxSize {
Ok(GenericMaxSize::LengthPercentage(length)) Ok(GenericMaxSize::LengthPercentage(length))
} }
} }
/// A specified non-negative `<length>` | `<number>`.
pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;

View file

@ -19,9 +19,10 @@ use crate::values::serialize_atom_identifier;
use crate::values::specified::calc::CalcNode; use crate::values::specified::calc::CalcNode;
use crate::{Atom, Namespace, Prefix}; use crate::{Atom, Namespace, Prefix};
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use num_traits::One; use num_traits::{One, Zero};
use std::f32; use std::f32;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::ops::Add;
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
@ -39,8 +40,9 @@ pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display};
pub use self::box_::{Appearance, BreakBetween, BreakWithin}; pub use self::box_::{Appearance, BreakBetween, BreakWithin};
pub use self::box_::{Clear, Float, Overflow, OverflowAnchor}; pub use self::box_::{Clear, Float, Overflow, OverflowAnchor};
pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize}; pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize};
pub use self::box_::{ScrollSnapType, TouchAction, TransitionProperty, VerticalAlign, WillChange}; pub use self::box_::{ScrollSnapAlign, ScrollSnapType};
pub use self::color::{Color, ColorPropertyValue, RGBAColor}; pub use self::box_::{TouchAction, TransitionProperty, VerticalAlign, WillChange};
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue, RGBAColor};
pub use self::column::ColumnCount; pub use self::column::ColumnCount;
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset}; pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
pub use self::easing::TimingFunction; pub use self::easing::TimingFunction;
@ -57,7 +59,7 @@ pub use self::gecko::ScrollSnapPoint;
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect}; pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect};
pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth}; pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth};
pub use self::length::{FontRelativeLength, Length, LengthOrNumber}; pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLengthOrNumber};
pub use self::length::{LengthPercentage, LengthPercentageOrAuto}; pub use self::length::{LengthPercentage, LengthPercentageOrAuto};
pub use self::length::{MaxSize, Size}; pub use self::length::{MaxSize, Size};
pub use self::length::{NoCalcLength, ViewportPercentageLength}; pub use self::length::{NoCalcLength, ViewportPercentageLength};
@ -70,14 +72,14 @@ pub use self::outline::OutlineStyle;
pub use self::percentage::Percentage; pub use self::percentage::Percentage;
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position}; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position};
pub use self::position::{PositionComponent, ZIndex}; pub use self::position::{PositionComponent, ZIndex};
pub use self::rect::LengthOrNumberRect; pub use self::rect::NonNegativeLengthOrNumberRect;
pub use self::resolution::Resolution; pub use self::resolution::Resolution;
pub use self::svg::MozContextProperties; pub use self::svg::MozContextProperties;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::svg_path::SVGPathData; pub use self::svg_path::SVGPathData;
pub use self::table::XSpan; pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign}; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextAlign};
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle}; pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle};
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
pub use self::time::Time; pub use self::time::Time;
@ -85,7 +87,7 @@ pub use self::transform::{Rotate, Scale, Transform};
pub use self::transform::{TransformOrigin, TransformStyle, Translate}; pub use self::transform::{TransformOrigin, TransformStyle, Translate};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub use self::ui::CursorImage; pub use self::ui::CursorImage;
pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon, UserSelect}; pub use self::ui::{Cursor, MozForceBrokenImageIcon, UserSelect};
pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -270,6 +272,26 @@ impl IsParallelTo for (Number, Number, Number) {
impl SpecifiedValueInfo for Number {} impl SpecifiedValueInfo for Number {}
impl Add for Number {
type Output = Self;
fn add(self, other: Self) -> Self {
Self::new(self.get() + other.get())
}
}
impl Zero for Number {
#[inline]
fn zero() -> Self {
Self::new(0.)
}
#[inline]
fn is_zero(&self) -> bool {
self.get() == 0.
}
}
impl From<Number> for f32 { impl From<Number> for f32 {
#[inline] #[inline]
fn from(n: Number) -> Self { fn from(n: Number) -> Self {
@ -563,7 +585,7 @@ impl Parse for PositiveInteger {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
Integer::parse_positive(context, input).map(GreaterThanOrEqualToOne::<Integer>) Integer::parse_positive(context, input).map(GreaterThanOrEqualToOne)
} }
} }

View file

@ -731,15 +731,3 @@ impl GridTemplateAreas {
/// A specified value for the `z-index` property. /// A specified value for the `z-index` property.
pub type ZIndex = GenericZIndex<Integer>; pub type ZIndex = GenericZIndex<Integer>;
impl Parse for ZIndex {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
return Ok(GenericZIndex::Auto);
}
Ok(GenericZIndex::Integer(Integer::parse(context, input)?))
}
}

View file

@ -4,22 +4,8 @@
//! Specified types for CSS borders. //! Specified types for CSS borders.
use crate::parser::ParserContext;
use crate::values::generics::rect::Rect; use crate::values::generics::rect::Rect;
use crate::values::specified::length::LengthOrNumber; use crate::values::specified::length::NonNegativeLengthOrNumber;
use cssparser::Parser;
use style_traits::ParseError;
/// A specified rectangle made of four `<length-or-number>` values. /// A specified rectangle made of four `<length-or-number>` values.
pub type LengthOrNumberRect = Rect<LengthOrNumber>; pub type NonNegativeLengthOrNumberRect = Rect<NonNegativeLengthOrNumber>;
impl LengthOrNumberRect {
/// Parses a `LengthOrNumberRect`, rejecting negative values.
#[inline]
pub fn parse_non_negative<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Rect::parse_with(context, input, LengthOrNumber::parse_non_negative)
}
}

View file

@ -23,31 +23,6 @@ pub type SVGPaint = generic::SVGPaint<Color, SpecifiedUrl>;
/// Specified SVG Paint Kind value /// Specified SVG Paint Kind value
pub type SVGPaintKind = generic::SVGPaintKind<Color, SpecifiedUrl>; pub type SVGPaintKind = generic::SVGPaintKind<Color, SpecifiedUrl>;
#[cfg(feature = "gecko")]
fn is_context_value_enabled() -> bool {
// The prefs can only be mutated on the main thread, so it is safe
// to read whenever we are on the main thread or the main thread is
// blocked.
use crate::gecko_bindings::structs::mozilla;
unsafe { mozilla::StaticPrefs_sVarCache_gfx_font_rendering_opentype_svg_enabled }
}
#[cfg(not(feature = "gecko"))]
fn is_context_value_enabled() -> bool {
false
}
fn parse_context_value<'i, 't, T>(
input: &mut Parser<'i, 't>,
value: T,
) -> Result<T, ParseError<'i>> {
if !is_context_value_enabled() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
input.expect_ident_matching("context-value")?;
Ok(value)
}
/// A value of <length> | <percentage> | <number> for stroke-dashoffset. /// A value of <length> | <percentage> | <number> for stroke-dashoffset.
/// <https://www.w3.org/TR/SVG11/painting.html#StrokeProperties> /// <https://www.w3.org/TR/SVG11/painting.html#StrokeProperties>
pub type SvgLengthPercentageOrNumber = pub type SvgLengthPercentageOrNumber =
@ -56,18 +31,6 @@ pub type SvgLengthPercentageOrNumber =
/// <length> | <percentage> | <number> | context-value /// <length> | <percentage> | <number> | context-value
pub type SVGLength = generic::SVGLength<SvgLengthPercentageOrNumber>; pub type SVGLength = generic::SVGLength<SvgLengthPercentageOrNumber>;
impl Parse for SVGLength {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
input
.try(|i| SvgLengthPercentageOrNumber::parse(context, i))
.map(Into::into)
.or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
}
}
impl From<SvgLengthPercentageOrNumber> for SVGLength { impl From<SvgLengthPercentageOrNumber> for SVGLength {
fn from(length: SvgLengthPercentageOrNumber) -> Self { fn from(length: SvgLengthPercentageOrNumber) -> Self {
generic::SVGLength::Length(length) generic::SVGLength::Length(length)
@ -82,18 +45,6 @@ pub type NonNegativeSvgLengthPercentageOrNumber =
/// A non-negative version of SVGLength. /// A non-negative version of SVGLength.
pub type SVGWidth = generic::SVGLength<NonNegativeSvgLengthPercentageOrNumber>; pub type SVGWidth = generic::SVGLength<NonNegativeSvgLengthPercentageOrNumber>;
impl Parse for SVGWidth {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
input
.try(|i| NonNegativeSvgLengthPercentageOrNumber::parse(context, i))
.map(Into::into)
.or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
}
}
impl From<NonNegativeSvgLengthPercentageOrNumber> for SVGWidth { impl From<NonNegativeSvgLengthPercentageOrNumber> for SVGWidth {
fn from(length: NonNegativeSvgLengthPercentageOrNumber) -> Self { fn from(length: NonNegativeSvgLengthPercentageOrNumber) -> Self {
generic::SVGLength::Length(length) generic::SVGLength::Length(length)
@ -113,11 +64,14 @@ impl Parse for SVGStrokeDashArray {
NonNegativeSvgLengthPercentageOrNumber::parse(context, i) NonNegativeSvgLengthPercentageOrNumber::parse(context, i)
}) })
}) { }) {
Ok(generic::SVGStrokeDashArray::Values(values)) return Ok(generic::SVGStrokeDashArray::Values(values));
} else if let Ok(_) = input.try(|i| i.expect_ident_matching("none")) { }
Ok(generic::SVGStrokeDashArray::Values(vec![]))
} else { try_match_ident_ignore_ascii_case! { input,
parse_context_value(input, generic::SVGStrokeDashArray::ContextValue) "context-value" if generic::is_context_value_enabled(context) => {
Ok(generic::SVGStrokeDashArray::ContextValue)
},
"none" => Ok(generic::SVGStrokeDashArray::Values(vec![])),
} }
} }
} }
@ -125,22 +79,6 @@ impl Parse for SVGStrokeDashArray {
/// <opacity-value> | context-fill-opacity | context-stroke-opacity /// <opacity-value> | context-fill-opacity | context-stroke-opacity
pub type SVGOpacity = generic::SVGOpacity<Opacity>; pub type SVGOpacity = generic::SVGOpacity<Opacity>;
impl Parse for SVGOpacity {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(opacity) = input.try(|i| Opacity::parse(context, i)) {
return Ok(generic::SVGOpacity::Opacity(opacity));
}
try_match_ident_ignore_ascii_case! { input,
"context-fill-opacity" => Ok(generic::SVGOpacity::ContextFillOpacity),
"context-stroke-opacity" => Ok(generic::SVGOpacity::ContextStrokeOpacity),
}
}
}
/// The specified value for a single CSS paint-order property. /// The specified value for a single CSS paint-order property.
#[repr(u8)] #[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, ToCss)] #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, ToCss)]

View file

@ -13,11 +13,10 @@ use crate::values::computed::text::TextOverflow as ComputedTextOverflow;
use crate::values::computed::{Context, ToComputedValue}; use crate::values::computed::{Context, ToComputedValue};
use crate::values::generics::text::InitialLetter as GenericInitialLetter; use crate::values::generics::text::InitialLetter as GenericInitialLetter;
use crate::values::generics::text::LineHeight as GenericLineHeight; use crate::values::generics::text::LineHeight as GenericLineHeight;
use crate::values::generics::text::MozTabSize as GenericMozTabSize;
use crate::values::generics::text::Spacing; use crate::values::generics::text::Spacing;
use crate::values::specified::length::NonNegativeLengthPercentage;
use crate::values::specified::length::{FontRelativeLength, Length}; use crate::values::specified::length::{FontRelativeLength, Length};
use crate::values::specified::length::{LengthPercentage, NoCalcLength}; use crate::values::specified::length::{LengthPercentage, NoCalcLength};
use crate::values::specified::length::{NonNegativeLength, NonNegativeLengthPercentage};
use crate::values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number}; use crate::values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number};
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
@ -420,7 +419,7 @@ pub enum TextAlignKeyword {
/// Specified value of text-align property. /// Specified value of text-align property.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, SpecifiedValueInfo, ToCss)] #[derive(Clone, Copy, Debug, Eq, Hash, Parse, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum TextAlign { pub enum TextAlign {
/// Keyword value of text-align property. /// Keyword value of text-align property.
Keyword(TextAlignKeyword), Keyword(TextAlignKeyword),
@ -436,27 +435,6 @@ pub enum TextAlign {
MozCenterOrInherit, MozCenterOrInherit,
} }
impl Parse for TextAlign {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
// MozCenterOrInherit cannot be parsed, only set directly on the elements
if let Ok(key) = input.try(TextAlignKeyword::parse) {
return Ok(TextAlign::Keyword(key));
}
#[cfg(feature = "gecko")]
{
input.expect_ident_matching("match-parent")?;
return Ok(TextAlign::MatchParent);
}
#[cfg(feature = "servo")]
{
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
}
}
impl TextAlign { impl TextAlign {
/// Convert an enumerated value coming from Gecko to a `TextAlign`. /// Convert an enumerated value coming from Gecko to a `TextAlign`.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -835,25 +813,6 @@ impl From<TextEmphasisPosition> for u8 {
} }
} }
/// A specified value for the `-moz-tab-size` property.
pub type MozTabSize = GenericMozTabSize<NonNegativeNumber, NonNegativeLength>;
impl Parse for MozTabSize {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(number) = input.try(|i| NonNegativeNumber::parse(context, i)) {
// Numbers need to be parsed first because `0` must be recognised
// as the number `0` and not the length `0px`.
return Ok(GenericMozTabSize::Number(number));
}
Ok(GenericMozTabSize::Length(NonNegativeLength::parse(
context, input,
)?))
}
}
/// Values for the `overflow-wrap` property. /// Values for the `overflow-wrap` property.
#[repr(u8)] #[repr(u8)]
#[derive( #[derive(

View file

@ -231,7 +231,7 @@ impl Parse for Transform {
} }
/// The specified value of a component of a CSS `<transform-origin>`. /// The specified value of a component of a CSS `<transform-origin>`.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] #[derive(Clone, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum OriginComponent<S> { pub enum OriginComponent<S> {
/// `center` /// `center`
Center, Center,
@ -295,25 +295,6 @@ impl Parse for TransformOrigin {
} }
} }
impl<S> Parse for OriginComponent<S>
where
S: Parse,
{
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("center")).is_ok() {
return Ok(OriginComponent::Center);
}
if let Ok(lp) = input.try(|i| LengthPercentage::parse(context, i)) {
return Ok(OriginComponent::Length(lp));
}
let keyword = S::parse(context, input)?;
Ok(OriginComponent::Side(keyword))
}
}
impl<S> ToComputedValue for OriginComponent<S> impl<S> ToComputedValue for OriginComponent<S>
where where
S: Side, S: Side,

View file

@ -9,14 +9,10 @@ use crate::values::generics::ui as generics;
use crate::values::specified::color::Color; use crate::values::specified::color::Color;
use crate::values::specified::url::SpecifiedImageUrl; use crate::values::specified::url::SpecifiedImageUrl;
use crate::values::specified::Number; use crate::values::specified::Number;
use crate::values::{Auto, Either};
use cssparser::Parser; use cssparser::Parser;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
/// auto | <color>
pub type ColorOrAuto = Either<Color, Auto>;
/// A specified value for the `cursor` property. /// A specified value for the `cursor` property.
pub type Cursor = generics::Cursor<CursorImage>; pub type Cursor = generics::Cursor<CursorImage>;

View file

@ -5,8 +5,8 @@
use crate::cg; use crate::cg;
use crate::to_css::CssVariantAttrs; use crate::to_css::CssVariantAttrs;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use syn::{DeriveInput, Path}; use syn::{self, DeriveInput, Path};
use synstructure; use synstructure::{Structure, VariantInfo};
#[darling(attributes(parse), default)] #[darling(attributes(parse), default)]
#[derive(Default, FromVariant)] #[derive(Default, FromVariant)]
@ -15,22 +15,90 @@ pub struct ParseVariantAttrs {
pub condition: Option<Path>, pub condition: Option<Path>,
} }
pub fn derive(input: DeriveInput) -> TokenStream { fn parse_non_keyword_variant(
name: &syn::Ident,
variant: &VariantInfo,
variant_attrs: &CssVariantAttrs,
parse_attrs: &ParseVariantAttrs,
skip_try: bool,
) -> TokenStream {
let bindings = variant.bindings();
assert!(parse_attrs.aliases.is_none());
assert!(variant_attrs.function.is_none());
assert!(variant_attrs.keyword.is_none());
assert_eq!(
bindings.len(),
1,
"We only support deriving parse for simple variants"
);
let variant_name = &variant.ast().ident;
let ty = &bindings[0].ast().ty;
let mut parse = if skip_try {
quote! {
let v = <#ty as crate::parser::Parse>::parse(context, input)?;
return Ok(#name::#variant_name(v));
}
} else {
quote! {
if let Ok(v) = input.try(|i| <#ty as crate::parser::Parse>::parse(context, i)) {
return Ok(#name::#variant_name(v));
}
}
};
if let Some(ref condition) = parse_attrs.condition {
parse = quote! {
if #condition(context) {
#parse
}
};
if skip_try {
// We're the last variant and we can fail to parse due to the
// condition clause. If that happens, we need to return an error.
parse = quote! {
#parse
Err(input.new_custom_error(style_traits::StyleParseErrorKind::UnspecifiedError))
};
}
}
parse
}
pub fn derive(mut input: DeriveInput) -> TokenStream {
{
let mut where_clause = input.generics.where_clause.take();
for param in input.generics.type_params() {
cg::add_predicate(
&mut where_clause,
parse_quote!(#param: crate::parser::Parse),
);
}
input.generics.where_clause = where_clause;
}
let name = &input.ident; let name = &input.ident;
let s = synstructure::Structure::new(&input); let s = Structure::new(&input);
let mut saw_condition = false; let mut saw_condition = false;
let match_body = s.variants().iter().fold(quote!(), |match_body, variant| { let mut match_keywords = quote! {};
let bindings = variant.bindings(); let mut non_keywords = vec![];
assert!(
bindings.is_empty(),
"Parse is only supported for single-variant enums for now"
);
let mut effective_variants = 0;
for variant in s.variants().iter() {
let css_variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast()); let css_variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast());
let parse_attrs = cg::parse_variant_attrs_from_ast::<ParseVariantAttrs>(&variant.ast()); let parse_attrs = cg::parse_variant_attrs_from_ast::<ParseVariantAttrs>(&variant.ast());
if css_variant_attrs.skip { if css_variant_attrs.skip {
return match_body; continue;
}
effective_variants += 1;
saw_condition |= parse_attrs.condition.is_some();
if !variant.bindings().is_empty() {
non_keywords.push((variant, css_variant_attrs, parse_attrs));
continue;
} }
let identifier = cg::to_css_identifier( let identifier = cg::to_css_identifier(
@ -40,55 +108,73 @@ pub fn derive(input: DeriveInput) -> TokenStream {
); );
let ident = &variant.ast().ident; let ident = &variant.ast().ident;
saw_condition |= parse_attrs.condition.is_some();
let condition = match parse_attrs.condition { let condition = match parse_attrs.condition {
Some(ref p) => quote! { if #p(context) }, Some(ref p) => quote! { if #p(context) },
None => quote! {}, None => quote! {},
}; };
let mut body = quote! { match_keywords.extend(quote! {
#match_body
#identifier #condition => Ok(#name::#ident), #identifier #condition => Ok(#name::#ident),
}; });
let aliases = match parse_attrs.aliases { let aliases = match parse_attrs.aliases {
Some(aliases) => aliases, Some(aliases) => aliases,
None => return body, None => continue,
}; };
for alias in aliases.split(',') { for alias in aliases.split(',') {
body = quote! { match_keywords.extend(quote! {
#body
#alias #condition => Ok(#name::#ident), #alias #condition => Ok(#name::#ident),
}; });
} }
}
body let needs_context = saw_condition || !non_keywords.is_empty();
});
let context_ident = if saw_condition { let context_ident = if needs_context {
quote! { context } quote! { context }
} else { } else {
quote! { _ } quote! { _ }
}; };
let parse_body = if saw_condition { let has_keywords = non_keywords.len() != effective_variants;
quote! {
let location = input.current_source_location(); let mut parse_non_keywords = quote! {};
let ident = input.expect_ident()?; for (i, (variant, css_attrs, parse_attrs)) in non_keywords.iter().enumerate() {
match_ignore_ascii_case! { &ident, let skip_try = !has_keywords && i == non_keywords.len() - 1;
#match_body let parse_variant =
_ => Err(location.new_unexpected_token_error( parse_non_keyword_variant(name, variant, css_attrs, parse_attrs, skip_try);
cssparser::Token::Ident(ident.clone()) parse_non_keywords.extend(parse_variant);
)) }
let parse_body = if needs_context {
let parse_keywords = if has_keywords {
quote! {
let location = input.current_source_location();
let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident,
#match_keywords
_ => Err(location.new_unexpected_token_error(
cssparser::Token::Ident(ident.clone())
))
}
} }
} else {
quote! {}
};
quote! {
#parse_non_keywords
#parse_keywords
} }
} else { } else {
quote! { Self::parse(input) } quote! { Self::parse(input) }
}; };
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let parse_trait_impl = quote! { let parse_trait_impl = quote! {
impl crate::parser::Parse for #name { impl #impl_generics crate::parser::Parse for #name #ty_generics #where_clause {
#[inline] #[inline]
fn parse<'i, 't>( fn parse<'i, 't>(
#context_ident: &crate::parser::ParserContext, #context_ident: &crate::parser::ParserContext,
@ -99,10 +185,12 @@ pub fn derive(input: DeriveInput) -> TokenStream {
} }
}; };
if saw_condition { if needs_context {
return parse_trait_impl; return parse_trait_impl;
} }
assert!(non_keywords.is_empty());
// TODO(emilio): It'd be nice to get rid of these, but that makes the // TODO(emilio): It'd be nice to get rid of these, but that makes the
// conversion harder... // conversion harder...
let methods_impl = quote! { let methods_impl = quote! {
@ -125,7 +213,7 @@ pub fn derive(input: DeriveInput) -> TokenStream {
#[inline] #[inline]
pub fn from_ident(ident: &str) -> Result<Self, ()> { pub fn from_ident(ident: &str) -> Result<Self, ()> {
match_ignore_ascii_case! { ident, match_ignore_ascii_case! { ident,
#match_body #match_keywords
_ => Err(()), _ => Err(()),
} }
} }