Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wip] layout: Use a magic pseudo-element for text styles. #12496

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -47,6 +47,7 @@ use style::computed_values::content::ContentItem;
use style::computed_values::position;
use style::computed_values::{caption_side, display, empty_cells, float, list_style_position};
use style::properties::{self, ComputedValues, ServoComputedValues};
use style::selector_impl::PseudoElement;
use style::servo::SharedStyleContext;
use table::TableFlow;
use table_caption::TableCaptionFlow;
@@ -235,7 +236,8 @@ impl InlineFragmentsAccumulator {
self.fragments.absolute_descendants.push_descendants(fragments.absolute_descendants);
}

fn to_intermediate_inline_fragments(self) -> IntermediateInlineFragments {
fn to_intermediate_inline_fragments(self,
style_context: &SharedStyleContext) -> IntermediateInlineFragments {
let InlineFragmentsAccumulator {
mut fragments,
enclosing_node,
@@ -258,10 +260,23 @@ impl InlineFragmentsAccumulator {
// Control characters are later discarded in transform_text, so they don't affect the
// is_first/is_last styles above.
if let Some((start, end)) = bidi_control_chars {
let style = style_context.stylist
.precomputed_values_for_pseudo(&PseudoElement::ServoReplacedContent,
Some(&enclosing_node.style)).unwrap();
let style = style_context.stylist
.precomputed_values_for_pseudo(&PseudoElement::ServoText,
Some(&style)).unwrap();

fragments.fragments.push_front(
control_chars_to_fragment(&enclosing_node, start, restyle_damage));
control_chars_to_fragment(&enclosing_node,
start,
restyle_damage,
style.clone()));
fragments.fragments.push_back(
control_chars_to_fragment(&enclosing_node, end, restyle_damage));
control_chars_to_fragment(&enclosing_node,
end,
restyle_damage,
style));
}
}
fragments
@@ -410,7 +425,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
flow_list: &mut Vec<FlowRef>,
absolute_descendants: &mut AbsoluteDescendants,
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() {
return
};
@@ -576,14 +591,12 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
whitespace_node,
whitespace_pseudo,
mut whitespace_style,
whitespace_style,
whitespace_damage)) => {
// Add whitespace results. They will be stripped out later on when
// between block elements, and retained when between inline elements.
let fragment_info = SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(" ".to_owned(), None));
properties::modify_style_for_replaced_content(&mut whitespace_style);
properties::modify_style_for_text(&mut whitespace_style);
let style_context = self.style_context();
let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
whitespace_pseudo,
@@ -713,8 +726,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
return
}

let mut style = (*style).clone();
properties::modify_style_for_text(&mut style);
self.style_context().stylist.precomputed_values_for_pseudo(&PseudoElement::ServoText,
Some(style)).unwrap();

let selected_style = node.selected_style(self.style_context());

