script: Rewrite the layout DOM wrappers#44114
Conversation
|
🔨 Triggering try run (#24280322148) for Linux (WPT) |
|
Test results for linux-wpt from try job (#24280322148): Flaky unexpected result (37)
Stable unexpected results that are known to be intermittent (20)
|
|
✨ Try run (#24280322148) succeeded. |
f78eb7a to
61335da
Compare
simonwuelker
left a comment
There was a problem hiding this comment.
This is a great improvement! I have some nits, mostly about comments but all in all this change LGTM. It was also significantly easier to review than I feared, the new file structure is significantly less chaotic (:
Also, thanks for adding all the documentation!
| fn as_node(&self) -> Self::ConcreteLayoutNode; | ||
|
|
||
| /// Returns access to a version of this LayoutElement that can be used by stylo | ||
| /// and selectors. This is dangerous as it allows more access to ancestors nodes |
There was a problem hiding this comment.
- /// and selectors. This is dangerous as it allows more access to ancestors nodes
+ /// and selectors. This is dangerous as it allows more access to ancestor nodes| /// Returns whether this node is a body element of an html element root | ||
| /// in an HTML element document. |
There was a problem hiding this comment.
nit: a Document is not an element (or a HTMLElement)
Suggestion:
- /// Returns whether this node is a body element of an html element root
- /// in an HTML element document.
+ /// Returns whether this node is a `<body>` element of an `<html>` element root
+ /// in an HTML document.| /// # Safety | ||
| /// | ||
| /// This method is unsafe because it modifies the given node during | ||
| /// layout. Callers should ensure that no other layout thread is | ||
| /// attempting to read or modify the opaque layout data of this node. | ||
| fn initialize_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self); |
There was a problem hiding this comment.
The doc comment states that this method is unsafe, but it isn`t.
There was a problem hiding this comment.
I've removed the safety documentation here. As an aside, I am going back and forth about whether all of the methods that mutate the node should be unsafe. Half of them were before, but it's really unclear if it buys us anything. it doesn't make it easier to see if some code is violating the interface anywhere else.
| fn flat_tree_children(&self) -> LayoutIterator<Self::ChildIterator>; | ||
|
|
||
| /// Returns an iterator over this node's children in the DOM. This | ||
| /// *does not* take into account shadow tree children and slottables. |
There was a problem hiding this comment.
hyper-nit about shadow-dom terminology:
- /// *does not* take into account shadow tree children and slottables.
+ /// *does not* take shadow roots and assigned slottables into acccount.There was a problem hiding this comment.
This reads much better.
| /// For that use [`Self::flat_tree_children`]. | ||
| fn dom_children(&self) -> LayoutIterator<Self::ChildIterator>; | ||
|
|
||
| /// Returns a LayoutElement if this is an element in an HTML namespace, None otherwise. |
There was a problem hiding this comment.
- /// Returns a LayoutElement if this is an element in an HTML namespace, None otherwise.
+ /// Returns a LayoutElement if this is an element in the HTML namespace, None otherwise.| pub enabled: bool, | ||
| } | ||
|
|
||
| pub type SharedSelection = std::sync::Arc<AtomicRefCell<ScriptSelection>>; |
| } | ||
|
|
||
| if ThreadSafeLayoutElement::is_root(&element) { | ||
| if LayoutElement::is_root(&element) { |
There was a problem hiding this comment.
can't we call is_root on element directly?
There was a problem hiding this comment.
Oh yes. This was necessary due to the previous design, but can be simplified now. from the previous design. Thanks.
This change reworks the layout DOM wrappers so that they are simpler and easier to reason about. The main changes here: **Combine layout wrappers into one interface:** - `LayoutNode`/`ThreadSafeLayoutNode` is combined into `LayoutNode`: The idea here is that `LayoutNode` is always thread-safe when used in layout as long as no `unsafe` calls are used. These interfaces only expose what is necessary for layout. - `LayoutElement`/`ThreadSafeLayoutElement` is combined into `LayoutElement`: See above. **Expose two new interfaces to be used *only* with `stylo` and `selectors`:** `DangerousStyleNode` and `DangerousStyleElement`. `stylo` and `selectors` have a different way of ensuring safety that is incompatible with Servo's layout (access all of the DOM tree anywhere, but ensure that writing only happens from a single-thread). These types only implement things like `TElement`, `TNode` and are not intended to be used by layout at all. All traits and implementations are moved to files that are named after the struct or trait inside them, in order to better understand what one is looking at. The main goals here are: - Make it easier to reason about the safe use of the DOM APIs. - Remove the interdependencies between the `stylo` and `selectors` interface implementations and the layout interface. This helps with the first point as well and makes it simpler to know where a method is implemented. - Reduce the amount of code. - Make it possible to eliminate `TrustedNodeAddress` in the future. - Document and bring the method naming up to modern Rust conventions. This is a lot of code changes, but is very well tested by the WPT tests. Unfortunately, it is difficult to make a change like this iteratively. In addition, this new design comes with new documentation at servo/book#225. Signed-off-by: Martin Robinson <mrobinson@fastmail.fm>
61335da to
428796e
Compare
mrobinson
left a comment
There was a problem hiding this comment.
Thank you so much for the review @simonwuelker. I know this PR was a bit of a monster, so I highly appreciate it!
| } | ||
|
|
||
| if ThreadSafeLayoutElement::is_root(&element) { | ||
| if LayoutElement::is_root(&element) { |
There was a problem hiding this comment.
Oh yes. This was necessary due to the previous design, but can be simplified now. from the previous design. Thanks.
| /// Returns whether this node is a body element of an html element root | ||
| /// in an HTML element document. |
| /// # Safety | ||
| /// | ||
| /// This method is unsafe because it modifies the given node during | ||
| /// layout. Callers should ensure that no other layout thread is | ||
| /// attempting to read or modify the opaque layout data of this node. | ||
| fn initialize_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self); |
There was a problem hiding this comment.
I've removed the safety documentation here. As an aside, I am going back and forth about whether all of the methods that mutate the node should be unsafe. Half of them were before, but it's really unclear if it buys us anything. it doesn't make it easier to see if some code is violating the interface anywhere else.
| fn flat_tree_children(&self) -> LayoutIterator<Self::ChildIterator>; | ||
|
|
||
| /// Returns an iterator over this node's children in the DOM. This | ||
| /// *does not* take into account shadow tree children and slottables. |
There was a problem hiding this comment.
This reads much better.
This change reworks the layout DOM wrappers so that they are simpler and
easier to reason about. The main changes here:
Combine layout wrappers into one interface:
LayoutNode/ThreadSafeLayoutNodeis combined intoLayoutNode:The idea here is that
LayoutNodeis always thread-safe when used inlayout as long as no
unsafecalls are used. These interfacesonly expose what is necessary for layout.
LayoutElement/ThreadSafeLayoutElementis combined intoLayoutElement: See above.Expose two new interfaces to be used only with
styloandselectors:DangerousStyleNodeandDangerousStyleElement.styloand
selectorshave a different way of ensuring safety that isincompatible with Servo's layout (access all of the DOM tree anywhere,
but ensure that writing only happens from a single-thread). These types
only implement things like
TElement,TNodeand are not intended tobe used by layout at all.
All traits and implementations are moved to files that are named after
the struct or trait inside them, in order to better understand what one
is looking at.
The main goals here are:
styloandselectorsinterface implementations and the layout interface. This helps
with the first point as well and makes it simpler to know where
a method is implemented.
TrustedNodeAddressin the future.This is a lot of code changes, but is very well tested by the WPT tests.
Unfortunately, it is difficult to make a change like this iteratively.
In addition, this new design comes with new documentation at
servo/book#225.
Testing: This should not change behavior so should be covered by existing
WPT tests.