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

style: Sync changes from mozilla-central.

See individual commits for details.

https://bugzilla.mozilla.org/show_bug.cgi?id=1587368

<!-- 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/24404)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-10-09 22:34:17 -04:00 committed by GitHub
commit 2c280ab6ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 561 additions and 744 deletions

View file

@ -17,6 +17,8 @@ use std::ops::{BitAnd, BitOr, BitXor, Sub};
use super::hash_map::{self, HashMap, Keys, RandomState}; use super::hash_map::{self, HashMap, Keys, RandomState};
use super::Recover; use super::Recover;
use crate::FailedAllocationError;
// Future Optimization (FIXME!) // Future Optimization (FIXME!)
// ============================= // =============================
// //
@ -589,6 +591,12 @@ where
self.map.insert(value, ()).is_none() self.map.insert(value, ()).is_none()
} }
/// Fallible version of `insert`.
#[inline]
pub fn try_insert(&mut self, value: T) -> Result<bool, FailedAllocationError> {
Ok(self.map.try_insert(value, ())?.is_none())
}
/// Adds a value to the set, replacing the existing value, if any, that is equal to the given /// Adds a value to the set, replacing the existing value, if any, that is equal to the given
/// one. Returns the replaced value. /// one. Returns the replaced value.
pub fn replace(&mut self, value: T) -> Option<T> { pub fn replace(&mut self, value: T) -> Option<T> {

View file

@ -25,6 +25,7 @@ servo-layout-2020 = []
gecko_debug = [] gecko_debug = []
gecko_refcount_logging = [] gecko_refcount_logging = []
gecko_profiler = [] gecko_profiler = []
moz_xbl = []
[dependencies] [dependencies]
app_units = "0.7" app_units = "0.7"

View file

@ -187,10 +187,11 @@ pub mod basic_shape {
impl<'a> From<&'a StyleShapeSource> for OffsetPath { impl<'a> From<&'a StyleShapeSource> for OffsetPath {
fn from(other: &'a StyleShapeSource) -> Self { fn from(other: &'a StyleShapeSource) -> Self {
use crate::values::generics::motion::GenericOffsetPath;
match other.mType { match other.mType {
StyleShapeSourceType::Path => { StyleShapeSourceType::Path => GenericOffsetPath::Path(
OffsetPath::Path(other.to_svg_path().expect("Cannot convert to SVGPathData")) other.to_svg_path().expect("Cannot convert to SVGPathData"),
}, ),
StyleShapeSourceType::None => OffsetPath::none(), StyleShapeSourceType::None => OffsetPath::none(),
StyleShapeSourceType::Shape | StyleShapeSourceType::Shape |
StyleShapeSourceType::Box | StyleShapeSourceType::Box |

View file

@ -44,6 +44,8 @@ use crate::gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWThe
use crate::gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags}; use crate::gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use crate::gecko_bindings::structs; use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsChangeHint; use crate::gecko_bindings::structs::nsChangeHint;
#[cfg(feature = "moz_xbl")]
use crate::gecko_bindings::structs::nsXBLBinding as RawGeckoXBLBinding;
use crate::gecko_bindings::structs::Document_DocumentTheme as DocumentTheme; use crate::gecko_bindings::structs::Document_DocumentTheme as DocumentTheme;
use crate::gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel; use crate::gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
use crate::gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT; use crate::gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
@ -53,9 +55,7 @@ use crate::gecko_bindings::structs::ELEMENT_HAS_SNAPSHOT;
use crate::gecko_bindings::structs::NODE_DESCENDANTS_NEED_FRAMES; use crate::gecko_bindings::structs::NODE_DESCENDANTS_NEED_FRAMES;
use crate::gecko_bindings::structs::NODE_NEEDS_FRAME; use crate::gecko_bindings::structs::NODE_NEEDS_FRAME;
use crate::gecko_bindings::structs::{nsAtom, nsIContent, nsINode_BooleanFlag}; use crate::gecko_bindings::structs::{nsAtom, nsIContent, nsINode_BooleanFlag};
use crate::gecko_bindings::structs::{ use crate::gecko_bindings::structs::{nsINode as RawGeckoNode, Element as RawGeckoElement};
nsINode as RawGeckoNode, nsXBLBinding as RawGeckoXBLBinding, Element as RawGeckoElement,
};
use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI}; use crate::gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
use crate::global_style_data::GLOBAL_STYLE_DATA; use crate::global_style_data::GLOBAL_STYLE_DATA;
use crate::hash::FxHashMap; use crate::hash::FxHashMap;
@ -86,6 +86,8 @@ use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
use std::ptr; use std::ptr;
#[cfg(not(feature = "moz_xbl"))]
use values::Impossible;
#[inline] #[inline]
fn elements_with_id<'a, 'le>( fn elements_with_id<'a, 'le>(
@ -529,9 +531,11 @@ impl<'a> Iterator for GeckoChildrenIterator<'a> {
} }
/// A Simple wrapper over a non-null Gecko `nsXBLBinding` pointer. /// A Simple wrapper over a non-null Gecko `nsXBLBinding` pointer.
#[cfg(feature = "moz_xbl")]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct GeckoXBLBinding<'lb>(pub &'lb RawGeckoXBLBinding); pub struct GeckoXBLBinding<'lb>(pub &'lb RawGeckoXBLBinding);
#[cfg(feature = "moz_xbl")]
impl<'lb> GeckoXBLBinding<'lb> { impl<'lb> GeckoXBLBinding<'lb> {
#[inline] #[inline]
fn base_binding(&self) -> Option<Self> { fn base_binding(&self) -> Option<Self> {
@ -556,6 +560,22 @@ impl<'lb> GeckoXBLBinding<'lb> {
} }
} }
/// A stub wraper for GeckoXBLBinding.
#[cfg(not(feature = "moz_xbl"))]
pub struct GeckoXBLBinding<'lb>(&'lb Impossible);
#[cfg(not(feature = "moz_xbl"))]
impl<'lb> GeckoXBLBinding<'lb> {
#[inline]
fn anon_content(&self) -> *const nsIContent {
match *self.0 {}
}
fn binding_with_content(&self) -> Option<Self> {
None
}
}
/// A simple wrapper over a non-null Gecko `Element` pointer. /// A simple wrapper over a non-null Gecko `Element` pointer.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct GeckoElement<'le>(pub &'le RawGeckoElement); pub struct GeckoElement<'le>(pub &'le RawGeckoElement);
@ -681,11 +701,13 @@ impl<'le> GeckoElement<'le> {
}) })
} }
#[cfg(feature = "moz_xbl")]
#[inline] #[inline]
fn may_be_in_binding_manager(&self) -> bool { fn may_be_in_binding_manager(&self) -> bool {
self.flags() & (structs::NODE_MAY_BE_IN_BINDING_MNGR as u32) != 0 self.flags() & (structs::NODE_MAY_BE_IN_BINDING_MNGR as u32) != 0
} }
#[cfg(feature = "moz_xbl")]
#[inline] #[inline]
fn xbl_binding(&self) -> Option<GeckoXBLBinding<'le>> { fn xbl_binding(&self) -> Option<GeckoXBLBinding<'le>> {
if !self.may_be_in_binding_manager() { if !self.may_be_in_binding_manager() {
@ -696,6 +718,12 @@ impl<'le> GeckoElement<'le> {
unsafe { slots.mXBLBinding.mRawPtr.as_ref().map(GeckoXBLBinding) } unsafe { slots.mXBLBinding.mRawPtr.as_ref().map(GeckoXBLBinding) }
} }
#[cfg(not(feature = "moz_xbl"))]
#[inline]
fn xbl_binding(&self) -> Option<GeckoXBLBinding<'le>> {
None
}
#[inline] #[inline]
fn xbl_binding_with_content(&self) -> Option<GeckoXBLBinding<'le>> { fn xbl_binding_with_content(&self) -> Option<GeckoXBLBinding<'le>> {
self.xbl_binding().and_then(|b| b.binding_with_content()) self.xbl_binding().and_then(|b| b.binding_with_content())

View file

@ -8,6 +8,7 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
use crate::dom::{TDocument, TElement, TNode}; use crate::dom::{TDocument, TElement, TNode};
use crate::hash::HashSet;
use crate::invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper}; use crate::invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
use crate::invalidation::element::restyle_hints::RestyleHint; use crate::invalidation::element::restyle_hints::RestyleHint;
use crate::media_queries::Device; use crate::media_queries::Device;
@ -17,9 +18,12 @@ use crate::stylesheets::{CssRule, StylesheetInDocument};
use crate::Atom; use crate::Atom;
use crate::CaseSensitivityExt; use crate::CaseSensitivityExt;
use crate::LocalName as SelectorLocalName; use crate::LocalName as SelectorLocalName;
use fxhash::FxHashSet; use fxhash::FxHasher;
use selectors::attr::CaseSensitivity; use selectors::attr::CaseSensitivity;
use selectors::parser::{Component, LocalName, Selector}; use selectors::parser::{Component, LocalName, Selector};
use std::hash::BuildHasherDefault;
type FxHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
/// A style sheet invalidation represents a kind of element or subtree that may /// A style sheet invalidation represents a kind of element or subtree that may
/// need to be restyled. Whether it represents a whole subtree or just a single /// need to be restyled. Whether it represents a whole subtree or just a single
@ -400,17 +404,22 @@ impl StylesheetInvalidationSet {
if let Some(s) = subtree_invalidation { if let Some(s) = subtree_invalidation {
debug!(" > Found subtree invalidation: {:?}", s); debug!(" > Found subtree invalidation: {:?}", s);
self.invalid_scopes.insert(s); if self.invalid_scopes.try_insert(s).is_ok() {
} else if let Some(s) = element_invalidation { return;
debug!(" > Found element invalidation: {:?}", s);
self.invalid_elements.insert(s);
} else {
// The selector was of a form that we can't handle. Any element
// could match it, so let's just bail out.
debug!(" > Can't handle selector, marking fully invalid");
self.fully_invalid = true;
} }
} }
if let Some(s) = element_invalidation {
debug!(" > Found element invalidation: {:?}", s);
if self.invalid_elements.try_insert(s).is_ok() {
return;
}
}
// The selector was of a form that we can't handle. Any element could
// match it, so let's just bail out.
debug!(" > Can't handle selector or OOMd, marking fully invalid");
self.fully_invalid = true;
}
/// Collects invalidations for a given CSS rule. /// Collects invalidations for a given CSS rule.
fn collect_invalidations_for_rule( fn collect_invalidations_for_rule(

View file

@ -50,16 +50,22 @@ bitflags!(
const LINE_INVERTED = 1 << 3; const LINE_INVERTED = 1 << 3;
/// direction is rtl. /// direction is rtl.
const RTL = 1 << 4; const RTL = 1 << 4;
/// Horizontal text within a vertical writing mode is displayed sideways /// All text within a vertical writing mode is displayed sideways
/// and runs top-to-bottom or bottom-to-top; set in these cases: /// and runs top-to-bottom or bottom-to-top; set in these cases:
/// ///
/// * writing-mode: vertical-rl; text-orientation: sideways;
/// * writing-mode: vertical-lr; text-orientation: sideways;
/// * writing-mode: sideways-rl; /// * writing-mode: sideways-rl;
/// * writing-mode: sideways-lr; /// * writing-mode: sideways-lr;
/// ///
/// Never set without VERTICAL. /// Never set without VERTICAL.
const SIDEWAYS = 1 << 5; const VERTICAL_SIDEWAYS = 1 << 5;
/// Similar to VERTICAL_SIDEWAYS, but is set via text-orientation;
/// set in these cases:
///
/// * writing-mode: vertical-rl; text-orientation: sideways;
/// * writing-mode: vertical-lr; text-orientation: sideways;
///
/// Never set without VERTICAL.
const TEXT_SIDEWAYS = 1 << 6;
/// Horizontal text within a vertical writing mode is displayed with each /// Horizontal text within a vertical writing mode is displayed with each
/// glyph upright; set in these cases: /// glyph upright; set in these cases:
/// ///
@ -67,7 +73,7 @@ bitflags!(
/// * writing-mode: vertical-lr: text-orientation: upright; /// * writing-mode: vertical-lr: text-orientation: upright;
/// ///
/// Never set without VERTICAL. /// Never set without VERTICAL.
const UPRIGHT = 1 << 6; const UPRIGHT = 1 << 7;
} }
); );
@ -112,7 +118,7 @@ impl WritingMode {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
SpecifiedWritingMode::SidewaysRl => { SpecifiedWritingMode::SidewaysRl => {
flags.insert(WritingMode::VERTICAL); flags.insert(WritingMode::VERTICAL);
flags.insert(WritingMode::SIDEWAYS); flags.insert(WritingMode::VERTICAL_SIDEWAYS);
if direction == Direction::Rtl { if direction == Direction::Rtl {
flags.insert(WritingMode::INLINE_REVERSED); flags.insert(WritingMode::INLINE_REVERSED);
} }
@ -121,7 +127,7 @@ impl WritingMode {
SpecifiedWritingMode::SidewaysLr => { SpecifiedWritingMode::SidewaysLr => {
flags.insert(WritingMode::VERTICAL); flags.insert(WritingMode::VERTICAL);
flags.insert(WritingMode::VERTICAL_LR); flags.insert(WritingMode::VERTICAL_LR);
flags.insert(WritingMode::SIDEWAYS); flags.insert(WritingMode::VERTICAL_SIDEWAYS);
if direction == Direction::Ltr { if direction == Direction::Ltr {
flags.insert(WritingMode::INLINE_REVERSED); flags.insert(WritingMode::INLINE_REVERSED);
} }
@ -140,9 +146,18 @@ impl WritingMode {
TextOrientation::Mixed => {}, TextOrientation::Mixed => {},
TextOrientation::Upright => { TextOrientation::Upright => {
flags.insert(WritingMode::UPRIGHT); flags.insert(WritingMode::UPRIGHT);
// https://drafts.csswg.org/css-writing-modes-3/#valdef-text-orientation-upright:
//
// > This value causes the used value of direction
// > to be ltr, and for the purposes of bidi
// > reordering, causes all characters to be treated
// > as strong LTR.
flags.remove(WritingMode::RTL);
flags.remove(WritingMode::INLINE_REVERSED);
}, },
TextOrientation::Sideways => { TextOrientation::Sideways => {
flags.insert(WritingMode::SIDEWAYS); flags.insert(WritingMode::TEXT_SIDEWAYS);
}, },
} }
}, },
@ -178,7 +193,7 @@ impl WritingMode {
#[inline] #[inline]
pub fn is_sideways(&self) -> bool { pub fn is_sideways(&self) -> bool {
self.intersects(WritingMode::SIDEWAYS) self.intersects(WritingMode::VERTICAL_SIDEWAYS | WritingMode::TEXT_SIDEWAYS)
} }
#[inline] #[inline]
@ -316,7 +331,7 @@ impl fmt::Display for WritingMode {
} else { } else {
write!(formatter, " RL")?; write!(formatter, " RL")?;
} }
if self.intersects(WritingMode::SIDEWAYS) { if self.is_sideways() {
write!(formatter, " Sideways")?; write!(formatter, " Sideways")?;
} }
if self.intersects(WritingMode::LINE_INVERTED) { if self.intersects(WritingMode::LINE_INVERTED) {

View file

@ -36,7 +36,7 @@ impl ToCss for AspectRatio {
W: fmt::Write, W: fmt::Write,
{ {
self.0.to_css(dest)?; self.0.to_css(dest)?;
dest.write_char('/')?; dest.write_str(" / ")?;
self.1.to_css(dest) self.1.to_css(dest)
} }
} }

View file

@ -362,9 +362,20 @@ fn should_ignore_declaration_when_ignoring_document_colors(
// Treat background-color a bit differently. If the specified color is // Treat background-color a bit differently. If the specified color is
// anything other than a fully transparent color, convert it into the // anything other than a fully transparent color, convert it into the
// Device's default background color. // Device's default background color.
// Also: for now, we treat background-image a bit differently, too.
// background-image is marked as ignored, but really, we only ignore
// it when backplates are disabled (since then text may be unreadable over
// a background image, if we're ignoring document colors).
// Here we check backplate status to decide if ignoring background-image
// is the right decision.
{ {
let background_color = match **declaration { let background_color = match **declaration {
PropertyDeclaration::BackgroundColor(ref color) => color, PropertyDeclaration::BackgroundColor(ref color) => color,
// In the future, if/when we remove the backplate pref, we can remove this
// special case along with the 'ignored_when_colors_disabled=True' mako line
// for the "background-image" property.
#[cfg(feature = "gecko")]
PropertyDeclaration::BackgroundImage(..) => return !static_prefs::pref!("browser.display.permit_backplate"),
_ => return true, _ => return true,
}; };

View file

@ -9,7 +9,8 @@
# "column-span", # "column-span",
# "offset-distance", # "offset-distance",
# "offset-path", # "offset-path",
# "offset-rotate" # "offset-rotate",
# "offset"
COUNTED_UNKNOWN_PROPERTIES = [ COUNTED_UNKNOWN_PROPERTIES = [
"-webkit-font-smoothing", "-webkit-font-smoothing",
"zoom", "zoom",
@ -82,7 +83,6 @@ COUNTED_UNKNOWN_PROPERTIES = [
"-webkit-ruby-position", "-webkit-ruby-position",
"-webkit-column-break-after", "-webkit-column-break-after",
"-webkit-margin-collapse", "-webkit-margin-collapse",
"offset",
"-webkit-border-before", "-webkit-border-before",
"-webkit-border-end", "-webkit-border-end",
"-webkit-border-after", "-webkit-border-after",

View file

@ -768,10 +768,12 @@ animated_list_impl!(<T> for crate::OwnedSlice<T>);
animated_list_impl!(<T> for SmallVec<[T; 1]>); animated_list_impl!(<T> for SmallVec<[T; 1]>);
animated_list_impl!(<T> for Vec<T>); animated_list_impl!(<T> for Vec<T>);
/// <https://drafts.csswg.org/css-transitions/#animtype-visibility> /// <https://drafts.csswg.org/web-animations-1/#animating-visibility>
impl Animate for Visibility { impl Animate for Visibility {
#[inline] #[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match procedure {
Procedure::Interpolate { .. } => {
let (this_weight, other_weight) = procedure.weights(); let (this_weight, other_weight) = procedure.weights();
match (*self, *other) { match (*self, *other) {
(Visibility::Visible, _) => { (Visibility::Visible, _) => {
@ -782,6 +784,9 @@ impl Animate for Visibility {
}, },
_ => Err(()), _ => Err(()),
} }
},
_ => Err(()),
}
} }
} }

View file

@ -126,7 +126,7 @@ ${helpers.predefined_type(
initial_value="generics::rect::Rect::all(computed::NonNegativeLengthOrNumber::zero())", initial_value="generics::rect::Rect::all(computed::NonNegativeLengthOrNumber::zero())",
initial_specified_value="generics::rect::Rect::all(specified::NonNegativeLengthOrNumber::zero())", initial_specified_value="generics::rect::Rect::all(specified::NonNegativeLengthOrNumber::zero())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset", spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
animation_value_type="discrete", animation_value_type="NonNegativeLengthOrNumberRect",
boxed=True, boxed=True,
)} )}
@ -147,7 +147,7 @@ ${helpers.predefined_type(
initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())", initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())",
initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())", initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-width", spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
animation_value_type="discrete", animation_value_type="BorderImageWidth",
boxed=True, boxed=True,
)} )}
@ -158,6 +158,6 @@ ${helpers.predefined_type(
initial_value="computed::BorderImageSlice::hundred_percent()", initial_value="computed::BorderImageSlice::hundred_percent()",
initial_specified_value="specified::BorderImageSlice::hundred_percent()", initial_specified_value="specified::BorderImageSlice::hundred_percent()",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice", spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
animation_value_type="discrete", animation_value_type="BorderImageSlice",
boxed=True, boxed=True,
)} )}

View file

@ -91,6 +91,7 @@ ${helpers.single_keyword(
extra_prefixes="webkit", extra_prefixes="webkit",
animation_value_type="discrete", animation_value_type="discrete",
servo_restyle_damage = "reflow", servo_restyle_damage = "reflow",
gecko_enum_prefix = "StyleFlexWrap",
)} )}
% if engine == "servo-2013": % if engine == "servo-2013":

View file

@ -1793,7 +1793,7 @@ impl ToCss for PropertyId {
} }
/// The counted unknown property list which is used for css use counters. /// The counted unknown property list which is used for css use counters.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, PartialEq)]
#[repr(u8)] #[repr(u8)]
pub enum CountedUnknownProperty { pub enum CountedUnknownProperty {
% for prop in data.counted_unknown_properties: % for prop in data.counted_unknown_properties:
@ -1821,16 +1821,6 @@ impl CountedUnknownProperty {
} }
} }
#[cfg(feature = "gecko")]
fn is_counted_unknown_use_counters_enabled() -> bool {
static_prefs::pref!("layout.css.use-counters-unimplemented.enabled")
}
#[cfg(feature = "servo")]
fn is_counted_unknown_use_counters_enabled() -> bool {
false
}
impl PropertyId { impl PropertyId {
/// Return the longhand id that this property id represents. /// Return the longhand id that this property id represents.
#[inline] #[inline]
@ -1890,11 +1880,9 @@ impl PropertyId {
StaticId::LonghandAlias(id, alias) => PropertyId::LonghandAlias(id, alias), StaticId::LonghandAlias(id, alias) => PropertyId::LonghandAlias(id, alias),
StaticId::ShorthandAlias(id, alias) => PropertyId::ShorthandAlias(id, alias), StaticId::ShorthandAlias(id, alias) => PropertyId::ShorthandAlias(id, alias),
StaticId::CountedUnknown(unknown_prop) => { StaticId::CountedUnknown(unknown_prop) => {
if is_counted_unknown_use_counters_enabled() {
if let Some(counters) = use_counters { if let Some(counters) = use_counters {
counters.counted_unknown_properties.record(unknown_prop); counters.counted_unknown_properties.record(unknown_prop);
} }
}
// Always return Err(()) because these aren't valid custom property names. // Always return Err(()) because these aren't valid custom property names.
return Err(()); return Err(());

View file

@ -365,3 +365,79 @@ ${helpers.two_properties_shorthand(
} }
} }
</%helpers:shorthand> </%helpers:shorthand>
<%helpers:shorthand name="offset"
engines="gecko"
sub_properties="offset-path offset-distance offset-rotate offset-anchor"
gecko_pref="layout.css.motion-path.enabled",
spec="https://drafts.fxtf.org/motion-1/#offset-shorthand">
use crate::parser::Parse;
use crate::values::specified::motion::{OffsetPath, OffsetRotate};
use crate::values::specified::position::PositionOrAuto;
use crate::values::specified::LengthPercentage;
use crate::Zero;
pub fn parse_value<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> {
// FIXME: Bug 1559232: Support offset-position.
// Per the spec, this must have offet-position and/or offset-path. However, we don't
// support offset-position, so offset-path is necessary now.
let offset_path = OffsetPath::parse(context, input)?;
let mut offset_distance = None;
let mut offset_rotate = None;
loop {
if offset_distance.is_none() {
if let Ok(value) = input.try(|i| LengthPercentage::parse(context, i)) {
offset_distance = Some(value);
}
}
if offset_rotate.is_none() {
if let Ok(value) = input.try(|i| OffsetRotate::parse(context, i)) {
offset_rotate = Some(value);
continue;
}
}
break;
}
let offset_anchor = input.try(|i| {
i.expect_delim('/')?;
PositionOrAuto::parse(context, i)
}).ok();
Ok(expanded! {
offset_path: offset_path,
offset_distance: offset_distance.unwrap_or(LengthPercentage::zero()),
offset_rotate: offset_rotate.unwrap_or(OffsetRotate::auto()),
offset_anchor: offset_anchor.unwrap_or(PositionOrAuto::auto()),
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
// FIXME: Bug 1559232: Support offset-position. We don't support offset-position,
// so always serialize offset-path now.
self.offset_path.to_css(dest)?;
if !self.offset_distance.is_zero() {
dest.write_str(" ")?;
self.offset_distance.to_css(dest)?;
}
if !self.offset_rotate.is_auto() {
dest.write_str(" ")?;
self.offset_rotate.to_css(dest)?;
}
if *self.offset_anchor != PositionOrAuto::auto() {
dest.write_str(" / ")?;
self.offset_anchor.to_css(dest)?;
}
Ok(())
}
}
</%helpers:shorthand>

View file

@ -26,13 +26,10 @@ impl Animate for LengthPercentage {
.animate(&other.unclamped_length(), procedure)?; .animate(&other.unclamped_length(), procedure)?;
let percentage = let percentage =
animate_percentage_half(self.specified_percentage(), other.specified_percentage())?; animate_percentage_half(self.specified_percentage(), other.specified_percentage())?;
let is_calc =
self.was_calc || other.was_calc || self.has_percentage != other.has_percentage;
Ok(Self::with_clamping_mode( Ok(Self::with_clamping_mode(
length, length,
percentage, percentage,
self.clamping_mode, self.clamping_mode,
is_calc,
)) ))
} }
} }

View file

@ -10,7 +10,10 @@
use crate::values::computed::position::Position; use crate::values::computed::position::Position;
use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::{Angle, Color, Context}; use crate::values::computed::{Angle, Color, Context};
use crate::values::computed::{Length, LengthPercentage, NumberOrPercentage, ToComputedValue}; use crate::values::computed::{
LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, NumberOrPercentage,
ToComputedValue,
};
use crate::values::generics::image::{self as generic, GradientCompatMode}; use crate::values::generics::image::{self as generic, GradientCompatMode};
use crate::values::specified::image::LineDirection as SpecifiedLineDirection; use crate::values::specified::image::LineDirection as SpecifiedLineDirection;
use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword}; use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword};
@ -27,12 +30,17 @@ pub type Image = generic::GenericImage<Gradient, MozImageRect, ComputedImageUrl>
/// Computed values for a CSS gradient. /// Computed values for a CSS gradient.
/// <https://drafts.csswg.org/css-images/#gradients> /// <https://drafts.csswg.org/css-images/#gradients>
pub type Gradient = pub type Gradient = generic::GenericGradient<
generic::GenericGradient<LineDirection, Length, LengthPercentage, Position, Color>; LineDirection,
LengthPercentage,
NonNegativeLength,
NonNegativeLengthPercentage,
Position,
Color,
>;
/// A computed gradient kind. /// A computed radial gradient ending shape.
pub type GradientKind = pub type EndingShape = generic::GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>;
generic::GenericGradientKind<LineDirection, Length, LengthPercentage, Position>;
/// A computed gradient line direction. /// A computed gradient line direction.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue)]
@ -48,9 +56,6 @@ pub enum LineDirection {
Corner(HorizontalPositionKeyword, VerticalPositionKeyword), Corner(HorizontalPositionKeyword, VerticalPositionKeyword),
} }
/// A computed radial gradient ending shape.
pub type EndingShape = generic::EndingShape<Length, LengthPercentage>;
/// A computed gradient item. /// A computed gradient item.
pub type GradientItem = generic::GenericGradientItem<Color, LengthPercentage>; pub type GradientItem = generic::GenericGradientItem<Color, LengthPercentage>;

View file

@ -85,25 +85,20 @@ pub struct LengthPercentage {
/// Whether we specified a percentage or not. /// Whether we specified a percentage or not.
#[animation(constant)] #[animation(constant)]
pub has_percentage: bool, pub has_percentage: bool,
/// Whether this was from a calc() expression. This is needed because right
/// now we don't treat calc() the same way as non-calc everywhere, but
/// that's a bug in most cases.
///
/// Please don't add new uses of this that aren't for converting to Gecko's
/// representation, or to interpolate values.
///
/// See https://github.com/w3c/csswg-drafts/issues/3482.
#[animation(constant)]
pub was_calc: bool,
} }
// FIXME(emilio): This is a bit of a hack that can disappear as soon as we share // NOTE(emilio): We don't compare `clamping_mode` since we want to preserve the
// representation of LengthPercentage with Gecko. The issue here is that Gecko // invariant that `from_computed_value(length).to_computed_value(..) == length`.
// uses CalcValue to represent position components, so they always come back as
// was_calc == true, and we mess up in the transitions code.
// //
// This was a pre-existing bug, though arguably so only in pretty obscure cases // Right now for e.g. a non-negative length, we set clamping_mode to `All`
// like calc(0px + 5%) and such. // unconditionally for non-calc values, and to `NonNegative` for calc.
//
// If we determine that it's sound, from_computed_value() can generate an
// absolute length, which then would get `All` as the clamping mode.
//
// We may want to just eagerly-detect whether we can clamp in
// `LengthPercentage::new` and switch to `AllowedNumericType::NonNegative` then,
// maybe.
impl PartialEq for LengthPercentage { impl PartialEq for LengthPercentage {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.length == other.length && self.length == other.length &&
@ -129,12 +124,7 @@ impl LengthPercentage {
/// Returns a new `LengthPercentage`. /// Returns a new `LengthPercentage`.
#[inline] #[inline]
pub fn new(length: Length, percentage: Option<Percentage>) -> Self { pub fn new(length: Length, percentage: Option<Percentage>) -> Self {
Self::with_clamping_mode( Self::with_clamping_mode(length, percentage, AllowedNumericType::All)
length,
percentage,
AllowedNumericType::All,
/* was_calc = */ false,
)
} }
/// Returns a new `LengthPercentage` with zero length and some percentage. /// Returns a new `LengthPercentage` with zero length and some percentage.
@ -148,14 +138,12 @@ impl LengthPercentage {
length: Length, length: Length,
percentage: Option<Percentage>, percentage: Option<Percentage>,
clamping_mode: AllowedNumericType, clamping_mode: AllowedNumericType,
was_calc: bool,
) -> Self { ) -> Self {
Self { Self {
clamping_mode, clamping_mode,
length, length,
percentage: percentage.unwrap_or_default(), percentage: percentage.unwrap_or_default(),
has_percentage: percentage.is_some(), has_percentage: percentage.is_some(),
was_calc,
} }
} }
@ -285,7 +273,6 @@ impl specified::CalcLengthPercentage {
Length::new(length.min(f32::MAX).max(f32::MIN)), Length::new(length.min(f32::MAX).max(f32::MIN)),
self.percentage, self.percentage,
self.clamping_mode, self.clamping_mode,
/* was_calc = */ true,
) )
} }
@ -381,35 +368,25 @@ impl LengthPercentage {
} }
/// Returns the clamped non-negative values. /// Returns the clamped non-negative values.
///
/// TODO(emilio): It's a bit unfortunate that this depends on whether the
/// value was a `calc()` value or not. Should it?
#[inline] #[inline]
pub fn clamp_to_non_negative(self) -> Self { pub fn clamp_to_non_negative(self) -> Self {
if self.was_calc {
return Self::with_clamping_mode(
self.length,
self.specified_percentage(),
AllowedNumericType::NonNegative,
self.was_calc,
);
}
debug_assert!(!self.has_percentage || self.unclamped_length() == Length::zero());
if let Some(p) = self.specified_percentage() { if let Some(p) = self.specified_percentage() {
// If we can eagerly clamp the percentage then just do that.
if self.length.is_zero() {
return Self::with_clamping_mode( return Self::with_clamping_mode(
Length::zero(), Length::zero(),
Some(p.clamp_to_non_negative()), Some(p.clamp_to_non_negative()),
AllowedNumericType::NonNegative, AllowedNumericType::NonNegative,
self.was_calc,
); );
} }
return Self::with_clamping_mode(self.length, Some(p), AllowedNumericType::NonNegative);
}
Self::with_clamping_mode( Self::with_clamping_mode(
self.length.clamp_to_non_negative(), self.length.clamp_to_non_negative(),
None, None,
AllowedNumericType::NonNegative, AllowedNumericType::NonNegative,
self.was_calc,
) )
} }
} }

View file

@ -577,7 +577,16 @@ impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive( #[derive(
Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
ToAnimatedZero,
ToCss,
ToResolvedValue,
)] )]
#[repr(C, u8)] #[repr(C, u8)]
pub enum NumberOrPercentage { pub enum NumberOrPercentage {

View file

@ -5,12 +5,11 @@
//! Computed types for CSS values that are related to motion path. //! Computed types for CSS values that are related to motion path.
use crate::values::computed::Angle; use crate::values::computed::Angle;
use crate::values::generics::motion::GenericOffsetPath;
use crate::Zero; use crate::Zero;
/// A computed offset-path. The computed value is as specified value. /// The computed value of `offset-path`.
/// pub type OffsetPath = GenericOffsetPath<Angle>;
/// https://drafts.fxtf.org/motion-1/#offset-path-property
pub use crate::values::specified::motion::OffsetPath;
#[inline] #[inline]
fn is_auto_zero_angle(auto: &bool, angle: &Angle) -> bool { fn is_auto_zero_angle(auto: &bool, angle: &Angle) -> bool {

View file

@ -12,12 +12,17 @@ use style_traits::{CssWriter, ToCss};
/// A generic value for a single side of a `border-image-width` property. /// A generic value for a single side of a `border-image-width` property.
#[derive( #[derive(
Animate,
Clone, Clone,
ComputeSquaredDistance,
Copy, Copy,
Debug, Debug,
MallocSizeOf, MallocSizeOf,
Parse,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue, ToComputedValue,
ToCss, ToCss,
ToResolvedValue, ToResolvedValue,
@ -25,10 +30,13 @@ use style_traits::{CssWriter, ToCss};
)] )]
#[repr(C, u8)] #[repr(C, u8)]
pub enum GenericBorderImageSideWidth<LP, N> { pub enum GenericBorderImageSideWidth<LP, N> {
/// `<number>`
///
/// NOTE: Numbers need to be before length-percentagess, in order to parse
/// them first, since `0` should be a number, not the `0px` length.
Number(N),
/// `<length-or-percentage>` /// `<length-or-percentage>`
LengthPercentage(LP), LengthPercentage(LP),
/// `<number>`
Number(N),
/// `auto` /// `auto`
Auto, Auto,
} }
@ -37,12 +45,16 @@ pub use self::GenericBorderImageSideWidth as BorderImageSideWidth;
/// A generic value for the `border-image-slice` property. /// A generic value for the `border-image-slice` property.
#[derive( #[derive(
Animate,
Clone, Clone,
ComputeSquaredDistance,
Copy, Copy,
Debug, Debug,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue, ToComputedValue,
ToCss, ToCss,
ToResolvedValue, ToResolvedValue,
@ -54,6 +66,7 @@ pub struct GenericBorderImageSlice<NumberOrPercentage> {
#[css(field_bound)] #[css(field_bound)]
pub offsets: Rect<NumberOrPercentage>, pub offsets: Rect<NumberOrPercentage>,
/// Whether to fill the middle part. /// Whether to fill the middle part.
#[animation(constant)]
#[css(represents_keyword)] #[css(represents_keyword)]
pub fill: bool, pub fill: bool,
} }

View file