@@ -725,7 +738,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
fragments.fragments.push_back(Fragment::from_opaque_node_and_style(
node.opaque(),
node.get_pseudo_element_type().strip(),
style,
style.clone(),
selected_style.clone(),
node.restyle_damage(),
specific_fragment_info))
@@ -785,7 +798,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
predecessors: mem::replace(
fragment_accumulator,
InlineFragmentsAccumulator::from_inline_node(
node, self.style_context())).to_intermediate_inline_fragments(),
node, self.style_context())).to_intermediate_inline_fragments(self.style_context()),
flow: kid_flow,
};
opt_inline_block_splits.push_back(split)
@@ -821,8 +834,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
predecessors:
mem::replace(
&mut fragment_accumulator,
InlineFragmentsAccumulator::from_inline_node(
node, self.style_context())).to_intermediate_inline_fragments(),
InlineFragmentsAccumulator::from_inline_node(node, self.style_context()))
.to_intermediate_inline_fragments(self.style_context()),
flow: flow,
};
opt_inline_block_splits.push_back(split);
@@ -865,13 +878,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
whitespace_node,
whitespace_pseudo,
mut whitespace_style,
whitespace_style,
whitespace_damage)) => {
// Instantiate the whitespace fragment.
let fragment_info = SpecificFragmentInfo::UnscannedText(
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,
whitespace_pseudo,
@@ -893,9 +904,12 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
// An empty inline box needs at least one fragment to draw its background and borders.
let info = SpecificFragmentInfo::UnscannedText(
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 modified_style = self.style_context().stylist
.precomputed_values_for_pseudo(&PseudoElement::ServoReplacedContent,
Some(&node_style)).unwrap();
let modified_style = self.style_context().stylist
.precomputed_values_for_pseudo(&PseudoElement::ServoText,
Some(&modified_style)).unwrap();
let fragment = Fragment::from_opaque_node_and_style(node.opaque(),
node.get_pseudo_element_type().strip(),
modified_style,
@@ -921,7 +935,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let construction_item = ConstructionItem::InlineFragments(
InlineFragmentsConstructionResult {
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)
} else {
@@ -940,17 +954,22 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>

// If this node is ignorable whitespace, bail out now.
if node.is_ignorable_whitespace(self.style_context()) {
let node_style = node.style(self.style_context());
let text_style = self.style_context()
.stylist.precomputed_values_for_pseudo(&PseudoElement::ServoText,
Some(&node_style)).unwrap();

return ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
node.opaque(),
node.get_pseudo_element_type().strip(),
node.style(self.style_context()).clone(),
text_style,
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()).clone();
properties::modify_style_for_replaced_content(&mut style);
let style = node.style(self.style_context());
let style = self.style_context().stylist
.precomputed_values_for_pseudo(&PseudoElement::ServoText,
Some(&style)).unwrap();

// 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
@@ -1001,7 +1020,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let construction_item =
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
splits: LinkedList::new(),
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
fragments: fragment_accumulator.to_intermediate_inline_fragments(self.style_context()),
});
ConstructionResult::ConstructionItem(construction_item)
}
@@ -1036,7 +1055,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let construction_item =
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
splits: LinkedList::new(),
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
fragments: fragment_accumulator.to_intermediate_inline_fragments(self.style_context()),
});
ConstructionResult::ConstructionItem(construction_item)
}
@@ -1392,7 +1411,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
return false
}

let mut style = node.style(self.style_context()).clone();
let style = node.style(self.style_context()).clone();
let mut data = node.mutate_layout_data().unwrap();
let damage = data.restyle_damage;
match *node.construction_result_mut(&mut *data) {
@@ -1462,9 +1481,15 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
_ => {
if node.is_replaced_content() {
properties::modify_style_for_replaced_content(&mut style);
let style =
self.style_context()
.stylist
.precomputed_values_for_pseudo(&PseudoElement::ServoReplacedContent,
Some(&style)).unwrap();
fragment.repair_style(&style);
} else {
fragment.repair_style(&style);
}
fragment.repair_style(&style);
}
}
}
@@ -1859,16 +1884,14 @@ fn bidi_control_chars(style: &Arc<ServoComputedValues>) -> Option<(&'static str,

fn control_chars_to_fragment(node: &InlineFragmentNodeInfo,
text: &str,
restyle_damage: RestyleDamage)
restyle_damage: RestyleDamage,
style: Arc<ServoComputedValues>)
-> Fragment {
let info = SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(String::from(text), None));
let mut style = node.style.clone();
properties::modify_style_for_replaced_content(&mut style);
properties::modify_style_for_text(&mut style);
Fragment::from_opaque_node_and_style(node.address,
node.pseudo,
style.clone(),
style,
node.selected_style.clone(),
restyle_damage,
info)
@@ -210,12 +210,13 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq {
.style_data
.per_pseudo.contains_key(&style_pseudo) {
let mut data = self.get_style_data().unwrap().borrow_mut();

let new_style =
context.stylist
.precomputed_values_for_pseudo(&style_pseudo,
data.style_data.style.as_ref());
context.stylist.precomputed_values_for_pseudo(&style_pseudo,
data.style_data.style.as_ref()).unwrap();

data.style_data.per_pseudo
.insert(style_pseudo.clone(), new_style.unwrap());
.insert(style_pseudo.clone(), new_style);
}
}
PseudoElementCascadeType::Lazy => {
@@ -2027,43 +2027,6 @@ pub fn modify_style_for_anonymous_flow(style: &mut Arc<ServoComputedValues>,
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.
#[inline]
pub fn modify_style_for_replaced_content(style: &mut Arc<ServoComputedValues>) {
// 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 first or last fragment
/// within the range of an element.
///
@@ -2138,42 +2101,6 @@ pub fn modify_style_for_outer_inline_block_fragment(style: &mut Arc<ServoCompute
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.
#[inline]
pub fn modify_style_for_text(style: &mut Arc<ServoComputedValues>) {
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 `margin` property as necessary to account for the text of an `input` element.
///
/// Margins apply to the `input` element itself, so including them in the text will cause them to
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.