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

style: Sync changes from mozilla-central.

See each individual commit 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/22641)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-01-06 19:27:39 -05:00 committed by GitHub
commit bffe2a699e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 512 additions and 775 deletions

38
Cargo.lock generated
View file

@ -684,7 +684,7 @@ dependencies = [
"crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -772,7 +772,7 @@ dependencies = [
"procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1123,7 +1123,7 @@ name = "fallible"
version = "0.0.1"
dependencies = [
"hashglobe 0.1.0",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1287,7 +1287,7 @@ dependencies = [
"servo_arc 0.1.1",
"servo_atoms 0.0.1",
"servo_url 0.0.1",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"truetype 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2012,7 +2012,7 @@ dependencies = [
"servo_geometry 0.0.1",
"servo_url 0.0.1",
"size_of_test 0.0.1",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
"style_traits 0.0.1",
"unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2136,7 +2136,7 @@ dependencies = [
"libservo 0.0.1",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2275,8 +2275,8 @@ dependencies = [
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_arc 0.1.1",
"smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2850,7 +2850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -3284,7 +3284,7 @@ dependencies = [
"servo_geometry 0.0.1",
"servo_rand 0.0.1",
"servo_url 0.0.1",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
"style_traits 0.0.1",
"swapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3400,7 +3400,7 @@ dependencies = [
"phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)",
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_arc 0.1.1",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -3528,7 +3528,7 @@ dependencies = [
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_media_derive 0.1.0 (git+https://github.com/servo/media)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -3762,12 +3762,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallbitvec"
version = "2.1.1"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.6.3"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3894,8 +3894,8 @@ dependencies = [
"servo_atoms 0.0.1",
"servo_config 0.0.1",
"servo_url 0.0.1",
"smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"style_derive 0.0.1",
"style_traits 0.0.1",
@ -4575,7 +4575,7 @@ dependencies = [
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender_api 0.57.2 (git+https://github.com/servo/webrender)",
@ -5115,8 +5115,8 @@ dependencies = [
"checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "<none>"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
"checksum smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c63726029f0069f88467873e47f392575f28f9f16b72ac65465263db4b3a13c"
"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8"
"checksum smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1764fe2b30ee783bfe3b9b37b2649d8d590b3148bb12e0079715d4d5c673562e"
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
"checksum smithay-client-toolkit 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ef227bd9251cf8f8e54f8dd9a4b164307e515f5312cd632ebc87b56f723893a2"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "48fa7d3136d8645909de1f7c7eb5416cc43057a75ace08fc39ae736bc9da8af1"

View file

@ -14,6 +14,7 @@ use style::values::computed::{BorderCornerRadius, BorderImageWidth};
use style::values::computed::{BorderImageSideWidth, LengthOrNumber};
use style::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use style::values::generics::rect::Rect as StyleRect;
use style::values::generics::NonNegative;
use style::values::Either;
use webrender_api::{BorderRadius, BorderSide, BorderStyle, ColorF};
use webrender_api::{LayoutSideOffsets, LayoutSize, NormalBorder};
@ -163,7 +164,7 @@ fn side_image_width(
) -> f32 {
match border_image_width {
GenericBorderImageSideWidth::Length(v) => v.to_used_value(total_length).to_f32_px(),
GenericBorderImageSideWidth::Number(x) => border_width * x,
GenericBorderImageSideWidth::Number(x) => border_width * x.0,
GenericBorderImageSideWidth::Auto => border_width,
}
}
@ -181,15 +182,15 @@ pub fn image_width(
)
}
fn resolve_percentage(value: NumberOrPercentage, length: i32) -> i32 {
match value {
fn resolve_percentage(value: NonNegative<NumberOrPercentage>, length: i32) -> i32 {
match value.0 {
NumberOrPercentage::Percentage(p) => (p.0 * length as f32).round() as i32,
NumberOrPercentage::Number(n) => n.round() as i32,
}
}
pub fn image_slice(
border_image_slice: &StyleRect<NumberOrPercentage>,
border_image_slice: &StyleRect<NonNegative<NumberOrPercentage>>,
width: i32,
height: i32,
) -> SideOffsets2D<i32> {

View file

@ -37,7 +37,7 @@ selectors = { path = "../selectors" }
serde = { version = "1.0.27", optional = true }
serde_bytes = { version = "0.10", optional = true }
servo_arc = { path = "../servo_arc" }
smallbitvec = "2.1.0"
smallbitvec = "2.3.0"
smallvec = "0.6"
string_cache = { version = "0.7", optional = true }
thin-slice = "0.1.0"

View file

@ -128,6 +128,7 @@ use style::selector_parser::{
};
use style::shared_lock::{Locked, SharedRwLock};
use style::thread_state;
use style::values::generics::NonNegative;
use style::values::{computed, specified};
use style::values::{CSSFloat, Either};
use style::CaseSensitivityExt;
@ -847,8 +848,9 @@ impl LayoutElementHelpers for LayoutDom<Element> {
};
if let Some(border) = border {
let width_value =
specified::BorderSideWidth::Length(specified::Length::from_px(border as f32));
let width_value = specified::BorderSideWidth::Length(NonNegative(
specified::Length::from_px(border as f32),
));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderTopWidth(width_value.clone()),

View file

@ -60,8 +60,8 @@ serde = {version = "1.0", optional = true, features = ["derive"]}
servo_arc = { path = "../servo_arc" }
servo_atoms = {path = "../atoms", optional = true}
servo_config = {path = "../config", optional = true}
smallbitvec = "2.1.1"
smallvec = "0.6"
smallbitvec = "2.3.0"
smallvec = "0.6.6"
string_cache = { version = "0.7", optional = true }
style_derive = {path = "../style_derive"}
style_traits = {path = "../style_traits"}

View file

@ -139,7 +139,9 @@ mod bindings {
// Disable rust unions, because we replace some types inside of
// them.
let mut builder = Builder::default().rust_target(RustTarget::Stable_1_0);
let mut builder = Builder::default()
.rust_target(RustTarget::Stable_1_25)
.disable_untagged_union();
let rustfmt_path = env::var_os("RUSTFMT")
// This can be replaced with

View file

@ -50,6 +50,7 @@ include = [
"ComputedTimingFunction",
"Display",
"DisplayMode",
"ExtremumLength",
"FillRule",
"FontDisplay",
"FontFaceSourceListComponent",

View file

@ -144,7 +144,7 @@ bitflags! {
/// Event-based document states.
///
/// NB: Is important for this to remain in sync with Gecko's
/// dom/base/nsIDocument.h.
/// dom/base/Document.h.
#[derive(MallocSizeOf)]
pub struct DocumentState: u64 {
/// RTL locale: specific to the XUL localedir attribute

View file

@ -5,6 +5,8 @@
//! This module contains conversion helpers between Servo and Gecko types
//! Ideally, it would be in geckolib itself, but coherence
//! forces us to keep the traits and implementations here
//!
//! FIXME(emilio): This file should generally just die.
#![allow(unsafe_code)]
@ -26,6 +28,7 @@ use crate::values::generics::box_::VerticalAlign;
use crate::values::generics::grid::{TrackListValue, TrackSize};
use crate::values::generics::image::{CompatMode, GradientItem, Image as GenericImage};
use crate::values::generics::rect::Rect;
use crate::values::generics::NonNegative;
use app_units::Au;
use std::f32::consts::PI;
@ -113,7 +116,6 @@ impl From<nsStyleCoord_CalcValue> for LengthOrPercentageOrAuto {
// disappear as we move more stuff to cbindgen.
impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto {
fn from(other: nsStyleCoord_CalcValue) -> Self {
use crate::values::generics::NonNegative;
use style_traits::values::specified::AllowedNumericType;
NonNegative(if other.mLength < 0 || other.mPercent < 0. {
LengthOrPercentageOrAuto::Calc(CalcLengthOrPercentage::with_clamping_mode(
@ -679,6 +681,7 @@ pub mod basic_shape {
use crate::values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource};
use crate::values::generics::border::BorderRadius as GenericBorderRadius;
use crate::values::generics::rect::Rect;
use crate::values::generics::NonNegative;
use crate::values::specified::SVGPathData;
use std::borrow::Borrow;
@ -838,10 +841,17 @@ pub mod basic_shape {
fn from(other: &'a nsStyleCorners) -> Self {
let get_corner = |index| {
BorderCornerRadius::new(
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
.expect("<border-radius> should be a length, percentage, or calc value"),
NonNegative(
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index)).expect(
"<border-radius> should be a length, percentage, or calc value",
),
),
NonNegative(
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
.expect("<border-radius> should be a length, percentage, or calc value"),
.expect(
"<border-radius> should be a length, percentage, or calc value",
),
),
)
};

View file

@ -7,9 +7,8 @@
use crate::context::QuirksMode;
use crate::dom::TElement;
use crate::gecko_bindings::bindings::{self, RawServoStyleSet};
use crate::gecko_bindings::structs::StyleSheet as DomStyleSheet;
use crate::gecko_bindings::structs::{nsIDocument, StyleSheetInfo};
use crate::gecko_bindings::structs::{RawGeckoPresContextBorrowed, ServoStyleSetSizes};
use crate::gecko_bindings::structs::{StyleSheet as DomStyleSheet, StyleSheetInfo};
use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use crate::invalidation::media_queries::{MediaListKey, ToMediaListKey};
use crate::media_queries::{Device, MediaList};
@ -151,8 +150,7 @@ impl PerDocumentStyleData {
// right now not always honored, see bug 1405543...
//
// Should we just force XBL Stylists to be NoQuirks?
let quirks_mode =
unsafe { (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode };
let quirks_mode = unsafe { (*device.pres_context().mDocument.mRawPtr).mCompatMode };
PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
stylist: Stylist::new(device, quirks_mode.into()),
@ -193,12 +191,7 @@ impl PerDocumentStyleDataImpl {
/// Returns whether visited styles are enabled.
#[inline]
pub fn visited_styles_enabled(&self) -> bool {
let doc = self
.stylist
.device()
.pres_context()
.mDocument
.raw::<nsIDocument>();
let doc = self.stylist.device().pres_context().mDocument.mRawPtr;
unsafe { bindings::Gecko_VisitedStylesEnabled(doc) }
}

View file

@ -9,7 +9,7 @@ use crate::gecko_bindings::structs;
use crate::media_queries::media_feature::{AllowsRanges, ParsingRequirements};
use crate::media_queries::media_feature::{Evaluator, MediaFeatureDescription};
use crate::media_queries::media_feature_expression::{AspectRatio, RangeOrOperator};
use crate::media_queries::Device;
use crate::media_queries::{Device, MediaType};
use crate::values::computed::CSSPixelLength;
use crate::values::computed::Resolution;
use crate::Atom;
@ -295,6 +295,59 @@ fn eval_prefers_reduced_motion(device: &Device, query_value: Option<PrefersReduc
}
}
#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
#[repr(u8)]
enum OverflowBlock {
None,
Scroll,
OptionalPaged,
Paged,
}
/// https://drafts.csswg.org/mediaqueries-4/#mf-overflow-block
fn eval_overflow_block(device: &Device, query_value: Option<OverflowBlock>) -> bool {
// For the time being, assume that printing (including previews)
// is the only time when we paginate, and we are otherwise always
// scrolling. This is true at the moment in Firefox, but may need
// updating in the future (e.g., ebook readers built with Stylo, a
// billboard mode that doesn't support overflow at all).
//
// If this ever changes, don't forget to change eval_overflow_inline too.
let scrolling = device.media_type() != MediaType::print();
let query_value = match query_value {
Some(v) => v,
None => return true,
};
match query_value {
OverflowBlock::None | OverflowBlock::OptionalPaged => false,
OverflowBlock::Scroll => scrolling,
OverflowBlock::Paged => !scrolling,
}
}
#[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
#[repr(u8)]
enum OverflowInline {
None,
Scroll,
}
/// https://drafts.csswg.org/mediaqueries-4/#mf-overflow-inline
fn eval_overflow_inline(device: &Device, query_value: Option<OverflowInline>) -> bool {
// See the note in eval_overflow_block.
let scrolling = device.media_type() != MediaType::print();
let query_value = match query_value {
Some(v) => v,
None => return scrolling,
};
match query_value {
OverflowInline::None => !scrolling,
OverflowInline::Scroll => scrolling,
}
}
/// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
bitflags! {
struct PointerCapabilities: u8 {
@ -473,7 +526,7 @@ lazy_static! {
/// to support new types in these entries and (2) ensuring that either
/// nsPresContext::MediaFeatureValuesChanged is called when the value that
/// would be returned by the evaluator function could change.
pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 48] = [
pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 50] = [
feature!(
atom!("width"),
AllowsRanges::Yes,
@ -592,6 +645,18 @@ lazy_static! {
keyword_evaluator!(eval_prefers_reduced_motion, PrefersReducedMotion),
ParsingRequirements::empty(),
),
feature!(
atom!("overflow-block"),
AllowsRanges::No,
keyword_evaluator!(eval_overflow_block, OverflowBlock),
ParsingRequirements::empty(),
),
feature!(
atom!("overflow-inline"),
AllowsRanges::No,
keyword_evaluator!(eval_overflow_inline, OverflowInline),
ParsingRequirements::empty(),
),
feature!(
atom!("pointer"),
AllowsRanges::No,

View file

@ -162,8 +162,8 @@ impl Device {
/// Gets the document pointer.
#[inline]
pub fn document(&self) -> *mut structs::nsIDocument {
self.pres_context().mDocument.raw::<structs::nsIDocument>()
pub fn document(&self) -> *mut structs::Document {
self.pres_context().mDocument.mRawPtr
}
/// Recreates the default computed values.

View file

@ -156,8 +156,6 @@ impl PseudoElement {
/// Construct a `CSSPseudoElementType` from a pseudo-element
#[inline]
fn pseudo_type(&self) -> CSSPseudoElementType {
use crate::gecko_bindings::structs::CSSPseudoElementType_InheritingAnonBox;
match *self {
% for pseudo in PSEUDOS:
% if not pseudo.is_anon_box():
@ -165,7 +163,7 @@ impl PseudoElement {
% elif pseudo.is_tree_pseudo_element():
PseudoElement::${pseudo.capitalized_pseudo()}(..) => CSSPseudoElementType::XULTree,
% elif pseudo.is_inheriting_anon_box():
PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::InheritingAnonBox,
% else:
PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::NonInheritingAnonBox,
% endif

View file

@ -83,7 +83,7 @@ impl GeckoRestyleDamage {
/// Gets restyle damage to reconstruct the entire frame, subsuming all
/// other damage.
pub fn reconstruct() -> Self {
GeckoRestyleDamage(structs::nsChangeHint_nsChangeHint_ReconstructFrame)
GeckoRestyleDamage(structs::nsChangeHint::nsChangeHint_ReconstructFrame)
}
}

View file

@ -13,12 +13,10 @@ use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, Coor
use crate::media_queries::Device;
use crate::values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
use crate::values::computed::FlexBasis as ComputedFlexBasis;
use crate::values::computed::NonNegativeNumber;
use crate::values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage};
use crate::values::computed::{LengthOrPercentageOrAuto, Percentage};
use crate::values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
use crate::values::computed::{MaxLength as ComputedMaxLength, MozLength as ComputedMozLength};
use crate::values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage};
use crate::values::generics::basic_shape::ShapeRadius;
use crate::values::generics::box_::Perspective;
use crate::values::generics::flex::FlexBasis;
@ -34,6 +32,9 @@ use nsstring::{nsACString, nsCStr};
use std::cmp::max;
/// A trait that defines an interface to convert from and to `nsStyleCoord`s.
///
/// TODO(emilio): Almost everything that is in this file should be somehow
/// switched to cbindgen.
pub trait GeckoStyleCoordConvertible: Sized {
/// Convert this to a `nsStyleCoord`.
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T);
@ -66,6 +67,19 @@ impl<A: GeckoStyleCoordConvertible, B: GeckoStyleCoordConvertible> GeckoStyleCoo
}
}
impl<Inner> GeckoStyleCoordConvertible for NonNegative<Inner>
where
Inner: GeckoStyleCoordConvertible,
{
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
self.0.to_gecko_style_coord(coord)
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
Some(NonNegative(Inner::from_gecko_style_coord(coord)?))
}
}
impl GeckoStyleCoordConvertible for ComputedFlexBasis {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
@ -152,16 +166,6 @@ impl GeckoStyleCoordConvertible for LengthOrPercentage {
}
}
impl GeckoStyleCoordConvertible for NonNegativeLengthOrPercentage {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
self.0.to_gecko_style_coord(coord);
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
LengthOrPercentage::from_gecko_style_coord(coord).map(NonNegative::<LengthOrPercentage>)
}
}
impl GeckoStyleCoordConvertible for Length {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
coord.set_value(CoordDataValue::Coord(self.to_i32_au()));
@ -175,26 +179,6 @@ impl GeckoStyleCoordConvertible for Length {
}
}
impl GeckoStyleCoordConvertible for NonNegativeLength {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
self.0.to_gecko_style_coord(coord);
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
Length::from_gecko_style_coord(coord).map(NonNegative::<Length>)
}
}
impl GeckoStyleCoordConvertible for NonNegativeNumber {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
self.0.to_gecko_style_coord(coord);
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
Number::from_gecko_style_coord(coord).map(NonNegative::<Number>)
}
}
impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
let value = match *self {
@ -302,7 +286,7 @@ impl GeckoStyleCoordConvertible for ComputedShapeRadius {
None
}
},
_ => LengthOrPercentage::from_gecko_style_coord(coord).map(ShapeRadius::Length),
_ => GeckoStyleCoordConvertible::from_gecko_style_coord(coord).map(ShapeRadius::Length),
}
}
}
@ -378,40 +362,13 @@ impl GeckoStyleCoordConvertible for Normal {
impl GeckoStyleCoordConvertible for ExtremumLength {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
use crate::gecko_bindings::structs::{
NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT,
};
use crate::gecko_bindings::structs::{
NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT,
};
coord.set_value(CoordDataValue::Enumerated(match *self {
ExtremumLength::MozMaxContent => NS_STYLE_WIDTH_MAX_CONTENT,
ExtremumLength::MozMinContent => NS_STYLE_WIDTH_MIN_CONTENT,
ExtremumLength::MozFitContent => NS_STYLE_WIDTH_FIT_CONTENT,
ExtremumLength::MozAvailable => NS_STYLE_WIDTH_AVAILABLE,
}))
coord.set_value(CoordDataValue::Enumerated(*self as u32));
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
use crate::gecko_bindings::structs::{
NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT,
};
use crate::gecko_bindings::structs::{
NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT,
};
use num_traits::FromPrimitive;
match coord.as_value() {
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MAX_CONTENT) => {
Some(ExtremumLength::MozMaxContent)
},
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MIN_CONTENT) => {
Some(ExtremumLength::MozMinContent)
},
CoordDataValue::Enumerated(NS_STYLE_WIDTH_FIT_CONTENT) => {
Some(ExtremumLength::MozFitContent)
},
CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => {
Some(ExtremumLength::MozAvailable)
},
CoordDataValue::Enumerated(v) => ExtremumLength::from_u32(v),
_ => None,
}
}

View file

@ -22,7 +22,6 @@ use crate::dom::{LayoutIterator, NodeInfo, OpaqueNode, TDocument, TElement, TNod
use crate::element_state::{DocumentState, ElementState};
use crate::font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
use crate::gecko::data::GeckoStyleSheet;
use crate::gecko::global_style_data::GLOBAL_STYLE_DATA;
use crate::gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
use crate::gecko::snapshot_helpers;
use crate::gecko_bindings::bindings;
@ -45,8 +44,8 @@ use crate::gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWThe
use crate::gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsChangeHint;
use crate::gecko_bindings::structs::nsIDocument_DocumentTheme as DocumentTheme;
use crate::gecko_bindings::structs::nsRestyleHint;
use crate::gecko_bindings::structs::Document_DocumentTheme as DocumentTheme;
use crate::gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
use crate::gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
use crate::gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
@ -57,6 +56,7 @@ use crate::gecko_bindings::structs::NODE_NEEDS_FRAME;
use crate::gecko_bindings::structs::{nsAtom, nsIContent, nsINode_BooleanFlag};
use crate::gecko_bindings::structs::{RawGeckoElement, RawGeckoNode, RawGeckoXBLBinding};
use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
use crate::global_style_data::GLOBAL_STYLE_DATA;
use crate::hash::FxHashMap;
use crate::logical_geometry::WritingMode;
use crate::media_queries::Device;
@ -107,9 +107,9 @@ fn elements_with_id<'a, 'le>(
}
}
/// A simple wrapper over `nsIDocument`.
/// A simple wrapper over `Document`.
#[derive(Clone, Copy)]
pub struct GeckoDocument<'ld>(pub &'ld structs::nsIDocument);
pub struct GeckoDocument<'ld>(pub &'ld structs::Document);
impl<'ld> TDocument for GeckoDocument<'ld> {
type ConcreteNode = GeckoNode<'ld>;
@ -121,7 +121,7 @@ impl<'ld> TDocument for GeckoDocument<'ld> {
#[inline]
fn is_html_document(&self) -> bool {
self.0.mType == structs::root::nsIDocument_Type::eHTML
self.0.mType == structs::Document_Type::eHTML
}
#[inline]
@ -1242,11 +1242,8 @@ impl<'le> TElement for GeckoElement<'le> {
}
fn owner_doc_matches_for_testing(&self, device: &Device) -> bool {
self.as_node().owner_doc().0 as *const structs::nsIDocument ==
device
.pres_context()
.mDocument
.raw::<structs::nsIDocument>()
self.as_node().owner_doc().0 as *const structs::Document ==
device.pres_context().mDocument.mRawPtr
}
fn style_attribute(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
@ -1501,9 +1498,6 @@ impl<'le> TElement for GeckoElement<'le> {
/// Process various tasks that are a result of animation-only restyle.
fn process_post_animation(&self, tasks: PostAnimationTasks) {
use crate::gecko_bindings::structs::nsChangeHint_nsChangeHint_Empty;
use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_Subtree;
debug_assert!(!tasks.is_empty(), "Should be involved a task");
// If display style was changed from none to other, we need to resolve
@ -1519,8 +1513,8 @@ impl<'le> TElement for GeckoElement<'le> {
);
unsafe {
self.note_explicit_hints(
nsRestyleHint_eRestyle_Subtree,
nsChangeHint_nsChangeHint_Empty,
nsRestyleHint::eRestyle_Subtree,
nsChangeHint::nsChangeHint_Empty,
);
}
}

View file

@ -5,17 +5,17 @@
//! Helper to iterate over `OriginFlags` bits.
use crate::gecko_bindings::structs::OriginFlags;
use crate::gecko_bindings::structs::OriginFlags_Author;
use crate::gecko_bindings::structs::OriginFlags_User;
use crate::gecko_bindings::structs::OriginFlags_UserAgent;
use crate::stylesheets::OriginSet;
/// Checks that the values for OriginFlags are the ones we expect.
pub fn assert_flags_match() {
use crate::stylesheets::origin::*;
debug_assert_eq!(OriginFlags_UserAgent.0, OriginSet::ORIGIN_USER_AGENT.bits());
debug_assert_eq!(OriginFlags_Author.0, OriginSet::ORIGIN_AUTHOR.bits());
debug_assert_eq!(OriginFlags_User.0, OriginSet::ORIGIN_USER.bits());
debug_assert_eq!(
OriginFlags::UserAgent.0,
OriginSet::ORIGIN_USER_AGENT.bits()
);
debug_assert_eq!(OriginFlags::Author.0, OriginSet::ORIGIN_AUTHOR.bits());
debug_assert_eq!(OriginFlags::User.0, OriginSet::ORIGIN_USER.bits());
}
impl From<OriginFlags> for OriginSet {

View file

@ -193,38 +193,35 @@ impl Default for RestyleHint {
#[cfg(feature = "gecko")]
impl From<nsRestyleHint> for RestyleHint {
fn from(mut raw: nsRestyleHint) -> Self {
use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_Force as eRestyle_Force;
use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_ForceDescendants as eRestyle_ForceDescendants;
use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_LaterSiblings as eRestyle_LaterSiblings;
use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_Self as eRestyle_Self;
use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_SomeDescendants as eRestyle_SomeDescendants;
use crate::gecko_bindings::structs::nsRestyleHint_eRestyle_Subtree as eRestyle_Subtree;
let mut hint = RestyleHint::empty();
debug_assert!(
raw.0 & eRestyle_LaterSiblings.0 == 0,
raw.0 & nsRestyleHint::eRestyle_LaterSiblings.0 == 0,
"Handle later siblings manually if necessary plz."
);
if (raw.0 & (eRestyle_Self.0 | eRestyle_Subtree.0)) != 0 {
raw.0 &= !eRestyle_Self.0;
if (raw.0 & (nsRestyleHint::eRestyle_Self.0 | nsRestyleHint::eRestyle_Subtree.0)) != 0 {
raw.0 &= !nsRestyleHint::eRestyle_Self.0;
hint.insert(RestyleHint::RESTYLE_SELF);
}
if (raw.0 & (eRestyle_Subtree.0 | eRestyle_SomeDescendants.0)) != 0 {
raw.0 &= !eRestyle_Subtree.0;
raw.0 &= !eRestyle_SomeDescendants.0;
if (raw.0 & (nsRestyleHint::eRestyle_Subtree.0 | nsRestyleHint::eRestyle_SomeDescendants.0)) !=
0
{
raw.0 &= !nsRestyleHint::eRestyle_Subtree.0;
raw.0 &= !nsRestyleHint::eRestyle_SomeDescendants.0;
hint.insert(RestyleHint::RESTYLE_DESCENDANTS);
}
if (raw.0 & (eRestyle_ForceDescendants.0 | eRestyle_Force.0)) != 0 {
raw.0 &= !eRestyle_Force.0;
if (raw.0 & (nsRestyleHint::eRestyle_ForceDescendants.0 | nsRestyleHint::eRestyle_Force.0)) !=
0
{
raw.0 &= !nsRestyleHint::eRestyle_Force.0;
hint.insert(RestyleHint::RECASCADE_SELF);
}
if (raw.0 & eRestyle_ForceDescendants.0) != 0 {
raw.0 &= !eRestyle_ForceDescendants.0;
if (raw.0 & nsRestyleHint::eRestyle_ForceDescendants.0) != 0 {
raw.0 &= !nsRestyleHint::eRestyle_ForceDescendants.0;
hint.insert(RestyleHint::RECASCADE_DESCENDANTS);
}
@ -248,7 +245,7 @@ pub fn assert_restyle_hints_match() {
if cfg!(debug_assertions) {
let mut replacements = RestyleHint::replacements();
$(
assert_eq!(structs::$a.0 as usize, $b.bits() as usize, stringify!($b));
assert_eq!(structs::nsRestyleHint::$a.0 as usize, $b.bits() as usize, stringify!($b));
replacements.remove($b);
)*
assert_eq!(replacements, RestyleHint::empty(),
@ -259,9 +256,9 @@ pub fn assert_restyle_hints_match() {
}
check_restyle_hints! {
nsRestyleHint_eRestyle_CSSTransitions => RestyleHint::RESTYLE_CSS_TRANSITIONS,
nsRestyleHint_eRestyle_CSSAnimations => RestyleHint::RESTYLE_CSS_ANIMATIONS,
nsRestyleHint_eRestyle_StyleAttribute => RestyleHint::RESTYLE_STYLE_ATTRIBUTE,
nsRestyleHint_eRestyle_StyleAttribute_Animations => RestyleHint::RESTYLE_SMIL,
eRestyle_CSSTransitions => RestyleHint::RESTYLE_CSS_TRANSITIONS,
eRestyle_CSSAnimations => RestyleHint::RESTYLE_CSS_ANIMATIONS,
eRestyle_StyleAttribute => RestyleHint::RESTYLE_STYLE_ATTRIBUTE,
eRestyle_StyleAttribute_Animations => RestyleHint::RESTYLE_SMIL,
}
}

View file

@ -388,12 +388,12 @@ class Shorthand(object):
and allowed_in_keyframe_block != "False"
def get_animatable(self):
animatable = False
if self.ident == "all":
return False
for sub in self.sub_properties:
if sub.animatable:
animatable = True
break
return animatable
return True
return False
def get_transitionable(self):
transitionable = False

View file

@ -39,7 +39,6 @@ use crate::gecko_bindings::bindings::RawGeckoPresContextBorrowed;
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsCSSPropertyID;
use crate::gecko_bindings::structs::mozilla::CSSPseudoElementType;
use crate::gecko_bindings::structs::mozilla::CSSPseudoElementType_InheritingAnonBox;
use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
use crate::gecko_bindings::sugar::refptr::RefPtr;
use crate::gecko::values::convert_nscolor_to_rgba;
@ -138,7 +137,7 @@ impl ComputedValues {
#[inline]
pub fn is_anon_box(&self) -> bool {
let our_type = self.get_pseudo_type();
return our_type == CSSPseudoElementType_InheritingAnonBox ||
return our_type == CSSPseudoElementType::InheritingAnonBox ||
our_type == CSSPseudoElementType::NonInheritingAnonBox;
}
@ -1687,8 +1686,8 @@ fn static_assert() {
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, NumberOrPercentage};
type NumberOrPercentageRect = crate::values::generics::rect::Rect<NumberOrPercentage>;
use crate::values::computed::{BorderImageSlice, NonNegativeNumberOrPercentage};
type NumberOrPercentageRect = crate::values::generics::rect::Rect<NonNegativeNumberOrPercentage>;
BorderImageSlice {
offsets:

View file

@ -108,7 +108,6 @@ ${helpers.single_keyword(
color-burn hard-light soft-light difference exclusion hue
saturation color luminosity""",
gecko_constant_prefix="NS_STYLE_BLEND",
gecko_pref="layout.css.background-blend-mode.enabled",
vector=True, products="gecko", animation_value_type="discrete",
spec="https://drafts.fxtf.org/compositing/#background-blend-mode",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",

View file

@ -88,7 +88,6 @@ ${helpers.single_keyword(
"box-decoration-break",
"slice clone",
gecko_enum_prefix="StyleBoxDecorationBreak",
gecko_pref="layout.css.box-decoration-break.enabled",
spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break",
products="gecko",
animation_value_type="discrete",
@ -153,14 +152,15 @@ ${helpers.predefined_type(
${helpers.predefined_type(
"border-image-slice",
"BorderImageSlice",
initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()",
initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage::new(1.)).into()",
initial_value="computed::BorderImageSlice::hundred_percent()",
initial_specified_value="specified::BorderImageSlice::hundred_percent()",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER",
boxed=True,
)}
// FIXME(emilio): Why does this live here? ;_;
#[cfg(feature = "gecko")]
impl crate::values::computed::BorderImageWidth {
pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) {
@ -177,7 +177,7 @@ impl crate::values::computed::BorderImageWidth {
l.to_gecko_style_coord(&mut sides.data_at_mut(${i}))
},
BorderImageSideWidth::Number(n) => {
sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n))
sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n.0))
},
}
% endfor
@ -191,6 +191,7 @@ impl crate::values::computed::BorderImageWidth {
use crate::gecko::values::GeckoStyleCoordConvertible;
use crate::values::computed::{LengthOrPercentage, Number};
use crate::values::generics::border::BorderImageSideWidth;
use crate::values::generics::NonNegative;
Some(
crate::values::computed::BorderImageWidth::new(
@ -201,13 +202,13 @@ impl crate::values::computed::BorderImageWidth {
},
eStyleUnit_Factor => {
BorderImageSideWidth::Number(
Number::from_gecko_style_coord(&sides.data_at(${i}))
.expect("sides[${i}] could not convert to Number"))
NonNegative(Number::from_gecko_style_coord(&sides.data_at(${i}))
.expect("sides[${i}] could not convert to Number")))
},
_ => {
BorderImageSideWidth::Length(
LengthOrPercentage::from_gecko_style_coord(&sides.data_at(${i}))
.expect("sides[${i}] could not convert to LengthOrPercentager"))
NonNegative(LengthOrPercentage::from_gecko_style_coord(&sides.data_at(${i}))
.expect("sides[${i}] could not convert to LengthOrPercentage")))
},
},
% endfor

View file

@ -389,7 +389,6 @@ ${helpers.predefined_type(
${helpers.single_keyword(
"scroll-behavior",
"auto smooth",
gecko_pref="layout.css.scroll-behavior.property-enabled",
products="gecko",
spec="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior",
animation_value_type="discrete",
@ -427,7 +426,6 @@ ${helpers.single_keyword(
"isolation",
"auto isolate",
products="gecko",
gecko_pref="layout.css.isolation.enabled",
spec="https://drafts.fxtf.org/compositing/#isolation",
flags="CREATES_STACKING_CONTEXT",
animation_value_type="discrete",
@ -559,6 +557,7 @@ ${helpers.predefined_type(
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
gecko_pref="layout.css.contain.enabled",
spec="https://drafts.csswg.org/css-contain/#contain-property",
enabled_in="chrome",
)}
// Non-standard
@ -626,7 +625,7 @@ ${helpers.predefined_type(
"generics::basic_shape::ShapeSource::None",
products="gecko",
boxed=True,
animation_value_type="ComputedValue",
animation_value_type="basic_shape::FloatAreaShape",
flags="APPLIES_TO_FIRST_LETTER",
spec="https://drafts.csswg.org/css-shapes/#shape-outside-property",
)}

View file

@ -62,6 +62,5 @@ ${helpers.single_keyword(
gecko_constant_prefix="NS_STYLE_BLEND",
animation_value_type="discrete",
flags="CREATES_STACKING_CONTEXT",
gecko_pref="layout.css.mix-blend-mode.enabled",
spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode",
)}

View file

@ -54,7 +54,7 @@ ${helpers.single_keyword(
${helpers.single_keyword(
"color-adjust",
"economy exact", products="gecko",
gecko_pref="layout.css.color-adjust.enabled",
gecko_enum_prefix="StyleColorAdjust",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-color/#propdef-color-adjust",
)}
@ -77,6 +77,5 @@ ${helpers.single_keyword(
products="gecko",
gecko_enum_prefix="StyleImageOrientation",
animation_value_type="discrete",
gecko_pref="layout.css.image-orientation.enabled",
spec="https://drafts.csswg.org/css-images/#propdef-image-orientation",
)}

View file

@ -295,7 +295,7 @@ ${helpers.predefined_type(
"-webkit-text-stroke-width",
"BorderSideWidth",
"crate::values::computed::NonNegativeLength::new(0.)",
initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
initial_specified_value="specified::BorderSideWidth::zero()",
computed_type="crate::values::computed::NonNegativeLength",
products="gecko",
gecko_pref="layout.css.prefixes.webkit",

View file

@ -244,21 +244,12 @@ ${helpers.predefined_type(
if logical:
spec = "https://drafts.csswg.org/css-logical-props/#propdef-%s"
%>
// NOTE: Block-size doesn't support -moz-*-content keywords, since they make
// no sense on the block axis, but it simplifies things the have that it has
// the same type as the other properties, since otherwise we'd need to
// handle logical props where the types are different, which looks like a
// pain.
% if product == "gecko":
<%
parse_function = "parse" if size != "block-size" else "parse_disallow_keyword"
%>
// width, height, block-size, inline-size
${helpers.predefined_type(
size,
"MozLength",
"computed::MozLength::auto()",
parse_function,
logical=logical,
logical_group="size",
allow_quirks=not logical,
@ -272,7 +263,6 @@ ${helpers.predefined_type(
"min-%s" % size,
"MozLength",
"computed::MozLength::auto()",
parse_function,
logical=logical,
logical_group="min-size",
allow_quirks=not logical,
@ -284,7 +274,6 @@ ${helpers.predefined_type(
"max-%s" % size,
"MaxLength",
"computed::MaxLength::none()",
parse_function,
logical=logical,
logical_group="max-size",
allow_quirks=not logical,

View file

@ -88,7 +88,7 @@ ${helpers.predefined_type(
"generics::basic_shape::ShapeSource::None",
products="gecko",
boxed=True,
animation_value_type="ComputedValue",
animation_value_type="basic_shape::ClippingShape",
flags="CREATES_STACKING_CONTEXT",
spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path",
)}

View file

@ -5,7 +5,7 @@
//! Collects a series of applicable rules for a given element.
use crate::applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
use crate::dom::{TElement, TShadowRoot};
use crate::dom::{TElement, TNode, TShadowRoot};
use crate::properties::{AnimationRules, PropertyDeclarationBlock};
use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder};
use crate::selector_map::SelectorMap;
@ -17,6 +17,43 @@ use selectors::matching::{ElementSelectorFlags, MatchingContext};
use servo_arc::ArcBorrow;
use smallvec::SmallVec;
/// This is a bit of a hack so <svg:use> matches the rules of the enclosing
/// tree.
///
/// This function returns the containing shadow host ignoring <svg:use> shadow
/// trees, since those match the enclosing tree's rules.
///
/// Only a handful of places need to really care about this. This is not a
/// problem for invalidation and that kind of stuff because they still don't
/// match rules based on elements outside of the shadow tree, and because the
/// <svg:use> subtrees are immutable and recreated each time the source tree
/// changes.
///
/// We historically allow cross-document <svg:use> to have these rules applied,
/// but I think that's not great. Gecko is the only engine supporting that.
///
/// See https://github.com/w3c/svgwg/issues/504 for the relevant spec
/// discussion.
#[inline]
pub fn containing_shadow_ignoring_svg_use<E: TElement>(
element: E,
) -> Option<<E::ConcreteNode as TNode>::ConcreteShadowRoot> {
let mut shadow = element.containing_shadow()?;
loop {
let host = shadow.host();
let host_is_svg_use_element =
host.is_svg_element() && host.local_name() == &*local_name!("use");
if !host_is_svg_use_element {
return Some(shadow);
}
debug_assert!(
shadow.style_data().is_none(),
"We allow no stylesheets in <svg:use> subtrees"
);
shadow = host.containing_shadow()?;
}
}
/// An object that we use with all the intermediate state needed for the
/// cascade.
///
@ -213,44 +250,19 @@ where
return;
}
let mut current_containing_shadow = self.rule_hash_target.containing_shadow();
while let Some(containing_shadow) = current_containing_shadow {
let containing_shadow = containing_shadow_ignoring_svg_use(self.rule_hash_target);
let containing_shadow = match containing_shadow {
Some(s) => s,
None => return,
};
self.matches_document_author_rules = false;
let cascade_data = containing_shadow.style_data();
let host = containing_shadow.host();
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element))
{
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) {
self.collect_rules_in_shadow_tree(host, map, CascadeLevel::SameTreeAuthorNormal);
}
let host_is_svg_use_element =
host.is_svg_element() && host.local_name() == &*local_name!("use");
if !host_is_svg_use_element {
self.matches_document_author_rules = false;
break;
}
debug_assert!(
cascade_data.is_none(),
"We allow no stylesheets in <svg:use> subtrees"
);
// NOTE(emilio): Hack so <svg:use> matches the rules of the
// enclosing tree.
//
// This is not a problem for invalidation and that kind of stuff
// because they still don't match rules based on elements
// outside of the shadow tree, and because the <svg:use>
// subtrees are immutable and recreated each time the source
// tree changes.
//
// We historically allow cross-document <svg:use> to have these
// rules applied, but I think that's not great. Gecko is the
// only engine supporting that.
//
// See https://github.com/w3c/svgwg/issues/504 for the relevant
// spec discussion.
current_containing_shadow = host.containing_shadow();
self.matches_document_author_rules = current_containing_shadow.is_none();
}
}
/// Collects the rules for the :host pseudo-class.

View file

@ -17,7 +17,7 @@ use crate::media_queries::Device;
use crate::properties::{self, CascadeMode, ComputedValues};
use crate::properties::{AnimationRules, PropertyDeclarationBlock};
use crate::rule_cache::{RuleCache, RuleCacheConditions};
use crate::rule_collector::RuleCollector;
use crate::rule_collector::{containing_shadow_ignoring_svg_use, RuleCollector};
use crate::rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource};
use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry};
use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
@ -1187,7 +1187,9 @@ impl Stylist {
}
}
if let Some(shadow) = element.containing_shadow() {
// Use the same rules to look for the containing host as we do for rule
// collection.
if let Some(shadow) = containing_shadow_ignoring_svg_use(element) {
if let Some(data) = shadow.style_data() {
try_find_in!(data);
}

View file

@ -12,7 +12,8 @@ use crate::properties::PropertyId;
use crate::values::computed::length::CalcLengthOrPercentage;
use crate::values::computed::url::ComputedUrl;
use crate::values::computed::Angle as ComputedAngle;
use crate::values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use crate::values::computed::Image;
use crate::values::specified::SVGPathData;
use crate::values::CSSFloat;
use app_units::Au;
use euclid::{Point2D, Size2D};
@ -339,23 +340,19 @@ trivial_to_animated_value!(ComputedAngle);
trivial_to_animated_value!(ComputedUrl);
trivial_to_animated_value!(bool);
trivial_to_animated_value!(f32);
impl ToAnimatedValue for ComputedBorderCornerRadius {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
ComputedBorderCornerRadius::new(
(animated.0).0.width.clamp_to_non_negative(),
(animated.0).0.height.clamp_to_non_negative(),
)
}
}
// Note: This implementation is for ToAnimatedValue of ShapeSource.
//
// SVGPathData uses Box<[T]>. If we want to derive ToAnimatedValue for all the
// types, we have to do "impl ToAnimatedValue for Box<[T]>" first.
// However, the general version of "impl ToAnimatedValue for Box<[T]>" needs to
// clone |T| and convert it into |T::AnimatedValue|. However, for SVGPathData
// that is unnecessary--moving |T| is sufficient. So here, we implement this
// trait manually.
trivial_to_animated_value!(SVGPathData);
// FIXME: Bug 1514342, Image is not animatable, but we still need to implement
// this to avoid adding this derive to generic::Image and all its arms. We can
// drop this after landing Bug 1514342.
trivial_to_animated_value!(Image);
impl ToAnimatedZero for Au {
#[inline]

View file

@ -8,7 +8,7 @@
//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
use crate::values::computed::url::ComputedUrl;
use crate::values::computed::{Image, LengthOrPercentage};
use crate::values::computed::{Image, LengthOrPercentage, NonNegativeLengthOrPercentage};
use crate::values::generics::basic_shape as generic;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
@ -23,20 +23,26 @@ pub type ClippingShape = generic::ClippingShape<BasicShape, ComputedUrl>;
pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>;
/// A computed basic shape.
pub type BasicShape =
generic::BasicShape<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>;
pub type BasicShape = generic::BasicShape<
LengthOrPercentage,
LengthOrPercentage,
LengthOrPercentage,
NonNegativeLengthOrPercentage,
>;
/// The computed value of `inset()`
pub type InsetRect = generic::InsetRect<LengthOrPercentage>;
pub type InsetRect = generic::InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// A computed circle.
pub type Circle = generic::Circle<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>;
pub type Circle =
generic::Circle<LengthOrPercentage, LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// A computed ellipse.
pub type Ellipse = generic::Ellipse<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>;
pub type Ellipse =
generic::Ellipse<LengthOrPercentage, LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// The computed value of `ShapeRadius`
pub type ShapeRadius = generic::ShapeRadius<LengthOrPercentage>;
pub type ShapeRadius = generic::ShapeRadius<NonNegativeLengthOrPercentage>;
impl ToCss for Circle {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result

View file

@ -4,9 +4,8 @@
//! Computed types for CSS values related to borders.
use crate::values::animated::ToAnimatedZero;
use crate::values::computed::length::{LengthOrPercentage, NonNegativeLength};
use crate::values::computed::{Number, NumberOrPercentage};
use crate::values::computed::length::{NonNegativeLength, NonNegativeLengthOrPercentage};
use crate::values::computed::{NonNegativeNumber, NonNegativeNumberOrPercentage};
use crate::values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use crate::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use crate::values::generics::border::BorderImageSlice as GenericBorderImageSlice;
@ -14,6 +13,7 @@ use crate::values::generics::border::BorderRadius as GenericBorderRadius;
use crate::values::generics::border::BorderSpacing as GenericBorderSpacing;
use crate::values::generics::rect::Rect;
use crate::values::generics::size::Size;
use crate::values::generics::NonNegative;
use app_units::Au;
pub use crate::values::specified::border::BorderImageRepeat;
@ -22,16 +22,17 @@ pub use crate::values::specified::border::BorderImageRepeat;
pub type BorderImageWidth = Rect<BorderImageSideWidth>;
/// A computed value for a single side of a `border-image-width` property.
pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>;
pub type BorderImageSideWidth =
GenericBorderImageSideWidth<NonNegativeLengthOrPercentage, NonNegativeNumber>;
/// A computed value for the `border-image-slice` property.
pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>;
pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>;
/// A computed value for the `border-radius` property.
pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>;
pub type BorderRadius = GenericBorderRadius<NonNegativeLengthOrPercentage>;
/// A computed value for the `border-*-radius` longhand properties.
pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>;
pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthOrPercentage>;
/// A computed value for the `border-spacing` longhand property.
pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>;
@ -40,7 +41,18 @@ impl BorderImageSideWidth {
/// Returns `1`.
#[inline]
pub fn one() -> Self {
GenericBorderImageSideWidth::Number(1.)
GenericBorderImageSideWidth::Number(NonNegative(1.))
}
}
impl BorderImageSlice {
/// Returns the `100%` value.
#[inline]
pub fn hundred_percent() -> Self {
GenericBorderImageSlice {
offsets: Rect::all(NonNegativeNumberOrPercentage::hundred_percent()),
fill: false,
}
}
}
@ -68,26 +80,18 @@ impl BorderCornerRadius {
/// Returns `0 0`.
pub fn zero() -> Self {
GenericBorderCornerRadius(Size::new(
LengthOrPercentage::zero(),
LengthOrPercentage::zero(),
NonNegativeLengthOrPercentage::zero(),
NonNegativeLengthOrPercentage::zero(),
))
}
}
impl ToAnimatedZero for BorderCornerRadius {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
// FIXME(nox): Why?
Err(())
}
}
impl BorderRadius {
/// Returns whether all the values are `0px`.
pub fn all_zero(&self) -> bool {
fn all(corner: &BorderCornerRadius) -> bool {
fn is_zero(l: &LengthOrPercentage) -> bool {
*l == LengthOrPercentage::zero()
fn is_zero(l: &NonNegativeLengthOrPercentage) -> bool {
*l == NonNegativeLengthOrPercentage::zero()
}
is_zero(corner.0.width()) && is_zero(corner.0.height())
}

View file

@ -975,6 +975,7 @@ pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPerce
Copy,
Debug,
Eq,
FromPrimitive,
MallocSizeOf,
Parse,
PartialEq,
@ -982,9 +983,12 @@ pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPerce
ToComputedValue,
ToCss,
)]
#[repr(u8)]
pub enum ExtremumLength {
MozMaxContent,
MozMinContent,
#[parse(aliases = "-moz-max-content")]
MaxContent,
#[parse(aliases = "-moz-min-content")]
MinContent,
MozFitContent,
MozAvailable,
}

View file

@ -543,6 +543,17 @@ pub enum NumberOrPercentage {
Number(Number),
}
impl NumberOrPercentage {
fn clamp_to_non_negative(self) -> Self {
match self {
NumberOrPercentage::Percentage(p) => {
NumberOrPercentage::Percentage(p.clamp_to_non_negative())
},
NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.max(0.)),
}
}
}
impl ToComputedValue for specified::NumberOrPercentage {
type ComputedValue = NumberOrPercentage;
@ -572,6 +583,31 @@ impl ToComputedValue for specified::NumberOrPercentage {
}
}
/// A non-negative <number-percentage>.
pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
impl NonNegativeNumberOrPercentage {
/// Returns the `100%` value.
#[inline]
pub fn hundred_percent() -> Self {
NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
}
}
impl ToAnimatedValue for NonNegativeNumberOrPercentage {
type AnimatedValue = NumberOrPercentage;
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
self.0
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
NonNegative(animated.clamp_to_non_negative())
}
}
/// A type used for opacity.
pub type Opacity = CSSFloat;

View file

@ -20,7 +20,16 @@ pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, U
/// <https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box>
#[allow(missing_docs)]
#[derive(
Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
Animate,
Clone,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
pub enum GeometryBox {
FillBox,
@ -45,6 +54,7 @@ pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, I
Parse,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
@ -59,7 +69,15 @@ pub enum ShapeBox {
#[allow(missing_docs)]
#[animation(no_bound(ImageOrUrl))]
#[derive(
Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
Animate,
Clone,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
#[animation(error)]
@ -82,13 +100,14 @@ pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
pub enum BasicShape<H, V, LengthOrPercentage> {
Inset(#[css(field_bound)] InsetRect<LengthOrPercentage>),
Circle(#[css(field_bound)] Circle<H, V, LengthOrPercentage>),
Ellipse(#[css(field_bound)] Ellipse<H, V, LengthOrPercentage>),
pub enum BasicShape<H, V, LengthOrPercentage, NonNegativeLengthOrPercentage> {
Inset(#[css(field_bound)] InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>),
Circle(#[css(field_bound)] Circle<H, V, NonNegativeLengthOrPercentage>),
Ellipse(#[css(field_bound)] Ellipse<H, V, NonNegativeLengthOrPercentage>),
Polygon(Polygon<LengthOrPercentage>),
}
@ -103,11 +122,12 @@ pub enum BasicShape<H, V, LengthOrPercentage> {
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
)]
pub struct InsetRect<LengthOrPercentage> {
pub struct InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage> {
pub rect: Rect<LengthOrPercentage>,
pub round: Option<BorderRadius<LengthOrPercentage>>,
pub round: Option<BorderRadius<NonNegativeLengthOrPercentage>>,
}
/// <https://drafts.csswg.org/css-shapes/#funcdef-circle>
@ -122,11 +142,12 @@ pub struct InsetRect<LengthOrPercentage> {
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
)]
pub struct Circle<H, V, LengthOrPercentage> {
pub struct Circle<H, V, NonNegativeLengthOrPercentage> {
pub position: Position<H, V>,
pub radius: ShapeRadius<LengthOrPercentage>,
pub radius: ShapeRadius<NonNegativeLengthOrPercentage>,
}
/// <https://drafts.csswg.org/css-shapes/#funcdef-ellipse>
@ -141,12 +162,13 @@ pub struct Circle<H, V, LengthOrPercentage> {
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
)]
pub struct Ellipse<H, V, LengthOrPercentage> {
pub struct Ellipse<H, V, NonNegativeLengthOrPercentage> {
pub position: Position<H, V>,
pub semiaxis_x: ShapeRadius<LengthOrPercentage>,
pub semiaxis_y: ShapeRadius<LengthOrPercentage>,
pub semiaxis_x: ShapeRadius<NonNegativeLengthOrPercentage>,
pub semiaxis_y: ShapeRadius<NonNegativeLengthOrPercentage>,
}
/// <https://drafts.csswg.org/css-shapes/#typedef-shape-radius>
@ -160,11 +182,12 @@ pub struct Ellipse<H, V, LengthOrPercentage> {
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
pub enum ShapeRadius<LengthOrPercentage> {
Length(LengthOrPercentage),
pub enum ShapeRadius<NonNegativeLengthOrPercentage> {
Length(NonNegativeLengthOrPercentage),
#[animation(error)]
ClosestSide,
#[animation(error)]
@ -175,7 +198,16 @@ pub enum ShapeRadius<LengthOrPercentage> {
///
/// <https://drafts.csswg.org/css-shapes/#funcdef-polygon>
#[css(comma, function)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
#[derive(
Clone,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
pub struct Polygon<LengthOrPercentage> {
/// The filling rule for a polygon.
#[css(skip_if = "fill_is_default")]
@ -186,7 +218,16 @@ pub struct Polygon<LengthOrPercentage> {
}
/// Coordinates for Polygon.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
#[derive(
Clone,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
pub struct PolygonCoord<LengthOrPercentage>(pub LengthOrPercentage, pub LengthOrPercentage);
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
@ -204,6 +245,7 @@ pub struct PolygonCoord<LengthOrPercentage>(pub LengthOrPercentage, pub LengthOr
Parse,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
@ -218,7 +260,15 @@ pub enum FillRule {
/// https://drafts.csswg.org/css-shapes-2/#funcdef-path
#[css(comma)]
#[derive(
Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
Animate,
Clone,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
)]
pub struct Path {
/// The filling rule for the svg path.
@ -258,9 +308,10 @@ impl<B, T, U> ToAnimatedZero for ShapeSource<B, T, U> {
}
}
impl<L> ToCss for InsetRect<L>
impl<Length, NonNegativeLength> ToCss for InsetRect<Length, NonNegativeLength>
where
L: ToCss + PartialEq,
Length: ToCss + PartialEq,
NonNegativeLength: ToCss + PartialEq,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where

View file

@ -45,6 +45,8 @@ pub struct BorderImageSlice<NumberOrPercentage> {
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToCss,
)]
@ -93,6 +95,7 @@ impl<L> BorderSpacing<L> {
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
)]
pub struct BorderRadius<LengthOrPercentage> {
@ -106,19 +109,6 @@ pub struct BorderRadius<LengthOrPercentage> {
pub bottom_left: BorderCornerRadius<LengthOrPercentage>,
}
impl<N> From<N> for BorderImageSlice<N>
where
N: Clone,
{
#[inline]
fn from(value: N) -> Self {
Self {
offsets: Rect::all(value),
fill: false,
}
}
}
impl<L> BorderRadius<L> {
/// Returns a new `BorderRadius<L>`.
#[inline]

View file

@ -15,6 +15,7 @@
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
)]

View file

@ -20,6 +20,7 @@ use style_traits::{CssWriter, ParseError, ToCss};
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
)]
pub struct Rect<T>(pub T, pub T, pub T, pub T);

View file

@ -16,8 +16,8 @@ use crate::values::specified::border::BorderRadius;
use crate::values::specified::image::Image;
use crate::values::specified::position::{HorizontalPosition, Position, VerticalPosition};
use crate::values::specified::url::SpecifiedUrl;
use crate::values::specified::LengthOrPercentage;
use crate::values::specified::SVGPathData;
use crate::values::specified::{LengthOrPercentage, NonNegativeLengthOrPercentage};
use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
@ -32,19 +32,26 @@ pub type ClippingShape = generic::ClippingShape<BasicShape, SpecifiedUrl>;
pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>;
/// A specified basic shape.
pub type BasicShape = generic::BasicShape<HorizontalPosition, VerticalPosition, LengthOrPercentage>;
pub type BasicShape = generic::BasicShape<
HorizontalPosition,
VerticalPosition,
LengthOrPercentage,
NonNegativeLengthOrPercentage,
>;
/// The specified value of `inset()`
pub type InsetRect = generic::InsetRect<LengthOrPercentage>;
pub type InsetRect = generic::InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// A specified circle.
pub type Circle = generic::Circle<HorizontalPosition, VerticalPosition, LengthOrPercentage>;
pub type Circle =
generic::Circle<HorizontalPosition, VerticalPosition, NonNegativeLengthOrPercentage>;
/// A specified ellipse.
pub type Ellipse = generic::Ellipse<HorizontalPosition, VerticalPosition, LengthOrPercentage>;
pub type Ellipse =
generic::Ellipse<HorizontalPosition, VerticalPosition, NonNegativeLengthOrPercentage>;
/// The specified value of `ShapeRadius`
pub type ShapeRadius = generic::ShapeRadius<LengthOrPercentage>;
pub type ShapeRadius = generic::ShapeRadius<NonNegativeLengthOrPercentage>;
/// The specified value of `Polygon`
pub type Polygon = generic::Polygon<LengthOrPercentage>;
@ -199,10 +206,7 @@ impl InsetRect {
} else {
None
};
Ok(generic::InsetRect {
rect: rect,
round: round,
})
Ok(generic::InsetRect { rect, round })
}
}
@ -312,7 +316,7 @@ impl Parse for ShapeRadius {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
if let Ok(lop) = input.try(|i| NonNegativeLengthOrPercentage::parse(context, i)) {
return Ok(generic::ShapeRadius::Length(lop));
}

View file

@ -13,8 +13,8 @@ use crate::values::generics::border::BorderRadius as GenericBorderRadius;
use crate::values::generics::border::BorderSpacing as GenericBorderSpacing;
use crate::values::generics::rect::Rect;
use crate::values::generics::size::Size;
use crate::values::specified::length::{Length, LengthOrPercentage, NonNegativeLength};
use crate::values::specified::{AllowQuirks, Number, NumberOrPercentage};
use crate::values::specified::length::{NonNegativeLength, NonNegativeLengthOrPercentage};
use crate::values::specified::{AllowQuirks, NonNegativeNumber, NonNegativeNumberOrPercentage};
use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};
@ -71,36 +71,53 @@ pub enum BorderSideWidth {
/// `thick`
Thick,
/// `<length>`
Length(Length),
Length(NonNegativeLength),
}
/// A specified value for the `border-image-width` property.
pub type BorderImageWidth = Rect<BorderImageSideWidth>;
/// A specified value for a single side of a `border-image-width` property.
pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>;
pub type BorderImageSideWidth =
GenericBorderImageSideWidth<NonNegativeLengthOrPercentage, NonNegativeNumber>;
/// A specified value for the `border-image-slice` property.
pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>;
pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>;
/// A specified value for the `border-radius` property.
pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>;
pub type BorderRadius = GenericBorderRadius<NonNegativeLengthOrPercentage>;
/// A specified value for the `border-*-radius` longhand properties.
pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>;
pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthOrPercentage>;
/// A specified value for the `border-spacing` longhand properties.
pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>;
impl BorderImageSlice {
/// Returns the `100%` value.
#[inline]
pub fn hundred_percent() -> Self {
GenericBorderImageSlice {
offsets: Rect::all(NonNegativeNumberOrPercentage::hundred_percent()),
fill: false,
}
}
}
impl BorderSideWidth {
/// Returns the `0px` value.
#[inline]
pub fn zero() -> Self {
BorderSideWidth::Length(NonNegativeLength::zero())
}
/// Parses, with quirks.
pub fn parse_quirky<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
if let Ok(length) =
input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks))
if let Ok(length) = input.try(|i| NonNegativeLength::parse_quirky(context, i, allow_quirks))
{
return Ok(BorderSideWidth::Length(length));
}
@ -130,9 +147,9 @@ impl ToComputedValue for BorderSideWidth {
// Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width
// Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0
match *self {
BorderSideWidth::Thin => Length::from_px(1.).to_computed_value(context),
BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context),
BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context),
BorderSideWidth::Thin => NonNegativeLength::from_px(1.).to_computed_value(context),
BorderSideWidth::Medium => NonNegativeLength::from_px(3.).to_computed_value(context),
BorderSideWidth::Thick => NonNegativeLength::from_px(5.).to_computed_value(context),
BorderSideWidth::Length(ref length) => length.to_computed_value(context),
}
.into()
@ -140,7 +157,7 @@ impl ToComputedValue for BorderSideWidth {
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
BorderSideWidth::Length(ToComputedValue::from_computed_value(&computed.0))
BorderSideWidth::Length(ToComputedValue::from_computed_value(computed))
}
}
@ -148,7 +165,7 @@ impl BorderImageSideWidth {
/// Returns `1`.
#[inline]
pub fn one() -> Self {
GenericBorderImageSideWidth::Number(Number::new(1.))
GenericBorderImageSideWidth::Number(NonNegativeNumber::new(1.))
}
}
@ -161,11 +178,11 @@ impl Parse for BorderImageSideWidth {
return Ok(GenericBorderImageSideWidth::Auto);
}
if let Ok(len) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
if let Ok(len) = input.try(|i| NonNegativeLengthOrPercentage::parse(context, i)) {
return Ok(GenericBorderImageSideWidth::Length(len));
}
let num = Number::parse_non_negative(context, input)?;
let num = NonNegativeNumber::parse(context, input)?;
Ok(GenericBorderImageSideWidth::Number(num))
}
}
@ -176,14 +193,11 @@ impl Parse for BorderImageSlice {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?;
let offsets = Rect::parse_with(context, input, NonNegativeNumberOrPercentage::parse)?;
if !fill {
fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
}
Ok(GenericBorderImageSlice {
offsets: offsets,
fill: fill,
})
Ok(GenericBorderImageSlice { offsets, fill })
}
}
@ -192,9 +206,9 @@ impl Parse for BorderRadius {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let widths = Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?;
let widths = Rect::parse_with(context, input, NonNegativeLengthOrPercentage::parse)?;
let heights = if input.try(|i| i.expect_delim('/')).is_ok() {
Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?
Rect::parse_with(context, input, NonNegativeLengthOrPercentage::parse)?
} else {
widths.clone()
};
@ -213,7 +227,7 @@ impl Parse for BorderCornerRadius {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Size::parse_with(context, input, LengthOrPercentage::parse_non_negative)
Size::parse_with(context, input, NonNegativeLengthOrPercentage::parse)
.map(GenericBorderCornerRadius)
}
}
@ -224,7 +238,7 @@ impl Parse for BorderSpacing {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Size::parse_with(context, input, |context, input| {
Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes).map(From::from)
NonNegativeLength::parse_quirky(context, input, AllowQuirks::Yes).map(From::from)
})
.map(GenericBorderSpacing)
}

View file

@ -717,6 +717,20 @@ impl NonNegativeLength {
pub fn from_px(px_value: CSSFloat) -> Self {
Length::from_px(px_value.max(0.)).into()
}
/// Parses a non-negative length, optionally with quirks.
#[inline]
pub fn parse_quirky<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
Ok(NonNegative(Length::parse_non_negative_quirky(
context,
input,
allow_quirks,
)?))
}
}
/// Either a NonNegativeLength or the `auto` keyword.
@ -1246,17 +1260,6 @@ impl Parse for MozLength {
}
impl MozLength {
/// Parses, without quirks, and disallowing ExtremumLength values.
///
/// Used for logical props in the block direction.
pub fn parse_disallow_keyword<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let length = LengthOrPercentageOrAuto::parse_non_negative(context, input)?;
Ok(GenericMozLength::LengthOrPercentageOrAuto(length))
}
/// Parses, with quirks.
pub fn parse_quirky<'i, 't>(
context: &ParserContext,
@ -1298,17 +1301,6 @@ impl Parse for MaxLength {
}
impl MaxLength {
/// Parses, without quirks, and disallowing ExtremumLength values.
///
/// Used for logical props in the block direction.
pub fn parse_disallow_keyword<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let length = LengthOrPercentageOrNone::parse_non_negative(context, input)?;
Ok(GenericMaxLength::LengthOrPercentageOrNone(length))
}
/// Parses, with quirks.
pub fn parse_quirky<'i, 't>(
context: &ParserContext,

View file

@ -359,6 +359,28 @@ impl Parse for NumberOrPercentage {
}
}
/// A non-negative <number> | <percentage>.
pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
impl NonNegativeNumberOrPercentage {
/// Returns the `100%` value.
#[inline]
pub fn hundred_percent() -> Self {
NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
}
}
impl Parse for NonNegativeNumberOrPercentage {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(NonNegative(NumberOrPercentage::parse_non_negative(
context, input,
)?))
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, ToCss)]
pub struct Opacity(Number);

View file

@ -10,9 +10,7 @@ use style::properties::parse_property_declaration_list;
use style::properties::{Importance, PropertyDeclaration};
use style::values::specified::url::SpecifiedUrl;
use style::values::specified::NoCalcLength;
use style::values::specified::{BorderSideWidth, BorderStyle, Color};
use style::values::specified::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::RGBA;
use style_traits::ToCss;
trait ToCssString {
@ -83,408 +81,6 @@ mod shorthand_serialization {
block.to_css_string()
}
mod four_sides_shorthands {
pub use super::*;
// we can use margin as a base to test out the different combinations
// but afterwards, we only need to to one test per "four sides shorthand"
#[test]
fn all_equal_properties_should_serialize_to_one_value() {
let mut properties = Vec::new();
let px_70 = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(70f32));
properties.push(PropertyDeclaration::MarginTop(px_70.clone()));
properties.push(PropertyDeclaration::MarginRight(px_70.clone()));
properties.push(PropertyDeclaration::MarginBottom(px_70.clone()));
properties.push(PropertyDeclaration::MarginLeft(px_70));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "margin: 70px;");
}
#[test]
fn equal_vertical_and_equal_horizontal_properties_should_serialize_to_two_value() {
let mut properties = Vec::new();
let vertical_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32));
let horizontal_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(5f32));
properties.push(PropertyDeclaration::MarginTop(vertical_px.clone()));
properties.push(PropertyDeclaration::MarginRight(horizontal_px.clone()));
properties.push(PropertyDeclaration::MarginBottom(vertical_px));
properties.push(PropertyDeclaration::MarginLeft(horizontal_px));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "margin: 10px 5px;");
}
#[test]
fn different_vertical_and_equal_horizontal_properties_should_serialize_to_three_values() {
let mut properties = Vec::new();
let top_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(8f32));
let bottom_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32));
let horizontal_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(5f32));
properties.push(PropertyDeclaration::MarginTop(top_px));
properties.push(PropertyDeclaration::MarginRight(horizontal_px.clone()));
properties.push(PropertyDeclaration::MarginBottom(bottom_px));
properties.push(PropertyDeclaration::MarginLeft(horizontal_px));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "margin: 8px 5px 10px;");
}
#[test]
fn different_properties_should_serialize_to_four_values() {
let mut properties = Vec::new();
let top_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(8f32));
let right_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(12f32));
let bottom_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32));
let left_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(14f32));
properties.push(PropertyDeclaration::MarginTop(top_px));
properties.push(PropertyDeclaration::MarginRight(right_px));
properties.push(PropertyDeclaration::MarginBottom(bottom_px));
properties.push(PropertyDeclaration::MarginLeft(left_px));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "margin: 8px 12px 10px 14px;");
}
#[test]
fn different_longhands_should_serialize_to_long_form() {
let mut properties = Vec::new();
let solid = BorderStyle::Solid;
properties.push(PropertyDeclaration::BorderTopStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderRightStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone()));
let px_30 = BorderSideWidth::Length(Length::from_px(30f32));
let px_10 = BorderSideWidth::Length(Length::from_px(10f32));
properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderLeftWidth(px_10.clone()));
let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
properties.push(PropertyDeclaration::BorderRightColor(blue.clone()));
properties.push(PropertyDeclaration::BorderBottomColor(blue.clone()));
properties.push(PropertyDeclaration::BorderLeftColor(blue.clone()));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization,
"border-style: solid; border-width: 30px 30px 30px 10px; border-color: rgb(0, 0, 255);");
}
#[test]
fn same_longhands_should_serialize_correctly() {
let mut properties = Vec::new();
let solid = BorderStyle::Solid;
properties.push(PropertyDeclaration::BorderTopStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderRightStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone()));
let px_30 = BorderSideWidth::Length(Length::from_px(30f32));
properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderLeftWidth(px_30.clone()));
let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
properties.push(PropertyDeclaration::BorderRightColor(blue.clone()));
properties.push(PropertyDeclaration::BorderBottomColor(blue.clone()));
properties.push(PropertyDeclaration::BorderLeftColor(blue.clone()));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(
serialization,
"border-style: solid; border-width: 30px; border-color: rgb(0, 0, 255);"
);
}
#[test]
fn padding_should_serialize_correctly() {
use style::values::specified::NonNegativeLengthOrPercentage;
let mut properties = Vec::new();
let px_10: NonNegativeLengthOrPercentage = NoCalcLength::from_px(10f32).into();
let px_15: NonNegativeLengthOrPercentage = NoCalcLength::from_px(15f32).into();
properties.push(PropertyDeclaration::PaddingTop(px_10.clone()));
properties.push(PropertyDeclaration::PaddingRight(px_15.clone()));
properties.push(PropertyDeclaration::PaddingBottom(px_10));
properties.push(PropertyDeclaration::PaddingLeft(px_15));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "padding: 10px 15px;");
}
#[test]
fn border_width_should_serialize_correctly() {
let mut properties = Vec::new();
let top_px = BorderSideWidth::Length(Length::from_px(10f32));
let bottom_px = BorderSideWidth::Length(Length::from_px(10f32));
let right_px = BorderSideWidth::Length(Length::from_px(15f32));
let left_px = BorderSideWidth::Length(Length::from_px(15f32));
properties.push(PropertyDeclaration::BorderTopWidth(top_px));
properties.push(PropertyDeclaration::BorderRightWidth(right_px));
properties.push(PropertyDeclaration::BorderBottomWidth(bottom_px));
properties.push(PropertyDeclaration::BorderLeftWidth(left_px));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-width: 10px 15px;");
}
#[test]
fn border_width_with_keywords_should_serialize_correctly() {
let mut properties = Vec::new();
let top_px = BorderSideWidth::Thin;
let right_px = BorderSideWidth::Medium;
let bottom_px = BorderSideWidth::Thick;
let left_px = BorderSideWidth::Length(Length::from_px(15f32));
properties.push(PropertyDeclaration::BorderTopWidth(top_px));
properties.push(PropertyDeclaration::BorderRightWidth(right_px));
properties.push(PropertyDeclaration::BorderBottomWidth(bottom_px));
properties.push(PropertyDeclaration::BorderLeftWidth(left_px));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-width: thin medium thick 15px;");
}
#[test]
fn border_color_should_serialize_correctly() {
let mut properties = Vec::new();
let red = Color::rgba(RGBA::new(255, 0, 0, 255));
let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
properties.push(PropertyDeclaration::BorderRightColor(red.clone()));
properties.push(PropertyDeclaration::BorderBottomColor(blue));
properties.push(PropertyDeclaration::BorderLeftColor(red));
let serialization = shorthand_properties_to_string(properties);
// TODO: Make the rgb test show border-color as blue red instead of below tuples
assert_eq!(
serialization,
"border-color: rgb(0, 0, 255) rgb(255, 0, 0);"
);
}
#[test]
fn border_style_should_serialize_correctly() {
let mut properties = Vec::new();
let solid = BorderStyle::Solid;
let dotted = BorderStyle::Dotted;
properties.push(PropertyDeclaration::BorderTopStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderRightStyle(dotted.clone()));
properties.push(PropertyDeclaration::BorderBottomStyle(solid));
properties.push(PropertyDeclaration::BorderLeftStyle(dotted));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-style: solid dotted;");
}
use style::values::specified::{BorderCornerRadius, Percentage};
#[test]
fn border_radius_should_serialize_correctly() {
let mut properties = Vec::new();
properties.push(PropertyDeclaration::BorderTopLeftRadius(Box::new(
BorderCornerRadius::new(Percentage::new(0.01).into(), Percentage::new(0.05).into()),
)));
properties.push(PropertyDeclaration::BorderTopRightRadius(Box::new(
BorderCornerRadius::new(Percentage::new(0.02).into(), Percentage::new(0.06).into()),
)));
properties.push(PropertyDeclaration::BorderBottomRightRadius(Box::new(
BorderCornerRadius::new(Percentage::new(0.03).into(), Percentage::new(0.07).into()),
)));
properties.push(PropertyDeclaration::BorderBottomLeftRadius(Box::new(
BorderCornerRadius::new(Percentage::new(0.04).into(), Percentage::new(0.08).into()),
)));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-radius: 1% 2% 3% 4% / 5% 6% 7% 8%;");
}
}
mod border_shorthands {
use super::*;
#[test]
fn border_top_and_color() {
let mut properties = Vec::new();
properties.push(PropertyDeclaration::BorderTopWidth(
BorderSideWidth::Length(Length::from_px(1.)),
));
properties.push(PropertyDeclaration::BorderTopStyle(BorderStyle::Solid));
let c = Color::Numeric {
parsed: RGBA::new(255, 0, 0, 255),
authored: Some("green".to_string().into_boxed_str()),
};
properties.push(PropertyDeclaration::BorderTopColor(c));
let c = Color::Numeric {
parsed: RGBA::new(0, 255, 0, 255),
authored: Some("red".to_string().into_boxed_str()),
};
properties.push(PropertyDeclaration::BorderTopColor(c.clone()));
properties.push(PropertyDeclaration::BorderBottomColor(c.clone()));
properties.push(PropertyDeclaration::BorderLeftColor(c.clone()));
properties.push(PropertyDeclaration::BorderRightColor(c.clone()));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(
serialization,
"border-top: 1px solid red; border-color: red;"
);
}
#[test]
fn border_color_and_top() {
let mut properties = Vec::new();
let c = Color::Numeric {
parsed: RGBA::new(0, 255, 0, 255),
authored: Some("red".to_string().into_boxed_str()),
};
properties.push(PropertyDeclaration::BorderTopColor(c.clone()));
properties.push(PropertyDeclaration::BorderBottomColor(c.clone()));
properties.push(PropertyDeclaration::BorderLeftColor(c.clone()));
properties.push(PropertyDeclaration::BorderRightColor(c.clone()));
properties.push(PropertyDeclaration::BorderTopWidth(
BorderSideWidth::Length(Length::from_px(1.)),
));
properties.push(PropertyDeclaration::BorderTopStyle(BorderStyle::Solid));
let c = Color::Numeric {
parsed: RGBA::new(255, 0, 0, 255),
authored: Some("green".to_string().into_boxed_str()),
};
properties.push(PropertyDeclaration::BorderTopColor(c));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(
serialization,
"border-color: green red red; border-top: 1px solid green;"
);
}
// we can use border-top as a base to test out the different combinations
// but afterwards, we only need to to one test per "directional border shorthand"
#[test]
fn directional_border_should_show_all_properties_when_values_are_set() {
let mut properties = Vec::new();
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = BorderStyle::Solid;
let color = RGBA::new(255, 0, 0, 255).into();
properties.push(PropertyDeclaration::BorderTopWidth(width));
properties.push(PropertyDeclaration::BorderTopStyle(style));
properties.push(PropertyDeclaration::BorderTopColor(color));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-top: 4px solid rgb(255, 0, 0);");
}
fn get_border_property_values() -> (BorderSideWidth, BorderStyle, Color) {
(
BorderSideWidth::Length(Length::from_px(4f32)),
BorderStyle::Solid,
Color::currentcolor(),
)
}
#[test]
fn border_top_should_serialize_correctly() {
let mut properties = Vec::new();
let (width, style, color) = get_border_property_values();
properties.push(PropertyDeclaration::BorderTopWidth(width));
properties.push(PropertyDeclaration::BorderTopStyle(style));
properties.push(PropertyDeclaration::BorderTopColor(color));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-top: 4px solid;");
}
#[test]
fn border_right_should_serialize_correctly() {
let mut properties = Vec::new();
let (width, style, color) = get_border_property_values();
properties.push(PropertyDeclaration::BorderRightWidth(width));
properties.push(PropertyDeclaration::BorderRightStyle(style));
properties.push(PropertyDeclaration::BorderRightColor(color));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-right: 4px solid;");
}
#[test]
fn border_bottom_should_serialize_correctly() {
let mut properties = Vec::new();
let (width, style, color) = get_border_property_values();
properties.push(PropertyDeclaration::BorderBottomWidth(width));
properties.push(PropertyDeclaration::BorderBottomStyle(style));
properties.push(PropertyDeclaration::BorderBottomColor(color));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-bottom: 4px solid;");
}
#[test]
fn border_left_should_serialize_correctly() {
let mut properties = Vec::new();
let (width, style, color) = get_border_property_values();
properties.push(PropertyDeclaration::BorderLeftWidth(width));
properties.push(PropertyDeclaration::BorderLeftStyle(style));
properties.push(PropertyDeclaration::BorderLeftColor(color));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-left: 4px solid;");
}
#[test]
fn border_should_serialize_correctly() {
// According to https://drafts.csswg.org/css-backgrounds-3/#the-border-shorthands,
// the border shorthand resets border-image to its initial value. To verify the
// serialization of 'border' shorthand, we need to set 'border-image' as well.
let block_text = "\
border-top: 4px solid; \
border-right: 4px solid; \
border-bottom: 4px solid; \
border-left: 4px solid; \
border-image: none;";
let block =
parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
let serialization = block.to_css_string();
assert_eq!(serialization, "border: 4px solid;");
}
}
mod list_style {
use super::*;
use style::properties::longhands::list_style_position::SpecifiedValue as ListStylePosition;