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);
#[cfg(feature = "servo")]
malloc_size_of_is_0!(csp::Destination);
#[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.
#[inline]
pub fn is_nested(&self) -> bool {

View file

@ -667,7 +667,7 @@ where
match *selector {
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) => {
// <slots> are never flattened tree slottables.
!element.is_html_slot_element() &&

View file

@ -607,7 +607,7 @@ impl<Impl: SelectorImpl> Selector<Impl> {
}
#[inline]
pub fn part(&self) -> Option<&Impl::PartName> {
pub fn parts(&self) -> Option<&[Impl::PartName]> {
if !self.is_part() {
return None;
}
@ -1013,7 +1013,7 @@ pub enum Component<Impl: SelectorImpl> {
Slotted(Selector<Impl>),
/// The `::part` pseudo-element.
/// 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:
///
/// https://drafts.csswg.org/css-scoping/#host-selector
@ -1302,9 +1302,14 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
selector.to_css(dest)?;
dest.write_char(')')
},
Part(ref part_name) => {
Part(ref part_names) => {
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(')')
},
PseudoElement(ref p) => p.to_css(dest),
@ -1626,7 +1631,7 @@ enum SimpleSelectorParseResult<Impl: SelectorImpl> {
SimpleSelector(Component<Impl>),
PseudoElement(Impl::PseudoElement),
SlottedPseudo(Selector<Impl>),
PartPseudo(Impl::PartName),
PartPseudo(Box<[Impl::PartName]>),
}
#[derive(Debug)]
@ -2029,10 +2034,10 @@ where
SimpleSelectorParseResult::SimpleSelector(s) => {
builder.push_simple_selector(s);
},
SimpleSelectorParseResult::PartPseudo(part_name) => {
SimpleSelectorParseResult::PartPseudo(part_names) => {
state.insert(SelectorParsingState::AFTER_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) => {
state.insert(SelectorParsingState::AFTER_SLOTTED);
@ -2193,10 +2198,15 @@ where
input.new_custom_error(SelectorParseErrorKind::InvalidState)
);
}
let name = input.parse_nested_block(|input| {
Ok(input.expect_ident()?.as_ref().into())
let names = input.parse_nested_block(|input| {
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 !state.allows_slotted() {
@ -3051,8 +3061,7 @@ pub mod tests {
assert!(parse("::part()").is_err());
assert!(parse("::part(42)").is_err());
// Though note https://github.com/w3c/csswg-drafts/issues/3502
assert!(parse("::part(foo bar)").is_err());
assert!(parse("::part(foo bar)").is_ok());
assert!(parse("::part(foo):hover").is_ok());
assert!(parse("::part(foo) + bar").is_err());

View file

@ -25,7 +25,6 @@ servo-layout-2020 = []
gecko_debug = []
gecko_refcount_logging = []
gecko_profiler = []
moz_xbl = []
[dependencies]
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 {
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());
add_headers_recursively(file, &mut *added_paths);
result

View file

@ -776,14 +776,6 @@ pub trait TElement:
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.
fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;

View file

@ -598,8 +598,7 @@ lazy_static! {
atom!("device-pixel-ratio"),
AllowsRanges::Yes,
Evaluator::Float(eval_device_pixel_ratio),
ParsingRequirements::WEBKIT_PREFIX |
ParsingRequirements::WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED,
ParsingRequirements::WEBKIT_PREFIX,
),
// -webkit-transform-3d.
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::structs;
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::EffectCompositor_CascadeLevel as CascadeLevel;
use crate::gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
@ -86,8 +84,6 @@ use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr;
#[cfg(not(feature = "moz_xbl"))]
use values::Impossible;
#[inline]
fn elements_with_id<'a, 'le>(
@ -317,7 +313,7 @@ impl<'ln> GeckoNode<'ln> {
}
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;
}
}
@ -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.
#[derive(Clone, Copy)]
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]
fn namespace_id(&self) -> i32 {
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
// StyleChildrenIterator::IsNeeded does, except that it might return
// 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() ||
self.has_xbl_binding_with_content() ||
self.is_html_slot_element() ||
self.shadow_root().is_some() ||
self.may_have_anonymous_children()
@ -1595,11 +1511,6 @@ impl<'le> TElement for GeckoElement<'le> {
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(
&self,
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
/// changes.
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,
matching_context: MatchingContext<'a, E::Impl>,
document_states_changed: DocumentState,

View file

@ -28,7 +28,7 @@ where
/// Whether the invalidation processor only cares about light-tree
/// 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 {
false
}
@ -455,11 +455,6 @@ where
let mut sibling_invalidations = InvalidationVector::new();
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() {
Some(e) => e,
None => continue,
@ -574,13 +569,6 @@ where
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() {
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 rayon;
extern crate selectors;
#[cfg(feature = "servo")]
#[macro_use]
extern crate serde;
pub extern crate servo_arc;

View file

@ -123,9 +123,6 @@ bitflags! {
const CHROME_AND_UA_ONLY = 1 << 0;
/// The feature requires a -webkit- prefix.
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 {
fn new(
feature_index: usize,
@ -279,81 +290,53 @@ impl MediaFeatureExpression {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
// FIXME: remove extra indented block when lifetimes are non-lexical
let feature_index;
let feature;
let range;
let mut requirements = ParsingRequirements::empty();
let location = input.current_source_location();
let ident = input.expect_ident()?;
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();
let ident = input.expect_ident()?;
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() {
Some((i, f)) => (i, f),
None => {
return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
));
}
))
},
};
if range.is_some() && !feature.allows_ranges() {
return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
));
}
if disabled_by_pref(&feature.name) ||
!requirements.contains(feature.requirements) ||
(range.is_some() && !feature.allows_ranges())
{
return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
));
}
let operator = input.try(consume_operation_or_colon);

View file

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

View file

@ -276,11 +276,6 @@ impl ComputedValuesInner {
pub fn get_raw_visited_style(&self) -> &Option<RawOffsetArc<ComputedValues>> {
&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)">

View file

@ -396,7 +396,7 @@ ${helpers.predefined_type(
engines="gecko",
animation_value_type="ComputedValue",
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",
servo_restyle_damage="reflow_out_of_flow"
)}
@ -409,6 +409,7 @@ ${helpers.predefined_type(
engines="gecko",
animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled",
flags="CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.fxtf.org/motion-1/#offset-distance-property",
servo_restyle_damage="reflow_out_of_flow"
)}
@ -421,6 +422,7 @@ ${helpers.predefined_type(
engines="gecko",
animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled",
flags="CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property",
servo_restyle_damage="reflow_out_of_flow"
)}
@ -433,6 +435,7 @@ ${helpers.predefined_type(
engines="gecko",
animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled",
flags="CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.fxtf.org/motion-1/#offset-anchor-property",
servo_restyle_damage="reflow_out_of_flow",
boxed=True
@ -453,7 +456,6 @@ ${helpers.predefined_type(
"ScrollSnapAlign",
"computed::ScrollSnapAlign::none()",
engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-align",
animation_value_type="discrete",
)}
@ -631,18 +633,6 @@ ${helpers.predefined_type(
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(
"-moz-orient",
"inline block horizontal vertical",

View file

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

View file

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

View file

@ -1876,7 +1876,19 @@ impl PropertyId {
if let Some(id) = static_id(property_name) {
return Ok(match *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::ShorthandAlias(id, alias) => PropertyId::ShorthandAlias(id, alias),
StaticId::CountedUnknown(unknown_prop) => {
@ -3065,10 +3077,6 @@ impl ComputedValuesInner {
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]
/// Returns whether the "content" property for the given style is completely
/// ineffective, and would yield an empty `::before` or `::after`

View file

@ -441,3 +441,58 @@ ${helpers.two_properties_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",
engines="gecko",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-margin",
gecko_pref="layout.css.scroll-snap-v1.enabled",
)}
${helpers.two_properties_shorthand(
@ -48,7 +47,6 @@ ${helpers.two_properties_shorthand(
"specified::Length::parse",
engines="gecko",
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(
@ -58,5 +56,4 @@ ${helpers.two_properties_shorthand(
"specified::Length::parse",
engines="gecko",
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",
"specified::NonNegativeLengthPercentageOrAuto::parse",
engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
spec="https://drafts.csswg.org/css-scroll-snap-1/#propdef-scroll-padding"
)}
@ -46,7 +45,6 @@ ${helpers.two_properties_shorthand(
"scroll-padding-block-end",
"specified::NonNegativeLengthPercentageOrAuto::parse",
engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
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",
"specified::NonNegativeLengthPercentageOrAuto::parse",
engines="gecko",
gecko_pref="layout.css.scroll-snap-v1.enabled",
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
// selectors inside, it's not worth using a whole
// 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
.get_or_insert_with(|| Box::new(Default::default()))
.for_insertion(pseudo_element)
.try_entry(part.clone())?
.try_entry(parts.last().unwrap().clone())?
.or_insert_with(SmallVec::new)
.try_push(rule)?;
} else {

View file

@ -267,7 +267,6 @@ pub trait DomTraversal<E: TElement>: Sync {
context: &mut StyleContext<E>,
parent: E,
parent_data: &ElementData,
is_initial_style: bool,
) -> bool {
debug_assert!(
parent.has_current_styles_for_traversal(parent_data, context.shared.traversal_flags)
@ -279,21 +278,6 @@ pub trait DomTraversal<E: TElement>: Sync {
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;
}
@ -520,8 +504,8 @@ pub fn recalc_style_at<E, D, F>(
!child_cascade_requirement.can_skip_cascade() ||
is_servo_nonincremental_layout();
traverse_children = traverse_children &&
!traversal.should_cull_subtree(context, element, &data, is_initial_style);
traverse_children =
traverse_children && !traversal.should_cull_subtree(context, element, &data);
// Examine our children, and enqueue the appropriate ones for traversal.
if traverse_children {

View file

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

View file

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

View file

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

View file

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

View file

@ -119,6 +119,10 @@ pub enum SystemColor {
Buttonshadow,
Buttontext,
Captiontext,
#[parse(aliases = "-moz-field")]
Field,
#[parse(aliases = "-moz-fieldtext")]
Fieldtext,
Graytext,
Highlight,
Highlighttext,
@ -139,8 +143,6 @@ pub enum SystemColor {
Windowframe,
Windowtext,
MozButtondefault,
MozField,
MozFieldtext,
MozDialog,
MozDialogtext,
/// 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 p = match_ignore_ascii_case! { &function,
"color-stop" => {
let p = match NumberOrPercentage::parse(context, i)? {
NumberOrPercentage::Number(number) => Percentage::new(number.value),
NumberOrPercentage::Percentage(p) => p,
};
let p = NumberOrPercentage::parse(context, i)?.to_percentage();
i.expect_comma()?;
p
},

View file

@ -179,13 +179,26 @@ impl Parse for Number {
impl Number {
/// Returns a new number with the value `val`.
pub fn new(val: CSSFloat) -> Self {
Number {
value: val,
calc_clamping_mode: None,
fn new_with_clamping_mode(
value: CSSFloat,
calc_clamping_mode: Option<AllowedNumericType>,
) -> 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.
#[inline]
pub fn was_calc(&self) -> bool {
@ -370,6 +383,22 @@ impl NumberOrPercentage {
) -> Result<Self, ParseError<'i>> {
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 {
@ -419,17 +448,7 @@ impl Parse for Opacity {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let number = match NumberOrPercentage::parse(context, input)? {
NumberOrPercentage::Percentage(p) => Number {
value: p.get(),
calc_clamping_mode: if p.is_calc() {
Some(AllowedNumericType::All)
} else {
None
},
},
NumberOrPercentage::Number(n) => n,
};
let number = NumberOrPercentage::parse(context, input)?.to_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::{Context, ToComputedValue};
use crate::values::specified::calc::CalcNode;
use crate::values::specified::Number;
use crate::values::{serialize_percentage, CSSFloat};
use cssparser::{Parser, Token};
use std::fmt::{self, Write};
@ -46,13 +47,21 @@ impl ToCss for Percentage {
impl Percentage {
/// 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 {
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%`
#[inline]
pub fn zero() -> Self {
@ -70,12 +79,18 @@ impl Percentage {
calc_clamping_mode: None,
}
}
/// Gets the underlying value for this float.
pub fn get(&self) -> CSSFloat {
self.calc_clamping_mode
.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.
pub fn is_calc(&self) -> bool {
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
/// command to an absolute command.
fn normalize(&self) -> Box<[PathCommand]> {
pub fn normalize(&self) -> Self {
let mut state = PathTraversalState {
subpath_start: CoordPair::new(0.0, 0.0),
pos: CoordPair::new(0.0, 0.0),
@ -56,7 +56,8 @@ impl SVGPathData {
.iter()
.map(|seg| seg.normalize(&mut state))
.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.
let result = self
.normalize()
.0
.iter()
.zip(other.normalize().iter())
.zip(other.normalize().0.iter())
.map(|(a, b)| a.animate(&b, procedure))
.collect::<Result<Vec<_>, _>>()?;
@ -134,8 +136,9 @@ impl ComputeSquaredDistance for SVGPathData {
return Err(());
}
self.normalize()
.0
.iter()
.zip(other.normalize().iter())
.zip(other.normalize().0.iter())
.map(|(this, other)| this.compute_squared_distance(&other))
.sum()
}

View file

@ -33,6 +33,27 @@ pub type TransformOrigin = generic::TransformOrigin<
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 {
/// 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| {
input
.try(|i| Length::parse(context, i))
.unwrap_or(Length::from_px(0.))
.unwrap_or(Length::zero())
};
match input.try(|i| OriginComponent::parse(context, i)) {
Ok(x_origin @ OriginComponent::Center) => {

View file

@ -10,7 +10,7 @@ name = "style_traits"
path = "lib.rs"
[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 = []
[dependencies]
@ -22,7 +22,7 @@ lazy_static = "1"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = "0.1"
selectors = { path = "../selectors" }
serde = {version = "1.0", optional = true}
serde = "1.0"
webrender_api = {git = "https://github.com/servo/webrender", optional = true}
servo_atoms = {path = "../atoms", optional = true}
servo_arc = { path = "../servo_arc" }

View file

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

View file

@ -507,7 +507,9 @@ pub mod specified {
/// Whether to allow negative lengths or not.
#[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 {
/// Allow all kind of numeric values.
All,