mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
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:
commit
4886788a8e
38 changed files with 270 additions and 305 deletions
|
@ -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")]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() &&
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ servo-layout-2020 = []
|
|||
gecko_debug = []
|
||||
gecko_refcount_logging = []
|
||||
gecko_profiler = []
|
||||
moz_xbl = []
|
||||
|
||||
[dependencies]
|
||||
app_units = "0.7"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
# "offset"
|
||||
COUNTED_UNKNOWN_PROPERTIES = [
|
||||
"-webkit-font-smoothing",
|
||||
"zoom",
|
||||
"-webkit-tap-highlight-color",
|
||||
"speak",
|
||||
"text-size-adjust",
|
||||
|
|
|
@ -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)">
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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",
|
||||
)}
|
||||
|
|
|
@ -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"
|
||||
)}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
)]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue