Auto merge of #16096 - stshine:die-modify-style-die, r=emilio

Use Servo-specific pseudo elements for anonymous box and text

<!-- Please describe your changes on the following line: -->

Use some fake pseudo elements to style servo-specific boxes in servo. Also, Since for nested inline elements non-inheritable properties are properly stored in the inline context of an inline fragment, so get
rid of them on the style using empty pseudo to do cascading.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #5625 (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [X] These changes do not require tests because refactoring

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- 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/16096)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-04-01 06:02:08 -05:00 committed by GitHub
commit 449758ef5d
9 changed files with 126 additions and 259 deletions

View file

@ -51,7 +51,7 @@ use style::computed_values::content::ContentItem;
use style::computed_values::position; use style::computed_values::position;
use style::context::SharedStyleContext; use style::context::SharedStyleContext;
use style::logical_geometry::Direction; use style::logical_geometry::Direction;
use style::properties::{self, ServoComputedValues}; use style::properties::ServoComputedValues;
use style::selector_parser::{PseudoElement, RestyleDamage}; use style::selector_parser::{PseudoElement, RestyleDamage};
use style::servo::restyle_damage::{BUBBLE_ISIZES, RECONSTRUCT_FLOW}; use style::servo::restyle_damage::{BUBBLE_ISIZES, RECONSTRUCT_FLOW};
use style::values::Either; use style::values::Either;
@ -178,7 +178,7 @@ impl InlineBlockSplit {
predecessors: mem::replace( predecessors: mem::replace(
fragment_accumulator, fragment_accumulator,
InlineFragmentsAccumulator::from_inline_node( InlineFragmentsAccumulator::from_inline_node(
node, style_context)).to_intermediate_inline_fragments(), node, style_context)).to_intermediate_inline_fragments(style_context),
flow: flow, flow: flow,
}; };
@ -273,7 +273,8 @@ impl InlineFragmentsAccumulator {
self.fragments.absolute_descendants.push_descendants(fragments.absolute_descendants); self.fragments.absolute_descendants.push_descendants(fragments.absolute_descendants);
} }
fn to_intermediate_inline_fragments(self) -> IntermediateInlineFragments { fn to_intermediate_inline_fragments(self, context: &SharedStyleContext)
-> IntermediateInlineFragments {
let InlineFragmentsAccumulator { let InlineFragmentsAccumulator {
mut fragments, mut fragments,
enclosing_node, enclosing_node,
@ -299,9 +300,9 @@ impl InlineFragmentsAccumulator {
if let Some((start, end)) = bidi_control_chars { if let Some((start, end)) = bidi_control_chars {
fragments.fragments.push_front( fragments.fragments.push_front(
control_chars_to_fragment(&enclosing_node, start, restyle_damage)); control_chars_to_fragment(&enclosing_node, context, start, restyle_damage));
fragments.fragments.push_back( fragments.fragments.push_back(
control_chars_to_fragment(&enclosing_node, end, restyle_damage)); control_chars_to_fragment(&enclosing_node, context, end, restyle_damage));
} }
} }
fragments fragments
@ -340,7 +341,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
} }
/// Builds the fragment for the given block or subclass thereof. /// Builds the fragment for the given block or subclass thereof.
fn build_fragment_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode) -> Fragment { fn build_fragment_for_block(&self, node: &ConcreteThreadSafeLayoutNode) -> Fragment {
let specific_fragment_info = match node.type_id() { let specific_fragment_info = match node.type_id() {
Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) => { Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) => {
SpecificFragmentInfo::Iframe(IframeFragmentInfo::new(node)) SpecificFragmentInfo::Iframe(IframeFragmentInfo::new(node))
@ -399,7 +400,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
absolute_descendants: &mut AbsoluteDescendants, absolute_descendants: &mut AbsoluteDescendants,
legalizer: &mut Legalizer, legalizer: &mut Legalizer,
node: &ConcreteThreadSafeLayoutNode) { node: &ConcreteThreadSafeLayoutNode) {
let mut fragments = fragment_accumulator.to_intermediate_inline_fragments(); let mut fragments = fragment_accumulator.to_intermediate_inline_fragments(self.style_context());
if fragments.is_empty() { if fragments.is_empty() {
return return
}; };
@ -546,14 +547,12 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
ConstructionResult::ConstructionItem(ConstructionItem::Whitespace( ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
whitespace_node, whitespace_node,
whitespace_pseudo, whitespace_pseudo,
mut whitespace_style, whitespace_style,
whitespace_damage)) => { whitespace_damage)) => {
// Add whitespace results. They will be stripped out later on when // Add whitespace results. They will be stripped out later on when
// between block elements, and retained when between inline elements. // between block elements, and retained when between inline elements.
let fragment_info = SpecificFragmentInfo::UnscannedText( let fragment_info = SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(" ".to_owned(), None)); box UnscannedTextFragmentInfo::new(" ".to_owned(), None));
properties::modify_style_for_replaced_content(&mut whitespace_style);
properties::modify_style_for_text(&mut whitespace_style);
let fragment = Fragment::from_opaque_node_and_style(whitespace_node, let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
whitespace_pseudo, whitespace_pseudo,
whitespace_style, whitespace_style,
@ -644,7 +643,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
/// `<textarea>`. /// `<textarea>`.
fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ConcreteThreadSafeLayoutNode) fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ConcreteThreadSafeLayoutNode)
-> ConstructionResult { -> ConstructionResult {
let mut initial_fragments = IntermediateInlineFragments::new(); let mut fragments = IntermediateInlineFragments::new();
let node_is_input_or_text_area = let node_is_input_or_text_area =
node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLInputElement)) || node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLInputElement)) ||
node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLTextAreaElement)); node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLTextAreaElement));
@ -658,17 +657,18 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
} }
} }
let mut style = node.style(self.style_context()); let context = self.style_context();
let mut style = node.style(context);
style = context.stylist.style_for_anonymous(
&context.guards, &PseudoElement::ServoText, &style);
if node_is_input_or_text_area { if node_is_input_or_text_area {
let context = self.style_context(); style = context.stylist.style_for_anonymous(
style = context.stylist.style_for_anonymous_box(
&context.guards, &PseudoElement::ServoInputText, &style) &context.guards, &PseudoElement::ServoInputText, &style)
} }
self.create_fragments_for_node_text_content(&mut initial_fragments, node, &style) self.create_fragments_for_node_text_content(&mut fragments, node, &style)
} }
self.build_flow_for_block_starting_with_fragments(flow, node, fragments)
self.build_flow_for_block_starting_with_fragments(flow, node, initial_fragments)
} }
/// Pushes fragments appropriate for the content of the given node onto the given list. /// Pushes fragments appropriate for the content of the given node onto the given list.
@ -682,13 +682,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
return return
} }
let mut style = (*style).clone(); let style = (*style).clone();
match node.get_pseudo_element_type() {
PseudoElementType::Before(_) |
PseudoElementType::After(_) => {}
_ => properties::modify_style_for_text(&mut style)
}
let selected_style = node.selected_style(); let selected_style = node.selected_style();
match text_content { match text_content {
@ -824,13 +818,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
ConstructionResult::ConstructionItem(ConstructionItem::Whitespace( ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
whitespace_node, whitespace_node,
whitespace_pseudo, whitespace_pseudo,
mut whitespace_style, whitespace_style,
whitespace_damage)) => { whitespace_damage)) => {
// Instantiate the whitespace fragment. // Instantiate the whitespace fragment.
let fragment_info = SpecificFragmentInfo::UnscannedText( let fragment_info = SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(" ".to_owned(), None)); box UnscannedTextFragmentInfo::new(" ".to_owned(), None));
properties::modify_style_for_replaced_content(&mut whitespace_style);
properties::modify_style_for_text(&mut whitespace_style);
let fragment = let fragment =
Fragment::from_opaque_node_and_style(whitespace_node, Fragment::from_opaque_node_and_style(whitespace_node,
whitespace_pseudo, whitespace_pseudo,
@ -852,12 +844,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
// An empty inline box needs at least one fragment to draw its background and borders. // An empty inline box needs at least one fragment to draw its background and borders.
let info = SpecificFragmentInfo::UnscannedText( let info = SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(String::new(), None)); box UnscannedTextFragmentInfo::new(String::new(), None));
let mut modified_style = node_style.clone();
properties::modify_style_for_replaced_content(&mut modified_style);
properties::modify_style_for_text(&mut modified_style);
let fragment = Fragment::from_opaque_node_and_style(node.opaque(), let fragment = Fragment::from_opaque_node_and_style(node.opaque(),
node.get_pseudo_element_type().strip(), node.get_pseudo_element_type().strip(),
modified_style, node_style.clone(),
node.selected_style(), node.selected_style(),
node.restyle_damage(), node.restyle_damage(),
info); info);
@ -880,7 +869,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let construction_item = ConstructionItem::InlineFragments( let construction_item = ConstructionItem::InlineFragments(
InlineFragmentsConstructionResult { InlineFragmentsConstructionResult {
splits: opt_inline_block_splits, splits: opt_inline_block_splits,
fragments: fragment_accumulator.to_intermediate_inline_fragments(), fragments: fragment_accumulator.to_intermediate_inline_fragments(self.style_context()),
}); });
ConstructionResult::ConstructionItem(construction_item) ConstructionResult::ConstructionItem(construction_item)
} else { } else {
@ -897,31 +886,27 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
self.set_flow_construction_result(&kid, ConstructionResult::None) self.set_flow_construction_result(&kid, ConstructionResult::None)
} }
let context = self.style_context();
let style = node.style(context);
// If this node is ignorable whitespace, bail out now. // If this node is ignorable whitespace, bail out now.
if node.is_ignorable_whitespace(self.style_context()) { if node.is_ignorable_whitespace(context) {
return ConstructionResult::ConstructionItem(ConstructionItem::Whitespace( return ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
node.opaque(), node.opaque(),
node.get_pseudo_element_type().strip(), node.get_pseudo_element_type().strip(),
node.style(self.style_context()), context.stylist.style_for_anonymous(
&context.guards, &PseudoElement::ServoText, &style),
node.restyle_damage())) node.restyle_damage()))
} }
// Modify the style as necessary. (See the comment in
// `properties::modify_style_for_replaced_content()`.)
let mut style = node.style(self.style_context());
match node.get_pseudo_element_type() {
PseudoElementType::Before(_) |
PseudoElementType::After(_) => {}
_ => properties::modify_style_for_replaced_content(&mut style)
}
// If this is generated content, then we need to initialize the accumulator with the // If this is generated content, then we need to initialize the accumulator with the
// fragment corresponding to that content. Otherwise, just initialize with the ordinary // fragment corresponding to that content. Otherwise, just initialize with the ordinary
// fragment that needs to be generated for this inline node. // fragment that needs to be generated for this inline node.
let mut fragments = IntermediateInlineFragments::new(); let mut fragments = IntermediateInlineFragments::new();
match (node.get_pseudo_element_type(), node.type_id()) { match (node.get_pseudo_element_type(), node.type_id()) {
(_, Some(LayoutNodeType::Text)) => { (_, Some(LayoutNodeType::Text)) => {
self.create_fragments_for_node_text_content(&mut fragments, node, &style) let text_style = context.stylist.style_for_anonymous(
&context.guards, &PseudoElement::ServoText, &style);
self.create_fragments_for_node_text_content(&mut fragments, node, &text_style)
} }
(PseudoElementType::Normal, _) => { (PseudoElementType::Normal, _) => {
fragments.fragments.push_back(self.build_fragment_for_block(node)); fragments.fragments.push_back(self.build_fragment_for_block(node));
@ -950,13 +935,15 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
_ => unreachable!() _ => unreachable!()
}; };
let mut modified_style = node.style(self.style_context()); let context = self.style_context();
properties::modify_style_for_outer_inline_block_fragment(&mut modified_style); let style = node.style(context);
let style = context.stylist.style_for_anonymous(
&context.guards, &PseudoElement::ServoInlineBlockWrapper, &style);
let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new( let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new(
block_flow)); block_flow));
let fragment = Fragment::from_opaque_node_and_style(node.opaque(), let fragment = Fragment::from_opaque_node_and_style(node.opaque(),
node.get_pseudo_element_type().strip(), node.get_pseudo_element_type().strip(),
modified_style, style,
node.selected_style(), node.selected_style(),
node.restyle_damage(), node.restyle_damage(),
fragment_info); fragment_info);
@ -968,7 +955,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let construction_item = let construction_item =
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
splits: LinkedList::new(), splits: LinkedList::new(),
fragments: fragment_accumulator.to_intermediate_inline_fragments(), fragments: fragment_accumulator.to_intermediate_inline_fragments(context),
}); });
ConstructionResult::ConstructionItem(construction_item) ConstructionResult::ConstructionItem(construction_item)
} }
@ -987,8 +974,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let fragment_info = SpecificFragmentInfo::InlineAbsoluteHypothetical( let fragment_info = SpecificFragmentInfo::InlineAbsoluteHypothetical(
InlineAbsoluteHypotheticalFragmentInfo::new(block_flow)); InlineAbsoluteHypotheticalFragmentInfo::new(block_flow));
let style_context = self.style_context(); let style_context = self.style_context();
let mut style = node.style(style_context); let style = node.style(style_context);
properties::modify_style_for_inline_absolute_hypothetical_fragment(&mut style); let style = style_context.stylist.style_for_anonymous(
&style_context.guards, &PseudoElement::ServoInlineAbsolute, &style);
let fragment = Fragment::from_opaque_node_and_style(node.opaque(), let fragment = Fragment::from_opaque_node_and_style(node.opaque(),
PseudoElementType::Normal, PseudoElementType::Normal,
style, style,
@ -1003,7 +991,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let construction_item = let construction_item =
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
splits: LinkedList::new(), splits: LinkedList::new(),
fragments: fragment_accumulator.to_intermediate_inline_fragments(), fragments: fragment_accumulator.to_intermediate_inline_fragments(style_context),
}); });
ConstructionResult::ConstructionItem(construction_item) ConstructionResult::ConstructionItem(construction_item)
} }
@ -1100,7 +1088,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
{ {
let context = self.style_context(); let context = self.style_context();
table_style = node.style(context); table_style = node.style(context);
wrapper_style = context.stylist.style_for_anonymous_box( wrapper_style = context.stylist.style_for_anonymous(
&context.guards, &PseudoElement::ServoTableWrapper, &table_style); &context.guards, &PseudoElement::ServoTableWrapper, &table_style);
} }
let wrapper_fragment = let wrapper_fragment =
@ -1367,7 +1355,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let mut set_has_newly_constructed_flow_flag = false; let mut set_has_newly_constructed_flow_flag = false;
let result = { let result = {
let mut style = node.style(self.style_context()); let style = node.style(self.style_context());
let damage = node.restyle_damage(); let damage = node.restyle_damage();
let mut data = node.mutate_layout_data().unwrap(); let mut data = node.mutate_layout_data().unwrap();
@ -1438,9 +1426,6 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
return false return false
} }
_ => { _ => {
if node.is_replaced_content() {
properties::modify_style_for_replaced_content(&mut style);
}
fragment.repair_style(&style); fragment.repair_style(&style);
set_has_newly_constructed_flow_flag = true; set_has_newly_constructed_flow_flag = true;
} }
@ -1842,17 +1827,17 @@ fn bidi_control_chars(style: &Arc<ServoComputedValues>) -> Option<(&'static str,
} }
fn control_chars_to_fragment(node: &InlineFragmentNodeInfo, fn control_chars_to_fragment(node: &InlineFragmentNodeInfo,
context: &SharedStyleContext,
text: &str, text: &str,
restyle_damage: RestyleDamage) restyle_damage: RestyleDamage)
-> Fragment { -> Fragment {
let info = SpecificFragmentInfo::UnscannedText( let info = SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(String::from(text), None)); box UnscannedTextFragmentInfo::new(String::from(text), None));
let mut style = node.style.clone(); let text_style = context.stylist.style_for_anonymous(
properties::modify_style_for_replaced_content(&mut style); &context.guards, &PseudoElement::ServoText, &node.style);
properties::modify_style_for_text(&mut style);
Fragment::from_opaque_node_and_style(node.address, Fragment::from_opaque_node_and_style(node.address,
node.pseudo, node.pseudo,
style.clone(), text_style,
node.selected_style.clone(), node.selected_style.clone(),
restyle_damage, restyle_damage,
info) info)
@ -2082,7 +2067,7 @@ impl Legalizer {
let reference_block = reference.as_block(); let reference_block = reference.as_block();
let mut new_style = reference_block.fragment.style.clone(); let mut new_style = reference_block.fragment.style.clone();
for pseudo in pseudos { for pseudo in pseudos {
new_style = context.stylist.style_for_anonymous_box(&context.guards, pseudo, &new_style) new_style = context.stylist.style_for_anonymous(&context.guards, pseudo, &new_style)
} }
let fragment = reference_block.fragment let fragment = reference_block.fragment
.create_similar_anonymous_fragment(new_style, .create_similar_anonymous_fragment(new_style,

View file

@ -1167,20 +1167,15 @@ impl Fragment {
/// can be expensive to compute, so if possible use the `border_padding` field instead. /// can be expensive to compute, so if possible use the `border_padding` field instead.
#[inline] #[inline]
pub fn border_width(&self) -> LogicalMargin<Au> { pub fn border_width(&self) -> LogicalMargin<Au> {
let style_border_width = match self.specific { let style_border_width = self.style().logical_border_width();
SpecificFragmentInfo::ScannedText(_) |
SpecificFragmentInfo::InlineBlock(_) => LogicalMargin::zero(self.style.writing_mode),
_ => self.style().logical_border_width(),
};
match self.inline_context { // NOTE: We can have nodes with different writing mode inside
None => style_border_width, // the inline fragment context, so we need to overwrite the
// writing mode to compute the child logical sizes.
let writing_mode = self.style.writing_mode;
let context_border = match self.inline_context {
None => LogicalMargin::zero(writing_mode),
Some(ref inline_fragment_context) => { Some(ref inline_fragment_context) => {
// NOTE: We can have nodes with different writing mode inside
// the inline fragment context, so we need to overwrite the
// writing mode to compute the child logical sizes.
let writing_mode = self.style.writing_mode;
inline_fragment_context.nodes.iter().fold(style_border_width, |accumulator, node| { inline_fragment_context.nodes.iter().fold(style_border_width, |accumulator, node| {
let mut this_border_width = let mut this_border_width =
node.style.border_width_for_writing_mode(writing_mode); node.style.border_width_for_writing_mode(writing_mode);
@ -1193,7 +1188,8 @@ impl Fragment {
accumulator + this_border_width accumulator + this_border_width
}) })
} }
} };
style_border_width + context_border
} }
/// Returns the border width in given direction if this fragment has property /// Returns the border width in given direction if this fragment has property
@ -1226,12 +1222,6 @@ impl Fragment {
self.margin.inline_end = Au(0); self.margin.inline_end = Au(0);
return return
} }
SpecificFragmentInfo::InlineBlock(_) => {
// Inline-blocks do not take self margins into account but do account for margins
// from outer inline contexts.
self.margin.inline_start = Au(0);
self.margin.inline_end = Au(0);
}
_ => { _ => {
let margin = self.style().logical_margin(); let margin = self.style().logical_margin();
self.margin.inline_start = self.margin.inline_start =
@ -1259,8 +1249,8 @@ impl Fragment {
containing_block_inline_size).specified_or_zero() containing_block_inline_size).specified_or_zero()
}; };
self.margin.inline_start = self.margin.inline_start + this_inline_start_margin; self.margin.inline_start += this_inline_start_margin;
self.margin.inline_end = self.margin.inline_end + this_inline_end_margin; self.margin.inline_end += this_inline_end_margin;
} }
} }
} }
@ -1309,14 +1299,10 @@ impl Fragment {
}; };
// Compute padding from the fragment's style. // Compute padding from the fragment's style.
//
// This is zero in the case of `inline-block` because that padding is applied to the
// wrapped block, not the fragment.
let padding_from_style = match self.specific { let padding_from_style = match self.specific {
SpecificFragmentInfo::TableColumn(_) | SpecificFragmentInfo::TableColumn(_) |
SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableRow |
SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::TableWrapper => LogicalMargin::zero(self.style.writing_mode),
SpecificFragmentInfo::InlineBlock(_) => LogicalMargin::zero(self.style.writing_mode),
_ => model::padding_from_style(self.style(), containing_block_inline_size, self.style().writing_mode), _ => model::padding_from_style(self.style(), containing_block_inline_size, self.style().writing_mode),
}; };

View file

@ -788,16 +788,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
self.node.type_id() self.node.type_id()
} }
fn style_for_text_node(&self) -> Arc<ComputedValues> { fn parent_style(&self) -> Arc<ComputedValues> {
// Text nodes get a copy of the parent style. Inheriting all non-
// inherited properties into the text node is odd from a CSS
// perspective, but makes fragment construction easier (by making
// properties like vertical-align on fragments have values that
// match the parent element). This is an implementation detail of
// Servo layout that is not central to how fragment construction
// works, but would be difficult to change. (Text node style is
// also not visible to script.)
debug_assert!(self.is_text_node());
let parent = self.node.parent_node().unwrap().as_element().unwrap(); let parent = self.node.parent_node().unwrap().as_element().unwrap();
let parent_data = parent.get_data().unwrap().borrow(); let parent_data = parent.get_data().unwrap().borrow();
parent_data.styles().primary.values().clone() parent_data.styles().primary.values().clone()

View file

@ -176,7 +176,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo
/// it can be used to reach siblings and cousins. A simple immutable borrow /// it can be used to reach siblings and cousins. A simple immutable borrow
/// of the parent data is fine, since the bottom-up traversal will not process /// of the parent data is fine, since the bottom-up traversal will not process
/// the parent until all the children have been processed. /// the parent until all the children have been processed.
fn style_for_text_node(&self) -> Arc<ServoComputedValues>; fn parent_style(&self) -> Arc<ServoComputedValues>;
#[inline] #[inline]
fn is_element_or_elements_pseudo(&self) -> bool { fn is_element_or_elements_pseudo(&self) -> bool {
@ -222,8 +222,10 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo
if let Some(el) = self.as_element() { if let Some(el) = self.as_element() {
el.style(context) el.style(context)
} else { } else {
// Text nodes are not styled during traversal,instead we simply
// return parent style here and do cascading during layout.
debug_assert!(self.is_text_node()); debug_assert!(self.is_text_node());
self.style_for_text_node() self.parent_style()
} }
} }
@ -232,7 +234,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo
el.selected_style() el.selected_style()
} else { } else {
debug_assert!(self.is_text_node()); debug_assert!(self.is_text_node());
self.style_for_text_node() // TODO(stshine): What should the selected style be for text?
self.parent_style()
} }
} }

View file

@ -2398,96 +2398,6 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
style style
} }
/// Modifies the style for an anonymous flow so it resets all its non-inherited
/// style structs, and set their borders and outlines to zero.
///
/// Also, it gets a new display value, which is honored except when it's
/// `inline`.
#[cfg(feature = "servo")]
pub fn modify_style_for_anonymous_flow(style: &mut Arc<ComputedValues>,
new_display_value: longhands::display::computed_value::T) {
// The 'align-self' property needs some special treatment since
// its value depends on the 'align-items' value of its parent.
% if "align-items" in data.longhands_by_name:
use computed_values::align_self::T as align_self;
use computed_values::align_items::T as align_items;
let self_align =
match style.position.align_items {
align_items::stretch => align_self::stretch,
align_items::baseline => align_self::baseline,
align_items::flex_start => align_self::flex_start,
align_items::flex_end => align_self::flex_end,
align_items::center => align_self::center,
};
% endif
let inital_values = &*INITIAL_SERVO_VALUES;
let mut style = Arc::make_mut(style);
% for style_struct in data.active_style_structs():
% if not style_struct.inherited:
style.${style_struct.ident} = inital_values.clone_${style_struct.name_lower}();
% endif
% endfor
% if "align-items" in data.longhands_by_name:
let position = Arc::make_mut(&mut style.position);
position.align_self = self_align;
% endif
if new_display_value != longhands::display::computed_value::T::inline {
let new_box = Arc::make_mut(&mut style.box_);
new_box.display = new_display_value;
}
let border = Arc::make_mut(&mut style.border);
% for side in ["top", "right", "bottom", "left"]:
// Like calling to_computed_value, which wouldn't type check.
border.border_${side}_width = Au(0);
% endfor
// Initial value of outline-style is always none for anonymous box.
let outline = Arc::make_mut(&mut style.outline);
outline.outline_width = Au(0);
}
/// Alters the given style to accommodate replaced content. This is called in
/// flow construction. It handles cases like:
///
/// <div style="position: absolute">foo bar baz</div>
///
/// (in which `foo`, `bar`, and `baz` must not be absolutely-positioned) and
/// cases like `<sup>Foo</sup>` (in which the `vertical-align: top` style of
/// `sup` must not propagate down into `Foo`).
///
/// FIXME(#5625, pcwalton): It would probably be cleaner and faster to do this
/// in the cascade.
#[cfg(feature = "servo")]
#[inline]
pub fn modify_style_for_replaced_content(style: &mut Arc<ComputedValues>) {
// Reset `position` to handle cases like `<div style="position: absolute">foo bar baz</div>`.
if style.box_.display != longhands::display::computed_value::T::inline {
let mut style = Arc::make_mut(style);
Arc::make_mut(&mut style.box_).display = longhands::display::computed_value::T::inline;
Arc::make_mut(&mut style.box_).position =
longhands::position::computed_value::T::static_;
}
// Reset `vertical-align` to handle cases like `<sup>foo</sup>`.
if style.box_.vertical_align != longhands::vertical_align::computed_value::T::baseline {
let mut style = Arc::make_mut(style);
Arc::make_mut(&mut style.box_).vertical_align =
longhands::vertical_align::computed_value::T::baseline
}
// Reset margins.
if style.margin.margin_top != computed::LengthOrPercentageOrAuto::Length(Au(0)) ||
style.margin.margin_left != computed::LengthOrPercentageOrAuto::Length(Au(0)) ||
style.margin.margin_bottom != computed::LengthOrPercentageOrAuto::Length(Au(0)) ||
style.margin.margin_right != computed::LengthOrPercentageOrAuto::Length(Au(0)) {
let mut style = Arc::make_mut(style);
let margin = Arc::make_mut(&mut style.margin);
margin.margin_top = computed::LengthOrPercentageOrAuto::Length(Au(0));
margin.margin_left = computed::LengthOrPercentageOrAuto::Length(Au(0));
margin.margin_bottom = computed::LengthOrPercentageOrAuto::Length(Au(0));
margin.margin_right = computed::LengthOrPercentageOrAuto::Length(Au(0));
}
}
/// Adjusts borders as appropriate to account for a fragment's status as the /// Adjusts borders as appropriate to account for a fragment's status as the
/// first or last fragment within the range of an element. /// first or last fragment within the range of an element.
/// ///
@ -2544,65 +2454,6 @@ pub fn modify_border_style_for_inline_sides(style: &mut Arc<ComputedValues>,
} }
} }
/// Adjusts the `position` property as necessary for the outer fragment wrapper
/// of an inline-block.
#[cfg(feature = "servo")]
#[inline]
pub fn modify_style_for_outer_inline_block_fragment(style: &mut Arc<ComputedValues>) {
let mut style = Arc::make_mut(style);
let box_style = Arc::make_mut(&mut style.box_);
box_style.position = longhands::position::computed_value::T::static_
}
/// Adjusts the `position` and `padding` properties as necessary to account for
/// text.
///
/// Text is never directly relatively positioned; it's always contained within
/// an element that is itself relatively positioned.
#[cfg(feature = "servo")]
#[inline]
pub fn modify_style_for_text(style: &mut Arc<ComputedValues>) {
if style.box_.position == longhands::position::computed_value::T::relative {
// We leave the `position` property set to `relative` so that we'll still establish a
// containing block if needed. But we reset all position offsets to `auto`.
let mut style = Arc::make_mut(style);
let mut position = Arc::make_mut(&mut style.position);
position.top = computed::LengthOrPercentageOrAuto::Auto;
position.right = computed::LengthOrPercentageOrAuto::Auto;
position.bottom = computed::LengthOrPercentageOrAuto::Auto;
position.left = computed::LengthOrPercentageOrAuto::Auto;
}
if style.padding.padding_top != computed::LengthOrPercentage::Length(Au(0)) ||
style.padding.padding_right != computed::LengthOrPercentage::Length(Au(0)) ||
style.padding.padding_bottom != computed::LengthOrPercentage::Length(Au(0)) ||
style.padding.padding_left != computed::LengthOrPercentage::Length(Au(0)) {
let mut style = Arc::make_mut(style);
let mut padding = Arc::make_mut(&mut style.padding);
padding.padding_top = computed::LengthOrPercentage::Length(Au(0));
padding.padding_right = computed::LengthOrPercentage::Length(Au(0));
padding.padding_bottom = computed::LengthOrPercentage::Length(Au(0));
padding.padding_left = computed::LengthOrPercentage::Length(Au(0));
}
if style.effects.opacity != 1.0 {
let mut style = Arc::make_mut(style);
let mut effects = Arc::make_mut(&mut style.effects);
effects.opacity = 1.0;
}
}
/// Adjusts the `clip` property so that an inline absolute hypothetical fragment
/// doesn't clip its children.
#[cfg(feature = "servo")]
pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<ComputedValues>) {
if !style.get_effects().clip.is_auto() {
let mut style = Arc::make_mut(style);
let effects_style = Arc::make_mut(&mut style.effects);
effects_style.clip = Either::auto()
}
}
#[macro_export] #[macro_export]
macro_rules! css_properties_accessors { macro_rules! css_properties_accessors {
($macro_name: ident) => { ($macro_name: ident) => {

View file

@ -32,6 +32,7 @@ pub enum PseudoElement {
Selection, Selection,
DetailsSummary, DetailsSummary,
DetailsContent, DetailsContent,
ServoText,
ServoInputText, ServoInputText,
ServoTableWrapper, ServoTableWrapper,
ServoAnonymousTableWrapper, ServoAnonymousTableWrapper,
@ -39,6 +40,8 @@ pub enum PseudoElement {
ServoAnonymousTableRow, ServoAnonymousTableRow,
ServoAnonymousTableCell, ServoAnonymousTableCell,
ServoAnonymousBlock, ServoAnonymousBlock,
ServoInlineBlockWrapper,
ServoInlineAbsolute,
} }
impl ToCss for PseudoElement { impl ToCss for PseudoElement {
@ -50,6 +53,7 @@ impl ToCss for PseudoElement {
Selection => "::selection", Selection => "::selection",
DetailsSummary => "::-servo-details-summary", DetailsSummary => "::-servo-details-summary",
DetailsContent => "::-servo-details-content", DetailsContent => "::-servo-details-content",
ServoText => "::-servo-text",
ServoInputText => "::-servo-input-text", ServoInputText => "::-servo-input-text",
ServoTableWrapper => "::-servo-table-wrapper", ServoTableWrapper => "::-servo-table-wrapper",
ServoAnonymousTableWrapper => "::-servo-anonymous-table-wrapper", ServoAnonymousTableWrapper => "::-servo-anonymous-table-wrapper",
@ -57,6 +61,8 @@ impl ToCss for PseudoElement {
ServoAnonymousTableRow => "::-servo-anonymous-table-row", ServoAnonymousTableRow => "::-servo-anonymous-table-row",
ServoAnonymousTableCell => "::-servo-anonymous-table-cell", ServoAnonymousTableCell => "::-servo-anonymous-table-cell",
ServoAnonymousBlock => "::-servo-anonymous-block", ServoAnonymousBlock => "::-servo-anonymous-block",
ServoInlineBlockWrapper => "::-servo-inline-block-wrapper",
ServoInlineAbsolute => "::-servo-inline-absolute",
}) })
} }
} }
@ -83,13 +89,16 @@ impl PseudoElement {
PseudoElement::Selection => PseudoElementCascadeType::Eager, PseudoElement::Selection => PseudoElementCascadeType::Eager,
PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy, PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy,
PseudoElement::DetailsContent | PseudoElement::DetailsContent |
PseudoElement::ServoText |
PseudoElement::ServoInputText | PseudoElement::ServoInputText |
PseudoElement::ServoTableWrapper | PseudoElement::ServoTableWrapper |
PseudoElement::ServoAnonymousTableWrapper | PseudoElement::ServoAnonymousTableWrapper |
PseudoElement::ServoAnonymousTable | PseudoElement::ServoAnonymousTable |
PseudoElement::ServoAnonymousTableRow | PseudoElement::ServoAnonymousTableRow |
PseudoElement::ServoAnonymousTableCell | PseudoElement::ServoAnonymousTableCell |
PseudoElement::ServoAnonymousBlock => PseudoElementCascadeType::Precomputed, PseudoElement::ServoAnonymousBlock |
PseudoElement::ServoInlineBlockWrapper |
PseudoElement::ServoInlineAbsolute => PseudoElementCascadeType::Precomputed,
} }
} }
} }
@ -278,6 +287,12 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
} }
DetailsContent DetailsContent
}, },
"-servo-text" => {
if !self.in_user_agent_stylesheet() {
return Err(())
}
ServoText
},
"-servo-input-text" => { "-servo-input-text" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(())
@ -320,6 +335,18 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
} }
ServoAnonymousBlock ServoAnonymousBlock
}, },
"-servo-inline-block-wrapper" => {
if !self.in_user_agent_stylesheet() {
return Err(())
}
ServoInlineBlockWrapper
},
"-servo-input-absolute" => {
if !self.in_user_agent_stylesheet() {
return Err(())
}
ServoInlineAbsolute
},
_ => return Err(()) _ => return Err(())
}; };
@ -352,6 +379,7 @@ impl SelectorImpl {
fun(PseudoElement::DetailsContent); fun(PseudoElement::DetailsContent);
fun(PseudoElement::DetailsSummary); fun(PseudoElement::DetailsSummary);
fun(PseudoElement::Selection); fun(PseudoElement::Selection);
fun(PseudoElement::ServoText);
fun(PseudoElement::ServoInputText); fun(PseudoElement::ServoInputText);
fun(PseudoElement::ServoTableWrapper); fun(PseudoElement::ServoTableWrapper);
fun(PseudoElement::ServoAnonymousTableWrapper); fun(PseudoElement::ServoAnonymousTableWrapper);
@ -359,6 +387,8 @@ impl SelectorImpl {
fun(PseudoElement::ServoAnonymousTableRow); fun(PseudoElement::ServoAnonymousTableRow);
fun(PseudoElement::ServoAnonymousTableCell); fun(PseudoElement::ServoAnonymousTableCell);
fun(PseudoElement::ServoAnonymousBlock); fun(PseudoElement::ServoAnonymousBlock);
fun(PseudoElement::ServoInlineBlockWrapper);
fun(PseudoElement::ServoInlineAbsolute);
} }
/// Returns the pseudo-class state flag for selector matching. /// Returns the pseudo-class state flag for selector matching.

View file

@ -385,20 +385,23 @@ impl Stylist {
/// Returns the style for an anonymous box of the given type. /// Returns the style for an anonymous box of the given type.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn style_for_anonymous_box(&self, pub fn style_for_anonymous(&self,
guards: &StylesheetGuards, guards: &StylesheetGuards,
pseudo: &PseudoElement, pseudo: &PseudoElement,
parent_style: &Arc<ComputedValues>) parent_style: &Arc<ComputedValues>)
-> Arc<ComputedValues> { -> Arc<ComputedValues> {
// For most (but not all) pseudo-elements, we inherit all values from the parent. // For most (but not all) pseudo-elements, we inherit all values from the parent.
let inherit_all = match *pseudo { let inherit_all = match *pseudo {
PseudoElement::ServoText |
PseudoElement::ServoInputText => false, PseudoElement::ServoInputText => false,
PseudoElement::ServoAnonymousBlock | PseudoElement::ServoAnonymousBlock |
PseudoElement::ServoAnonymousTable | PseudoElement::ServoAnonymousTable |
PseudoElement::ServoAnonymousTableCell | PseudoElement::ServoAnonymousTableCell |
PseudoElement::ServoAnonymousTableRow | PseudoElement::ServoAnonymousTableRow |
PseudoElement::ServoAnonymousTableWrapper | PseudoElement::ServoAnonymousTableWrapper |
PseudoElement::ServoTableWrapper => true, PseudoElement::ServoTableWrapper |
PseudoElement::ServoInlineBlockWrapper |
PseudoElement::ServoInlineAbsolute => true,
PseudoElement::Before | PseudoElement::Before |
PseudoElement::After | PseudoElement::After |
PseudoElement::Selection | PseudoElement::Selection |

View file

@ -168,6 +168,12 @@ svg > * {
display: none; display: none;
} }
/* style for text node. */
*|*::-servo-text {
margin: 0;
}
/* style for text in input elements. */
*|*::-servo-input-text { *|*::-servo-input-text {
margin: 0; margin: 0;
} }
@ -215,3 +221,18 @@ svg > * {
height: auto; height: auto;
} }
/* The outer fragment wrapper of an inline-block. */
*|*::-servo-inline-block-wrapper {
position: static;
border: none;
padding: 0;
margin: 0;
}
/* The outer fragment wrapper of an inline absolute hypothetical fragment. */
*|*::-servo-inline-absolute {
clip: auto;
border: none;
padding: 0;
margin: 0;
}

View file

@ -1,3 +0,0 @@
[flexbox_nested-flex.htm]
type: reftest
expected: FAIL