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 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

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

This is an example that partially addresses
#8570, hoping that other people will
complete it based on an example like this.

Actually, we do approximately the same amount of work now, but we could mark
this pseudos as "eagerly" cascaded, and do less work in layout, at the expense
of (possibly) wasted work.
  • Loading branch information
emilio committed Jul 18, 2016
commit 2632e3926b0f83eb19496e801ef50c78b0a41f9a
@@ -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,21 @@ 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 mut style = style_context.stylist
.precomputed_values_for_pseudo(&PseudoElement::ServoText,
Some(&enclosing_node.style)).unwrap();
properties::modify_style_for_replaced_content(&mut style);

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 +423,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
};
@@ -583,7 +596,6 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
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 +725,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 +737,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 +797,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 +833,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);
@@ -871,7 +883,6 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
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,10 @@ 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();
let mut modified_style = self.style_context().stylist
.precomputed_values_for_pseudo(&PseudoElement::ServoText,
Some(&node_style)).unwrap();
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(),
node.get_pseudo_element_type().strip(),
modified_style,
@@ -921,7 +933,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,10 +952,15 @@ 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()))
}

@@ -1001,7 +1018,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 +1053,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)
}
@@ -1859,16 +1876,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 => {
@@ -2138,42 +2138,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
@@ -110,6 +110,7 @@ pub enum PseudoElement {
Selection,
DetailsSummary,
DetailsContent,
ServoText,
}

impl PseudoElement {
@@ -129,6 +130,7 @@ impl PseudoElement {
PseudoElement::After |
PseudoElement::Selection => PseudoElementCascadeType::Eager,
PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy,
PseudoElement::ServoText |
PseudoElement::DetailsContent => PseudoElementCascadeType::Precomputed,
}
}
@@ -233,6 +235,12 @@ impl SelectorImpl for ServoSelectorImpl {
}
DetailsContent
},
"-servo-text" => {
if !context.in_user_agent_stylesheet {
return Err(())
}
ServoText
},
_ => return Err(())
};

@@ -256,6 +264,7 @@ impl SelectorImplExt for ServoSelectorImpl {
fun(PseudoElement::DetailsContent);
fun(PseudoElement::DetailsSummary);
fun(PseudoElement::Selection);
fun(PseudoElement::ServoText);
}

#[inline]
@@ -286,3 +286,15 @@ video { object-fit: contain; }


textarea { white-space: pre-wrap; }

/**
* This is a special pseudo-element whose styles apply to text nodes.
*/
*|*::-servo-text {
top: auto;
right: auto;
bottom: auto;
left: auto;
padding: 0;
opacity: 1;
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.