@ -646,11 +646,8 @@ impl Parse for LineNameList {
if let Ok((mut names_list, count)) = repeat_parse_result { if let Ok((mut names_list, count)) = repeat_parse_result {
match count { match count {
// FIXME(emilio): we probably shouldn't expand repeat() at // FIXME(emilio): we shouldn't expand repeat() at
// parse time for subgrid. // parse time for subgrid. (bug 1583429)
//
// Also this doesn't have the merging semantics that
// non-subgrid has... But maybe that's ok?
RepeatCount::Number(num) => line_names.extend( RepeatCount::Number(num) => line_names.extend(
names_list names_list
.iter() .iter()
@ -660,6 +657,8 @@ impl Parse for LineNameList {
), ),
RepeatCount::AutoFill if fill_idx.is_none() => { RepeatCount::AutoFill if fill_idx.is_none() => {
// `repeat(autof-fill, ..)` should have just one line name. // `repeat(autof-fill, ..)` should have just one line name.
// FIXME(bug 1341507) the above comment is wrong per:
// https://drafts.csswg.org/css-grid-2/#typedef-name-repeat
if names_list.len() != 1 { if names_list.len() != 1 {
return Err( return Err(
input.new_custom_error(StyleParseErrorKind::UnspecifiedError) input.new_custom_error(StyleParseErrorKind::UnspecifiedError)

View file

@ -73,9 +73,21 @@ pub use self::GenericImage as Image;
/// <https://drafts.csswg.org/css-images/#gradients> /// <https://drafts.csswg.org/css-images/#gradients>
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
#[repr(C)] #[repr(C)]
pub struct GenericGradient<LineDirection, Length, LengthPercentage, Position, Color> { pub struct GenericGradient<
LineDirection,
LengthPercentage,
NonNegativeLength,
NonNegativeLengthPercentage,
Position,
Color,
> {
/// Gradients can be linear or radial. /// Gradients can be linear or radial.
pub kind: GenericGradientKind<LineDirection, Length, LengthPercentage, Position>, pub kind: GenericGradientKind<
LineDirection,
NonNegativeLength,
NonNegativeLengthPercentage,
Position,
>,
/// The color stops and interpolation hints. /// The color stops and interpolation hints.
pub items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>, pub items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>,
/// True if this is a repeating gradient. /// True if this is a repeating gradient.
@ -101,11 +113,19 @@ pub enum GradientCompatMode {
/// A gradient kind. /// A gradient kind.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
#[repr(C, u8)] #[repr(C, u8)]
pub enum GenericGradientKind<LineDirection, Length, LengthPercentage, Position> { pub enum GenericGradientKind<
LineDirection,
NonNegativeLength,
NonNegativeLengthPercentage,
Position,
> {
/// A linear gradient. /// A linear gradient.
Linear(LineDirection), Linear(LineDirection),
/// A radial gradient. /// A radial gradient.
Radial(GenericEndingShape<Length, LengthPercentage>, Position), Radial(
GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>,
Position,
),
} }
pub use self::GenericGradientKind as GradientKind; pub use self::GenericGradientKind as GradientKind;
@ -115,11 +135,11 @@ pub use self::GenericGradientKind as GradientKind;
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
)] )]
#[repr(C, u8)] #[repr(C, u8)]
pub enum GenericEndingShape<Length, LengthPercentage> { pub enum GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage> {
/// A circular gradient. /// A circular gradient.
Circle(GenericCircle<Length>), Circle(GenericCircle<NonNegativeLength>),
/// An elliptic gradient. /// An elliptic gradient.
Ellipse(GenericEllipse<LengthPercentage>), Ellipse(GenericEllipse<NonNegativeLengthPercentage>),
} }
pub use self::GenericEndingShape as EndingShape; pub use self::GenericEndingShape as EndingShape;
@ -127,9 +147,9 @@ pub use self::GenericEndingShape as EndingShape;
/// A circle shape. /// A circle shape.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
#[repr(C, u8)] #[repr(C, u8)]
pub enum GenericCircle<Length> { pub enum GenericCircle<NonNegativeLength> {
/// A circle radius. /// A circle radius.
Radius(Length), Radius(NonNegativeLength),
/// A circle extent. /// A circle extent.
Extent(ShapeExtent), Extent(ShapeExtent),
} }
@ -141,9 +161,9 @@ pub use self::GenericCircle as Circle;
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
)] )]
#[repr(C, u8)] #[repr(C, u8)]
pub enum GenericEllipse<LengthPercentage> { pub enum GenericEllipse<NonNegativeLengthPercentage> {
/// An ellipse pair of radii. /// An ellipse pair of radii.
Radii(LengthPercentage, LengthPercentage), Radii(NonNegativeLengthPercentage, NonNegativeLengthPercentage),
/// An ellipse extent. /// An ellipse extent.
Extent(ShapeExtent), Extent(ShapeExtent),
} }
@ -314,11 +334,12 @@ where
} }
} }
impl<D, L, LoP, P, C> ToCss for Gradient<D, L, LoP, P, C> impl<D, LP, NL, NLP, P, C> ToCss for Gradient<D, LP, NL, NLP, P, C>
where where
D: LineDirection, D: LineDirection,
L: ToCss, LP: ToCss,
LoP: ToCss, NL: ToCss,
NLP: ToCss,
P: ToCss, P: ToCss,
C: ToCss, C: ToCss,
{ {

View file

@ -29,6 +29,7 @@ pub mod font;
pub mod grid; pub mod grid;
pub mod image; pub mod image;
pub mod length; pub mod length;
pub mod motion;
pub mod position; pub mod position;
pub mod rect; pub mod rect;
pub mod size; pub mod size;

View file

@ -0,0 +1,110 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Generic types for CSS Motion Path.
use crate::values::specified::SVGPathData;
/// The <size> in ray() function.
///
/// https://drafts.fxtf.org/motion-1/#valdef-offsetpath-size
#[allow(missing_docs)]
#[derive(
Clone,
Copy,
Debug,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[repr(u8)]
pub enum RaySize {
ClosestSide,
ClosestCorner,
FarthestSide,
FarthestCorner,
Sides,
}
/// The `ray()` function, `ray( [ <angle> && <size> && contain? ] )`
///
/// https://drafts.fxtf.org/motion-1/#valdef-offsetpath-ray
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct RayFunction<Angle> {
/// The bearing angle with `0deg` pointing up and positive angles
/// representing clockwise rotation.
pub angle: Angle,
/// Decide the path length used when `offset-distance` is expressed
/// as a percentage.
#[animation(constant)]
pub size: RaySize,
/// Clamp `offset-distance` so that the box is entirely contained
/// within the path.
#[animation(constant)]
#[css(represents_keyword)]
pub contain: bool,
}
/// The offset-path value.
///
/// https://drafts.fxtf.org/motion-1/#offset-path-property
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[repr(C, u8)]
pub enum GenericOffsetPath<Angle> {
// We could merge SVGPathData into ShapeSource, so we could reuse them. However,
// we don't want to support other value for offset-path, so use SVGPathData only for now.
/// Path value for path(<string>).
#[css(function)]
Path(SVGPathData),
/// ray() function, which defines a path in the polar coordinate system.
#[css(function)]
Ray(RayFunction<Angle>),
/// None value.
#[animation(error)]
None,
// Bug 1186329: Implement <basic-shape>, <geometry-box>, and <url>.
}
pub use self::GenericOffsetPath as OffsetPath;
impl<Angle> OffsetPath<Angle> {
/// Return None.
#[inline]
pub fn none() -> Self {
OffsetPath::None
}
}

View file

@ -21,6 +21,7 @@ use style_traits::{CssWriter, ParseError, ToCss};
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero,
ToComputedValue, ToComputedValue,
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,

View file

@ -180,24 +180,6 @@ impl BorderImageSideWidth {
} }
} }
impl Parse for BorderImageSideWidth {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
return Ok(GenericBorderImageSideWidth::Auto);
}
if let Ok(len) = input.try(|i| NonNegativeLengthPercentage::parse(context, i)) {
return Ok(GenericBorderImageSideWidth::LengthPercentage(len));
}
let num = NonNegativeNumber::parse(context, input)?;
Ok(GenericBorderImageSideWidth::Number(num))
}
}
impl Parse for BorderImageSlice { impl Parse for BorderImageSlice {
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,

View file

@ -393,6 +393,22 @@ impl Display {
}; };
Display::from3(DisplayOutside::Block, inside, self.is_list_item()) Display::from3(DisplayOutside::Block, inside, self.is_list_item())
}, },
// If this pref is true, then we'll blockify "-moz-inline-box" to
// "-moz-box", and blockify "-moz-box" to itself. Otherwise, we
// blockify both to "block".
#[cfg(feature = "gecko")]
DisplayOutside::XUL => {
if static_prefs::pref!(
"layout.css.xul-box-display-values.survive-blockification.enabled"
) {
match self.inside() {
DisplayInside::MozInlineBox | DisplayInside::MozBox => Display::MozBox,
_ => Display::Block,
}
} else {
Display::Block
}
},
DisplayOutside::Block | DisplayOutside::None => *self, DisplayOutside::Block | DisplayOutside::None => *self,
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
_ => Display::Block, _ => Display::Block,
@ -1140,6 +1156,8 @@ fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
let mut flags = match longhand { let mut flags = match longhand {
LonghandId::Opacity => WillChangeBits::OPACITY, LonghandId::Opacity => WillChangeBits::OPACITY,
LonghandId::Transform => WillChangeBits::TRANSFORM, LonghandId::Transform => WillChangeBits::TRANSFORM,
#[cfg(feature = "gecko")]
LonghandId::Translate | LonghandId::Rotate | LonghandId::Scale => WillChangeBits::TRANSFORM,
_ => WillChangeBits::empty(), _ => WillChangeBits::empty(),
}; };

View file

@ -15,10 +15,13 @@ use crate::values::generics::image::{
self as generic, Circle, Ellipse, GradientCompatMode, ShapeExtent, self as generic, Circle, Ellipse, GradientCompatMode, ShapeExtent,
}; };
use crate::values::generics::position::Position as GenericPosition; use crate::values::generics::position::Position as GenericPosition;
use crate::values::generics::NonNegative;
use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword}; use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword};
use crate::values::specified::position::{Position, PositionComponent, Side}; use crate::values::specified::position::{Position, PositionComponent, Side};
use crate::values::specified::url::SpecifiedImageUrl; use crate::values::specified::url::SpecifiedImageUrl;
use crate::values::specified::{Angle, Color, Length, LengthPercentage}; use crate::values::specified::{
Angle, Color, Length, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage,
};
use crate::values::specified::{Number, NumberOrPercentage, Percentage}; use crate::values::specified::{Number, NumberOrPercentage, Percentage};
use crate::Atom; use crate::Atom;
use cssparser::{Delimiter, Parser, Token}; use cssparser::{Delimiter, Parser, Token};
@ -54,7 +57,14 @@ pub type Image = generic::Image<Gradient, MozImageRect, SpecifiedImageUrl>;
/// Specified values for a CSS gradient. /// Specified values for a CSS gradient.
/// <https://drafts.csswg.org/css-images/#gradients> /// <https://drafts.csswg.org/css-images/#gradients>
pub type Gradient = generic::Gradient<LineDirection, Length, LengthPercentage, Position, Color>; pub type Gradient = generic::Gradient<
LineDirection,
LengthPercentage,
NonNegativeLength,
NonNegativeLengthPercentage,
Position,
Color,
>;
impl SpecifiedValueInfo for Gradient { impl SpecifiedValueInfo for Gradient {
const SUPPORTED_TYPES: u8 = CssType::GRADIENT; const SUPPORTED_TYPES: u8 = CssType::GRADIENT;
@ -80,7 +90,8 @@ impl SpecifiedValueInfo for Gradient {
} }
/// A specified gradient kind. /// A specified gradient kind.
pub type GradientKind = generic::GradientKind<LineDirection, Length, LengthPercentage, Position>; pub type GradientKind =
generic::GradientKind<LineDirection, NonNegativeLength, NonNegativeLengthPercentage, Position>;
/// A specified gradient line direction. /// A specified gradient line direction.
/// ///
@ -98,7 +109,7 @@ pub enum LineDirection {
} }
/// A specified ending shape. /// A specified ending shape.
pub type EndingShape = generic::EndingShape<Length, LengthPercentage>; pub type EndingShape = generic::EndingShape<NonNegativeLength, NonNegativeLengthPercentage>;
/// A specified gradient item. /// A specified gradient item.
pub type GradientItem = generic::GradientItem<Color, LengthPercentage>; pub type GradientItem = generic::GradientItem<Color, LengthPercentage>;
@ -391,11 +402,11 @@ impl Gradient {
"radial" => { "radial" => {
let first_point = Point::parse(context, input)?; let first_point = Point::parse(context, input)?;
input.expect_comma()?; input.expect_comma()?;
let first_radius = Number::parse(context, input)?; let first_radius = Number::parse_non_negative(context, input)?;
input.expect_comma()?; input.expect_comma()?;
let second_point = Point::parse(context, input)?; let second_point = Point::parse(context, input)?;
input.expect_comma()?; input.expect_comma()?;
let second_radius = Number::parse(context, input)?; let second_radius = Number::parse_non_negative(context, input)?;
let (reverse_stops, point, radius) = if second_radius.value >= first_radius.value { let (reverse_stops, point, radius) = if second_radius.value >= first_radius.value {
(false, second_point, second_radius) (false, second_point, second_radius)
@ -403,7 +414,7 @@ impl Gradient {
(true, first_point, first_radius) (true, first_point, first_radius)
}; };
let rad = Circle::Radius(Length::from_px(radius.value)); let rad = Circle::Radius(NonNegative(Length::from_px(radius.value)));
let shape = generic::EndingShape::Circle(rad); let shape = generic::EndingShape::Circle(rad);
let position: Position = point.into(); let position: Position = point.into();
@ -678,7 +689,7 @@ impl EndingShape {
return Ok(generic::EndingShape::Circle(Circle::Extent(extent))); return Ok(generic::EndingShape::Circle(Circle::Extent(extent)));
} }
if compat_mode == GradientCompatMode::Modern { if compat_mode == GradientCompatMode::Modern {
if let Ok(length) = input.try(|i| Length::parse(context, i)) { if let Ok(length) = input.try(|i| NonNegativeLength::parse(context, i)) {
return Ok(generic::EndingShape::Circle(Circle::Radius(length))); return Ok(generic::EndingShape::Circle(Circle::Radius(length)));
} }
} }
@ -692,8 +703,8 @@ impl EndingShape {
} }
if compat_mode == GradientCompatMode::Modern { if compat_mode == GradientCompatMode::Modern {
let pair: Result<_, ParseError> = input.try(|i| { let pair: Result<_, ParseError> = input.try(|i| {
let x = LengthPercentage::parse(context, i)?; let x = NonNegativeLengthPercentage::parse(context, i)?;
let y = LengthPercentage::parse(context, i)?; let y = NonNegativeLengthPercentage::parse(context, i)?;
Ok((x, y)) Ok((x, y))
}); });
if let Ok((x, y)) = pair { if let Ok((x, y)) = pair {
@ -704,24 +715,24 @@ impl EndingShape {
ShapeExtent::FarthestCorner, ShapeExtent::FarthestCorner,
))); )));
} }
if let Ok(length) = input.try(|i| Length::parse(context, i)) { if let Ok(length) = input.try(|i| NonNegativeLength::parse(context, i)) {
if let Ok(y) = input.try(|i| LengthPercentage::parse(context, i)) { if let Ok(y) = input.try(|i| NonNegativeLengthPercentage::parse(context, i)) {
if compat_mode == GradientCompatMode::Modern { if compat_mode == GradientCompatMode::Modern {
let _ = input.try(|i| i.expect_ident_matching("ellipse")); let _ = input.try(|i| i.expect_ident_matching("ellipse"));
} }
return Ok(generic::EndingShape::Ellipse(Ellipse::Radii( return Ok(generic::EndingShape::Ellipse(Ellipse::Radii(
length.into(), NonNegative(LengthPercentage::from(length.0)),
y, y,
))); )));
} }
if compat_mode == GradientCompatMode::Modern { if compat_mode == GradientCompatMode::Modern {
let y = input.try(|i| { let y = input.try(|i| {
i.expect_ident_matching("ellipse")?; i.expect_ident_matching("ellipse")?;
LengthPercentage::parse(context, i) NonNegativeLengthPercentage::parse(context, i)
}); });
if let Ok(y) = y { if let Ok(y) = y {
return Ok(generic::EndingShape::Ellipse(Ellipse::Radii( return Ok(generic::EndingShape::Ellipse(Ellipse::Radii(
length.into(), NonNegative(LengthPercentage::from(length.0)),
y, y,
))); )));
} }
@ -731,8 +742,8 @@ impl EndingShape {
return Ok(generic::EndingShape::Circle(Circle::Radius(length))); return Ok(generic::EndingShape::Circle(Circle::Radius(length)));
} }
input.try(|i| { input.try(|i| {
let x = Percentage::parse(context, i)?; let x = Percentage::parse_non_negative(context, i)?;
let y = if let Ok(y) = i.try(|i| LengthPercentage::parse(context, i)) { let y = if let Ok(y) = i.try(|i| NonNegativeLengthPercentage::parse(context, i)) {
if compat_mode == GradientCompatMode::Modern { if compat_mode == GradientCompatMode::Modern {
let _ = i.try(|i| i.expect_ident_matching("ellipse")); let _ = i.try(|i| i.expect_ident_matching("ellipse"));
} }
@ -741,9 +752,12 @@ impl EndingShape {
if compat_mode == GradientCompatMode::Modern { if compat_mode == GradientCompatMode::Modern {
i.expect_ident_matching("ellipse")?; i.expect_ident_matching("ellipse")?;
} }
LengthPercentage::parse(context, i)? NonNegativeLengthPercentage::parse(context, i)?
}; };
Ok(generic::EndingShape::Ellipse(Ellipse::Radii(x.into(), y))) Ok(generic::EndingShape::Ellipse(Ellipse::Radii(
NonNegative(LengthPercentage::from(x)),
y,
)))
}) })
} }
} }

View file

@ -704,14 +704,14 @@ impl Parse for NonNegativeLength {
impl From<NoCalcLength> for NonNegativeLength { impl From<NoCalcLength> for NonNegativeLength {
#[inline] #[inline]
fn from(len: NoCalcLength) -> Self { fn from(len: NoCalcLength) -> Self {
NonNegative::<Length>(Length::NoCalc(len)) NonNegative(Length::NoCalc(len))
} }
} }
impl From<Length> for NonNegativeLength { impl From<Length> for NonNegativeLength {
#[inline] #[inline]
fn from(len: Length) -> Self { fn from(len: Length) -> Self {
NonNegative::<Length>(len) NonNegative(len)
} }
} }

View file

@ -62,7 +62,9 @@ pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLe
pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
pub use self::length::{MaxSize, Size}; pub use self::length::{MaxSize, Size};
pub use self::length::{NoCalcLength, ViewportPercentageLength}; pub use self::length::{NoCalcLength, ViewportPercentageLength};
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto}; pub use self::length::{
NonNegativeLength, NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto,
};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub use self::list::ListStyleType; pub use self::list::ListStyleType;
pub use self::list::MozListReversed; pub use self::list::MozListReversed;

View file

@ -7,46 +7,53 @@
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::values::computed::motion::OffsetRotate as ComputedOffsetRotate; use crate::values::computed::motion::OffsetRotate as ComputedOffsetRotate;
use crate::values::computed::{Context, ToComputedValue}; use crate::values::computed::{Context, ToComputedValue};
use crate::values::generics::motion::{GenericOffsetPath, RayFunction, RaySize};
use crate::values::specified::{Angle, SVGPathData}; use crate::values::specified::{Angle, SVGPathData};
use crate::Zero; use crate::Zero;
use cssparser::Parser; use cssparser::Parser;
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, StyleParseErrorKind};
/// The offset-path value. /// The specified value of `offset-path`.
/// pub type OffsetPath = GenericOffsetPath<Angle>;
/// https://drafts.fxtf.org/motion-1/#offset-path-property
#[derive( impl Parse for RayFunction<Angle> {
Animate, fn parse<'i, 't>(
Clone, context: &ParserContext,
ComputeSquaredDistance, input: &mut Parser<'i, 't>,
Debug, ) -> Result<Self, ParseError<'i>> {
MallocSizeOf, let mut angle = None;
PartialEq, let mut size = None;
SpecifiedValueInfo, let mut contain = false;
ToAnimatedZero, loop {
ToComputedValue, if angle.is_none() {
ToCss, angle = input.try(|i| Angle::parse(context, i)).ok();
ToResolvedValue,
ToShmem,
)]
#[repr(C, u8)]
pub enum OffsetPath {
// We could merge SVGPathData into ShapeSource, so we could reuse them. However,
// we don't want to support other value for offset-path, so use SVGPathData only for now.
/// Path value for path(<string>).
#[css(function)]
Path(SVGPathData),
/// None value.
#[animation(error)]
None,
// Bug 1186329: Implement ray(), <basic-shape>, <geometry-box>, and <url>.
} }
impl OffsetPath { if size.is_none() {
/// Return None. size = input.try(RaySize::parse).ok();
#[inline] if size.is_some() {
pub fn none() -> Self { continue;
OffsetPath::None }
}
if !contain {
contain = input.try(|i| i.expect_ident_matching("contain")).is_ok();
if contain {
continue;
}
}
break;
}
if angle.is_none() || size.is_none() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(RayFunction {
angle: angle.unwrap(),
size: size.unwrap(),
contain,
})
} }
} }
@ -65,9 +72,10 @@ impl Parse for OffsetPath {
let function = input.expect_function()?.clone(); let function = input.expect_function()?.clone();
input.parse_nested_block(move |i| { input.parse_nested_block(move |i| {
match_ignore_ascii_case! { &function, match_ignore_ascii_case! { &function,
// Bug 1186329: Implement the parser for ray(), <basic-shape>, <geometry-box>, // Bug 1186329: Implement the parser for <basic-shape>, <geometry-box>,
// and <url>. // and <url>.
"path" => SVGPathData::parse(context, i).map(OffsetPath::Path), "path" => SVGPathData::parse(context, i).map(GenericOffsetPath::Path),
"ray" => RayFunction::parse(context, i).map(GenericOffsetPath::Ray),
_ => { _ => {
Err(location.new_custom_error( Err(location.new_custom_error(
StyleParseErrorKind::UnexpectedFunction(function.clone()) StyleParseErrorKind::UnexpectedFunction(function.clone())
@ -122,6 +130,23 @@ pub struct OffsetRotate {
angle: Angle, angle: Angle,
} }
impl OffsetRotate {
/// Returns the initial value, auto.
#[inline]
pub fn auto() -> Self {
OffsetRotate {
direction: OffsetRotateDirection::Auto,
angle: Angle::zero(),
}
}
/// Returns true if self is auto 0deg.
#[inline]
pub fn is_auto(&self) -> bool {
self.direction == OffsetRotateDirection::Auto && self.angle.is_zero()
}
}
impl Parse for OffsetRotate { impl Parse for OffsetRotate {
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,

View file

@ -297,12 +297,7 @@ impl<S: Side> ToComputedValue for PositionComponent<S> {
let p = Percentage(1. - length.percentage()); let p = Percentage(1. - length.percentage());
let l = -length.unclamped_length(); let l = -length.unclamped_length();
// We represent `<end-side> <length>` as `calc(100% - <length>)`. // We represent `<end-side> <length>` as `calc(100% - <length>)`.
ComputedLengthPercentage::with_clamping_mode( ComputedLengthPercentage::with_clamping_mode(l, Some(p), length.clamping_mode)
l,
Some(p),
length.clamping_mode,
/* was_calc = */ true,
)
}, },
PositionComponent::Side(_, Some(ref length)) | PositionComponent::Side(_, Some(ref length)) |
PositionComponent::Length(ref length) => length.to_computed_value(context), PositionComponent::Length(ref length) => length.to_computed_value(context),

View file

@ -6,20 +6,44 @@ use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect, LogicalSize, WritingMode}; use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect, LogicalSize, WritingMode};
#[cfg(test)] #[cfg(test)]
fn modes() -> [WritingMode; 13] { fn modes() -> [WritingMode; 21] {
[ [
WritingMode::empty(), WritingMode::empty(),
WritingMode::VERTICAL, WritingMode::VERTICAL,
WritingMode::VERTICAL | WritingMode::VERTICAL_LR, WritingMode::VERTICAL | WritingMode::VERTICAL_LR,
WritingMode::VERTICAL | WritingMode::VERTICAL_LR | WritingMode::SIDEWAYS, WritingMode::VERTICAL | WritingMode::VERTICAL_LR | WritingMode::VERTICAL_SIDEWAYS,
WritingMode::VERTICAL | WritingMode::SIDEWAYS, WritingMode::VERTICAL | WritingMode::VERTICAL_LR | WritingMode::TEXT_SIDEWAYS,
WritingMode::VERTICAL |
WritingMode::VERTICAL_LR |
WritingMode::VERTICAL_SIDEWAYS |
WritingMode::TEXT_SIDEWAYS,
WritingMode::VERTICAL | WritingMode::VERTICAL_SIDEWAYS,
WritingMode::VERTICAL | WritingMode::TEXT_SIDEWAYS,
WritingMode::VERTICAL | WritingMode::VERTICAL_SIDEWAYS | WritingMode::TEXT_SIDEWAYS,
WritingMode::VERTICAL | WritingMode::UPRIGHT, WritingMode::VERTICAL | WritingMode::UPRIGHT,
WritingMode::RTL, WritingMode::RTL,
WritingMode::VERTICAL | WritingMode::RTL, WritingMode::VERTICAL | WritingMode::RTL,
WritingMode::VERTICAL | WritingMode::VERTICAL_LR | WritingMode::RTL, WritingMode::VERTICAL | WritingMode::VERTICAL_LR | WritingMode::RTL,
WritingMode::VERTICAL | WritingMode::VERTICAL_LR | WritingMode::SIDEWAYS | WritingMode::RTL, WritingMode::VERTICAL |
WritingMode::VERTICAL_LR |
WritingMode::VERTICAL_SIDEWAYS |
WritingMode::RTL,
WritingMode::VERTICAL |
WritingMode::VERTICAL_LR |
WritingMode::TEXT_SIDEWAYS |
WritingMode::RTL,
WritingMode::VERTICAL |
WritingMode::VERTICAL_LR |
WritingMode::VERTICAL_SIDEWAYS |
WritingMode::TEXT_SIDEWAYS |
WritingMode::RTL,
WritingMode::VERTICAL | WritingMode::VERTICAL_LR | WritingMode::UPRIGHT | WritingMode::RTL, WritingMode::VERTICAL | WritingMode::VERTICAL_LR | WritingMode::UPRIGHT | WritingMode::RTL,
WritingMode::VERTICAL | WritingMode::SIDEWAYS | WritingMode::RTL, WritingMode::VERTICAL | WritingMode::VERTICAL_SIDEWAYS | WritingMode::RTL,
WritingMode::VERTICAL | WritingMode::TEXT_SIDEWAYS | WritingMode::RTL,
WritingMode::VERTICAL |
WritingMode::VERTICAL_SIDEWAYS |
WritingMode::TEXT_SIDEWAYS |
WritingMode::RTL,
WritingMode::VERTICAL | WritingMode::UPRIGHT | WritingMode::RTL, WritingMode::VERTICAL | WritingMode::UPRIGHT | WritingMode::RTL,
] ]
} }

View file

@ -1,10 +0,0 @@
[background-image-computed.sub.html]
[Property background-image value 'radial-gradient(ellipse calc(-0.5em + 10px) calc(0.5em + 10px) at 20px 30px, red, blue)' computes to 'radial-gradient(0px 30px at 20px 30px, rgb(255, 0, 0), rgb(0, 0, 255))']
expected: FAIL
[Property background-image value 'radial-gradient(circle calc(-0.5em + 10px) at calc(-1em + 10px) calc(-2em + 10px), red, blue)' computes to 'radial-gradient(0px at -30px -70px, rgb(255, 0, 0), rgb(0, 0, 255))']
expected: FAIL
[Property background-image value 'radial-gradient(ellipse calc(0.5em + 10px) calc(-0.5em + 10px) at 20px 30px, red, blue)' computes to 'radial-gradient(30px 0px at 20px 30px, rgb(255, 0, 0), rgb(0, 0, 255))']
expected: FAIL

View file

@ -1,19 +0,0 @@
[background-image-invalid.html]
[e.style['background-image'\] = "radial-gradient(ellipse -20px 30px at center, red, blue)" should not set the property value]
expected: FAIL
[e.style['background-image'\] = "repeating-radial-gradient(-20% 30% at center, red, blue)" should not set the property value]
expected: FAIL
[e.style['background-image'\] = "radial-gradient(circle -10px at center, red, blue)" should not set the property value]
expected: FAIL
[e.style['background-image'\] = "repeating-radial-gradient(20px -30px ellipse at center, red, blue)" should not set the property value]
expected: FAIL
[e.style['background-image'\] = "radial-gradient(20px -30px at center, red, blue)" should not set the property value]
expected: FAIL
[e.style['background-image'\] = "repeating-radial-gradient(-10px at center, red, blue)" should not set the property value]
expected: FAIL

View file

@ -1,4 +0,0 @@
[border-image-width-computed.html]
[Property border-image-width value '0' computes to '0']
expected: FAIL

View file

@ -1,481 +0,0 @@
[font-valid.html]
[message-box should be a supported system font.]
expected: FAIL
[status-bar should be a supported system font.]
expected: FAIL
[menu should be a supported system font.]
expected: FAIL
[icon should be a supported system font.]
expected: FAIL
[small-caption should be a supported system font.]
expected: FAIL
[caption should be a supported system font.]
expected: FAIL
[e.style['font'\] = "italic normal extra-expanded 900 calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "expanded normal bolder italic xx-large/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "condensed italic normal small-caps calc(30% - 40px)/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps oblique ultra-expanded lighter 20%/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-expanded 900 normal larger/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "bold italic small-caps ultra-condensed calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal small-caps 20%/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "italic extra-expanded small-caps larger/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique normal expanded small-caps 20%/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-expanded normal normal larger/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal italic normal 20%/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "100 normal small-caps condensed larger/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique expanded normal bolder xx-large/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique normal 20%/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique extra-condensed 20%/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "condensed 100 italic calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal oblique bolder calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "900 normal italic extra-condensed calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "normal italic 900 semi-condensed xx-large/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal xx-large/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique normal normal 100 xx-large/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "100 normal oblique small-caps 20%/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "italic bold larger/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "100 extra-condensed small-caps 20%/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-expanded italic small-caps 900 larger/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "normal oblique normal normal calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "100 oblique semi-condensed small-caps xx-large/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique normal lighter small-caps xx-large/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps 900 normal xx-large/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps normal bolder larger/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal italic expanded larger/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal extra-expanded bolder oblique larger/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps bolder condensed calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "lighter normal extra-expanded small-caps calc(30% - 40px)/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "lighter normal small-caps oblique xx-large/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "bold extra-condensed 20%/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "bolder small-caps oblique expanded xx-large/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal lighter semi-condensed calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal lighter condensed calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal bold oblique 20%/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique extra-condensed 100 20%/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal normal bolder 20%/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps oblique normal normal 20%/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "lighter small-caps extra-expanded larger/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique normal small-caps 900 20%/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal oblique lighter xx-large/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "expanded oblique small-caps normal xx-large/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-condensed normal normal small-caps 20%/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique lighter small-caps expanded xx-large/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "normal 100 small-caps larger/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-expanded normal lighter small-caps larger/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal normal small-caps 20%/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "italic normal normal calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "italic normal normal ultra-condensed larger/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal extra-condensed italic xx-large/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps oblique bold normal xx-large/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "lighter small-caps normal italic 20%/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "italic small-caps 100 ultra-condensed calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "italic 900 normal semi-expanded calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal bold normal normal larger/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-condensed lighter normal small-caps 20%/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal extra-condensed small-caps normal 20%/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-condensed small-caps oblique 900 20%/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal extra-expanded italic small-caps larger/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal condensed lighter larger/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "italic condensed normal calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "bold normal 20%/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "normal 900 normal xx-large/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-expanded lighter small-caps normal larger/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique 100 normal small-caps 20%/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "condensed normal normal bolder calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "expanded 100 xx-large/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal normal larger/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps expanded bolder xx-large/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "italic small-caps normal bold larger/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "condensed small-caps bold calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal oblique small-caps larger/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal oblique semi-expanded larger/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal bolder small-caps 20%/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps italic normal 100 calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique small-caps lighter normal 20%/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique small-caps semi-condensed 900 xx-large/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps condensed italic calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "900 normal normal small-caps xx-large/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "900 condensed small-caps normal calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "normal condensed small-caps italic calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-condensed oblique normal normal 20%/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "bolder normal expanded italic 20%/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "900 small-caps larger/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-condensed normal small-caps oblique 20%/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps bolder normal italic xx-large/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "condensed small-caps calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps italic bolder semi-expanded larger/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "100 small-caps normal semi-expanded calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal bolder small-caps extra-condensed 20%/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal ultra-expanded small-caps larger/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "bold oblique normal normal xx-large/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "italic condensed 900 normal calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal small-caps normal calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "bold normal normal ultra-condensed larger/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "bold extra-expanded italic larger/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps extra-condensed normal 900 20%/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps extra-expanded lighter normal larger/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps italic lighter calc(30% - 40px)/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "normal italic ultra-expanded bold 20%/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal xx-large/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal condensed normal small-caps calc(30% - 40px)/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps bold italic larger/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps oblique normal 20%/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps expanded xx-large/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-condensed oblique lighter small-caps 20%/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "normal expanded oblique normal xx-large/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "normal extra-condensed normal oblique 20%/1.2 cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal normal larger/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "expanded normal oblique small-caps xx-large/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "oblique small-caps normal normal xx-large/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "900 oblique small-caps normal 20%/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal extra-expanded italic xx-large/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps bold oblique extra-condensed 20%/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "expanded small-caps normal italic xx-large/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "italic 100 extra-expanded larger/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "normal expanded bold normal xx-large/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal 900 oblique calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps expanded oblique calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "condensed normal small-caps 100 calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-expanded small-caps normal 100 larger/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "italic normal 100 condensed larger/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal normal bold calc(30% - 40px)/calc(120% + 1.2em) serif" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal normal semi-expanded calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps calc(30% - 40px)/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps 100 calc(30% - 40px)/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps lighter normal ultra-condensed larger/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "normal bold expanded small-caps xx-large/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "normal extra-expanded larger/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps normal bolder extra-expanded calc(30% - 40px)/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "italic normal small-caps extra-condensed calc(30% - 40px)/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal 100 larger/calc(120% + 1.2em) Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "extra-expanded normal italic lighter larger/calc(120% + 1.2em) sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps normal oblique xx-large/1.2 sans-serif" should set the property value]
expected: FAIL
[e.style['font'\] = "bolder italic normal small-caps larger/calc(120% + 1.2em) fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal oblique small-caps larger/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "normal lighter italic ultra-condensed xx-large/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "normal 100 normal ultra-expanded 20%/1.2 serif" should set the property value]
expected: FAIL
[e.style['font'\] = "normal italic small-caps condensed 20%/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "normal italic normal extra-condensed xx-large/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal italic normal xx-large/1.2 fantasy" should set the property value]
expected: FAIL
[e.style['font'\] = "small-caps extra-expanded normal larger/calc(120% + 1.2em) \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "bolder condensed normal calc(30% - 40px)/calc(120% + 1.2em) cursive" should set the property value]
expected: FAIL
[e.style['font'\] = "normal small-caps semi-expanded normal 20%/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "expanded normal xx-large/1.2 \\"FB Armada\\"" should set the property value]
expected: FAIL
[e.style['font'\] = "bolder normal normal calc(30% - 40px)/calc(120% + 1.2em) monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "expanded bolder small-caps xx-large/1.2 Menu" should set the property value]
expected: FAIL
[e.style['font'\] = "normal normal small-caps condensed xx-large/1.2 monospace" should set the property value]
expected: FAIL
[e.style['font'\] = "900 expanded normal small-caps xx-large/1.2 Menu" should set the property value]
expected: FAIL

View file

@ -1,4 +0,0 @@
[font-shorthand-serialization.html]
[The font shorthand should be serialized just like any other shorthand.]
expected: FAIL