style: Add some flags to the computed values.

This will allow us to fix propagation of text-decoration, and also to implement
inlinization of ruby kids.

Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
This commit is contained in:
Emilio Cobos Álvarez 2017-06-26 22:50:43 +02:00
parent 3f2d747689
commit 5c7632f4c4
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
4 changed files with 135 additions and 81 deletions

View 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
}
}

View file

@ -54,9 +54,8 @@ 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::computed_value_flags::ComputedValueFlags;
use properties:: FontComputationData; use properties::{longhands, FontComputationData, Importance, LonghandId};
use properties::{Importance, LonghandId};
use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId}; use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId};
use rule_tree::StrongRuleNode; use rule_tree::StrongRuleNode;
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
@ -75,16 +74,16 @@ pub mod style_structs {
% endfor % endfor
} }
// FIXME(emilio): Unify both definitions, since they're equal now.
#[derive(Clone)] #[derive(Clone)]
pub struct ComputedValues { pub struct ComputedValues {
% for style_struct in data.style_structs: % for style_struct in data.style_structs:
${style_struct.ident}: Arc<style_structs::${style_struct.name}>, ${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor % endfor
custom_properties: Option<Arc<ComputedValuesMap>>, custom_properties: Option<Arc<ComputedValuesMap>>,
pub writing_mode: WritingMode, pub writing_mode: WritingMode,
pub font_computation_data: FontComputationData, pub font_computation_data: FontComputationData,
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
@ -100,6 +99,7 @@ impl ComputedValues {
pub fn new(custom_properties: Option<Arc<ComputedValuesMap>>, pub fn new(custom_properties: Option<Arc<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)>,
flags: ComputedValueFlags,
rules: Option<StrongRuleNode>, rules: Option<StrongRuleNode>,
visited_style: Option<Arc<ComputedValues>>, visited_style: Option<Arc<ComputedValues>>,
% for style_struct in data.style_structs: % for style_struct in data.style_structs:
@ -107,13 +107,14 @@ impl ComputedValues {
% endfor % endfor
) -> Self { ) -> Self {
ComputedValues { ComputedValues {
custom_properties: custom_properties, custom_properties,
writing_mode: writing_mode, writing_mode,
font_computation_data: FontComputationData::new(font_size_keyword), font_computation_data: FontComputationData::new(font_size_keyword),
rules: rules, flags,
rules,
visited_style: visited_style, visited_style: visited_style,
% for style_struct in data.style_structs: % for style_struct in data.style_structs:
${style_struct.ident}: ${style_struct.ident}, ${style_struct.ident},
% endfor % endfor
} }
} }

View file

@ -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;

View file

@ -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;
@ -1823,10 +1826,14 @@ 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.
@ -1836,23 +1843,27 @@ pub struct ComputedValues {
#[cfg(feature = "servo")] #[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(
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)>,
flags: ComputedValueFlags,
rules: Option<StrongRuleNode>, rules: Option<StrongRuleNode>,
visited_style: Option<Arc<ComputedValues>>, visited_style: Option<Arc<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}>,
% endfor % endfor
) -> Self { ) -> Self {
let font_computation_data = FontComputationData::new(font_size_keyword);
ComputedValues { ComputedValues {
custom_properties: custom_properties, custom_properties,
writing_mode: writing_mode, writing_mode,
font_computation_data: FontComputationData::new(font_size_keyword), font_computation_data,
rules: rules, flags,
visited_style: visited_style, rules,
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},
% endfor % endfor
} }
} }
@ -2297,6 +2308,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,24 +2331,28 @@ 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,
visited_style,
% for style_struct in data.active_style_structs(): % for style_struct in data.active_style_structs():
${style_struct.ident}: StyleStructRef::Borrowed(${style_struct.ident}), % 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 % endfor
} }
} }
@ -2348,19 +2365,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,
default: &'a ComputedValues
) -> Self {
Self::new(
parent,
default,
/* rules = */ None,
parent.custom_properties(), parent.custom_properties(),
parent.writing_mode, parent.writing_mode,
parent.font_computation_data.font_size_keyword, parent.font_computation_data.font_size_keyword,
parent.clone_visited_style(), parent.clone_visited_style()
% for style_struct in data.active_style_structs():
% if style_struct.inherited:
parent.${style_struct.name_lower}_arc(),
% else:
default.${style_struct.name_lower}_arc(),
% endif
% endfor
) )
} }
@ -2423,9 +2439,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 +2471,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 +2488,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 +2654,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 +2665,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 +2709,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