mirror of
https://github.com/servo/servo.git
synced 2025-09-29 16:19:14 +01:00
layout: Support storing layout data for two-level nested pseudo-elements (#38678)
Add basic support for storing layout data for pseudo-elements nested to up to two levels. This removes the last unstored layout result and fixes a double-borrow issue. This change does not add properly parsing nor styling of these element types, but does prepare for those changes which must come from stylo. Testing: This fixes a intermittent panic in `tests/wpt/tests/css/css-lists/nested-marker-styling.html` Fixes: #38177. Closes: #38183. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
43da933247
commit
99ce81cf64
10 changed files with 273 additions and 177 deletions
|
@ -10,7 +10,9 @@ use atomic_refcell::{AtomicRef, AtomicRefMut};
|
|||
use embedder_traits::UntrustedNodeAddress;
|
||||
use html5ever::{LocalName, Namespace, local_name, ns};
|
||||
use js::jsapi::JSObject;
|
||||
use layout_api::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||
use layout_api::wrapper_traits::{
|
||||
LayoutNode, PseudoElementChain, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||
};
|
||||
use layout_api::{LayoutDamage, LayoutNodeType, StyleData};
|
||||
use selectors::Element as _;
|
||||
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
|
||||
|
@ -967,11 +969,11 @@ impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
|
|||
/// ever access safe properties and cannot race on elements.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ServoThreadSafeLayoutElement<'dom> {
|
||||
/// The wrapped [`ServoLayoutNode`].
|
||||
pub(super) element: ServoLayoutElement<'dom>,
|
||||
|
||||
/// The pseudo-element type for this element, or `None` if it is the non-pseudo
|
||||
/// version of the element.
|
||||
pub(super) pseudo: Option<PseudoElement>,
|
||||
/// The possibly nested [`PseudoElementChain`] for this node.
|
||||
pub(super) pseudo_element_chain: PseudoElementChain,
|
||||
}
|
||||
|
||||
impl<'dom> ServoThreadSafeLayoutElement<'dom> {
|
||||
|
@ -995,32 +997,32 @@ impl<'dom> ThreadSafeLayoutElement<'dom> for ServoThreadSafeLayoutElement<'dom>
|
|||
fn as_node(&self) -> ServoThreadSafeLayoutNode<'dom> {
|
||||
ServoThreadSafeLayoutNode {
|
||||
node: self.element.as_node(),
|
||||
pseudo: self.pseudo,
|
||||
pseudo_element_chain: self.pseudo_element_chain,
|
||||
}
|
||||
}
|
||||
|
||||
fn pseudo_element(&self) -> Option<PseudoElement> {
|
||||
self.pseudo
|
||||
fn pseudo_element_chain(&self) -> PseudoElementChain {
|
||||
self.pseudo_element_chain
|
||||
}
|
||||
|
||||
fn with_pseudo(&self, pseudo_element_type: PseudoElement) -> Option<Self> {
|
||||
if pseudo_element_type.is_eager() &&
|
||||
fn with_pseudo(&self, pseudo_element: PseudoElement) -> Option<Self> {
|
||||
if pseudo_element.is_eager() &&
|
||||
self.style_data()
|
||||
.styles
|
||||
.pseudos
|
||||
.get(&pseudo_element_type)
|
||||
.get(&pseudo_element)
|
||||
.is_none()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if pseudo_element_type == PseudoElement::DetailsSummary &&
|
||||
if pseudo_element == PseudoElement::DetailsSummary &&
|
||||
(!self.has_local_name(&local_name!("details")) || !self.has_namespace(&ns!(html)))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if pseudo_element_type == PseudoElement::DetailsContent &&
|
||||
if pseudo_element == PseudoElement::DetailsContent &&
|
||||
(!self.has_local_name(&local_name!("details")) ||
|
||||
!self.has_namespace(&ns!(html)) ||
|
||||
self.get_attr(&ns!(), &local_name!("open")).is_none())
|
||||
|
@ -1028,9 +1030,16 @@ impl<'dom> ThreadSafeLayoutElement<'dom> for ServoThreadSafeLayoutElement<'dom>
|
|||
return None;
|
||||
}
|
||||
|
||||
// These pseudo-element type cannot be nested.
|
||||
if !self.pseudo_element_chain.is_empty() {
|
||||
assert!(!pseudo_element.is_eager());
|
||||
assert!(pseudo_element != PseudoElement::DetailsSummary);
|
||||
assert!(pseudo_element != PseudoElement::DetailsContent);
|
||||
}
|
||||
|
||||
Some(ServoThreadSafeLayoutElement {
|
||||
element: self.element,
|
||||
pseudo: Some(pseudo_element_type),
|
||||
pseudo_element_chain: self.pseudo_element_chain.with_pseudo(pseudo_element),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::iter::FusedIterator;
|
|||
use base::id::{BrowsingContextId, PipelineId};
|
||||
use fonts_traits::ByteIndex;
|
||||
use layout_api::wrapper_traits::{
|
||||
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||
LayoutDataTrait, LayoutNode, PseudoElementChain, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||
};
|
||||
use layout_api::{
|
||||
GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType,
|
||||
|
@ -218,18 +218,20 @@ impl<'dom> LayoutNode<'dom> for ServoLayoutNode<'dom> {
|
|||
/// never access any other node apart from its parent.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct ServoThreadSafeLayoutNode<'dom> {
|
||||
/// The wrapped `ServoLayoutNode`.
|
||||
/// The wrapped [`ServoLayoutNode`].
|
||||
pub(super) node: ServoLayoutNode<'dom>,
|
||||
|
||||
/// The pseudo-element type for this node, or `None` if it is the non-pseudo
|
||||
/// version of the element.
|
||||
pub(super) pseudo: Option<PseudoElement>,
|
||||
/// The possibly nested [`PseudoElementChain`] for this node.
|
||||
pub(super) pseudo_element_chain: PseudoElementChain,
|
||||
}
|
||||
|
||||
impl<'dom> ServoThreadSafeLayoutNode<'dom> {
|
||||
/// Creates a new `ServoThreadSafeLayoutNode` from the given `ServoLayoutNode`.
|
||||
pub fn new(node: ServoLayoutNode<'dom>) -> Self {
|
||||
ServoThreadSafeLayoutNode { node, pseudo: None }
|
||||
ServoThreadSafeLayoutNode {
|
||||
node,
|
||||
pseudo_element_chain: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the interior of this node as a `LayoutDom`. This is highly unsafe for layout to
|
||||
|
@ -267,7 +269,8 @@ impl<'dom> ServoThreadSafeLayoutNode<'dom> {
|
|||
// 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())
|
||||
(self.pseudo_element_chain.is_empty() &&
|
||||
self.node.node.is_text_container_of_single_line_input())
|
||||
}
|
||||
|
||||
pub fn is_text_input(&self) -> bool {
|
||||
|
@ -316,12 +319,12 @@ impl<'dom> ThreadSafeLayoutNode<'dom> for ServoThreadSafeLayoutNode<'dom> {
|
|||
unsafe { self.get_jsmanaged().opaque() }
|
||||
}
|
||||
|
||||
fn pseudo_element(&self) -> Option<PseudoElement> {
|
||||
self.pseudo
|
||||
fn pseudo_element_chain(&self) -> PseudoElementChain {
|
||||
self.pseudo_element_chain
|
||||
}
|
||||
|
||||
fn type_id(&self) -> Option<LayoutNodeType> {
|
||||
if self.pseudo.is_none() {
|
||||
if self.pseudo_element_chain.is_empty() {
|
||||
Some(self.node.type_id())
|
||||
} else {
|
||||
None
|
||||
|
@ -356,7 +359,7 @@ impl<'dom> ThreadSafeLayoutNode<'dom> for ServoThreadSafeLayoutNode<'dom> {
|
|||
.as_element()
|
||||
.map(|el| ServoThreadSafeLayoutElement {
|
||||
element: el,
|
||||
pseudo: self.pseudo,
|
||||
pseudo_element_chain: self.pseudo_element_chain,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -460,6 +463,13 @@ impl<'dom> ThreadSafeLayoutNode<'dom> for ServoThreadSafeLayoutNode<'dom> {
|
|||
.get_rowspan()
|
||||
}
|
||||
}
|
||||
|
||||
fn with_pseudo_element_chain(&self, pseudo_element_chain: PseudoElementChain) -> Self {
|
||||
Self {
|
||||
node: self.node,
|
||||
pseudo_element_chain,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue