mirror of
https://github.com/servo/servo.git
synced 2025-09-27 23:30:08 +01:00
layout: Use the PseudoElement
from ServoThreadSafeLayoutNode
in NodeAndStyleInfo
(#38630)
Instead of storing the non-pseudo version of the node in `NodeAndStyleInfo`, store the pseudo version and use that to query the `PseudoElement` that a `NodeAndStyleInfo` refers to. This is a step on the way toward fixing nested pseudo-elements in Servo. Testing: This should not change behavior and is thus covered by existing WPT tests. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
ee7c1d9109
commit
5ff084a688
6 changed files with 34 additions and 38 deletions
|
@ -228,7 +228,7 @@ impl<'a, 'dom> ModernContainerBuilder<'a, 'dom> {
|
||||||
|
|
||||||
let anonymous_info = LazyLock::new(|| {
|
let anonymous_info = LazyLock::new(|| {
|
||||||
self.info
|
self.info
|
||||||
.pseudo(self.context, PseudoElement::ServoAnonymousBox)
|
.with_pseudo_element(self.context, PseudoElement::ServoAnonymousBox)
|
||||||
.expect("Should always be able to construct info for anonymous boxes.")
|
.expect("Should always be able to construct info for anonymous boxes.")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOuts
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct NodeAndStyleInfo<'dom> {
|
pub(crate) struct NodeAndStyleInfo<'dom> {
|
||||||
pub node: ServoThreadSafeLayoutNode<'dom>,
|
pub node: ServoThreadSafeLayoutNode<'dom>,
|
||||||
pub pseudo_element_type: Option<PseudoElement>,
|
|
||||||
pub style: ServoArc<ComputedValues>,
|
pub style: ServoArc<ComputedValues>,
|
||||||
pub damage: LayoutDamage,
|
pub damage: LayoutDamage,
|
||||||
}
|
}
|
||||||
|
@ -44,37 +43,24 @@ impl<'dom> NodeAndStyleInfo<'dom> {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
node,
|
node,
|
||||||
pseudo_element_type: None,
|
|
||||||
style,
|
style,
|
||||||
damage,
|
damage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this is a container for the text within a single-line text input. This
|
pub(crate) fn pseudo_element(&self) -> Option<PseudoElement> {
|
||||||
/// is used to solve the special case of line height for a text entry widget.
|
self.node.pseudo_element()
|
||||||
/// <https://html.spec.whatwg.org/multipage/#the-input-element-as-a-text-entry-widget>
|
|
||||||
// TODO(stevennovaryo): Remove the addition of HTMLInputElement here once all of the
|
|
||||||
// input element is implemented with UA shadow DOM. This is temporary
|
|
||||||
// workaround for past version of input element where we are
|
|
||||||
// rendering it as a bare html element.
|
|
||||||
pub(crate) fn is_single_line_text_input(&self) -> bool {
|
|
||||||
self.node.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLInputElement)) ||
|
|
||||||
self.node.is_text_container_of_single_line_input()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pseudo(
|
pub(crate) fn with_pseudo_element(
|
||||||
&self,
|
&self,
|
||||||
context: &LayoutContext,
|
context: &LayoutContext,
|
||||||
pseudo_element_type: PseudoElement,
|
pseudo_element_type: PseudoElement,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let style = self
|
let element = self.node.as_element()?.with_pseudo(pseudo_element_type)?;
|
||||||
.node
|
let style = element.style(&context.style_context);
|
||||||
.as_element()?
|
|
||||||
.with_pseudo(pseudo_element_type)?
|
|
||||||
.style(&context.style_context);
|
|
||||||
Some(NodeAndStyleInfo {
|
Some(NodeAndStyleInfo {
|
||||||
node: self.node,
|
node: element.as_node(),
|
||||||
pseudo_element_type: Some(pseudo_element_type),
|
|
||||||
style,
|
style,
|
||||||
damage: self.damage,
|
damage: self.damage,
|
||||||
})
|
})
|
||||||
|
@ -88,7 +74,7 @@ impl<'dom> NodeAndStyleInfo<'dom> {
|
||||||
impl<'dom> From<&NodeAndStyleInfo<'dom>> for BaseFragmentInfo {
|
impl<'dom> From<&NodeAndStyleInfo<'dom>> for BaseFragmentInfo {
|
||||||
fn from(info: &NodeAndStyleInfo<'dom>) -> Self {
|
fn from(info: &NodeAndStyleInfo<'dom>) -> Self {
|
||||||
let threadsafe_node = info.node;
|
let threadsafe_node = info.node;
|
||||||
let pseudo = info.pseudo_element_type;
|
let pseudo = info.node.pseudo_element();
|
||||||
let mut flags = FragmentFlags::empty();
|
let mut flags = FragmentFlags::empty();
|
||||||
|
|
||||||
// Anonymous boxes should not have a tag, because they should not take part in hit testing.
|
// Anonymous boxes should not have a tag, because they should not take part in hit testing.
|
||||||
|
@ -284,7 +270,8 @@ fn traverse_eager_pseudo_element<'dom>(
|
||||||
|
|
||||||
// If this node doesn't have this eager pseudo-element, exit early. This depends on
|
// If this node doesn't have this eager pseudo-element, exit early. This depends on
|
||||||
// the style applied to the element.
|
// the style applied to the element.
|
||||||
let Some(pseudo_element_info) = node_info.pseudo(context, pseudo_element_type) else {
|
let Some(pseudo_element_info) = node_info.with_pseudo_element(context, pseudo_element_type)
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if pseudo_element_info.style.ineffective_content_property() {
|
if pseudo_element_info.style.ineffective_content_property() {
|
||||||
|
@ -328,7 +315,7 @@ fn traverse_pseudo_element_contents<'dom>(
|
||||||
PseudoElementContentItem::Text(text) => handler.handle_text(info, text.into()),
|
PseudoElementContentItem::Text(text) => handler.handle_text(info, text.into()),
|
||||||
PseudoElementContentItem::Replaced(contents) => {
|
PseudoElementContentItem::Replaced(contents) => {
|
||||||
let anonymous_info = anonymous_info.get_or_insert_with(|| {
|
let anonymous_info = anonymous_info.get_or_insert_with(|| {
|
||||||
info.pseudo(context, PseudoElement::ServoAnonymousBox)
|
info.with_pseudo_element(context, PseudoElement::ServoAnonymousBox)
|
||||||
.unwrap_or_else(|| info.clone())
|
.unwrap_or_else(|| info.clone())
|
||||||
});
|
});
|
||||||
let display_inline = DisplayGeneratingBox::OutsideInside {
|
let display_inline = DisplayGeneratingBox::OutsideInside {
|
||||||
|
|
|
@ -228,7 +228,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
self.inline_formatting_context_builder.take()?.finish(
|
self.inline_formatting_context_builder.take()?.finish(
|
||||||
self.context,
|
self.context,
|
||||||
!self.have_already_seen_first_line_for_text_indent,
|
!self.have_already_seen_first_line_for_text_indent,
|
||||||
self.info.is_single_line_text_input(),
|
self.info.node.is_single_line_text_input(),
|
||||||
self.info.style.to_bidi_level(),
|
self.info.style.to_bidi_level(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -414,7 +414,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
// TODO: We do not currently support saving box slots for ::marker pseudo-elements
|
// TODO: We do not currently support saving box slots for ::marker pseudo-elements
|
||||||
// that are part nested in ::before and ::after pseudo elements. For now, just
|
// that are part nested in ::before and ::after pseudo elements. For now, just
|
||||||
// forget about them once they are built.
|
// forget about them once they are built.
|
||||||
let box_slot = match container_info.pseudo_element_type {
|
let box_slot = match container_info.pseudo_element() {
|
||||||
Some(_) => BoxSlot::dummy(),
|
Some(_) => BoxSlot::dummy(),
|
||||||
None => marker_info
|
None => marker_info
|
||||||
.node
|
.node
|
||||||
|
@ -441,7 +441,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
// TODO: We do not currently support saving box slots for ::marker pseudo-elements
|
// TODO: We do not currently support saving box slots for ::marker pseudo-elements
|
||||||
// that are part nested in ::before and ::after pseudo elements. For now, just
|
// that are part nested in ::before and ::after pseudo elements. For now, just
|
||||||
// forget about them once they are built.
|
// forget about them once they are built.
|
||||||
let box_slot = match container_info.pseudo_element_type {
|
let box_slot = match container_info.pseudo_element() {
|
||||||
Some(_) => BoxSlot::dummy(),
|
Some(_) => BoxSlot::dummy(),
|
||||||
None => marker_info
|
None => marker_info
|
||||||
.node
|
.node
|
||||||
|
@ -686,7 +686,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
.anonymous_box_info
|
.anonymous_box_info
|
||||||
.get_or_insert_with(|| {
|
.get_or_insert_with(|| {
|
||||||
self.info
|
self.info
|
||||||
.pseudo(layout_context, PseudoElement::ServoAnonymousBox)
|
.with_pseudo_element(layout_context, PseudoElement::ServoAnonymousBox)
|
||||||
.expect("Should never fail to create anonymous box")
|
.expect("Should never fail to create anonymous box")
|
||||||
})
|
})
|
||||||
.clone();
|
.clone();
|
||||||
|
|
|
@ -15,7 +15,8 @@ pub(crate) fn make_marker<'dom>(
|
||||||
context: &LayoutContext,
|
context: &LayoutContext,
|
||||||
info: &NodeAndStyleInfo<'dom>,
|
info: &NodeAndStyleInfo<'dom>,
|
||||||
) -> Option<(NodeAndStyleInfo<'dom>, Vec<PseudoElementContentItem>)> {
|
) -> Option<(NodeAndStyleInfo<'dom>, Vec<PseudoElementContentItem>)> {
|
||||||
let marker_info = info.pseudo(context, style::selector_parser::PseudoElement::Marker)?;
|
let marker_info =
|
||||||
|
info.with_pseudo_element(context, style::selector_parser::PseudoElement::Marker)?;
|
||||||
let style = &marker_info.style;
|
let style = &marker_info.style;
|
||||||
let list_style = style.get_list();
|
let list_style = style.get_list();
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl Table {
|
||||||
propagated_data: PropagatedBoxTreeData,
|
propagated_data: PropagatedBoxTreeData,
|
||||||
) -> (NodeAndStyleInfo<'dom>, IndependentFormattingContext) {
|
) -> (NodeAndStyleInfo<'dom>, IndependentFormattingContext) {
|
||||||
let table_info = parent_info
|
let table_info = parent_info
|
||||||
.pseudo(context, PseudoElement::ServoAnonymousTable)
|
.with_pseudo_element(context, PseudoElement::ServoAnonymousTable)
|
||||||
.expect("Should never fail to create anonymous table info.");
|
.expect("Should never fail to create anonymous table info.");
|
||||||
let table_style = table_info.style.clone();
|
let table_style = table_info.style.clone();
|
||||||
let mut table_builder =
|
let mut table_builder =
|
||||||
|
@ -688,7 +688,7 @@ impl<'style, 'dom> TableBuilderTraversal<'style, 'dom> {
|
||||||
let row_content = std::mem::take(&mut self.current_anonymous_row_content);
|
let row_content = std::mem::take(&mut self.current_anonymous_row_content);
|
||||||
let anonymous_info = self
|
let anonymous_info = self
|
||||||
.info
|
.info
|
||||||
.pseudo(self.context, PseudoElement::ServoAnonymousTableRow)
|
.with_pseudo_element(self.context, PseudoElement::ServoAnonymousTableRow)
|
||||||
.expect("Should never fail to create anonymous row info.");
|
.expect("Should never fail to create anonymous row info.");
|
||||||
let mut row_builder =
|
let mut row_builder =
|
||||||
TableRowBuilder::new(self, &anonymous_info, self.current_propagated_data);
|
TableRowBuilder::new(self, &anonymous_info, self.current_propagated_data);
|
||||||
|
@ -957,7 +957,7 @@ impl<'style, 'builder, 'dom, 'a> TableRowBuilder<'style, 'builder, 'dom, 'a> {
|
||||||
let context = self.table_traversal.context;
|
let context = self.table_traversal.context;
|
||||||
let anonymous_info = self
|
let anonymous_info = self
|
||||||
.info
|
.info
|
||||||
.pseudo(context, PseudoElement::ServoAnonymousTableCell)
|
.with_pseudo_element(context, PseudoElement::ServoAnonymousTableCell)
|
||||||
.expect("Should never fail to create anonymous table cell info");
|
.expect("Should never fail to create anonymous table cell info");
|
||||||
let propagated_data = self.propagated_data.disallowing_percentage_table_columns();
|
let propagated_data = self.propagated_data.disallowing_percentage_table_columns();
|
||||||
let mut builder = BlockContainerBuilder::new(context, &anonymous_info, propagated_data);
|
let mut builder = BlockContainerBuilder::new(context, &anonymous_info, propagated_data);
|
||||||
|
@ -1027,7 +1027,7 @@ impl<'dom> TraversalHandler<'dom> for TableRowBuilder<'_, '_, 'dom, '_> {
|
||||||
let cell = old_cell.unwrap_or_else(|| {
|
let cell = old_cell.unwrap_or_else(|| {
|
||||||
// This value will already have filtered out rowspan=0
|
// This value will already have filtered out rowspan=0
|
||||||
// in quirks mode, so we don't have to worry about that.
|
// in quirks mode, so we don't have to worry about that.
|
||||||
let (rowspan, colspan) = if info.pseudo_element_type.is_none() {
|
let (rowspan, colspan) = if info.pseudo_element().is_none() {
|
||||||
let rowspan = info.node.get_rowspan().unwrap_or(1) as usize;
|
let rowspan = info.node.get_rowspan().unwrap_or(1) as usize;
|
||||||
let colspan = info.node.get_colspan().unwrap_or(1) as usize;
|
let colspan = info.node.get_colspan().unwrap_or(1) as usize;
|
||||||
|
|
||||||
|
@ -1148,7 +1148,7 @@ fn add_column(
|
||||||
is_anonymous: bool,
|
is_anonymous: bool,
|
||||||
old_column: Option<ArcRefCell<TableTrack>>,
|
old_column: Option<ArcRefCell<TableTrack>>,
|
||||||
) -> ArcRefCell<TableTrack> {
|
) -> ArcRefCell<TableTrack> {
|
||||||
let span = if column_info.pseudo_element_type.is_none() {
|
let span = if column_info.pseudo_element().is_none() {
|
||||||
column_info.node.get_span().unwrap_or(1)
|
column_info.node.get_span().unwrap_or(1)
|
||||||
} else {
|
} else {
|
||||||
1
|
1
|
||||||
|
|
|
@ -14,8 +14,8 @@ use layout_api::wrapper_traits::{
|
||||||
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||||
};
|
};
|
||||||
use layout_api::{
|
use layout_api::{
|
||||||
GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutNodeType, SVGElementData, StyleData,
|
GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType,
|
||||||
TrustedNodeAddress,
|
SVGElementData, StyleData, TrustedNodeAddress,
|
||||||
};
|
};
|
||||||
use net_traits::image_cache::Image;
|
use net_traits::image_cache::Image;
|
||||||
use pixels::ImageMetadata;
|
use pixels::ImageMetadata;
|
||||||
|
@ -258,8 +258,16 @@ impl<'dom> ServoThreadSafeLayoutNode<'dom> {
|
||||||
.map(Self::new)
|
.map(Self::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_text_container_of_single_line_input(&self) -> bool {
|
/// Whether this is a container for the text within a single-line text input. This
|
||||||
self.pseudo.is_none() && self.node.node.is_text_container_of_single_line_input()
|
/// is used to solve the special case of line height for a text entry widget.
|
||||||
|
/// <https://html.spec.whatwg.org/multipage/#the-input-element-as-a-text-entry-widget>
|
||||||
|
// TODO(stevennovaryo): Remove the addition of HTMLInputElement here once all of the
|
||||||
|
// input element is implemented with UA shadow DOM. This is temporary
|
||||||
|
// workaround for past version of input element where we are
|
||||||
|
// rendering it as a bare html element.
|
||||||
|
pub fn is_single_line_text_input(&self) -> bool {
|
||||||
|
self.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLInputElement)) ||
|
||||||
|
(self.pseudo.is_none() && self.node.node.is_text_container_of_single_line_input())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_text_input(&self) -> bool {
|
pub fn is_text_input(&self) -> bool {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue