mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Merge pull request #15745 from servo/hoist
Cascade: skip duplicated properties before rather than after a virtual call
This commit is contained in:
commit
7c5ac06cd2
10 changed files with 169 additions and 207 deletions
|
@ -218,7 +218,7 @@ impl CSSStyleDeclaration {
|
||||||
|
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
|
|
||||||
self.owner.with_block(|ref pdb| {
|
self.owner.with_block(|pdb| {
|
||||||
pdb.property_value_to_css(&id, &mut string).unwrap();
|
pdb.property_value_to_css(&id, &mut string).unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ impl CSSStyleDeclaration {
|
||||||
impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
|
||||||
fn Length(&self) -> u32 {
|
fn Length(&self) -> u32 {
|
||||||
self.owner.with_block(|ref pdb| {
|
self.owner.with_block(|pdb| {
|
||||||
pdb.declarations.len() as u32
|
pdb.declarations.len() as u32
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
return DOMString::new()
|
return DOMString::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.owner.with_block(|ref pdb| {
|
self.owner.with_block(|pdb| {
|
||||||
if pdb.property_priority(&id).important() {
|
if pdb.property_priority(&id).important() {
|
||||||
DOMString::from("important")
|
DOMString::from("important")
|
||||||
} else {
|
} else {
|
||||||
|
@ -406,7 +406,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
|
|
||||||
// https://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
|
// https://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
|
||||||
fn IndexedGetter(&self, index: u32) -> Option<DOMString> {
|
fn IndexedGetter(&self, index: u32) -> Option<DOMString> {
|
||||||
self.owner.with_block(|ref pdb| {
|
self.owner.with_block(|pdb| {
|
||||||
pdb.declarations.get(index as usize).map(|entry| {
|
pdb.declarations.get(index as usize).map(|entry| {
|
||||||
let (ref declaration, importance) = *entry;
|
let (ref declaration, importance) = *entry;
|
||||||
let mut css = declaration.to_css_string();
|
let mut css = declaration.to_css_string();
|
||||||
|
@ -420,7 +420,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-csstext
|
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-csstext
|
||||||
fn CssText(&self) -> DOMString {
|
fn CssText(&self) -> DOMString {
|
||||||
self.owner.with_block(|ref pdb| {
|
self.owner.with_block(|pdb| {
|
||||||
DOMString::from(pdb.to_css_string())
|
DOMString::from(pdb.to_css_string())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ use parking_lot::RwLock;
|
||||||
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
||||||
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
|
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
|
||||||
use properties::{PropertyDeclarationId, LonghandId, DeclaredValue};
|
use properties::{PropertyDeclarationId, LonghandId, DeclaredValue};
|
||||||
|
use properties::LonghandIdSet;
|
||||||
use properties::PropertyDeclarationParseResult;
|
use properties::PropertyDeclarationParseResult;
|
||||||
use properties::animated_properties::TransitionProperty;
|
use properties::animated_properties::TransitionProperty;
|
||||||
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
|
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
|
||||||
use properties::property_bit_field::PropertyBitField;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
@ -248,7 +248,7 @@ pub struct KeyframesAnimation {
|
||||||
/// Get all the animated properties in a keyframes animation.
|
/// Get all the animated properties in a keyframes animation.
|
||||||
fn get_animated_properties(keyframes: &[Arc<RwLock<Keyframe>>]) -> Vec<TransitionProperty> {
|
fn get_animated_properties(keyframes: &[Arc<RwLock<Keyframe>>]) -> Vec<TransitionProperty> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
let mut seen = PropertyBitField::new();
|
let mut seen = LonghandIdSet::new();
|
||||||
// NB: declarations are already deduplicated, so we don't have to check for
|
// NB: declarations are already deduplicated, so we don't have to check for
|
||||||
// it here.
|
// it here.
|
||||||
for keyframe in keyframes {
|
for keyframe in keyframes {
|
||||||
|
|
|
@ -274,6 +274,39 @@ impl PropertyDeclarationBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Only keep the "winning" declaration for any given property, by importance then source order.
|
||||||
|
pub fn deduplicate(&mut self) {
|
||||||
|
let mut deduplicated = Vec::with_capacity(self.declarations.len());
|
||||||
|
let mut seen_normal = PropertyDeclarationIdSet::new();
|
||||||
|
let mut seen_important = PropertyDeclarationIdSet::new();
|
||||||
|
|
||||||
|
for (declaration, importance) in self.declarations.drain(..).rev() {
|
||||||
|
if importance.important() {
|
||||||
|
let id = declaration.id();
|
||||||
|
if seen_important.contains(id) {
|
||||||
|
self.important_count -= 1;
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if seen_normal.contains(id) {
|
||||||
|
let previous_len = deduplicated.len();
|
||||||
|
deduplicated.retain(|&(ref d, _)| PropertyDeclaration::id(d) != id);
|
||||||
|
debug_assert_eq!(deduplicated.len(), previous_len - 1);
|
||||||
|
}
|
||||||
|
seen_important.insert(id);
|
||||||
|
} else {
|
||||||
|
let id = declaration.id();
|
||||||
|
if seen_normal.contains(id) ||
|
||||||
|
seen_important.contains(id) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen_normal.insert(id)
|
||||||
|
}
|
||||||
|
deduplicated.push((declaration, importance))
|
||||||
|
}
|
||||||
|
deduplicated.reverse();
|
||||||
|
self.declarations = deduplicated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for PropertyDeclarationBlock {
|
impl ToCss for PropertyDeclarationBlock {
|
||||||
|
@ -612,6 +645,6 @@ pub fn parse_property_declaration_list(context: &ParserContext,
|
||||||
declarations: iter.parser.declarations,
|
declarations: iter.parser.declarations,
|
||||||
important_count: important_count,
|
important_count: important_count,
|
||||||
};
|
};
|
||||||
super::deduplicate_property_declarations(&mut block);
|
block.deduplicate();
|
||||||
block
|
block
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,10 +159,6 @@ impl ComputedValues {
|
||||||
!self.get_box().gecko.mBinding.mRawPtr.is_null()
|
!self.get_box().gecko.mBinding.mRawPtr.is_null()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_font_size(&self) -> Au { self.root_font_size }
|
|
||||||
pub fn set_root_font_size(&mut self, s: Au) { self.root_font_size = s; }
|
|
||||||
pub fn set_writing_mode(&mut self, mode: WritingMode) { self.writing_mode = mode; }
|
|
||||||
|
|
||||||
// FIXME(bholley): Implement this properly.
|
// FIXME(bholley): Implement this properly.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_multicol(&self) -> bool { false }
|
pub fn is_multicol(&self) -> bool { false }
|
||||||
|
@ -1247,9 +1243,6 @@ fn static_assert() {
|
||||||
unsafe { transmute(self.gecko.mFont.weight) }
|
unsafe { transmute(self.gecko.mFont.weight) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used for PartialEq, which we don't implement for gecko style structs.
|
|
||||||
pub fn compute_font_hash(&mut self) {}
|
|
||||||
|
|
||||||
pub fn set_font_synthesis(&mut self, v: longhands::font_synthesis::computed_value::T) {
|
pub fn set_font_synthesis(&mut self, v: longhands::font_synthesis::computed_value::T) {
|
||||||
use gecko_bindings::structs::{NS_FONT_SYNTHESIS_WEIGHT, NS_FONT_SYNTHESIS_STYLE};
|
use gecko_bindings::structs::{NS_FONT_SYNTHESIS_WEIGHT, NS_FONT_SYNTHESIS_STYLE};
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,7 @@
|
||||||
use cascade_info::CascadeInfo;
|
use cascade_info::CascadeInfo;
|
||||||
use error_reporting::ParseErrorReporter;
|
use error_reporting::ParseErrorReporter;
|
||||||
use properties::longhands;
|
use properties::longhands;
|
||||||
use properties::property_bit_field::PropertyBitField;
|
use properties::LonghandIdSet;
|
||||||
use properties::{ComputedValues, PropertyDeclaration};
|
use properties::{ComputedValues, PropertyDeclaration};
|
||||||
use properties::style_structs;
|
use properties::style_structs;
|
||||||
use std::boxed::Box as StdBox;
|
use std::boxed::Box as StdBox;
|
||||||
|
@ -245,7 +245,6 @@
|
||||||
inherited_style: &ComputedValues,
|
inherited_style: &ComputedValues,
|
||||||
default_style: &Arc<ComputedValues>,
|
default_style: &Arc<ComputedValues>,
|
||||||
context: &mut computed::Context,
|
context: &mut computed::Context,
|
||||||
seen: &mut PropertyBitField,
|
|
||||||
cacheable: &mut bool,
|
cacheable: &mut bool,
|
||||||
cascade_info: &mut Option<<&mut CascadeInfo>,
|
cascade_info: &mut Option<<&mut CascadeInfo>,
|
||||||
error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
|
error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
|
||||||
|
@ -256,16 +255,7 @@
|
||||||
_ => panic!("entered the wrong cascade_property() implementation"),
|
_ => panic!("entered the wrong cascade_property() implementation"),
|
||||||
};
|
};
|
||||||
|
|
||||||
% if property.logical:
|
|
||||||
let wm = context.style.writing_mode;
|
|
||||||
% endif
|
|
||||||
<% maybe_wm = "wm" if property.logical else "" %>
|
|
||||||
<% maybe_physical = "_physical" if property.logical else "" %>
|
|
||||||
% if not property.derived_from:
|
% if not property.derived_from:
|
||||||
if seen.get${maybe_physical}_${property.ident}(${maybe_wm}) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
seen.set${maybe_physical}_${property.ident}(${maybe_wm});
|
|
||||||
{
|
{
|
||||||
let custom_props = context.style().custom_properties();
|
let custom_props = context.style().custom_properties();
|
||||||
::properties::substitute_variables_${property.ident}(
|
::properties::substitute_variables_${property.ident}(
|
||||||
|
@ -275,6 +265,9 @@
|
||||||
cascade_info.on_cascade_property(&declaration,
|
cascade_info.on_cascade_property(&declaration,
|
||||||
&value);
|
&value);
|
||||||
}
|
}
|
||||||
|
% if property.logical:
|
||||||
|
let wm = context.style.writing_mode;
|
||||||
|
% endif
|
||||||
<% maybe_wm = ", wm" if property.logical else "" %>
|
<% maybe_wm = ", wm" if property.logical else "" %>
|
||||||
match *value {
|
match *value {
|
||||||
DeclaredValue::Value(ref specified_value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
|
@ -321,7 +314,6 @@
|
||||||
cascade_property_custom(declaration,
|
cascade_property_custom(declaration,
|
||||||
inherited_style,
|
inherited_style,
|
||||||
context,
|
context,
|
||||||
seen,
|
|
||||||
cacheable,
|
cacheable,
|
||||||
error_reporter);
|
error_reporter);
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -84,7 +84,6 @@
|
||||||
fn cascade_property_custom(_declaration: &PropertyDeclaration,
|
fn cascade_property_custom(_declaration: &PropertyDeclaration,
|
||||||
_inherited_style: &ComputedValues,
|
_inherited_style: &ComputedValues,
|
||||||
context: &mut computed::Context,
|
context: &mut computed::Context,
|
||||||
_seen: &mut PropertyBitField,
|
|
||||||
_cacheable: &mut bool,
|
_cacheable: &mut bool,
|
||||||
_error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
|
_error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
|
||||||
longhands::_servo_display_for_hypothetical_box::derive_from_display(context);
|
longhands::_servo_display_for_hypothetical_box::derive_from_display(context);
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
<% from data import Method %>
|
<% from data import Method %>
|
||||||
|
|
||||||
<% data.new_style_struct("Font",
|
<% data.new_style_struct("Font",
|
||||||
inherited=True,
|
inherited=True) %>
|
||||||
additional_methods=[Method("compute_font_hash", is_mut=True)]) %>
|
|
||||||
<%helpers:longhand name="font-family" animatable="False" need_index="True"
|
<%helpers:longhand name="font-family" animatable="False" need_index="True"
|
||||||
spec="https://drafts.csswg.org/css-fonts/#propdef-font-family">
|
spec="https://drafts.csswg.org/css-fonts/#propdef-font-family">
|
||||||
use self::computed_value::{FontFamily, FamilyName};
|
use self::computed_value::{FontFamily, FamilyName};
|
||||||
|
|
|
@ -204,7 +204,6 @@ ${helpers.single_keyword("unicode-bidi",
|
||||||
fn cascade_property_custom(_declaration: &PropertyDeclaration,
|
fn cascade_property_custom(_declaration: &PropertyDeclaration,
|
||||||
_inherited_style: &ComputedValues,
|
_inherited_style: &ComputedValues,
|
||||||
context: &mut computed::Context,
|
context: &mut computed::Context,
|
||||||
_seen: &mut PropertyBitField,
|
|
||||||
_cacheable: &mut bool,
|
_cacheable: &mut bool,
|
||||||
_error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
|
_error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
|
||||||
longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context);
|
longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context);
|
||||||
|
|
|
@ -29,6 +29,7 @@ use font_metrics::FontMetricsProvider;
|
||||||
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
|
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
use parser::{Parse, ParserContext, ParserContextExtraData};
|
use parser::{Parse, ParserContext, ParserContextExtraData};
|
||||||
|
use properties::animated_properties::TransitionProperty;
|
||||||
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
|
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
@ -39,7 +40,6 @@ use cascade_info::CascadeInfo;
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
#[cfg(feature = "servo")] use values::specified::BorderStyle;
|
#[cfg(feature = "servo")] use values::specified::BorderStyle;
|
||||||
|
|
||||||
use self::property_bit_field::PropertyBitField;
|
|
||||||
pub use self::declaration_block::*;
|
pub use self::declaration_block::*;
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -178,92 +178,92 @@ pub mod animated_properties {
|
||||||
<%include file="/helpers/animated_properties.mako.rs" />
|
<%include file="/helpers/animated_properties.mako.rs" />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A set of longhand properties
|
||||||
|
pub struct LonghandIdSet {
|
||||||
|
storage: [u32; (${len(data.longhands)} - 1 + 32) / 32]
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(SimonSapin): Convert this to a syntax extension rather than a Mako template.
|
impl LonghandIdSet {
|
||||||
// Maybe submit for inclusion in libstd?
|
/// Create an empty set
|
||||||
#[allow(missing_docs)]
|
#[inline]
|
||||||
pub mod property_bit_field {
|
pub fn new() -> LonghandIdSet {
|
||||||
use logical_geometry::WritingMode;
|
LonghandIdSet { storage: [0; (${len(data.longhands)} - 1 + 32) / 32] }
|
||||||
use properties::animated_properties::TransitionProperty;
|
|
||||||
|
|
||||||
/// A bitfield for all longhand properties, in order to quickly test whether
|
|
||||||
/// we've seen one of them.
|
|
||||||
pub struct PropertyBitField {
|
|
||||||
storage: [u32; (${len(data.longhands)} - 1 + 32) / 32]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyBitField {
|
/// Return whether the given property is in the set
|
||||||
/// Create a new `PropertyBitField`, with all the bits set to zero.
|
#[inline]
|
||||||
#[inline]
|
pub fn contains(&self, id: LonghandId) -> bool {
|
||||||
pub fn new() -> PropertyBitField {
|
let bit = id as usize;
|
||||||
PropertyBitField { storage: [0; (${len(data.longhands)} - 1 + 32) / 32] }
|
(self.storage[bit / 32] & (1 << (bit % 32))) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
/// Add the given property to the set
|
||||||
fn get(&self, bit: usize) -> bool {
|
#[inline]
|
||||||
(self.storage[bit / 32] & (1 << (bit % 32))) != 0
|
pub fn insert(&mut self, id: LonghandId) {
|
||||||
}
|
let bit = id as usize;
|
||||||
|
self.storage[bit / 32] |= 1 << (bit % 32);
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
/// Set the corresponding bit of TransitionProperty.
|
||||||
fn set(&mut self, bit: usize) {
|
/// This function will panic if TransitionProperty::All is given.
|
||||||
self.storage[bit / 32] |= 1 << (bit % 32)
|
pub fn set_transition_property_bit(&mut self, property: &TransitionProperty) {
|
||||||
|
match *property {
|
||||||
|
% for prop in data.longhands:
|
||||||
|
% if prop.animatable:
|
||||||
|
TransitionProperty::${prop.camel_case} => self.insert(LonghandId::${prop.camel_case}),
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
TransitionProperty::All => unreachable!("Tried to set TransitionProperty::All in a PropertyBitfield"),
|
||||||
}
|
}
|
||||||
% for i, property in enumerate(data.longhands):
|
}
|
||||||
% if not property.derived_from:
|
|
||||||
#[allow(non_snake_case, missing_docs)]
|
|
||||||
#[inline]
|
|
||||||
pub fn get_${property.ident}(&self) -> bool {
|
|
||||||
self.get(${i})
|
|
||||||
}
|
|
||||||
#[allow(non_snake_case, missing_docs)]
|
|
||||||
#[inline]
|
|
||||||
pub fn set_${property.ident}(&mut self) {
|
|
||||||
self.set(${i})
|
|
||||||
}
|
|
||||||
% endif
|
|
||||||
% if property.logical:
|
|
||||||
#[allow(non_snake_case, missing_docs)]
|
|
||||||
pub fn get_physical_${property.ident}(&self, wm: WritingMode) -> bool {
|
|
||||||
<%helpers:logical_setter_helper name="${property.name}">
|
|
||||||
<%def name="inner(physical_ident)">
|
|
||||||
self.get_${physical_ident}()
|
|
||||||
</%def>
|
|
||||||
</%helpers:logical_setter_helper>
|
|
||||||
}
|
|
||||||
#[allow(non_snake_case, missing_docs)]
|
|
||||||
pub fn set_physical_${property.ident}(&mut self, wm: WritingMode) {
|
|
||||||
<%helpers:logical_setter_helper name="${property.name}">
|
|
||||||
<%def name="inner(physical_ident)">
|
|
||||||
self.set_${physical_ident}()
|
|
||||||
</%def>
|
|
||||||
</%helpers:logical_setter_helper>
|
|
||||||
}
|
|
||||||
% endif
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
/// Set the corresponding bit of TransitionProperty.
|
/// Return true if the corresponding bit of TransitionProperty is set.
|
||||||
/// This function will panic if TransitionProperty::All is given.
|
/// This function will panic if TransitionProperty::All is given.
|
||||||
pub fn set_transition_property_bit(&mut self, property: &TransitionProperty) {
|
pub fn has_transition_property_bit(&self, property: &TransitionProperty) -> bool {
|
||||||
match *property {
|
match *property {
|
||||||
% for i, prop in enumerate(data.longhands):
|
% for prop in data.longhands:
|
||||||
% if prop.animatable:
|
% if prop.animatable:
|
||||||
TransitionProperty::${prop.camel_case} => self.set(${i}),
|
TransitionProperty::${prop.camel_case} => self.contains(LonghandId::${prop.camel_case}),
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
TransitionProperty::All => unreachable!("Tried to set TransitionProperty::All in a PropertyBitfield"),
|
TransitionProperty::All => unreachable!("Tried to get TransitionProperty::All in a PropertyBitfield"),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return true if the corresponding bit of TransitionProperty is set.
|
/// A specialized set of PropertyDeclarationId
|
||||||
/// This function will panic if TransitionProperty::All is given.
|
pub struct PropertyDeclarationIdSet {
|
||||||
pub fn has_transition_property_bit(&self, property: &TransitionProperty) -> bool {
|
longhands: LonghandIdSet,
|
||||||
match *property {
|
|
||||||
% for i, prop in enumerate(data.longhands):
|
// FIXME: Use a HashSet instead? This Vec is usually small, so linear scan might be ok.
|
||||||
% if prop.animatable:
|
custom: Vec<::custom_properties::Name>,
|
||||||
TransitionProperty::${prop.camel_case} => self.get(${i}),
|
}
|
||||||
% endif
|
|
||||||
% endfor
|
impl PropertyDeclarationIdSet {
|
||||||
TransitionProperty::All => unreachable!("Tried to get TransitionProperty::All in a PropertyBitfield"),
|
/// Empty set
|
||||||
|
pub fn new() -> Self {
|
||||||
|
PropertyDeclarationIdSet {
|
||||||
|
longhands: LonghandIdSet::new(),
|
||||||
|
custom: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the given ID is in the set
|
||||||
|
pub fn contains(&mut self, id: PropertyDeclarationId) -> bool {
|
||||||
|
match id {
|
||||||
|
PropertyDeclarationId::Longhand(id) => self.longhands.contains(id),
|
||||||
|
PropertyDeclarationId::Custom(name) => self.custom.contains(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert the given ID in the set
|
||||||
|
pub fn insert(&mut self, id: PropertyDeclarationId) {
|
||||||
|
match id {
|
||||||
|
PropertyDeclarationId::Longhand(id) => self.longhands.insert(id),
|
||||||
|
PropertyDeclarationId::Custom(name) => {
|
||||||
|
if !self.custom.contains(name) {
|
||||||
|
self.custom.push(name.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,79 +367,6 @@ pub mod property_bit_field {
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
/// Given a property declaration block, only keep the "winning" declaration for
|
|
||||||
/// any given property, by importance then source order.
|
|
||||||
///
|
|
||||||
/// The input and output are in source order
|
|
||||||
fn deduplicate_property_declarations(block: &mut PropertyDeclarationBlock) {
|
|
||||||
let mut deduplicated = Vec::with_capacity(block.declarations.len());
|
|
||||||
let mut seen_normal = PropertyBitField::new();
|
|
||||||
let mut seen_important = PropertyBitField::new();
|
|
||||||
let mut seen_custom_normal = Vec::new();
|
|
||||||
let mut seen_custom_important = Vec::new();
|
|
||||||
|
|
||||||
for (declaration, importance) in block.declarations.drain(..).rev() {
|
|
||||||
match declaration {
|
|
||||||
% for property in data.longhands:
|
|
||||||
PropertyDeclaration::${property.camel_case}(..) => {
|
|
||||||
% if not property.derived_from:
|
|
||||||
if importance.important() {
|
|
||||||
if seen_important.get_${property.ident}() {
|
|
||||||
block.important_count -= 1;
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if seen_normal.get_${property.ident}() {
|
|
||||||
remove_one(&mut deduplicated, |d| {
|
|
||||||
matches!(d, &(PropertyDeclaration::${property.camel_case}(..), _))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
seen_important.set_${property.ident}()
|
|
||||||
} else {
|
|
||||||
if seen_normal.get_${property.ident}() ||
|
|
||||||
seen_important.get_${property.ident}() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seen_normal.set_${property.ident}()
|
|
||||||
}
|
|
||||||
% else:
|
|
||||||
unreachable!();
|
|
||||||
% endif
|
|
||||||
},
|
|
||||||
% endfor
|
|
||||||
PropertyDeclaration::Custom(ref name, _) => {
|
|
||||||
if importance.important() {
|
|
||||||
if seen_custom_important.contains(name) {
|
|
||||||
block.important_count -= 1;
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if seen_custom_normal.contains(name) {
|
|
||||||
remove_one(&mut deduplicated, |d| {
|
|
||||||
matches!(d, &(PropertyDeclaration::Custom(ref n, _), _) if n == name)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
seen_custom_important.push(name.clone())
|
|
||||||
} else {
|
|
||||||
if seen_custom_normal.contains(name) ||
|
|
||||||
seen_custom_important.contains(name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seen_custom_normal.push(name.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deduplicated.push((declaration, importance))
|
|
||||||
}
|
|
||||||
deduplicated.reverse();
|
|
||||||
block.declarations = deduplicated;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn remove_one<T, F: FnMut(&T) -> bool>(v: &mut Vec<T>, mut remove_this: F) {
|
|
||||||
let previous_len = v.len();
|
|
||||||
v.retain(|x| !remove_this(x));
|
|
||||||
debug_assert_eq!(v.len(), previous_len - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An enum to represent a CSS Wide keyword.
|
/// An enum to represent a CSS Wide keyword.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum CSSWideKeyword {
|
pub enum CSSWideKeyword {
|
||||||
|
@ -483,6 +410,25 @@ impl LonghandId {
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this is a logical property, return the corresponding physical one in the given writing mode.
|
||||||
|
/// Otherwise, return unchanged.
|
||||||
|
pub fn to_physical(&self, wm: WritingMode) -> Self {
|
||||||
|
match *self {
|
||||||
|
% for property in data.longhands:
|
||||||
|
% if property.logical:
|
||||||
|
LonghandId::${property.camel_case} => {
|
||||||
|
<%helpers:logical_setter_helper name="${property.name}">
|
||||||
|
<%def name="inner(physical_ident)">
|
||||||
|
LonghandId::${to_camel_case(physical_ident)}
|
||||||
|
</%def>
|
||||||
|
</%helpers:logical_setter_helper>
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
_ => *self
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An identifier for a given shorthand property.
|
/// An identifier for a given shorthand property.
|
||||||
|
@ -653,7 +599,7 @@ impl<T: ToCss> ToCss for DeclaredValue<T> {
|
||||||
|
|
||||||
/// An identifier for a given property declaration, which can be either a
|
/// An identifier for a given property declaration, which can be either a
|
||||||
/// longhand or a custom property.
|
/// longhand or a custom property.
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum PropertyDeclarationId<'a> {
|
pub enum PropertyDeclarationId<'a> {
|
||||||
/// A longhand.
|
/// A longhand.
|
||||||
|
@ -1438,14 +1384,6 @@ impl ComputedValues {
|
||||||
/// Since this isn't supported in Servo, this is always false for Servo.
|
/// Since this isn't supported in Servo, this is always false for Servo.
|
||||||
pub fn is_display_contents(&self) -> bool { false }
|
pub fn is_display_contents(&self) -> bool { false }
|
||||||
|
|
||||||
/// Get the root font size.
|
|
||||||
fn root_font_size(&self) -> Au { self.root_font_size }
|
|
||||||
|
|
||||||
/// Set the root font size.
|
|
||||||
fn set_root_font_size(&mut self, size: Au) { self.root_font_size = size }
|
|
||||||
/// Set the writing mode for this style.
|
|
||||||
pub fn set_writing_mode(&mut self, mode: WritingMode) { self.writing_mode = mode; }
|
|
||||||
|
|
||||||
/// Whether the current style is multicolumn.
|
/// Whether the current style is multicolumn.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_multicol(&self) -> bool {
|
pub fn is_multicol(&self) -> bool {
|
||||||
|
@ -1730,7 +1668,6 @@ pub type CascadePropertyFn =
|
||||||
inherited_style: &ComputedValues,
|
inherited_style: &ComputedValues,
|
||||||
default_style: &Arc<ComputedValues>,
|
default_style: &Arc<ComputedValues>,
|
||||||
context: &mut computed::Context,
|
context: &mut computed::Context,
|
||||||
seen: &mut PropertyBitField,
|
|
||||||
cacheable: &mut bool,
|
cacheable: &mut bool,
|
||||||
cascade_info: &mut Option<<&mut CascadeInfo>,
|
cascade_info: &mut Option<<&mut CascadeInfo>,
|
||||||
error_reporter: &mut StdBox<ParseErrorReporter + Send>);
|
error_reporter: &mut StdBox<ParseErrorReporter + Send>);
|
||||||
|
@ -1855,7 +1792,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
ComputedValues::new(custom_properties,
|
ComputedValues::new(custom_properties,
|
||||||
flags.contains(SHAREABLE),
|
flags.contains(SHAREABLE),
|
||||||
WritingMode::empty(),
|
WritingMode::empty(),
|
||||||
inherited_style.root_font_size(),
|
inherited_style.root_font_size,
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
% if style_struct.inherited:
|
% if style_struct.inherited:
|
||||||
inherited_style.clone_${style_struct.name_lower}(),
|
inherited_style.clone_${style_struct.name_lower}(),
|
||||||
|
@ -1868,7 +1805,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
ComputedValues::new(custom_properties,
|
ComputedValues::new(custom_properties,
|
||||||
flags.contains(SHAREABLE),
|
flags.contains(SHAREABLE),
|
||||||
WritingMode::empty(),
|
WritingMode::empty(),
|
||||||
inherited_style.root_font_size(),
|
inherited_style.root_font_size,
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
inherited_style.clone_${style_struct.name_lower}(),
|
inherited_style.clone_${style_struct.name_lower}(),
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -1890,7 +1827,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
// NB: The cacheable boolean is not used right now, but will be once we
|
// NB: The cacheable boolean is not used right now, but will be once we
|
||||||
// start caching computed values in the rule nodes.
|
// start caching computed values in the rule nodes.
|
||||||
let mut cacheable = true;
|
let mut cacheable = true;
|
||||||
let mut seen = PropertyBitField::new();
|
let mut seen = LonghandIdSet::new();
|
||||||
|
|
||||||
// Declaration blocks are stored in increasing precedence order, we want
|
// Declaration blocks are stored in increasing precedence order, we want
|
||||||
// them in decreasing order here.
|
// them in decreasing order here.
|
||||||
|
@ -1940,19 +1877,25 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<% maybe_to_physical = ".to_physical(writing_mode)" if category_to_cascade_now != "early" else "" %>
|
||||||
|
let physical_longhand_id = longhand_id ${maybe_to_physical};
|
||||||
|
if seen.contains(physical_longhand_id) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen.insert(physical_longhand_id);
|
||||||
|
|
||||||
let discriminant = longhand_id as usize;
|
let discriminant = longhand_id as usize;
|
||||||
(CASCADE_PROPERTY[discriminant])(declaration,
|
(CASCADE_PROPERTY[discriminant])(declaration,
|
||||||
inherited_style,
|
inherited_style,
|
||||||
default_style,
|
default_style,
|
||||||
&mut context,
|
&mut context,
|
||||||
&mut seen,
|
|
||||||
&mut cacheable,
|
&mut cacheable,
|
||||||
&mut cascade_info,
|
&mut cascade_info,
|
||||||
&mut error_reporter);
|
&mut error_reporter);
|
||||||
}
|
}
|
||||||
% if category_to_cascade_now == "early":
|
% if category_to_cascade_now == "early":
|
||||||
let mode = get_writing_mode(context.style.get_inheritedbox());
|
let writing_mode = get_writing_mode(context.style.get_inheritedbox());
|
||||||
context.style.set_writing_mode(mode);
|
context.style.writing_mode = writing_mode;
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
|
@ -2090,13 +2033,17 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
|
|
||||||
if is_root_element {
|
if is_root_element {
|
||||||
let s = style.get_font().clone_font_size();
|
let s = style.get_font().clone_font_size();
|
||||||
style.set_root_font_size(s);
|
style.root_font_size = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if seen.get_font_style() || seen.get_font_weight() || seen.get_font_stretch() ||
|
% if product == "servo":
|
||||||
seen.get_font_family() {
|
if seen.contains(LonghandId::FontStyle) ||
|
||||||
style.mutate_font().compute_font_hash();
|
seen.contains(LonghandId::FontWeight) ||
|
||||||
}
|
seen.contains(LonghandId::FontStretch) ||
|
||||||
|
seen.contains(LonghandId::FontFamily) {
|
||||||
|
style.mutate_font().compute_font_hash();
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
|
||||||
style
|
style
|
||||||
}
|
}
|
||||||
|
|
|
@ -1338,8 +1338,8 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
|
||||||
pres_context: RawGeckoPresContextBorrowed,
|
pres_context: RawGeckoPresContextBorrowed,
|
||||||
computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut)
|
computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut)
|
||||||
{
|
{
|
||||||
|
use style::properties::LonghandIdSet;
|
||||||
use style::properties::declaration_block::Importance;
|
use style::properties::declaration_block::Importance;
|
||||||
use style::properties::property_bit_field::PropertyBitField;
|
|
||||||
use style::values::computed::Context;
|
use style::values::computed::Context;
|
||||||
|
|
||||||
let style = ComputedValues::as_arc(&style);
|
let style = ComputedValues::as_arc(&style);
|
||||||
|
@ -1359,7 +1359,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
|
||||||
for (index, keyframe) in keyframes.iter().enumerate() {
|
for (index, keyframe) in keyframes.iter().enumerate() {
|
||||||
let ref mut animation_values = computed_keyframes[index];
|
let ref mut animation_values = computed_keyframes[index];
|
||||||
|
|
||||||
let mut seen = PropertyBitField::new();
|
let mut seen = LonghandIdSet::new();
|
||||||
|
|
||||||
// mServoDeclarationBlock is null in the case where we have an invalid css property.
|
// mServoDeclarationBlock is null in the case where we have an invalid css property.
|
||||||
let iter = keyframe.mPropertyValues.iter()
|
let iter = keyframe.mPropertyValues.iter()
|
||||||
|
@ -1429,7 +1429,7 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
|
||||||
style: ServoComputedValuesBorrowed,
|
style: ServoComputedValuesBorrowed,
|
||||||
keyframes: RawGeckoKeyframeListBorrowedMut) -> bool {
|
keyframes: RawGeckoKeyframeListBorrowedMut) -> bool {
|
||||||
use style::gecko_bindings::structs::Keyframe;
|
use style::gecko_bindings::structs::Keyframe;
|
||||||
use style::properties::property_bit_field::PropertyBitField;
|
use style::properties::LonghandIdSet;
|
||||||
|
|
||||||
let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
||||||
let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) };
|
let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) };
|
||||||
|
@ -1482,7 +1482,7 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
|
||||||
declaration.is_animatable()
|
declaration.is_animatable()
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut seen = PropertyBitField::new();
|
let mut seen = LonghandIdSet::new();
|
||||||
|
|
||||||
for (index, &(ref declaration, _)) in animatable.enumerate() {
|
for (index, &(ref declaration, _)) in animatable.enumerate() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue