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

style: Sync changes from mozilla-central.

See individual commits for details.

https://bugzilla.mozilla.org/show_bug.cgi?id=1593642
This commit is contained in:
bors-servo 2019-11-04 17:04:52 -05:00 committed by GitHub
commit 4886788a8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 270 additions and 305 deletions

View file

@ -837,6 +837,7 @@ malloc_size_of_is_0!(app_units::Au);
malloc_size_of_is_0!(cssparser::RGBA, cssparser::TokenSerializationType); malloc_size_of_is_0!(cssparser::RGBA, cssparser::TokenSerializationType);
#[cfg(feature = "servo")]
malloc_size_of_is_0!(csp::Destination); malloc_size_of_is_0!(csp::Destination);
#[cfg(feature = "url")] #[cfg(feature = "url")]

View file

@ -189,15 +189,6 @@ where
} }
} }
/// Override the quirks mode we're matching against.
///
/// FIXME(emilio): This is a hack for XBL quirks-mode mismatches.
#[inline]
pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) {
self.quirks_mode = quirks_mode;
self.classes_and_ids_case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
}
/// Whether we're matching a nested selector. /// Whether we're matching a nested selector.
#[inline] #[inline]
pub fn is_nested(&self) -> bool { pub fn is_nested(&self) -> bool {

View file

@ -667,7 +667,7 @@ where
match *selector { match *selector {
Component::Combinator(_) => unreachable!(), Component::Combinator(_) => unreachable!(),
Component::Part(ref part) => element.is_part(part), Component::Part(ref parts) => parts.iter().all(|part| element.is_part(part)),
Component::Slotted(ref selector) => { Component::Slotted(ref selector) => {
// <slots> are never flattened tree slottables. // <slots> are never flattened tree slottables.
!element.is_html_slot_element() && !element.is_html_slot_element() &&

View file

@ -607,7 +607,7 @@ impl<Impl: SelectorImpl> Selector<Impl> {
} }
#[inline] #[inline]
pub fn part(&self) -> Option<&Impl::PartName> { pub fn parts(&self) -> Option<&[Impl::PartName]> {
if !self.is_part() { if !self.is_part() {
return None; return None;
} }
@ -1013,7 +1013,7 @@ pub enum Component<Impl: SelectorImpl> {
Slotted(Selector<Impl>), Slotted(Selector<Impl>),
/// The `::part` pseudo-element. /// The `::part` pseudo-element.
/// https://drafts.csswg.org/css-shadow-parts/#part /// https://drafts.csswg.org/css-shadow-parts/#part
Part(#[shmem(field_bound)] Impl::PartName), Part(#[shmem(field_bound)] Box<[Impl::PartName]>),
/// The `:host` pseudo-class: /// The `:host` pseudo-class:
/// ///
/// https://drafts.csswg.org/css-scoping/#host-selector /// https://drafts.csswg.org/css-scoping/#host-selector
@ -1302,9 +1302,14 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
selector.to_css(dest)?; selector.to_css(dest)?;
dest.write_char(')') dest.write_char(')')
}, },
Part(ref part_name) => { Part(ref part_names) => {
dest.write_str("::part(")?; dest.write_str("::part(")?;
display_to_css_identifier(part_name, dest)?; for (i, name) in part_names.iter().enumerate() {
if i != 0 {
dest.write_char(' ')?;
}
display_to_css_identifier(name, dest)?;
}
dest.write_char(')') dest.write_char(')')
}, },
PseudoElement(ref p) => p.to_css(dest), PseudoElement(ref p) => p.to_css(dest),
@ -1626,7 +1631,7 @@ enum SimpleSelectorParseResult<Impl: SelectorImpl> {
SimpleSelector(Component<Impl>), SimpleSelector(Component<Impl>),
PseudoElement(Impl::PseudoElement), PseudoElement(Impl::PseudoElement),
SlottedPseudo(Selector<Impl>), SlottedPseudo(Selector<Impl>),
PartPseudo(Impl::PartName), PartPseudo(Box<[Impl::PartName]>),
} }
#[derive(Debug)] #[derive(Debug)]
@ -2029,10 +2034,10 @@ where
SimpleSelectorParseResult::SimpleSelector(s) => { SimpleSelectorParseResult::SimpleSelector(s) => {
builder.push_simple_selector(s); builder.push_simple_selector(s);
}, },
SimpleSelectorParseResult::PartPseudo(part_name) => { SimpleSelectorParseResult::PartPseudo(part_names) => {
state.insert(SelectorParsingState::AFTER_PART); state.insert(SelectorParsingState::AFTER_PART);
builder.push_combinator(Combinator::Part); builder.push_combinator(Combinator::Part);
builder.push_simple_selector(Component::Part(part_name)); builder.push_simple_selector(Component::Part(part_names));
}, },
SimpleSelectorParseResult::SlottedPseudo(selector) => { SimpleSelectorParseResult::SlottedPseudo(selector) => {
state.insert(SelectorParsingState::AFTER_SLOTTED); state.insert(SelectorParsingState::AFTER_SLOTTED);
@ -2193,10 +2198,15 @@ where
input.new_custom_error(SelectorParseErrorKind::InvalidState) input.new_custom_error(SelectorParseErrorKind::InvalidState)
); );
} }
let name = input.parse_nested_block(|input| { let names = input.parse_nested_block(|input| {
Ok(input.expect_ident()?.as_ref().into()) let mut result = Vec::with_capacity(1);
result.push(input.expect_ident()?.as_ref().into());
while !input.is_exhausted() {
result.push(input.expect_ident()?.as_ref().into());
}
Ok(result.into_boxed_slice())
})?; })?;
return Ok(Some(SimpleSelectorParseResult::PartPseudo(name))); return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
} }
if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") { if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
if !state.allows_slotted() { if !state.allows_slotted() {
@ -3051,8 +3061,7 @@ pub mod tests {
assert!(parse("::part()").is_err()); assert!(parse("::part()").is_err());
assert!(parse("::part(42)").is_err()); assert!(parse("::part(42)").is_err());
// Though note https://github.com/w3c/csswg-drafts/issues/3502 assert!(parse("::part(foo bar)").is_ok());
assert!(parse("::part(foo bar)").is_err());
assert!(parse("::part(foo):hover").is_ok()); assert!(parse("::part(foo):hover").is_ok());
assert!(parse("::part(foo) + bar").is_err()); assert!(parse("::part(foo) + bar").is_err());

View file

@ -25,7 +25,6 @@ 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

@ -109,7 +109,10 @@ fn add_headers_recursively(path: PathBuf, added_paths: &mut HashSet<PathBuf>) {
fn add_include(name: &str) -> String { fn add_include(name: &str) -> String {
let mut added_paths = ADDED_PATHS.lock().unwrap(); let mut added_paths = ADDED_PATHS.lock().unwrap();
let file = search_include(name).expect("Include not found!"); let file = match search_include(name) {
Some(file) => file,
None => panic!("Include not found: {}", name),
};
let result = String::from(file.to_str().unwrap()); let result = String::from(file.to_str().unwrap());
add_headers_recursively(file, &mut *added_paths); add_headers_recursively(file, &mut *added_paths);
result result

View file

@ -776,14 +776,6 @@ pub trait TElement:
return data.hint.has_animation_hint(); return data.hint.has_animation_hint();
} }
/// Returns the anonymous content for the current element's XBL binding,
/// given if any.
///
/// This is used in Gecko for XBL.
fn xbl_binding_anonymous_content(&self) -> Option<Self::ConcreteNode> {
None
}
/// The shadow root this element is a host of. /// The shadow root this element is a host of.
fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>; fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;

View file

@ -598,8 +598,7 @@ lazy_static! {
atom!("device-pixel-ratio"), atom!("device-pixel-ratio"),
AllowsRanges::Yes, AllowsRanges::Yes,
Evaluator::Float(eval_device_pixel_ratio), Evaluator::Float(eval_device_pixel_ratio),
ParsingRequirements::WEBKIT_PREFIX | ParsingRequirements::WEBKIT_PREFIX,
ParsingRequirements::WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED,
), ),
// -webkit-transform-3d. // -webkit-transform-3d.
feature!( feature!(

View file

@ -44,8 +44,6 @@ 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;
@ -86,8 +84,6 @@ 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>(
@ -317,7 +313,7 @@ impl<'ln> GeckoNode<'ln> {
} }
if let Some(parent) = parent_el { if let Some(parent) = parent_el {
if parent.shadow_root().is_some() || parent.xbl_binding().is_some() { if parent.shadow_root().is_some() {
return false; return false;
} }
} }
@ -530,52 +526,6 @@ impl<'a> Iterator for GeckoChildrenIterator<'a> {
} }
} }
/// A Simple wrapper over a non-null Gecko `nsXBLBinding` pointer.
#[cfg(feature = "moz_xbl")]
#[derive(Clone, Copy)]
pub struct GeckoXBLBinding<'lb>(pub &'lb RawGeckoXBLBinding);
#[cfg(feature = "moz_xbl")]
impl<'lb> GeckoXBLBinding<'lb> {
#[inline]
fn base_binding(&self) -> Option<Self> {
unsafe { self.0.mNextBinding.mRawPtr.as_ref().map(GeckoXBLBinding) }
}
#[inline]
fn anon_content(&self) -> *const nsIContent {
self.0.mContent.raw::<nsIContent>()
}
// This duplicates the logic in Gecko's
// nsBindingManager::GetBindingWithContent.
fn binding_with_content(&self) -> Option<Self> {
let mut binding = *self;
loop {
if !binding.anon_content().is_null() {
return Some(binding);
}
binding = binding.base_binding()?;
}
}
}
/// 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);
@ -701,39 +651,6 @@ impl<'le> GeckoElement<'le> {
}) })
} }
#[cfg(feature = "moz_xbl")]
#[inline]
fn may_be_in_binding_manager(&self) -> bool {
self.flags() & (structs::NODE_MAY_BE_IN_BINDING_MNGR as u32) != 0
}
#[cfg(feature = "moz_xbl")]
#[inline]
fn xbl_binding(&self) -> Option<GeckoXBLBinding<'le>> {
if !self.may_be_in_binding_manager() {
return None;
}
let slots = self.extended_slots()?;
unsafe { slots.mXBLBinding.mRawPtr.as_ref().map(GeckoXBLBinding) }
}
#[cfg(not(feature = "moz_xbl"))]
#[inline]
fn xbl_binding(&self) -> Option<GeckoXBLBinding<'le>> {
None
}
#[inline]
fn xbl_binding_with_content(&self) -> Option<GeckoXBLBinding<'le>> {
self.xbl_binding().and_then(|b| b.binding_with_content())
}
#[inline]
fn has_xbl_binding_with_content(&self) -> bool {
!self.xbl_binding_with_content().is_none()
}
#[inline] #[inline]
fn namespace_id(&self) -> i32 { fn namespace_id(&self) -> i32 {
self.as_node().node_info().mInner.mNamespaceID self.as_node().node_info().mInner.mNamespaceID
@ -1107,9 +1024,8 @@ impl<'le> TElement for GeckoElement<'le> {
// This condition is similar to the check that // This condition is similar to the check that
// StyleChildrenIterator::IsNeeded does, except that it might return // StyleChildrenIterator::IsNeeded does, except that it might return
// true if we used to (but no longer) have anonymous content from // true if we used to (but no longer) have anonymous content from
// ::before/::after, XBL bindings, or nsIAnonymousContentCreators. // ::before/::after, or nsIAnonymousContentCreators.
if self.is_in_anonymous_subtree() || if self.is_in_anonymous_subtree() ||
self.has_xbl_binding_with_content() ||
self.is_html_slot_element() || self.is_html_slot_element() ||
self.shadow_root().is_some() || self.shadow_root().is_some() ||
self.may_have_anonymous_children() self.may_have_anonymous_children()
@ -1595,11 +1511,6 @@ impl<'le> TElement for GeckoElement<'le> {
self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) } self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) }
} }
fn xbl_binding_anonymous_content(&self) -> Option<GeckoNode<'le>> {
self.xbl_binding_with_content()
.map(|b| unsafe { GeckoNode::from_content(&*b.anon_content()) })
}
fn might_need_transitions_update( fn might_need_transitions_update(
&self, &self,
old_style: Option<&ComputedValues>, old_style: Option<&ComputedValues>,

View file

@ -31,9 +31,6 @@ impl Default for InvalidationMatchingData {
/// An invalidation processor for style changes due to state and attribute /// An invalidation processor for style changes due to state and attribute
/// changes. /// changes.
pub struct DocumentStateInvalidationProcessor<'a, E: TElement, I> { pub struct DocumentStateInvalidationProcessor<'a, E: TElement, I> {
// TODO(emilio): We might want to just run everything for every possible
// binding along with the document data, or just apply the XBL stuff to the
// bound subtrees.
rules: I, rules: I,
matching_context: MatchingContext<'a, E::Impl>, matching_context: MatchingContext<'a, E::Impl>,
document_states_changed: DocumentState, document_states_changed: DocumentState,

View file

@ -28,7 +28,7 @@ where
/// Whether the invalidation processor only cares about light-tree /// Whether the invalidation processor only cares about light-tree
/// descendants of a given element, that is, doesn't invalidate /// descendants of a given element, that is, doesn't invalidate
/// pseudo-elements, NAC, or XBL anon content. /// pseudo-elements, NAC, shadow dom...
fn light_tree_only(&self) -> bool { fn light_tree_only(&self) -> bool {
false false
} }
@ -455,11 +455,6 @@ where
let mut sibling_invalidations = InvalidationVector::new(); let mut sibling_invalidations = InvalidationVector::new();
for child in parent.dom_children() { for child in parent.dom_children() {
// TODO(emilio): We handle <xbl:children> fine, because they appear
// in selector-matching (note bug 1374247, though).
//
// This probably needs a shadow root check on `child` here, and
// recursing if that's the case.
let child = match child.as_element() { let child = match child.as_element() {
Some(e) => e, Some(e) => e,
None => continue, None => continue,
@ -574,13 +569,6 @@ where
any_descendant |= self.invalidate_dom_descendants_of(root.as_node(), invalidations); any_descendant |= self.invalidate_dom_descendants_of(root.as_node(), invalidations);
} }
// This is needed for XBL (technically) unconditionally, because XBL
// bindings do not block combinators in any way. However this is kinda
// broken anyway, since we should be looking at XBL rules too.
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |= self.invalidate_dom_descendants_of(anon_content, invalidations);
}
if let Some(marker) = self.element.marker_pseudo_element() { if let Some(marker) = self.element.marker_pseudo_element() {
any_descendant |= self.invalidate_pseudo_element_or_nac(marker, invalidations); any_descendant |= self.invalidate_pseudo_element_or_nac(marker, invalidations);
} }

View file

@ -78,7 +78,6 @@ extern crate parking_lot;
extern crate precomputed_hash; extern crate precomputed_hash;
extern crate rayon; extern crate rayon;
extern crate selectors; extern crate selectors;
#[cfg(feature = "servo")]
#[macro_use] #[macro_use]
extern crate serde; extern crate serde;
pub extern crate servo_arc; pub extern crate servo_arc;

View file

@ -123,9 +123,6 @@ bitflags! {
const CHROME_AND_UA_ONLY = 1 << 0; const CHROME_AND_UA_ONLY = 1 << 0;
/// The feature requires a -webkit- prefix. /// The feature requires a -webkit- prefix.
const WEBKIT_PREFIX = 1 << 1; const WEBKIT_PREFIX = 1 << 1;
/// The feature requires the webkit-device-pixel-ratio preference to be
/// enabled.
const WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED = 1 << 2;
} }
} }

View file

@ -242,6 +242,17 @@ fn consume_operation_or_colon(input: &mut Parser) -> Result<Option<Operator>, ()
})) }))
} }
#[allow(unused_variables)]
fn disabled_by_pref(feature: &Atom) -> bool {
#[cfg(feature = "gecko")]
{
if *feature == atom!("-moz-touch-enabled") {
return !static_prefs::pref!("layout.css.moz-touch-enabled.enabled");
}
}
false
}
impl MediaFeatureExpression { impl MediaFeatureExpression {
fn new( fn new(
feature_index: usize, feature_index: usize,
@ -279,81 +290,53 @@ impl MediaFeatureExpression {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// FIXME: remove extra indented block when lifetimes are non-lexical let mut requirements = ParsingRequirements::empty();
let feature_index; let location = input.current_source_location();
let feature; let ident = input.expect_ident()?;
let range;
if context.in_ua_or_chrome_sheet() {
requirements.insert(ParsingRequirements::CHROME_AND_UA_ONLY);
}
let mut feature_name = &**ident;
if starts_with_ignore_ascii_case(feature_name, "-webkit-") {
feature_name = &feature_name[8..];
requirements.insert(ParsingRequirements::WEBKIT_PREFIX);
}
let range = if starts_with_ignore_ascii_case(feature_name, "min-") {
feature_name = &feature_name[4..];
Some(Range::Min)
} else if starts_with_ignore_ascii_case(feature_name, "max-") {
feature_name = &feature_name[4..];
Some(Range::Max)
} else {
None
};
let atom = Atom::from(string_as_ascii_lowercase(feature_name));
let (feature_index, feature) = match MEDIA_FEATURES
.iter()
.enumerate()
.find(|(_, f)| f.name == atom)
{ {
let location = input.current_source_location(); Some((i, f)) => (i, f),
let ident = input.expect_ident()?; None => {
let mut requirements = ParsingRequirements::empty();
if context.in_ua_or_chrome_sheet() {
requirements.insert(ParsingRequirements::CHROME_AND_UA_ONLY);
}
let result = {
let mut feature_name = &**ident;
#[cfg(feature = "gecko")]
{
if starts_with_ignore_ascii_case(feature_name, "-webkit-") {
feature_name = &feature_name[8..];
requirements.insert(ParsingRequirements::WEBKIT_PREFIX);
if static_prefs::pref!("layout.css.prefixes.device-pixel-ratio-webkit") {
requirements.insert(
ParsingRequirements::WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED,
);
}
}
}
let range = if starts_with_ignore_ascii_case(feature_name, "min-") {
feature_name = &feature_name[4..];
Some(Range::Min)
} else if starts_with_ignore_ascii_case(feature_name, "max-") {
feature_name = &feature_name[4..];
Some(Range::Max)
} else {
None
};
let atom = Atom::from(string_as_ascii_lowercase(feature_name));
match MEDIA_FEATURES
.iter()
.enumerate()
.find(|(_, f)| f.name == atom)
{
Some((i, f)) => Ok((i, f, range)),
None => Err(()),
}
};
match result {
Ok((i, f, r)) => {
feature_index = i;
feature = f;
range = r;
},
Err(()) => {
return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
));
},
}
if !(feature.requirements & !requirements).is_empty() {
return Err(location.new_custom_error( return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()), StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
)); ))
} },
};
if range.is_some() && !feature.allows_ranges() { if disabled_by_pref(&feature.name) ||
return Err(location.new_custom_error( !requirements.contains(feature.requirements) ||
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()), (range.is_some() && !feature.allows_ranges())
)); {
} return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
));
} }
let operator = input.try(consume_operation_or_colon); let operator = input.try(consume_operation_or_colon);

View file

@ -13,7 +13,6 @@
# "offset" # "offset"
COUNTED_UNKNOWN_PROPERTIES = [ COUNTED_UNKNOWN_PROPERTIES = [
"-webkit-font-smoothing", "-webkit-font-smoothing",
"zoom",
"-webkit-tap-highlight-color", "-webkit-tap-highlight-color",
"speak", "speak",
"text-size-adjust", "text-size-adjust",

View file

@ -276,11 +276,6 @@ impl ComputedValuesInner {
pub fn get_raw_visited_style(&self) -> &Option<RawOffsetArc<ComputedValues>> { pub fn get_raw_visited_style(&self) -> &Option<RawOffsetArc<ComputedValues>> {
&self.visited_style &self.visited_style
} }
#[allow(non_snake_case)]
pub fn has_moz_binding(&self) -> bool {
!self.get_box().gecko.mBinding.is_none()
}
} }
<%def name="declare_style_struct(style_struct)"> <%def name="declare_style_struct(style_struct)">

View file

@ -396,7 +396,7 @@ ${helpers.predefined_type(
engines="gecko", engines="gecko",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled", gecko_pref="layout.css.motion-path.enabled",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB", flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.fxtf.org/motion-1/#offset-path-property", spec="https://drafts.fxtf.org/motion-1/#offset-path-property",
servo_restyle_damage="reflow_out_of_flow" servo_restyle_damage="reflow_out_of_flow"
)} )}
@ -409,6 +409,7 @@ ${helpers.predefined_type(
engines="gecko", engines="gecko",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled", gecko_pref="layout.css.motion-path.enabled",
flags="CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.fxtf.org/motion-1/#offset-distance-property", spec="https://drafts.fxtf.org/motion-1/#offset-distance-property",
servo_restyle_damage="reflow_out_of_flow" servo_restyle_damage="reflow_out_of_flow"
)} )}
@ -421,6 +422,7 @@ ${helpers.predefined_type(
engines="gecko", engines="gecko",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled", gecko_pref="layout.css.motion-path.enabled",
flags="CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property", spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property",
servo_restyle_damage="reflow_out_of_flow" servo_restyle_damage="reflow_out_of_flow"
)} )}
@ -433,6 +435,7 @@ ${helpers.predefined_type(
engines="gecko", engines="gecko",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled", gecko_pref="layout.css.motion-path.enabled",
flags="CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.fxtf.org/motion-1/#offset-anchor-property", spec="https://drafts.fxtf.org/motion-1/#offset-anchor-property",
servo_restyle_damage="reflow_out_of_flow", servo_restyle_damage="reflow_out_of_flow",
boxed=True boxed=True
@ -453,7 +456,6 @@ ${helpers.predefined_type(
"ScrollSnapAlign", "ScrollSnapAlign",
"computed::ScrollSnapAlign::none()", "computed::ScrollSnapAlign::none()",
engines="gecko", engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-align", spec="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-align",
animation_value_type="discrete", animation_value_type="discrete",
)} )}
@ -631,18 +633,6 @@ ${helpers.predefined_type(
gecko_ffi_name="mAppearance", gecko_ffi_name="mAppearance",
)} )}
${helpers.predefined_type(
"-moz-binding",
"url::UrlOrNone",
"computed::url::UrlOrNone::none()",
engines="gecko",
animation_value_type="none",
gecko_ffi_name="mBinding",
gecko_pref="layout.css.moz-binding.content.enabled",
enabled_in="chrome",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding)",
)}
${helpers.single_keyword( ${helpers.single_keyword(
"-moz-orient", "-moz-orient",
"inline block horizontal vertical", "inline block horizontal vertical",

View file

@ -34,7 +34,6 @@
"Length", "Length",
"computed::Length::zero()", "computed::Length::zero()",
engines="gecko", engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
logical=side[1], logical=side[1],
logical_group="scroll-margin", logical_group="scroll-margin",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-%s" % side[0], spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-%s" % side[0],

View file

@ -33,7 +33,6 @@
"NonNegativeLengthPercentageOrAuto", "NonNegativeLengthPercentageOrAuto",
"computed::NonNegativeLengthPercentageOrAuto::auto()", "computed::NonNegativeLengthPercentageOrAuto::auto()",
engines="gecko", engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
logical=side[1], logical=side[1],
logical_group="scroll-padding", logical_group="scroll-padding",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-%s" % side[0], spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-%s" % side[0],

View file

@ -1876,7 +1876,19 @@ impl PropertyId {
if let Some(id) = static_id(property_name) { if let Some(id) = static_id(property_name) {
return Ok(match *id { return Ok(match *id {
StaticId::Longhand(id) => PropertyId::Longhand(id), StaticId::Longhand(id) => PropertyId::Longhand(id),
StaticId::Shorthand(id) => PropertyId::Shorthand(id), StaticId::Shorthand(id) => {
#[cfg(feature = "gecko")]
{
// We want to count `zoom` even if disabled.
if matches!(id, ShorthandId::Zoom) {
if let Some(counters) = use_counters {
counters.non_custom_properties.record(id.into());
}
}
}
PropertyId::Shorthand(id)
},
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) => {
@ -3065,10 +3077,6 @@ impl ComputedValuesInner {
self.rules.as_ref().unwrap() self.rules.as_ref().unwrap()
} }
/// Whether this style has a -moz-binding value. This is always false for
/// Servo for obvious reasons.
pub fn has_moz_binding(&self) -> bool { false }
#[inline] #[inline]
/// Returns whether the "content" property for the given style is completely /// Returns whether the "content" property for the given style is completely
/// ineffective, and would yield an empty `::before` or `::after` /// ineffective, and would yield an empty `::before` or `::after`

View file

@ -441,3 +441,58 @@ ${helpers.two_properties_shorthand(
} }
} }
</%helpers:shorthand> </%helpers:shorthand>
<%helpers:shorthand name="zoom" engines="gecko"
sub_properties="transform transform-origin"
gecko_pref="layout.css.zoom-transform-hack.enabled"
flags="SHORTHAND_IN_GETCS IS_LEGACY_SHORTHAND"
spec="Not a standard, only a compat hack">
use crate::parser::Parse;
use crate::values::specified::{Number, NumberOrPercentage, TransformOrigin};
use crate::values::generics::transform::{Transform, TransformOperation};
pub fn parse_value<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> {
let zoom = match input.try(|input| NumberOrPercentage::parse(context, input)) {
Ok(number_or_percent) => number_or_percent.to_number(),
Err(..) => {
input.expect_ident_matching("normal")?;
Number::new(1.0)
},
};
// Make sure that the initial value matches the values for the
// longhands, just for general sanity.
//
// FIXME: Should we just do this for the "normal" case? Seems weird
// either way, so maybe not?
Ok(if zoom.get() == 1.0 {
expanded! {
transform: Transform::none(),
transform_origin: TransformOrigin::initial_value(),
}
} else {
expanded! {
transform: Transform(vec![TransformOperation::Scale(zoom, zoom)].into()),
transform_origin: TransformOrigin::zero_zero(),
}
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
if self.transform.0.is_empty() && *self.transform_origin == TransformOrigin::initial_value() {
return 1.0f32.to_css(dest);
}
if *self.transform_origin != TransformOrigin::zero_zero() {
return Ok(())
}
match &*self.transform.0 {
[TransformOperation::Scale(x, y)] if x == y => x.to_css(dest),
_ => Ok(()),
}
}
}
</%helpers:shorthand>

View file

@ -38,7 +38,6 @@ ${helpers.four_sides_shorthand(
"specified::Length::parse", "specified::Length::parse",
engines="gecko", engines="gecko",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin", spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin",
gecko_pref="layout.css.scroll-snap-v1.enabled",
)} )}
${helpers.two_properties_shorthand( ${helpers.two_properties_shorthand(
@ -48,7 +47,6 @@ ${helpers.two_properties_shorthand(
"specified::Length::parse", "specified::Length::parse",
engines="gecko", engines="gecko",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-block", spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-block",
gecko_pref="layout.css.scroll-snap-v1.enabled",
)} )}
${helpers.two_properties_shorthand( ${helpers.two_properties_shorthand(
@ -58,5 +56,4 @@ ${helpers.two_properties_shorthand(
"specified::Length::parse", "specified::Length::parse",
engines="gecko", engines="gecko",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-inline", spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin-inline",
gecko_pref="layout.css.scroll-snap-v1.enabled",
)} )}

View file

@ -36,7 +36,6 @@ ${helpers.four_sides_shorthand(
"scroll-padding-%s", "scroll-padding-%s",
"specified::NonNegativeLengthPercentageOrAuto::parse", "specified::NonNegativeLengthPercentageOrAuto::parse",
engines="gecko", engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding" spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding"
)} )}
@ -46,7 +45,6 @@ ${helpers.two_properties_shorthand(
"scroll-padding-block-end", "scroll-padding-block-end",
"specified::NonNegativeLengthPercentageOrAuto::parse", "specified::NonNegativeLengthPercentageOrAuto::parse",
engines="gecko", engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-block" spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-block"
)} )}
@ -56,7 +54,6 @@ ${helpers.two_properties_shorthand(
"scroll-padding-inline-end", "scroll-padding-inline-end",
"specified::NonNegativeLengthPercentageOrAuto::parse", "specified::NonNegativeLengthPercentageOrAuto::parse",
engines="gecko", engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-inline" spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding-inline"
)} )}

View file

@ -2032,11 +2032,17 @@ impl CascadeData {
// Part is special, since given it doesn't have any // Part is special, since given it doesn't have any
// selectors inside, it's not worth using a whole // selectors inside, it's not worth using a whole
// SelectorMap for it. // SelectorMap for it.
if let Some(part) = selector.part() { if let Some(parts) = selector.parts() {
// ::part() has all semantics, so we just need to
// put any of them in the selector map.
//
// We choose the last one quite arbitrarily,
// expecting it's slightly more likely to be more
// specific.
self.part_rules self.part_rules
.get_or_insert_with(|| Box::new(Default::default())) .get_or_insert_with(|| Box::new(Default::default()))
.for_insertion(pseudo_element) .for_insertion(pseudo_element)
.try_entry(part.clone())? .try_entry(parts.last().unwrap().clone())?
.or_insert_with(SmallVec::new) .or_insert_with(SmallVec::new)
.try_push(rule)?; .try_push(rule)?;
} else { } else {

View file

@ -267,7 +267,6 @@ pub trait DomTraversal<E: TElement>: Sync {
context: &mut StyleContext<E>, context: &mut StyleContext<E>,
parent: E, parent: E,
parent_data: &ElementData, parent_data: &ElementData,
is_initial_style: bool,
) -> bool { ) -> bool {
debug_assert!( debug_assert!(
parent.has_current_styles_for_traversal(parent_data, context.shared.traversal_flags) parent.has_current_styles_for_traversal(parent_data, context.shared.traversal_flags)
@ -279,21 +278,6 @@ pub trait DomTraversal<E: TElement>: Sync {
return true; return true;
} }
// Gecko-only XBL handling.
//
// When we apply the XBL binding during frame construction, we restyle
// the whole subtree again if the binding is valid, so assuming it's
// likely to load valid bindings, we avoid wasted work here, which may
// be a very big perf hit when elements with bindings are nested
// heavily.
if cfg!(feature = "gecko") &&
is_initial_style &&
parent_data.styles.primary().has_moz_binding()
{
debug!("Parent {:?} has XBL binding, deferring traversal", parent);
return true;
}
return false; return false;
} }
@ -520,8 +504,8 @@ pub fn recalc_style_at<E, D, F>(
!child_cascade_requirement.can_skip_cascade() || !child_cascade_requirement.can_skip_cascade() ||
is_servo_nonincremental_layout(); is_servo_nonincremental_layout();
traverse_children = traverse_children && traverse_children =
!traversal.should_cull_subtree(context, element, &data, is_initial_style); traverse_children && !traversal.should_cull_subtree(context, element, &data);
// Examine our children, and enqueue the appropriate ones for traversal. // Examine our children, and enqueue the appropriate ones for traversal.
if traverse_children { if traverse_children {

View file

@ -13,16 +13,17 @@ use std::{f32, f64};
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
/// A computed angle in degrees. /// A computed angle in degrees.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive( #[derive(
Add, Add,
Animate, Animate,
Clone, Clone,
Copy, Copy,
Debug, Debug,
Deserialize,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
PartialOrd, PartialOrd,
Serialize,
ToAnimatedZero, ToAnimatedZero,
ToResolvedValue, ToResolvedValue,
)] )]

View file

@ -75,7 +75,9 @@ impl ToComputedValue for specified::Length {
/// ///
/// https://drafts.csswg.org/css-values-4/#typedef-length-percentage /// https://drafts.csswg.org/css-values-4/#typedef-length-percentage
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, ToAnimatedZero, ToResolvedValue)] #[derive(
Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue,
)]
#[repr(C)] #[repr(C)]
pub struct LengthPercentage { pub struct LengthPercentage {
length: Length, length: Length,
@ -605,15 +607,16 @@ impl Size {
} }
/// The computed `<length>` value. /// The computed `<length>` value.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive( #[derive(
Animate, Animate,
Clone, Clone,
ComputeSquaredDistance, ComputeSquaredDistance,
Copy, Copy,
Deserialize,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
PartialOrd, PartialOrd,
Serialize,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,
ToResolvedValue, ToResolvedValue,

View file

@ -12,7 +12,6 @@ use std::fmt;
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
/// A computed percentage. /// A computed percentage.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive( #[derive(
Animate, Animate,
Clone, Clone,
@ -20,9 +19,11 @@ use style_traits::{CssWriter, ToCss};
Copy, Copy,
Debug, Debug,
Default, Default,
Deserialize,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
PartialOrd, PartialOrd,
Serialize,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,

View file

@ -14,9 +14,11 @@ use crate::values::specified::SVGPathData;
Clone, Clone,
Copy, Copy,
Debug, Debug,
Deserialize,
MallocSizeOf, MallocSizeOf,
Parse, Parse,
PartialEq, PartialEq,
Serialize,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue, ToComputedValue,
@ -41,8 +43,10 @@ pub enum RaySize {
Clone, Clone,
ComputeSquaredDistance, ComputeSquaredDistance,
Debug, Debug,
Deserialize,
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
Serialize,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue, ToComputedValue,

View file

@ -119,6 +119,10 @@ pub enum SystemColor {
Buttonshadow, Buttonshadow,
Buttontext, Buttontext,
Captiontext, Captiontext,
#[parse(aliases = "-moz-field")]
Field,
#[parse(aliases = "-moz-fieldtext")]
Fieldtext,
Graytext, Graytext,
Highlight, Highlight,
Highlighttext, Highlighttext,
@ -139,8 +143,6 @@ pub enum SystemColor {
Windowframe, Windowframe,
Windowtext, Windowtext,
MozButtondefault, MozButtondefault,
MozField,
MozFieldtext,
MozDialog, MozDialog,
MozDialogtext, MozDialogtext,
/// Used to highlight valid regions to drop something onto. /// Used to highlight valid regions to drop something onto.

View file

@ -435,10 +435,7 @@ impl Gradient {
let (color, mut p) = i.parse_nested_block(|i| { let (color, mut p) = i.parse_nested_block(|i| {
let p = match_ignore_ascii_case! { &function, let p = match_ignore_ascii_case! { &function,
"color-stop" => { "color-stop" => {
let p = match NumberOrPercentage::parse(context, i)? { let p = NumberOrPercentage::parse(context, i)?.to_percentage();
NumberOrPercentage::Number(number) => Percentage::new(number.value),
NumberOrPercentage::Percentage(p) => p,
};
i.expect_comma()?; i.expect_comma()?;
p p
}, },

View file

@ -179,13 +179,26 @@ impl Parse for Number {
impl Number { impl Number {
/// Returns a new number with the value `val`. /// Returns a new number with the value `val`.
pub fn new(val: CSSFloat) -> Self { fn new_with_clamping_mode(
Number { value: CSSFloat,
value: val, calc_clamping_mode: Option<AllowedNumericType>,
calc_clamping_mode: None, ) -> Self {
Self {
value,
calc_clamping_mode,
} }
} }
/// Returns this percentage as a number.
pub fn to_percentage(&self) -> Percentage {
Percentage::new_with_clamping_mode(self.value, self.calc_clamping_mode)
}
/// Returns a new number with the value `val`.
pub fn new(val: CSSFloat) -> Self {
Self::new_with_clamping_mode(val, None)
}
/// Returns whether this number came from a `calc()` expression. /// Returns whether this number came from a `calc()` expression.
#[inline] #[inline]
pub fn was_calc(&self) -> bool { pub fn was_calc(&self) -> bool {
@ -370,6 +383,22 @@ impl NumberOrPercentage {
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative) Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
} }
/// Convert the number or the percentage to a number.
pub fn to_percentage(self) -> Percentage {
match self {
Self::Percentage(p) => p,
Self::Number(n) => n.to_percentage(),
}
}
/// Convert the number or the percentage to a number.
pub fn to_number(self) -> Number {
match self {
Self::Percentage(p) => p.to_number(),
Self::Number(n) => n,
}
}
} }
impl Parse for NumberOrPercentage { impl Parse for NumberOrPercentage {
@ -419,17 +448,7 @@ impl Parse for Opacity {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
let number = match NumberOrPercentage::parse(context, input)? { let number = NumberOrPercentage::parse(context, input)?.to_number();
NumberOrPercentage::Percentage(p) => Number {
value: p.get(),
calc_clamping_mode: if p.is_calc() {
Some(AllowedNumericType::All)
} else {
None
},
},
NumberOrPercentage::Number(n) => n,
};
Ok(Opacity(number)) Ok(Opacity(number))
} }
} }

View file

@ -8,6 +8,7 @@ use crate::parser::{Parse, ParserContext};
use crate::values::computed::percentage::Percentage as ComputedPercentage; use crate::values::computed::percentage::Percentage as ComputedPercentage;
use crate::values::computed::{Context, ToComputedValue}; use crate::values::computed::{Context, ToComputedValue};
use crate::values::specified::calc::CalcNode; use crate::values::specified::calc::CalcNode;
use crate::values::specified::Number;
use crate::values::{serialize_percentage, CSSFloat}; use crate::values::{serialize_percentage, CSSFloat};
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
@ -46,13 +47,21 @@ impl ToCss for Percentage {
impl Percentage { impl Percentage {
/// Creates a percentage from a numeric value. /// Creates a percentage from a numeric value.
pub fn new(value: CSSFloat) -> Self { pub(super) fn new_with_clamping_mode(
value: CSSFloat,
calc_clamping_mode: Option<AllowedNumericType>,
) -> Self {
Self { Self {
value, value,
calc_clamping_mode: None, calc_clamping_mode,
} }
} }
/// Creates a percentage from a numeric value.
pub fn new(value: CSSFloat) -> Self {
Self::new_with_clamping_mode(value, None)
}
/// `0%` /// `0%`
#[inline] #[inline]
pub fn zero() -> Self { pub fn zero() -> Self {
@ -70,12 +79,18 @@ impl Percentage {
calc_clamping_mode: None, calc_clamping_mode: None,
} }
} }
/// Gets the underlying value for this float. /// Gets the underlying value for this float.
pub fn get(&self) -> CSSFloat { pub fn get(&self) -> CSSFloat {
self.calc_clamping_mode self.calc_clamping_mode
.map_or(self.value, |mode| mode.clamp(self.value)) .map_or(self.value, |mode| mode.clamp(self.value))
} }
/// Returns this percentage as a number.
pub fn to_number(&self) -> Number {
Number::new_with_clamping_mode(self.value, self.calc_clamping_mode)
}
/// Returns whether this percentage is a `calc()` value. /// Returns whether this percentage is a `calc()` value.
pub fn is_calc(&self) -> bool { pub fn is_calc(&self) -> bool {
self.calc_clamping_mode.is_some() self.calc_clamping_mode.is_some()

View file

@ -46,7 +46,7 @@ impl SVGPathData {
/// Create a normalized copy of this path by converting each relative /// Create a normalized copy of this path by converting each relative
/// command to an absolute command. /// command to an absolute command.
fn normalize(&self) -> Box<[PathCommand]> { pub fn normalize(&self) -> Self {
let mut state = PathTraversalState { let mut state = PathTraversalState {
subpath_start: CoordPair::new(0.0, 0.0), subpath_start: CoordPair::new(0.0, 0.0),
pos: CoordPair::new(0.0, 0.0), pos: CoordPair::new(0.0, 0.0),
@ -56,7 +56,8 @@ impl SVGPathData {
.iter() .iter()
.map(|seg| seg.normalize(&mut state)) .map(|seg| seg.normalize(&mut state))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
result.into_boxed_slice()
SVGPathData(crate::ArcSlice::from_iter(result.into_iter()))
} }
} }
@ -119,8 +120,9 @@ impl Animate for SVGPathData {
// re-normalize again. // re-normalize again.
let result = self let result = self
.normalize() .normalize()
.0
.iter() .iter()
.zip(other.normalize().iter()) .zip(other.normalize().0.iter())
.map(|(a, b)| a.animate(&b, procedure)) .map(|(a, b)| a.animate(&b, procedure))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
@ -134,8 +136,9 @@ impl ComputeSquaredDistance for SVGPathData {
return Err(()); return Err(());
} }
self.normalize() self.normalize()
.0
.iter() .iter()
.zip(other.normalize().iter()) .zip(other.normalize().0.iter())
.map(|(this, other)| this.compute_squared_distance(&other)) .map(|(this, other)| this.compute_squared_distance(&other))
.sum() .sum()
} }

View file

@ -33,6 +33,27 @@ pub type TransformOrigin = generic::TransformOrigin<
Length, Length,
>; >;
impl TransformOrigin {
/// Returns the initial specified value for `transform-origin`.
#[inline]
pub fn initial_value() -> Self {
Self::new(
OriginComponent::Length(LengthPercentage::Percentage(ComputedPercentage(0.5))),
OriginComponent::Length(LengthPercentage::Percentage(ComputedPercentage(0.5))),
Length::zero(),
)
}
/// Returns the `0 0` value.
pub fn zero_zero() -> Self {
Self::new(
OriginComponent::Length(LengthPercentage::zero()),
OriginComponent::Length(LengthPercentage::zero()),
Length::zero(),
)
}
}
impl Transform { impl Transform {
/// Internal parse function for deciding if we wish to accept prefixed values or not /// Internal parse function for deciding if we wish to accept prefixed values or not
/// ///
@ -260,7 +281,7 @@ impl Parse for TransformOrigin {
let parse_depth = |input: &mut Parser| { let parse_depth = |input: &mut Parser| {
input input
.try(|i| Length::parse(context, i)) .try(|i| Length::parse(context, i))
.unwrap_or(Length::from_px(0.)) .unwrap_or(Length::zero())
}; };
match input.try(|i| OriginComponent::parse(context, i)) { match input.try(|i| OriginComponent::parse(context, i)) {
Ok(x_origin @ OriginComponent::Center) => { Ok(x_origin @ OriginComponent::Center) => {

View file

@ -10,7 +10,7 @@ name = "style_traits"
path = "lib.rs" path = "lib.rs"
[features] [features]
servo = ["serde", "servo_atoms", "cssparser/serde", "webrender_api", "servo_url", "euclid/serde"] servo = ["servo_atoms", "cssparser/serde", "webrender_api", "servo_url", "euclid/serde"]
gecko = [] gecko = []
[dependencies] [dependencies]
@ -22,7 +22,7 @@ lazy_static = "1"
malloc_size_of = { path = "../malloc_size_of" } malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = "0.1" malloc_size_of_derive = "0.1"
selectors = { path = "../selectors" } selectors = { path = "../selectors" }
serde = {version = "1.0", optional = true} serde = "1.0"
webrender_api = {git = "https://github.com/servo/webrender", optional = true} webrender_api = {git = "https://github.com/servo/webrender", optional = true}
servo_atoms = {path = "../atoms", optional = true} servo_atoms = {path = "../atoms", optional = true}
servo_arc = { path = "../servo_arc" } servo_arc = { path = "../servo_arc" }

View file

@ -22,7 +22,6 @@ extern crate malloc_size_of;
#[macro_use] #[macro_use]
extern crate malloc_size_of_derive; extern crate malloc_size_of_derive;
extern crate selectors; extern crate selectors;
#[cfg(feature = "servo")]
#[macro_use] #[macro_use]
extern crate serde; extern crate serde;
extern crate servo_arc; extern crate servo_arc;

View file

@ -507,7 +507,9 @@ pub mod specified {
/// Whether to allow negative lengths or not. /// Whether to allow negative lengths or not.
#[repr(u8)] #[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, ToShmem)] #[derive(
Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, PartialOrd, Serialize, ToShmem,
)]
pub enum AllowedNumericType { pub enum AllowedNumericType {
/// Allow all kind of numeric values. /// Allow all kind of numeric values.
All, All,