mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
Auto merge of #17525 - emilio:text-decoration, r=heycam
style: Fix propagation of text-decoration lines. This also paves up the ground to be able to fix #16825. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17525) <!-- Reviewable:end -->
This commit is contained in:
commit
79ee821bef
6 changed files with 253 additions and 256 deletions
|
@ -47,9 +47,10 @@ impl GeckoRestyleDamage {
|
||||||
/// them, but Gecko has an interesting optimization when they mark accessed
|
/// them, but Gecko has an interesting optimization when they mark accessed
|
||||||
/// structs, so they effectively only diff structs that have ever been
|
/// structs, so they effectively only diff structs that have ever been
|
||||||
/// accessed from layout.
|
/// accessed from layout.
|
||||||
pub fn compute_style_difference(source: &nsStyleContext,
|
pub fn compute_style_difference(
|
||||||
new_style: &Arc<ComputedValues>)
|
source: &nsStyleContext,
|
||||||
-> StyleDifference {
|
new_style: &Arc<ComputedValues>
|
||||||
|
) -> StyleDifference {
|
||||||
// TODO(emilio): Const-ify this?
|
// TODO(emilio): Const-ify this?
|
||||||
let context = source as *const nsStyleContext as *mut nsStyleContext;
|
let context = source as *const nsStyleContext as *mut nsStyleContext;
|
||||||
let mut any_style_changed: bool = false;
|
let mut any_style_changed: bool = false;
|
||||||
|
|
|
@ -98,15 +98,6 @@ pub enum ChildCascadeRequirement {
|
||||||
MustCascadeDescendants,
|
MustCascadeDescendants,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StyleChange> for ChildCascadeRequirement {
|
|
||||||
fn from(change: StyleChange) -> ChildCascadeRequirement {
|
|
||||||
match change {
|
|
||||||
StyleChange::Unchanged => ChildCascadeRequirement::CanSkipCascade,
|
|
||||||
StyleChange::Changed => ChildCascadeRequirement::MustCascadeChildren,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Flags that represent the result of replace_rules.
|
/// Flags that represent the result of replace_rules.
|
||||||
pub flags RulesChanged: u8 {
|
pub flags RulesChanged: u8 {
|
||||||
|
@ -783,6 +774,8 @@ trait PrivateMatchMethods: TElement {
|
||||||
new_values: &Arc<ComputedValues>,
|
new_values: &Arc<ComputedValues>,
|
||||||
pseudo: Option<&PseudoElement>)
|
pseudo: Option<&PseudoElement>)
|
||||||
-> ChildCascadeRequirement {
|
-> ChildCascadeRequirement {
|
||||||
|
use properties::computed_value_flags::*;
|
||||||
|
|
||||||
// Don't accumulate damage if we're in a restyle for reconstruction.
|
// Don't accumulate damage if we're in a restyle for reconstruction.
|
||||||
if shared_context.traversal_flags.for_reconstruct() {
|
if shared_context.traversal_flags.for_reconstruct() {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildCascadeRequirement::MustCascadeChildren;
|
||||||
|
@ -798,13 +791,26 @@ trait PrivateMatchMethods: TElement {
|
||||||
let skip_applying_damage =
|
let skip_applying_damage =
|
||||||
restyle.reconstructed_self_or_ancestor();
|
restyle.reconstructed_self_or_ancestor();
|
||||||
|
|
||||||
let difference = self.compute_style_difference(&old_values,
|
let difference =
|
||||||
&new_values,
|
self.compute_style_difference(&old_values, &new_values, pseudo);
|
||||||
pseudo);
|
|
||||||
if !skip_applying_damage {
|
if !skip_applying_damage {
|
||||||
restyle.damage |= difference.damage;
|
restyle.damage |= difference.damage;
|
||||||
}
|
}
|
||||||
difference.change.into()
|
|
||||||
|
match difference.change {
|
||||||
|
StyleChange::Unchanged => {
|
||||||
|
// We need to cascade the children in order to ensure the
|
||||||
|
// correct propagation of text-decoration-line, which is a reset
|
||||||
|
// property.
|
||||||
|
if old_values.flags.contains(HAS_TEXT_DECORATION_LINE) !=
|
||||||
|
new_values.flags.contains(HAS_TEXT_DECORATION_LINE) {
|
||||||
|
return ChildCascadeRequirement::MustCascadeChildren;
|
||||||
|
}
|
||||||
|
ChildCascadeRequirement::CanSkipCascade
|
||||||
|
},
|
||||||
|
StyleChange::Changed => ChildCascadeRequirement::MustCascadeChildren,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes and applies restyle damage unless we've already maxed it out.
|
/// Computes and applies restyle damage unless we've already maxed it out.
|
||||||
|
@ -818,7 +824,10 @@ trait PrivateMatchMethods: TElement {
|
||||||
-> ChildCascadeRequirement {
|
-> ChildCascadeRequirement {
|
||||||
let difference = self.compute_style_difference(&old_values, &new_values, pseudo);
|
let difference = self.compute_style_difference(&old_values, &new_values, pseudo);
|
||||||
restyle.damage |= difference.damage;
|
restyle.damage |= difference.damage;
|
||||||
difference.change.into()
|
match difference.change {
|
||||||
|
StyleChange::Changed => ChildCascadeRequirement::MustCascadeChildren,
|
||||||
|
StyleChange::Unchanged => ChildCascadeRequirement::CanSkipCascade,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
|
|
45
components/style/properties/computed_value_flags.rs
Normal file
45
components/style/properties/computed_value_flags.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Misc information about a given computed style.
|
||||||
|
|
||||||
|
use properties::{ComputedValues, StyleBuilder};
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Misc information about a given computed style.
|
||||||
|
pub flags ComputedValueFlags: u8 {
|
||||||
|
/// Whether the style or any of the ancestors has a text-decoration
|
||||||
|
/// property that should get propagated to descendants.
|
||||||
|
///
|
||||||
|
/// text-decoration is a reset property, but gets propagated in the
|
||||||
|
/// frame/box tree.
|
||||||
|
const HAS_TEXT_DECORATION_LINE = 1 << 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComputedValueFlags {
|
||||||
|
/// Get the computed value flags for the initial style.
|
||||||
|
pub fn initial() -> Self {
|
||||||
|
Self::empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the flags for this style, given the parent style.
|
||||||
|
pub fn compute(
|
||||||
|
this_style: &StyleBuilder,
|
||||||
|
parent_style: &ComputedValues,
|
||||||
|
) -> Self {
|
||||||
|
let mut ret = Self::empty();
|
||||||
|
|
||||||
|
// FIXME(emilio): This feels like it wants to look at the
|
||||||
|
// layout_parent_style, but the way it works in Gecko means it's not
|
||||||
|
// needed (we'd recascade a bit more when it changes, but that's fine),
|
||||||
|
// and this way it simplifies the code for text styles and similar.
|
||||||
|
if parent_style.flags.contains(HAS_TEXT_DECORATION_LINE) ||
|
||||||
|
!this_style.get_text().clone_text_decoration_line().is_empty() {
|
||||||
|
ret.insert(HAS_TEXT_DECORATION_LINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,6 @@
|
||||||
<%namespace name="helpers" file="/helpers.mako.rs" />
|
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use custom_properties::ComputedValuesMap;
|
|
||||||
use gecko_bindings::bindings;
|
use gecko_bindings::bindings;
|
||||||
% for style_struct in data.style_structs:
|
% for style_struct in data.style_structs:
|
||||||
use gecko_bindings::structs::${style_struct.gecko_ffi_name};
|
use gecko_bindings::structs::${style_struct.gecko_ffi_name};
|
||||||
|
@ -54,18 +53,14 @@ use gecko::values::round_border_to_device_pixels;
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use properties::animated_properties::TransitionProperty;
|
use properties::animated_properties::TransitionProperty;
|
||||||
use properties::longhands;
|
use properties::{longhands, ComputedValues, LonghandId, PropertyDeclarationId};
|
||||||
use properties:: FontComputationData;
|
|
||||||
use properties::{Importance, LonghandId};
|
|
||||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId};
|
|
||||||
use rule_tree::StrongRuleNode;
|
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::mem::{forget, transmute, zeroed};
|
use std::mem::{forget, transmute, zeroed};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use stylearc::Arc;
|
use stylearc::Arc;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use values::{Auto, CustomIdent, Either, KeyframesName};
|
use values::{Auto, CustomIdent, Either, KeyframesName};
|
||||||
use values::computed::{Shadow, ToComputedValue};
|
use values::computed::Shadow;
|
||||||
use values::specified::length::Percentage;
|
use values::specified::length::Percentage;
|
||||||
use computed_values::border_style;
|
use computed_values::border_style;
|
||||||
|
|
||||||
|
@ -75,155 +70,6 @@ pub mod style_structs {
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ComputedValues {
|
|
||||||
% for style_struct in data.style_structs:
|
|
||||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
custom_properties: Option<Arc<ComputedValuesMap>>,
|
|
||||||
pub writing_mode: WritingMode,
|
|
||||||
pub font_computation_data: FontComputationData,
|
|
||||||
|
|
||||||
/// The rule node representing the ordered list of rules matched for this
|
|
||||||
/// node. Can be None for default values and text nodes. This is
|
|
||||||
/// essentially an optimization to avoid referencing the root rule node.
|
|
||||||
pub rules: Option<StrongRuleNode>,
|
|
||||||
/// The element's computed values if visited, only computed if there's a
|
|
||||||
/// relevant link for this element. A element's "relevant link" is the
|
|
||||||
/// element being matched if it is a link or the nearest ancestor link.
|
|
||||||
visited_style: Option<Arc<ComputedValues>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ComputedValues {
|
|
||||||
pub fn new(custom_properties: Option<Arc<ComputedValuesMap>>,
|
|
||||||
writing_mode: WritingMode,
|
|
||||||
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
|
|
||||||
rules: Option<StrongRuleNode>,
|
|
||||||
visited_style: Option<Arc<ComputedValues>>,
|
|
||||||
% for style_struct in data.style_structs:
|
|
||||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
|
||||||
% endfor
|
|
||||||
) -> Self {
|
|
||||||
ComputedValues {
|
|
||||||
custom_properties: custom_properties,
|
|
||||||
writing_mode: writing_mode,
|
|
||||||
font_computation_data: FontComputationData::new(font_size_keyword),
|
|
||||||
rules: rules,
|
|
||||||
visited_style: visited_style,
|
|
||||||
% for style_struct in data.style_structs:
|
|
||||||
${style_struct.ident}: ${style_struct.ident},
|
|
||||||
% endfor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_values(pres_context: RawGeckoPresContextBorrowed) -> Arc<Self> {
|
|
||||||
Arc::new(ComputedValues {
|
|
||||||
custom_properties: None,
|
|
||||||
writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious
|
|
||||||
font_computation_data: FontComputationData::default_values(),
|
|
||||||
rules: None,
|
|
||||||
visited_style: None,
|
|
||||||
% for style_struct in data.style_structs:
|
|
||||||
${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context),
|
|
||||||
% endfor
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_display_contents(&self) -> bool {
|
|
||||||
self.get_box().clone_display() == longhands::display::computed_value::T::contents
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the value of the `content` property would make a
|
|
||||||
/// pseudo-element not rendered.
|
|
||||||
#[inline]
|
|
||||||
pub fn ineffective_content_property(&self) -> bool {
|
|
||||||
self.get_counters().ineffective_content_property()
|
|
||||||
}
|
|
||||||
|
|
||||||
% for style_struct in data.style_structs:
|
|
||||||
#[inline]
|
|
||||||
pub fn clone_${style_struct.name_lower}(&self) -> Arc<style_structs::${style_struct.name}> {
|
|
||||||
self.${style_struct.ident}.clone()
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn get_${style_struct.name_lower}(&self) -> &style_structs::${style_struct.name} {
|
|
||||||
&self.${style_struct.ident}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ${style_struct.name_lower}_arc(&self) -> &Arc<style_structs::${style_struct.name}> {
|
|
||||||
&self.${style_struct.ident}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mutate_${style_struct.name_lower}(&mut self) -> &mut style_structs::${style_struct.name} {
|
|
||||||
Arc::make_mut(&mut self.${style_struct.ident})
|
|
||||||
}
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
/// Gets a reference to the rule node. Panic if no rule node exists.
|
|
||||||
pub fn rules(&self) -> &StrongRuleNode {
|
|
||||||
self.rules.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the visited style, if any.
|
|
||||||
pub fn get_visited_style(&self) -> Option<<&Arc<ComputedValues>> {
|
|
||||||
self.visited_style.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the visited style. Panic if no visited style exists.
|
|
||||||
pub fn visited_style(&self) -> &Arc<ComputedValues> {
|
|
||||||
self.get_visited_style().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clone the visited style. Used for inheriting parent styles in
|
|
||||||
/// StyleBuilder::for_inheritance.
|
|
||||||
pub fn clone_visited_style(&self) -> Option<Arc<ComputedValues>> {
|
|
||||||
self.visited_style.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn custom_properties(&self) -> Option<Arc<ComputedValuesMap>> {
|
|
||||||
self.custom_properties.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub fn has_moz_binding(&self) -> bool {
|
|
||||||
!self.get_box().gecko.mBinding.mPtr.mRawPtr.is_null()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(bholley): Implement this properly.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_multicol(&self) -> bool { false }
|
|
||||||
|
|
||||||
pub fn to_declaration_block(&self, property: PropertyDeclarationId) -> PropertyDeclarationBlock {
|
|
||||||
match property {
|
|
||||||
% for prop in data.longhands:
|
|
||||||
% if prop.animatable:
|
|
||||||
PropertyDeclarationId::Longhand(LonghandId::${prop.camel_case}) => {
|
|
||||||
PropertyDeclarationBlock::with_one(
|
|
||||||
PropertyDeclaration::${prop.camel_case}(
|
|
||||||
% if prop.boxed:
|
|
||||||
Box::new(
|
|
||||||
% endif
|
|
||||||
longhands::${prop.ident}::SpecifiedValue::from_computed_value(
|
|
||||||
&self.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}())
|
|
||||||
% if prop.boxed:
|
|
||||||
)
|
|
||||||
% endif
|
|
||||||
),
|
|
||||||
Importance::Normal
|
|
||||||
)
|
|
||||||
},
|
|
||||||
% endif
|
|
||||||
% endfor
|
|
||||||
PropertyDeclarationId::Custom(_name) => unimplemented!(),
|
|
||||||
_ => unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
<%def name="declare_style_struct(style_struct)">
|
<%def name="declare_style_struct(style_struct)">
|
||||||
pub struct ${style_struct.gecko_struct_name} {
|
pub struct ${style_struct.gecko_struct_name} {
|
||||||
gecko: ${style_struct.gecko_ffi_name},
|
gecko: ${style_struct.gecko_ffi_name},
|
||||||
|
|
|
@ -150,6 +150,7 @@ ${helpers.single_keyword("unicode-bidi",
|
||||||
|
|
||||||
<%helpers:longhand name="text-decoration-line"
|
<%helpers:longhand name="text-decoration-line"
|
||||||
custom_cascade="${product == 'servo'}"
|
custom_cascade="${product == 'servo'}"
|
||||||
|
need_clone=True
|
||||||
animation_value_type="discrete"
|
animation_value_type="discrete"
|
||||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line">
|
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line">
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -262,7 +263,7 @@ ${helpers.single_keyword("unicode-bidi",
|
||||||
context: &mut computed::Context,
|
context: &mut computed::Context,
|
||||||
_cacheable: &mut bool,
|
_cacheable: &mut bool,
|
||||||
_error_reporter: &ParseErrorReporter) {
|
_error_reporter: &ParseErrorReporter) {
|
||||||
longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context);
|
longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context);
|
||||||
}
|
}
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ use values::generics::text::LineHeight;
|
||||||
use values::computed;
|
use values::computed;
|
||||||
use cascade_info::CascadeInfo;
|
use cascade_info::CascadeInfo;
|
||||||
use rule_tree::{CascadeLevel, StrongRuleNode};
|
use rule_tree::{CascadeLevel, StrongRuleNode};
|
||||||
|
use self::computed_value_flags::ComputedValueFlags;
|
||||||
use style_adjuster::StyleAdjuster;
|
use style_adjuster::StyleAdjuster;
|
||||||
#[cfg(feature = "servo")] use values::specified::BorderStyle;
|
#[cfg(feature = "servo")] use values::specified::BorderStyle;
|
||||||
|
|
||||||
|
@ -77,6 +78,8 @@ macro_rules! impl_bitflags_conversions {
|
||||||
import os.path
|
import os.path
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
#[path="${repr(os.path.join(os.path.dirname(__file__), 'computed_value_flags.rs'))[1:-1]}"]
|
||||||
|
pub mod computed_value_flags;
|
||||||
#[path="${repr(os.path.join(os.path.dirname(__file__), 'declaration_block.rs'))[1:-1]}"]
|
#[path="${repr(os.path.join(os.path.dirname(__file__), 'declaration_block.rs'))[1:-1]}"]
|
||||||
pub mod declaration_block;
|
pub mod declaration_block;
|
||||||
|
|
||||||
|
@ -1798,9 +1801,6 @@ pub mod style_structs {
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
pub use gecko_properties::ComputedValues;
|
|
||||||
|
|
||||||
/// A legacy alias for a servo-version of ComputedValues. Should go away soon.
|
/// A legacy alias for a servo-version of ComputedValues. Should go away soon.
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
pub type ServoComputedValues = ComputedValues;
|
pub type ServoComputedValues = ComputedValues;
|
||||||
|
@ -1811,8 +1811,7 @@ pub type ServoComputedValues = ComputedValues;
|
||||||
/// every kind of style struct.
|
/// every kind of style struct.
|
||||||
///
|
///
|
||||||
/// When needed, the structs may be copied in order to get mutated.
|
/// When needed, the structs may be copied in order to get mutated.
|
||||||
#[cfg(feature = "servo")]
|
#[derive(Clone)]
|
||||||
#[cfg_attr(feature = "servo", derive(Clone))]
|
|
||||||
pub struct ComputedValues {
|
pub struct ComputedValues {
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
||||||
|
@ -1823,43 +1822,47 @@ pub struct ComputedValues {
|
||||||
/// The keyword behind the current font-size property, if any
|
/// The keyword behind the current font-size property, if any
|
||||||
pub font_computation_data: FontComputationData,
|
pub font_computation_data: FontComputationData,
|
||||||
|
|
||||||
|
/// A set of flags we use to store misc information regarding this style.
|
||||||
|
pub flags: ComputedValueFlags,
|
||||||
|
|
||||||
/// The rule node representing the ordered list of rules matched for this
|
/// The rule node representing the ordered list of rules matched for this
|
||||||
/// node. Can be None for default values and text nodes. This is
|
/// node. Can be None for default values and text nodes. This is
|
||||||
/// essentially an optimization to avoid referencing the root rule node.
|
/// essentially an optimization to avoid referencing the root rule node.
|
||||||
pub rules: Option<StrongRuleNode>,
|
pub rules: Option<StrongRuleNode>,
|
||||||
|
|
||||||
/// The element's computed values if visited, only computed if there's a
|
/// The element's computed values if visited, only computed if there's a
|
||||||
/// relevant link for this element. A element's "relevant link" is the
|
/// relevant link for this element. A element's "relevant link" is the
|
||||||
/// element being matched if it is a link or the nearest ancestor link.
|
/// element being matched if it is a link or the nearest ancestor link.
|
||||||
visited_style: Option<Arc<ComputedValues>>,
|
visited_style: Option<Arc<ComputedValues>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "servo")]
|
|
||||||
impl ComputedValues {
|
impl ComputedValues {
|
||||||
/// Construct a `ComputedValues` instance.
|
/// Construct a `ComputedValues` instance.
|
||||||
pub fn new(custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
pub fn new(
|
||||||
writing_mode: WritingMode,
|
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||||
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
|
writing_mode: WritingMode,
|
||||||
rules: Option<StrongRuleNode>,
|
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
|
||||||
visited_style: Option<Arc<ComputedValues>>,
|
flags: ComputedValueFlags,
|
||||||
% for style_struct in data.active_style_structs():
|
rules: Option<StrongRuleNode>,
|
||||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
visited_style: Option<Arc<ComputedValues>>,
|
||||||
% endfor
|
|
||||||
) -> Self {
|
|
||||||
ComputedValues {
|
|
||||||
custom_properties: custom_properties,
|
|
||||||
writing_mode: writing_mode,
|
|
||||||
font_computation_data: FontComputationData::new(font_size_keyword),
|
|
||||||
rules: rules,
|
|
||||||
visited_style: visited_style,
|
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
${style_struct.ident}: ${style_struct.ident},
|
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
||||||
|
% endfor
|
||||||
|
) -> Self {
|
||||||
|
let font_computation_data = FontComputationData::new(font_size_keyword);
|
||||||
|
ComputedValues {
|
||||||
|
custom_properties,
|
||||||
|
writing_mode,
|
||||||
|
font_computation_data,
|
||||||
|
flags,
|
||||||
|
rules,
|
||||||
|
visited_style,
|
||||||
|
% for style_struct in data.active_style_structs():
|
||||||
|
${style_struct.ident},
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the initial computed values.
|
|
||||||
pub fn initial_values() -> &'static Self { &*INITIAL_SERVO_VALUES }
|
|
||||||
|
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
/// Clone the ${style_struct.name} struct.
|
/// Clone the ${style_struct.name} struct.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1886,6 +1889,30 @@ impl ComputedValues {
|
||||||
}
|
}
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
|
/// Get the initial computed values.
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
pub fn initial_values() -> &'static Self { &*INITIAL_SERVO_VALUES }
|
||||||
|
|
||||||
|
/// Get the default computed values for a given document.
|
||||||
|
///
|
||||||
|
/// This takes into account zoom, etc.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
pub fn default_values(
|
||||||
|
pres_context: bindings::RawGeckoPresContextBorrowed
|
||||||
|
) -> Arc<Self> {
|
||||||
|
Arc::new(ComputedValues {
|
||||||
|
custom_properties: None,
|
||||||
|
writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious
|
||||||
|
font_computation_data: FontComputationData::default_values(),
|
||||||
|
flags: ComputedValueFlags::initial(),
|
||||||
|
rules: None,
|
||||||
|
visited_style: None,
|
||||||
|
% for style_struct in data.style_structs:
|
||||||
|
${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context),
|
||||||
|
% endfor
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets a reference to the rule node. Panic if no rule node exists.
|
/// Gets a reference to the rule node. Panic if no rule node exists.
|
||||||
pub fn rules(&self) -> &StrongRuleNode {
|
pub fn rules(&self) -> &StrongRuleNode {
|
||||||
self.rules.as_ref().unwrap()
|
self.rules.as_ref().unwrap()
|
||||||
|
@ -1918,23 +1945,77 @@ impl ComputedValues {
|
||||||
///
|
///
|
||||||
/// Cloning the Arc here is fine because it only happens in the case where
|
/// Cloning the Arc here is fine because it only happens in the case where
|
||||||
/// we have custom properties, and those are both rare and expensive.
|
/// we have custom properties, and those are both rare and expensive.
|
||||||
fn custom_properties(&self) -> Option<Arc<::custom_properties::ComputedValuesMap>> {
|
pub fn custom_properties(&self) -> Option<Arc<::custom_properties::ComputedValuesMap>> {
|
||||||
self.custom_properties.clone()
|
self.custom_properties.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a declaration block representing the computed value for a given
|
||||||
|
/// property.
|
||||||
|
///
|
||||||
|
/// Currently only implemented for animated properties.
|
||||||
|
pub fn to_declaration_block(
|
||||||
|
&self,
|
||||||
|
property: PropertyDeclarationId
|
||||||
|
) -> PropertyDeclarationBlock {
|
||||||
|
use values::computed::ToComputedValue;
|
||||||
|
|
||||||
|
match property {
|
||||||
|
% for prop in data.longhands:
|
||||||
|
% if prop.animatable:
|
||||||
|
PropertyDeclarationId::Longhand(LonghandId::${prop.camel_case}) => {
|
||||||
|
PropertyDeclarationBlock::with_one(
|
||||||
|
PropertyDeclaration::${prop.camel_case}(
|
||||||
|
% if prop.boxed:
|
||||||
|
Box::new(
|
||||||
|
% endif
|
||||||
|
longhands::${prop.ident}::SpecifiedValue::from_computed_value(
|
||||||
|
&self.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}())
|
||||||
|
% if prop.boxed:
|
||||||
|
)
|
||||||
|
% endif
|
||||||
|
),
|
||||||
|
Importance::Normal
|
||||||
|
)
|
||||||
|
},
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
PropertyDeclarationId::Custom(_name) => unimplemented!(),
|
||||||
|
_ => unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this style has a -moz-binding value. This is always false for
|
/// Whether this style has a -moz-binding value. This is always false for
|
||||||
/// Servo for obvious reasons.
|
/// Servo for obvious reasons.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
pub fn has_moz_binding(&self) -> bool { false }
|
pub fn has_moz_binding(&self) -> bool { false }
|
||||||
|
|
||||||
|
/// Whether this style has a -moz-binding value.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
pub fn has_moz_binding(&self) -> bool {
|
||||||
|
!self.get_box().gecko().mBinding.mPtr.mRawPtr.is_null()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns whether this style's display value is equal to contents.
|
/// Returns whether this style's display value is equal to contents.
|
||||||
///
|
///
|
||||||
/// 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.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
pub fn is_display_contents(&self) -> bool { false }
|
pub fn is_display_contents(&self) -> bool { false }
|
||||||
|
|
||||||
|
/// Returns whether this style's display value is equal to contents.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
pub fn is_display_contents(&self) -> bool {
|
||||||
|
self.get_box().clone_display() == longhands::display::computed_value::T::contents
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns whether the "content" property for the given style is completely
|
/// Returns whether the "content" property for the given style is completely
|
||||||
/// ineffective, and would yield an empty `::before` or `::after`
|
/// ineffective, and would yield an empty `::before` or `::after`
|
||||||
/// pseudo-element.
|
/// pseudo-element.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
pub fn ineffective_content_property(&self) -> bool {
|
pub fn ineffective_content_property(&self) -> bool {
|
||||||
use properties::longhands::content::computed_value::T;
|
use properties::longhands::content::computed_value::T;
|
||||||
match self.get_counters().content {
|
match self.get_counters().content {
|
||||||
|
@ -1943,8 +2024,23 @@ impl ComputedValues {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the current style is multicolumn.
|
/// Returns true if the value of the `content` property would make a
|
||||||
|
/// pseudo-element not rendered.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
pub fn ineffective_content_property(&self) -> bool {
|
||||||
|
self.get_counters().ineffective_content_property()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
/// Whether the current style is multicolumn.
|
||||||
|
/// FIXME(bholley): Implement this properly.
|
||||||
|
pub fn is_multicol(&self) -> bool { false }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
/// Whether the current style is multicolumn.
|
||||||
pub fn is_multicol(&self) -> bool {
|
pub fn is_multicol(&self) -> bool {
|
||||||
let style = self.get_column();
|
let style = self.get_column();
|
||||||
match style.column_width {
|
match style.column_width {
|
||||||
|
@ -1955,7 +2051,10 @@ impl ComputedValues {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
impl ComputedValues {
|
||||||
/// Resolves the currentColor keyword.
|
/// Resolves the currentColor keyword.
|
||||||
///
|
///
|
||||||
/// Any color value from computed values (except for the 'color' property
|
/// Any color value from computed values (except for the 'color' property
|
||||||
|
@ -2297,6 +2396,8 @@ impl<'a, T: 'a> Deref for StyleStructRef<'a, T> {
|
||||||
/// actually cloning them, until we either build the style, or mutate the
|
/// actually cloning them, until we either build the style, or mutate the
|
||||||
/// inherited value.
|
/// inherited value.
|
||||||
pub struct StyleBuilder<'a> {
|
pub struct StyleBuilder<'a> {
|
||||||
|
/// The style we're inheriting from.
|
||||||
|
inherited_style: &'a ComputedValues,
|
||||||
/// The rule node representing the ordered list of rules matched for this
|
/// The rule node representing the ordered list of rules matched for this
|
||||||
/// node.
|
/// node.
|
||||||
rules: Option<StrongRuleNode>,
|
rules: Option<StrongRuleNode>,
|
||||||
|
@ -2318,25 +2419,29 @@ pub struct StyleBuilder<'a> {
|
||||||
|
|
||||||
impl<'a> StyleBuilder<'a> {
|
impl<'a> StyleBuilder<'a> {
|
||||||
/// Trivially construct a `StyleBuilder`.
|
/// Trivially construct a `StyleBuilder`.
|
||||||
pub fn new(
|
fn new(
|
||||||
|
inherited_style: &'a ComputedValues,
|
||||||
|
reset_style: &'a ComputedValues,
|
||||||
rules: Option<StrongRuleNode>,
|
rules: Option<StrongRuleNode>,
|
||||||
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||||
writing_mode: WritingMode,
|
writing_mode: WritingMode,
|
||||||
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
|
font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
|
||||||
visited_style: Option<Arc<ComputedValues>>,
|
visited_style: Option<Arc<ComputedValues>>,
|
||||||
% for style_struct in data.active_style_structs():
|
|
||||||
${style_struct.ident}: &'a Arc<style_structs::${style_struct.name}>,
|
|
||||||
% endfor
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
StyleBuilder {
|
StyleBuilder {
|
||||||
rules: rules,
|
inherited_style,
|
||||||
custom_properties: custom_properties,
|
rules,
|
||||||
writing_mode: writing_mode,
|
custom_properties,
|
||||||
font_size_keyword: font_size_keyword,
|
writing_mode,
|
||||||
visited_style: visited_style,
|
font_size_keyword,
|
||||||
% for style_struct in data.active_style_structs():
|
visited_style,
|
||||||
${style_struct.ident}: StyleStructRef::Borrowed(${style_struct.ident}),
|
% for style_struct in data.active_style_structs():
|
||||||
% endfor
|
% if style_struct.inherited:
|
||||||
|
${style_struct.ident}: StyleStructRef::Borrowed(inherited_style.${style_struct.name_lower}_arc()),
|
||||||
|
% else:
|
||||||
|
${style_struct.ident}: StyleStructRef::Borrowed(reset_style.${style_struct.name_lower}_arc()),
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2348,19 +2453,18 @@ impl<'a> StyleBuilder<'a> {
|
||||||
|
|
||||||
/// Inherits style from the parent element, accounting for the default
|
/// Inherits style from the parent element, accounting for the default
|
||||||
/// computed values that need to be provided as well.
|
/// computed values that need to be provided as well.
|
||||||
pub fn for_inheritance(parent: &'a ComputedValues, default: &'a ComputedValues) -> Self {
|
pub fn for_inheritance(
|
||||||
Self::new(/* rules = */ None,
|
parent: &'a ComputedValues,
|
||||||
parent.custom_properties(),
|
default: &'a ComputedValues
|
||||||
parent.writing_mode,
|
) -> Self {
|
||||||
parent.font_computation_data.font_size_keyword,
|
Self::new(
|
||||||
parent.clone_visited_style(),
|
parent,
|
||||||
% for style_struct in data.active_style_structs():
|
default,
|
||||||
% if style_struct.inherited:
|
/* rules = */ None,
|
||||||
parent.${style_struct.name_lower}_arc(),
|
parent.custom_properties(),
|
||||||
% else:
|
parent.writing_mode,
|
||||||
default.${style_struct.name_lower}_arc(),
|
parent.font_computation_data.font_size_keyword,
|
||||||
% endif
|
parent.clone_visited_style()
|
||||||
% endfor
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2423,9 +2527,11 @@ impl<'a> StyleBuilder<'a> {
|
||||||
|
|
||||||
/// Turns this `StyleBuilder` into a proper `ComputedValues` instance.
|
/// Turns this `StyleBuilder` into a proper `ComputedValues` instance.
|
||||||
pub fn build(self) -> ComputedValues {
|
pub fn build(self) -> ComputedValues {
|
||||||
|
let flags = ComputedValueFlags::compute(&self, &self.inherited_style);
|
||||||
ComputedValues::new(self.custom_properties,
|
ComputedValues::new(self.custom_properties,
|
||||||
self.writing_mode,
|
self.writing_mode,
|
||||||
self.font_size_keyword,
|
self.font_size_keyword,
|
||||||
|
flags,
|
||||||
self.rules,
|
self.rules,
|
||||||
self.visited_style,
|
self.visited_style,
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
|
@ -2453,6 +2559,7 @@ mod lazy_static_module {
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
use stylearc::Arc;
|
use stylearc::Arc;
|
||||||
use super::{ComputedValues, longhands, style_structs, FontComputationData};
|
use super::{ComputedValues, longhands, style_structs, FontComputationData};
|
||||||
|
use super::computed_value_flags::ComputedValueFlags;
|
||||||
|
|
||||||
/// The initial values for all style structs as defined by the specification.
|
/// The initial values for all style structs as defined by the specification.
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -2469,6 +2576,7 @@ mod lazy_static_module {
|
||||||
% endfor
|
% endfor
|
||||||
custom_properties: None,
|
custom_properties: None,
|
||||||
writing_mode: WritingMode::empty(),
|
writing_mode: WritingMode::empty(),
|
||||||
|
flags: ComputedValueFlags::initial(),
|
||||||
font_computation_data: FontComputationData::default_values(),
|
font_computation_data: FontComputationData::default_values(),
|
||||||
rules: None,
|
rules: None,
|
||||||
visited_style: None,
|
visited_style: None,
|
||||||
|
@ -2634,33 +2742,10 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
|
||||||
::custom_properties::finish_cascade(
|
::custom_properties::finish_cascade(
|
||||||
custom_properties, &inherited_custom_properties);
|
custom_properties, &inherited_custom_properties);
|
||||||
|
|
||||||
// We'd really like to own the rules here to avoid refcount traffic, but
|
let reset_style = if flags.contains(INHERIT_ALL) {
|
||||||
// animation's usage of `apply_declarations` make this tricky. See bug
|
inherited_style
|
||||||
// 1375525.
|
|
||||||
let builder = if !flags.contains(INHERIT_ALL) {
|
|
||||||
StyleBuilder::new(Some(rules.clone()),
|
|
||||||
custom_properties,
|
|
||||||
WritingMode::empty(),
|
|
||||||
inherited_style.font_computation_data.font_size_keyword,
|
|
||||||
visited_style,
|
|
||||||
% for style_struct in data.active_style_structs():
|
|
||||||
% if style_struct.inherited:
|
|
||||||
inherited_style.${style_struct.name_lower}_arc(),
|
|
||||||
% else:
|
|
||||||
default_style.${style_struct.name_lower}_arc(),
|
|
||||||
% endif
|
|
||||||
% endfor
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
StyleBuilder::new(Some(rules.clone()),
|
default_style
|
||||||
custom_properties,
|
|
||||||
WritingMode::empty(),
|
|
||||||
inherited_style.font_computation_data.font_size_keyword,
|
|
||||||
visited_style,
|
|
||||||
% for style_struct in data.active_style_structs():
|
|
||||||
inherited_style.${style_struct.name_lower}_arc(),
|
|
||||||
% endfor
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut context = computed::Context {
|
let mut context = computed::Context {
|
||||||
|
@ -2668,7 +2753,18 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
|
||||||
device: device,
|
device: device,
|
||||||
inherited_style: inherited_style,
|
inherited_style: inherited_style,
|
||||||
layout_parent_style: layout_parent_style,
|
layout_parent_style: layout_parent_style,
|
||||||
style: builder,
|
// We'd really like to own the rules here to avoid refcount traffic, but
|
||||||
|
// animation's usage of `apply_declarations` make this tricky. See bug
|
||||||
|
// 1375525.
|
||||||
|
style: StyleBuilder::new(
|
||||||
|
inherited_style,
|
||||||
|
reset_style,
|
||||||
|
Some(rules.clone()),
|
||||||
|
custom_properties,
|
||||||
|
WritingMode::empty(),
|
||||||
|
inherited_style.font_computation_data.font_size_keyword,
|
||||||
|
visited_style,
|
||||||
|
),
|
||||||
font_metrics_provider: font_metrics_provider,
|
font_metrics_provider: font_metrics_provider,
|
||||||
cached_system_font: None,
|
cached_system_font: None,
|
||||||
in_media_query: false,
|
in_media_query: false,
|
||||||
|
@ -2701,9 +2797,8 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
|
||||||
// virtual dispatch instead.
|
// virtual dispatch instead.
|
||||||
% for category_to_cascade_now in ["early", "other"]:
|
% for category_to_cascade_now in ["early", "other"]:
|
||||||
% if category_to_cascade_now == "early":
|
% if category_to_cascade_now == "early":
|
||||||
// Pull these out so that we can
|
// Pull these out so that we can compute them in a specific order
|
||||||
// compute them in a specific order without
|
// without introducing more iterations.
|
||||||
// introducing more iterations
|
|
||||||
let mut font_size = None;
|
let mut font_size = None;
|
||||||
let mut font_family = None;
|
let mut font_family = None;
|
||||||
% endif
|
% endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue