mirror of
https://github.com/servo/servo.git
synced 2025-07-16 11:53:39 +01:00
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:
commit
bffe2a699e
44 changed files with 512 additions and 775 deletions
38
Cargo.lock
generated
38
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -50,6 +50,7 @@ include = [
|
|||
"ComputedTimingFunction",
|
||||
"Display",
|
||||
"DisplayMode",
|
||||
"ExtremumLength",
|
||||
"FillRule",
|
||||
"FontDisplay",
|
||||
"FontFaceSourceListComponent",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"),
|
||||
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
|
||||
.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",
|
||||
),
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
)}
|
||||
|
|
|
@ -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",
|
||||
)}
|
||||
|
|
|
@ -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",
|
||||
)}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
)}
|
||||
|
|
|
@ -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,43 +250,18 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let mut current_containing_shadow = self.rule_hash_target.containing_shadow();
|
||||
while let Some(containing_shadow) = current_containing_shadow {
|
||||
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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
let containing_shadow = containing_shadow_ignoring_svg_use(self.rule_hash_target);
|
||||
let containing_shadow = match containing_shadow {
|
||||
Some(s) => s,
|
||||
None => return,
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
cascade_data.is_none(),
|
||||
"We allow no stylesheets in <svg:use> subtrees"
|
||||
);
|
||||
self.matches_document_author_rules = false;
|
||||
|
||||
// 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();
|
||||
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)) {
|
||||
self.collect_rules_in_shadow_tree(host, map, CascadeLevel::SameTreeAuthorNormal);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
MallocSizeOf,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
ToAnimatedValue,
|
||||
ToAnimatedZero,
|
||||
ToComputedValue,
|
||||
)]
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue