mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Lay out the contents of slot elements (#35220)
* Make Slottable match layout/alignment of NonNull<Node> Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Implement ServoLayoutElement::slotted_nodes Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Bump mozjs Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Layout the contents of slot elements Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Implement ServoLayoutElement::assigned_slot Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * implement ServoLayoutElement::traversal_parent Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Simplify slottable name update Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Don't iterate over children of shadow hosts Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Recompute slot style when contents change Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Change match_slottable to a function instead of a macro Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Fix crown errors Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update WPT expectations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Reset a slottable's assigned slot when it's removed from the slot Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
parent
938baf6bf3
commit
6a2e37183c
26 changed files with 263 additions and 143 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
@ -469,7 +469,7 @@ dependencies = [
|
||||||
"bitflags 2.8.0",
|
"bitflags 2.8.0",
|
||||||
"cexpr",
|
"cexpr",
|
||||||
"clang-sys",
|
"clang-sys",
|
||||||
"itertools 0.13.0",
|
"itertools 0.10.5",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"regex",
|
"regex",
|
||||||
|
@ -1008,7 +1008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1923,7 +1923,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2450,7 +2450,7 @@ dependencies = [
|
||||||
"gobject-sys",
|
"gobject-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"system-deps",
|
"system-deps",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3902,7 +3902,7 @@ checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.4.0",
|
"hermit-abi 0.4.0",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4248,7 +4248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4650,7 +4650,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mozjs"
|
name = "mozjs"
|
||||||
version = "0.14.1"
|
version = "0.14.1"
|
||||||
source = "git+https://github.com/servo/mozjs#0081fc4a3f5fc9891d4377844a874651f7c46041"
|
source = "git+https://github.com/servo/mozjs#87cabf4e9ddf9fafe19713a3d6bc8c5e6105544c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen 0.71.1",
|
"bindgen 0.71.1",
|
||||||
"cc",
|
"cc",
|
||||||
|
@ -4663,7 +4663,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mozjs_sys"
|
name = "mozjs_sys"
|
||||||
version = "0.128.6-1"
|
version = "0.128.6-1"
|
||||||
source = "git+https://github.com/servo/mozjs#0081fc4a3f5fc9891d4377844a874651f7c46041"
|
source = "git+https://github.com/servo/mozjs#87cabf4e9ddf9fafe19713a3d6bc8c5e6105544c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen 0.71.1",
|
"bindgen 0.71.1",
|
||||||
"cc",
|
"cc",
|
||||||
|
@ -6128,7 +6128,7 @@ dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -7430,7 +7430,7 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -8729,7 +8729,7 @@ version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
use html5ever::{local_name, LocalName};
|
use html5ever::{local_name, LocalName};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
@ -464,18 +465,49 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn iter_child_nodes<'dom, Node>(parent: Node) -> impl Iterator<Item = Node>
|
pub enum ChildNodeIterator<Node> {
|
||||||
|
/// Iterating over the children of a node
|
||||||
|
Node(Option<Node>),
|
||||||
|
/// Iterating over the assigned nodes of a `HTMLSlotElement`
|
||||||
|
Slottables(<Vec<Node> as IntoIterator>::IntoIter),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_to_owned)] // Clippy is wrong.
|
||||||
|
pub(crate) fn iter_child_nodes<'dom, Node>(parent: Node) -> ChildNodeIterator<Node>
|
||||||
where
|
where
|
||||||
Node: NodeExt<'dom>,
|
Node: NodeExt<'dom>,
|
||||||
{
|
{
|
||||||
if let Some(shadow) = parent.as_element().and_then(|e| e.shadow_root()) {
|
if let Some(element) = parent.as_element() {
|
||||||
|
if let Some(shadow) = element.shadow_root() {
|
||||||
return iter_child_nodes(shadow.as_node());
|
return iter_child_nodes(shadow.as_node());
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut next = parent.first_child();
|
let slotted_nodes = element.slotted_nodes();
|
||||||
std::iter::from_fn(move || {
|
if !slotted_nodes.is_empty() {
|
||||||
next.inspect(|child| {
|
return ChildNodeIterator::Slottables(slotted_nodes.to_owned().into_iter());
|
||||||
next = child.next_sibling();
|
}
|
||||||
})
|
}
|
||||||
})
|
|
||||||
|
let first = parent.first_child();
|
||||||
|
ChildNodeIterator::Node(first)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'dom, Node> Iterator for ChildNodeIterator<Node>
|
||||||
|
where
|
||||||
|
Node: NodeExt<'dom>,
|
||||||
|
{
|
||||||
|
type Item = Node;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self {
|
||||||
|
Self::Node(node) => {
|
||||||
|
let old = *node;
|
||||||
|
*node = old?.next_sibling();
|
||||||
|
old
|
||||||
|
},
|
||||||
|
Self::Slottables(slots) => slots.next(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'dom, Node> FusedIterator for ChildNodeIterator<Node> where Node: NodeExt<'dom> {}
|
||||||
|
|
|
@ -335,6 +335,7 @@ where
|
||||||
///
|
///
|
||||||
/// This should only be used as a field in other DOM objects.
|
/// This should only be used as a field in other DOM objects.
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub(crate) struct Dom<T> {
|
pub(crate) struct Dom<T> {
|
||||||
ptr: ptr::NonNull<T>,
|
ptr: ptr::NonNull<T>,
|
||||||
}
|
}
|
||||||
|
@ -444,6 +445,7 @@ where
|
||||||
/// An unrooted reference to a DOM object for use in layout. `Layout*Helpers`
|
/// An unrooted reference to a DOM object for use in layout. `Layout*Helpers`
|
||||||
/// traits must be implemented on this.
|
/// traits must be implemented on this.
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub(crate) struct LayoutDom<'dom, T> {
|
pub(crate) struct LayoutDom<'dom, T> {
|
||||||
value: &'dom T,
|
value: &'dom T,
|
||||||
}
|
}
|
||||||
|
|
|
@ -626,8 +626,8 @@ impl Element {
|
||||||
Some(assigned_slot)
|
Some(assigned_slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_assigned_slot(&self, assigned_slot: DomRoot<HTMLSlotElement>) {
|
pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
|
||||||
self.ensure_rare_data().slottable_data.assigned_slot = Some(assigned_slot.as_traced());
|
self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
|
pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
|
||||||
|
@ -727,6 +727,7 @@ pub(crate) trait LayoutElementHelpers<'dom> {
|
||||||
) -> Option<&'dom AttrValue>;
|
) -> Option<&'dom AttrValue>;
|
||||||
fn get_attr_val_for_layout(self, namespace: &Namespace, name: &LocalName) -> Option<&'dom str>;
|
fn get_attr_val_for_layout(self, namespace: &Namespace, name: &LocalName) -> Option<&'dom str>;
|
||||||
fn get_attr_vals_for_layout(self, name: &LocalName) -> Vec<&'dom AttrValue>;
|
fn get_attr_vals_for_layout(self, name: &LocalName) -> Vec<&'dom AttrValue>;
|
||||||
|
fn get_assigned_slot(&self) -> Option<LayoutDom<'dom, HTMLSlotElement>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutDom<'_, Element> {
|
impl LayoutDom<'_, Element> {
|
||||||
|
@ -1260,6 +1261,20 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn get_assigned_slot(&self) -> Option<LayoutDom<'dom, HTMLSlotElement>> {
|
||||||
|
unsafe {
|
||||||
|
self.unsafe_get()
|
||||||
|
.rare_data
|
||||||
|
.borrow_for_layout()
|
||||||
|
.as_ref()?
|
||||||
|
.slottable_data
|
||||||
|
.assigned_slot
|
||||||
|
.as_ref()
|
||||||
|
.map(|slot| slot.to_layout())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element {
|
impl Element {
|
||||||
|
@ -3525,7 +3540,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
|
||||||
|
|
||||||
// > The assignedSlot getter steps are to return the result of
|
// > The assignedSlot getter steps are to return the result of
|
||||||
// > find a slot given this and with the open flag set.
|
// > find a slot given this and with the open flag set.
|
||||||
rooted!(in(*cx) let slottable = Slottable::Element(Dom::from_ref(self)));
|
rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
|
||||||
slottable.find_a_slot(true)
|
slottable.find_a_slot(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3671,7 +3686,8 @@ impl VirtualMethods for Element {
|
||||||
&local_name!("slot") => {
|
&local_name!("slot") => {
|
||||||
// Update slottable data
|
// Update slottable data
|
||||||
let cx = GlobalScope::get_cx();
|
let cx = GlobalScope::get_cx();
|
||||||
rooted!(in(*cx) let slottable = Slottable::Element(Dom::from_ref(self)));
|
|
||||||
|
rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
|
||||||
|
|
||||||
// Slottable name change steps from https://dom.spec.whatwg.org/#light-tree-slotables
|
// Slottable name change steps from https://dom.spec.whatwg.org/#light-tree-slotables
|
||||||
if let Some(assigned_slot) = slottable.assigned_slot() {
|
if let Some(assigned_slot) = slottable.assigned_slot() {
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, Ref, RefCell};
|
||||||
|
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
|
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
|
||||||
use js::gc::{RootedGuard, RootedVec};
|
use js::gc::RootedVec;
|
||||||
use js::rust::HandleObject;
|
use js::rust::HandleObject;
|
||||||
|
|
||||||
use crate::dom::attr::Attr;
|
use crate::dom::attr::Attr;
|
||||||
|
@ -18,6 +18,7 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Bindi
|
||||||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
|
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
|
||||||
ShadowRootMode, SlotAssignmentMode,
|
ShadowRootMode, SlotAssignmentMode,
|
||||||
};
|
};
|
||||||
|
use crate::dom::bindings::codegen::InheritTypes::{CharacterDataTypeId, NodeTypeId};
|
||||||
use crate::dom::bindings::codegen::UnionTypes::ElementOrText;
|
use crate::dom::bindings::codegen::UnionTypes::ElementOrText;
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||||
|
@ -27,7 +28,7 @@ use crate::dom::element::{AttributeMutation, Element};
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::htmlelement::HTMLElement;
|
use crate::dom::htmlelement::HTMLElement;
|
||||||
use crate::dom::mutationobserver::MutationObserver;
|
use crate::dom::mutationobserver::MutationObserver;
|
||||||
use crate::dom::node::{Node, ShadowIncluding};
|
use crate::dom::node::{Node, NodeDamage, ShadowIncluding};
|
||||||
use crate::dom::text::Text;
|
use crate::dom::text::Text;
|
||||||
use crate::dom::virtualmethods::VirtualMethods;
|
use crate::dom::virtualmethods::VirtualMethods;
|
||||||
use crate::script_runtime::CanGc;
|
use crate::script_runtime::CanGc;
|
||||||
|
@ -103,8 +104,8 @@ impl HTMLSlotElementMethods<crate::DomTypeHolder> for HTMLSlotElement {
|
||||||
// Step 3. For each node of nodes:
|
// Step 3. For each node of nodes:
|
||||||
for element_or_text in nodes.into_iter() {
|
for element_or_text in nodes.into_iter() {
|
||||||
rooted!(in(*cx) let node = match element_or_text {
|
rooted!(in(*cx) let node = match element_or_text {
|
||||||
ElementOrText::Element(element) => Slottable::Element(Dom::from_ref(&element)),
|
ElementOrText::Element(element) => Slottable(Dom::from_ref(element.upcast())),
|
||||||
ElementOrText::Text(text) => Slottable::Text(Dom::from_ref(&text)),
|
ElementOrText::Text(text) => Slottable(Dom::from_ref(text.upcast())),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Step 3.1 If node's manual slot assignment refers to a slot,
|
// Step 3.1 If node's manual slot assignment refers to a slot,
|
||||||
|
@ -139,13 +140,17 @@ impl HTMLSlotElementMethods<crate::DomTypeHolder> for HTMLSlotElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://dom.spec.whatwg.org/#concept-slotable>
|
/// <https://dom.spec.whatwg.org/#concept-slotable>
|
||||||
|
///
|
||||||
|
/// The contained node is assumed to be either `Element` or `Text`
|
||||||
|
///
|
||||||
|
/// This field is public to make it easy to construct slottables.
|
||||||
|
/// As such, it is possible to put Nodes that are not slottables
|
||||||
|
/// in there. Using a [Slottable] like this will quickly lead to
|
||||||
|
/// a panic.
|
||||||
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
|
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||||
pub(crate) enum Slottable {
|
#[repr(transparent)]
|
||||||
Element(Dom<Element>),
|
pub(crate) struct Slottable(pub Dom<Node>);
|
||||||
Text(Dom<Text>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Data shared between all [slottables](https://dom.spec.whatwg.org/#concept-slotable)
|
/// Data shared between all [slottables](https://dom.spec.whatwg.org/#concept-slotable)
|
||||||
///
|
///
|
||||||
/// Note that the [slottable name](https://dom.spec.whatwg.org/#slotable-name) is not
|
/// Note that the [slottable name](https://dom.spec.whatwg.org/#slotable-name) is not
|
||||||
|
@ -213,10 +218,13 @@ impl HTMLSlotElement {
|
||||||
// child of slot, in tree order, to slottables.
|
// child of slot, in tree order, to slottables.
|
||||||
if slottables.is_empty() {
|
if slottables.is_empty() {
|
||||||
for child in self.upcast::<Node>().children() {
|
for child in self.upcast::<Node>().children() {
|
||||||
if let Some(element) = child.downcast::<Element>() {
|
let is_slottable = matches!(
|
||||||
slottables.push(Slottable::Element(Dom::from_ref(element)));
|
child.type_id(),
|
||||||
} else if let Some(text) = child.downcast::<Text>() {
|
NodeTypeId::Element(_) |
|
||||||
slottables.push(Slottable::Text(Dom::from_ref(text)));
|
NodeTypeId::CharacterData(CharacterDataTypeId::Text(_))
|
||||||
|
);
|
||||||
|
if is_slottable {
|
||||||
|
slottables.push(Slottable(child.as_traced()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,12 +232,7 @@ impl HTMLSlotElement {
|
||||||
// Step 5. For each node in slottables:
|
// Step 5. For each node in slottables:
|
||||||
for slottable in slottables.iter() {
|
for slottable in slottables.iter() {
|
||||||
// Step 5.1 If node is a slot whose root is a shadow root:
|
// Step 5.1 If node is a slot whose root is a shadow root:
|
||||||
// NOTE: Only elements can be slots
|
match slottable.0.downcast::<HTMLSlotElement>() {
|
||||||
let maybe_slot_element = match &slottable {
|
|
||||||
Slottable::Element(element) => element.downcast::<HTMLSlotElement>(),
|
|
||||||
Slottable::Text(_) => None,
|
|
||||||
};
|
|
||||||
match maybe_slot_element {
|
|
||||||
Some(slot_element)
|
Some(slot_element)
|
||||||
if slot_element
|
if slot_element
|
||||||
.upcast::<Node>()
|
.upcast::<Node>()
|
||||||
|
@ -291,7 +294,14 @@ impl HTMLSlotElement {
|
||||||
}
|
}
|
||||||
// Step 6. Otherwise, for each slottable child slottable of host, in tree order:
|
// Step 6. Otherwise, for each slottable child slottable of host, in tree order:
|
||||||
else {
|
else {
|
||||||
let mut for_slottable = |slottable: RootedGuard<Slottable>| {
|
for child in host.upcast::<Node>().children() {
|
||||||
|
let is_slottable = matches!(
|
||||||
|
child.type_id(),
|
||||||
|
NodeTypeId::Element(_) |
|
||||||
|
NodeTypeId::CharacterData(CharacterDataTypeId::Text(_))
|
||||||
|
);
|
||||||
|
if is_slottable {
|
||||||
|
rooted!(in(*cx) let slottable = Slottable(child.as_traced()));
|
||||||
// Step 6.1 Let foundSlot be the result of finding a slot given slottable.
|
// Step 6.1 Let foundSlot be the result of finding a slot given slottable.
|
||||||
let found_slot = slottable.find_a_slot(false);
|
let found_slot = slottable.find_a_slot(false);
|
||||||
|
|
||||||
|
@ -299,16 +309,6 @@ impl HTMLSlotElement {
|
||||||
if found_slot.is_some_and(|found_slot| &*found_slot == self) {
|
if found_slot.is_some_and(|found_slot| &*found_slot == self) {
|
||||||
result.push(slottable.clone());
|
result.push(slottable.clone());
|
||||||
}
|
}
|
||||||
};
|
|
||||||
for child in host.upcast::<Node>().children() {
|
|
||||||
if let Some(element) = child.downcast::<Element>() {
|
|
||||||
rooted!(in(*cx) let slottable = Slottable::Element(Dom::from_ref(element)));
|
|
||||||
for_slottable(slottable);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(text) = child.downcast::<Text>() {
|
|
||||||
rooted!(in(*cx) let slottable = Slottable::Text(Dom::from_ref(text)));
|
|
||||||
for_slottable(slottable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,17 +329,26 @@ impl HTMLSlotElement {
|
||||||
self.signal_a_slot_change();
|
self.signal_a_slot_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: This is not written in the spec, which is likely a bug (https://github.com/whatwg/dom/issues/1352)
|
||||||
|
// If we don't disconnect the old slottables from this slot then they'll stay implictly
|
||||||
|
// connected, which causes problems later on
|
||||||
|
for slottable in self.assigned_nodes().iter() {
|
||||||
|
slottable.set_assigned_slot(None);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 3. Set slot’s assigned nodes to slottables.
|
// Step 3. Set slot’s assigned nodes to slottables.
|
||||||
*self.assigned_nodes.borrow_mut() = slottables.iter().cloned().collect();
|
*self.assigned_nodes.borrow_mut() = slottables.iter().cloned().collect();
|
||||||
|
|
||||||
// Step 4. For each slottable in slottables, set slottable’s assigned slot to slot.
|
// Step 4. For each slottable in slottables, set slottable’s assigned slot to slot.
|
||||||
for slottable in slottables.iter() {
|
for slottable in slottables.iter() {
|
||||||
slottable.set_assigned_slot(DomRoot::from_ref(self));
|
slottable.set_assigned_slot(Some(self));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://dom.spec.whatwg.org/#signal-a-slot-change>
|
/// <https://dom.spec.whatwg.org/#signal-a-slot-change>
|
||||||
pub(crate) fn signal_a_slot_change(&self) {
|
pub(crate) fn signal_a_slot_change(&self) {
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
|
||||||
if self.is_in_agents_signal_slots.get() {
|
if self.is_in_agents_signal_slots.get() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -356,6 +365,12 @@ impl HTMLSlotElement {
|
||||||
debug_assert!(self.is_in_agents_signal_slots.get());
|
debug_assert!(self.is_in_agents_signal_slots.get());
|
||||||
self.is_in_agents_signal_slots.set(false);
|
self.is_in_agents_signal_slots.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the slot's assigned nodes if the root's slot assignment mode
|
||||||
|
/// is "named", or the manually assigned nodes otherwise
|
||||||
|
pub(crate) fn assigned_nodes(&self) -> Ref<'_, [Slottable]> {
|
||||||
|
Ref::map(self.assigned_nodes.borrow(), Vec::as_slice)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Slottable {
|
impl Slottable {
|
||||||
|
@ -418,16 +433,13 @@ impl Slottable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node(&self) -> &Node {
|
fn node(&self) -> &Node {
|
||||||
match self {
|
&self.0
|
||||||
Self::Element(element) => element.upcast(),
|
|
||||||
Self::Text(text) => text.upcast(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
|
pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
|
||||||
match self {
|
self.match_slottable(
|
||||||
Self::Element(element) => element.assigned_slot(),
|
|element: &Element| element.assigned_slot(),
|
||||||
Self::Text(text) => {
|
|text: &Text| {
|
||||||
let assigned_slot = text
|
let assigned_slot = text
|
||||||
.slottable_data()
|
.slottable_data()
|
||||||
.borrow()
|
.borrow()
|
||||||
|
@ -436,51 +448,72 @@ impl Slottable {
|
||||||
.as_rooted();
|
.as_rooted();
|
||||||
Some(assigned_slot)
|
Some(assigned_slot)
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_assigned_slot(&self, assigned_slot: DomRoot<HTMLSlotElement>) {
|
pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
|
||||||
match self {
|
self.match_slottable(
|
||||||
Self::Element(element) => element.set_assigned_slot(assigned_slot),
|
|element: &Element| element.set_assigned_slot(assigned_slot),
|
||||||
Self::Text(text) => {
|
|text: &Text| {
|
||||||
text.slottable_data().borrow_mut().assigned_slot = Some(assigned_slot.as_traced())
|
text.slottable_data().borrow_mut().assigned_slot = assigned_slot.map(Dom::from_ref);
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_manual_slot_assignment(
|
pub(crate) fn set_manual_slot_assignment(
|
||||||
&self,
|
&self,
|
||||||
manually_assigned_slot: Option<&HTMLSlotElement>,
|
manually_assigned_slot: Option<&HTMLSlotElement>,
|
||||||
) {
|
) {
|
||||||
match self {
|
self.match_slottable(
|
||||||
Self::Element(element) => element.set_manual_slot_assignment(manually_assigned_slot),
|
|element: &Element| element.set_manual_slot_assignment(manually_assigned_slot),
|
||||||
Self::Text(text) => {
|
|text: &Text| {
|
||||||
text.slottable_data().borrow_mut().manual_slot_assignment =
|
text.slottable_data().borrow_mut().manual_slot_assignment =
|
||||||
manually_assigned_slot.map(Dom::from_ref)
|
manually_assigned_slot.map(Dom::from_ref)
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
|
pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
|
||||||
match self {
|
self.match_slottable(
|
||||||
Self::Element(element) => element.manual_slot_assignment(),
|
|element: &Element| element.manual_slot_assignment(),
|
||||||
Self::Text(text) => text
|
|text: &Text| {
|
||||||
.slottable_data()
|
text.slottable_data()
|
||||||
.borrow()
|
.borrow()
|
||||||
.manual_slot_assignment
|
.manual_slot_assignment
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(Dom::as_rooted),
|
.map(Dom::as_rooted)
|
||||||
}
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(&self) -> DOMString {
|
fn name(&self) -> DOMString {
|
||||||
// NOTE: Only elements have non-empty names
|
// NOTE: Only elements have non-empty names
|
||||||
let Self::Element(element) = self else {
|
let Some(element) = self.0.downcast::<Element>() else {
|
||||||
return DOMString::new();
|
return DOMString::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
element.get_string_attribute(&local_name!("slot"))
|
element.get_string_attribute(&local_name!("slot"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the `element_function` if the slottable is an Element, otherwise the
|
||||||
|
/// `text_function`
|
||||||
|
pub(crate) fn match_slottable<E, T, R>(&self, element_function: E, text_function: T) -> R
|
||||||
|
where
|
||||||
|
E: FnOnce(&Element) -> R,
|
||||||
|
T: FnOnce(&Text) -> R,
|
||||||
|
{
|
||||||
|
match self.0.type_id() {
|
||||||
|
NodeTypeId::Element(_) => {
|
||||||
|
let element: &Element = self.0.downcast::<Element>().unwrap();
|
||||||
|
element_function(element)
|
||||||
|
},
|
||||||
|
NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
|
||||||
|
let text: &Text = self.0.downcast::<Text>().unwrap();
|
||||||
|
text_function(text)
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualMethods for HTMLSlotElement {
|
impl VirtualMethods for HTMLSlotElement {
|
||||||
|
|
|
@ -2155,12 +2155,8 @@ impl Node {
|
||||||
if let Some(shadow_root) = parent.downcast::<Element>().and_then(Element::shadow_root) {
|
if let Some(shadow_root) = parent.downcast::<Element>().and_then(Element::shadow_root) {
|
||||||
if shadow_root.SlotAssignment() == SlotAssignmentMode::Named {
|
if shadow_root.SlotAssignment() == SlotAssignmentMode::Named {
|
||||||
let cx = GlobalScope::get_cx();
|
let cx = GlobalScope::get_cx();
|
||||||
if let Some(element) = node.downcast::<Element>() {
|
if node.is::<Element>() || node.is::<Text>() {
|
||||||
rooted!(in(*cx) let slottable = Slottable::Element(Dom::from_ref(element)));
|
rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(node)));
|
||||||
slottable.assign_a_slot();
|
|
||||||
}
|
|
||||||
if let Some(text) = node.downcast::<Text>() {
|
|
||||||
rooted!(in(*cx) let slottable = Slottable::Text(Dom::from_ref(text)));
|
|
||||||
slottable.assign_a_slot();
|
slottable.assign_a_slot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ impl TextMethods<crate::DomTypeHolder> for Text {
|
||||||
|
|
||||||
// > The assignedSlot getter steps are to return the result of
|
// > The assignedSlot getter steps are to return the result of
|
||||||
// > find a slot given this and with the open flag set.
|
// > find a slot given this and with the open flag set.
|
||||||
rooted!(in(*cx) let slottable = Slottable::Text(Dom::from_ref(self)));
|
rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
|
||||||
slottable.find_a_slot(true)
|
slottable.find_a_slot(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
use std::{fmt, slice};
|
||||||
|
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
||||||
use html5ever::{local_name, namespace_url, ns, LocalName, Namespace};
|
use html5ever::{local_name, namespace_url, ns, LocalName, Namespace};
|
||||||
|
@ -40,12 +40,13 @@ use style_dom::ElementState;
|
||||||
|
|
||||||
use crate::dom::attr::AttrHelpersForLayout;
|
use crate::dom::attr::AttrHelpersForLayout;
|
||||||
use crate::dom::bindings::inheritance::{
|
use crate::dom::bindings::inheritance::{
|
||||||
CharacterDataTypeId, DocumentFragmentTypeId, ElementTypeId, HTMLElementTypeId, NodeTypeId,
|
Castable, CharacterDataTypeId, DocumentFragmentTypeId, ElementTypeId, HTMLElementTypeId,
|
||||||
TextTypeId,
|
NodeTypeId, TextTypeId,
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::root::LayoutDom;
|
use crate::dom::bindings::root::LayoutDom;
|
||||||
use crate::dom::characterdata::LayoutCharacterDataHelpers;
|
use crate::dom::characterdata::LayoutCharacterDataHelpers;
|
||||||
use crate::dom::element::{Element, LayoutElementHelpers};
|
use crate::dom::element::{Element, LayoutElementHelpers};
|
||||||
|
use crate::dom::htmlslotelement::HTMLSlotElement;
|
||||||
use crate::dom::node::{LayoutNodeHelpers, Node, NodeFlags};
|
use crate::dom::node::{LayoutNodeHelpers, Node, NodeFlags};
|
||||||
use crate::layout_dom::{ServoLayoutNode, ServoShadowRoot, ServoThreadSafeLayoutNode};
|
use crate::layout_dom::{ServoLayoutNode, ServoShadowRoot, ServoThreadSafeLayoutNode};
|
||||||
|
|
||||||
|
@ -138,26 +139,77 @@ impl<'dom> ServoLayoutElement<'dom> {
|
||||||
Some(node) => matches!(node.script_type_id(), NodeTypeId::Document(_)),
|
Some(node) => matches!(node.script_type_id(), NodeTypeId::Document(_)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assigned_slot(&self) -> Option<Self> {
|
||||||
|
let slot = self.element.get_assigned_slot()?;
|
||||||
|
Some(Self::from_layout_js(slot.upcast()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum DOMDescendantIterator<E>
|
||||||
|
where
|
||||||
|
E: TElement,
|
||||||
|
{
|
||||||
|
/// Iterating over the children of a node, including children of a potential
|
||||||
|
/// [ShadowRoot](crate::dom::shadow_root::ShadowRoot)
|
||||||
|
Children(DomChildren<E::ConcreteNode>),
|
||||||
|
/// Iterating over the content's of a [`<slot>`](HTMLSlotElement) element.
|
||||||
|
Slottables { slot: E, index: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> Iterator for DOMDescendantIterator<E>
|
||||||
|
where
|
||||||
|
E: TElement,
|
||||||
|
{
|
||||||
|
type Item = E::ConcreteNode;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self {
|
||||||
|
Self::Children(children) => children.next(),
|
||||||
|
Self::Slottables { slot, index } => {
|
||||||
|
let slottables = slot.slotted_nodes();
|
||||||
|
let slot = slottables.get(*index)?;
|
||||||
|
*index += 1;
|
||||||
|
Some(*slot)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'dom> style::dom::TElement for ServoLayoutElement<'dom> {
|
impl<'dom> style::dom::TElement for ServoLayoutElement<'dom> {
|
||||||
type ConcreteNode = ServoLayoutNode<'dom>;
|
type ConcreteNode = ServoLayoutNode<'dom>;
|
||||||
type TraversalChildrenIterator = DomChildren<Self::ConcreteNode>;
|
type TraversalChildrenIterator = DOMDescendantIterator<Self>;
|
||||||
|
|
||||||
fn as_node(&self) -> ServoLayoutNode<'dom> {
|
fn as_node(&self) -> ServoLayoutNode<'dom> {
|
||||||
ServoLayoutNode::from_layout_js(self.element.upcast())
|
ServoLayoutNode::from_layout_js(self.element.upcast())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn traversal_children(&self) -> LayoutIterator<Self::TraversalChildrenIterator> {
|
fn traversal_children(&self) -> LayoutIterator<Self::TraversalChildrenIterator> {
|
||||||
let iterator = if let Some(shadow_root) = self.shadow_root() {
|
let iterator = if self.slotted_nodes().is_empty() {
|
||||||
|
let children = if let Some(shadow_root) = self.shadow_root() {
|
||||||
shadow_root.as_node().dom_children()
|
shadow_root.as_node().dom_children()
|
||||||
} else {
|
} else {
|
||||||
self.as_node().dom_children()
|
self.as_node().dom_children()
|
||||||
};
|
};
|
||||||
|
DOMDescendantIterator::Children(children)
|
||||||
|
} else {
|
||||||
|
DOMDescendantIterator::Slottables {
|
||||||
|
slot: *self,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
LayoutIterator(iterator)
|
LayoutIterator(iterator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn traversal_parent(&self) -> Option<Self> {
|
||||||
|
if let Some(assigned_slot) = self.assigned_slot() {
|
||||||
|
Some(assigned_slot)
|
||||||
|
} else {
|
||||||
|
self.as_node().traversal_parent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_html_element(&self) -> bool {
|
fn is_html_element(&self) -> bool {
|
||||||
ServoLayoutElement::is_html_element(self)
|
ServoLayoutElement::is_html_element(self)
|
||||||
}
|
}
|
||||||
|
@ -457,6 +509,24 @@ impl<'dom> style::dom::TElement for ServoLayoutElement<'dom> {
|
||||||
servo_layout_node.as_element().unwrap()
|
servo_layout_node.as_element().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
|
||||||
|
let Some(slot_element) = self.element.unsafe_get().downcast::<HTMLSlotElement>() else {
|
||||||
|
return &[];
|
||||||
|
};
|
||||||
|
let assigned_nodes = slot_element.assigned_nodes();
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// Self::ConcreteNode (aka ServoLayoutNode) and Slottable are guaranteed to have the same
|
||||||
|
// layout and alignment as ptr::NonNull<T>. Lifetimes are not an issue because the
|
||||||
|
// slottables are being kept alive by the slot element.
|
||||||
|
unsafe {
|
||||||
|
slice::from_raw_parts(
|
||||||
|
assigned_nodes.as_ptr() as *const Self::ConcreteNode,
|
||||||
|
assigned_nodes.len(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
|
impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
|
||||||
|
@ -670,7 +740,12 @@ impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_html_slot_element(&self) -> bool {
|
fn is_html_slot_element(&self) -> bool {
|
||||||
self.element.is_html_element() && self.local_name() == &local_name!("slot")
|
self.element.is::<HTMLSlotElement>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn assigned_slot(&self) -> Option<Self> {
|
||||||
|
self.assigned_slot()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_html_element_in_html_document(&self) -> bool {
|
fn is_html_element_in_html_document(&self) -> bool {
|
||||||
|
|
|
@ -45,6 +45,7 @@ use crate::dom::text::Text;
|
||||||
/// should only be used on a single thread. If you need to use nodes across
|
/// should only be used on a single thread. If you need to use nodes across
|
||||||
/// threads use ServoThreadSafeLayoutNode.
|
/// threads use ServoThreadSafeLayoutNode.
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct ServoLayoutNode<'dom> {
|
pub struct ServoLayoutNode<'dom> {
|
||||||
/// The wrapped private DOM node.
|
/// The wrapped private DOM node.
|
||||||
pub(super) node: LayoutDom<'dom, Node>,
|
pub(super) node: LayoutDom<'dom, Node>,
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[quotes-slot-scoping.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[display-contents-slot-attach-whitespace.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[counter-slot-order-scoping.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[counter-slot-order.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[text-decoration-propagation-shadow.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[remove-slotted-with-whitespace-sibling.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[2d.text-outside-of-the-flat-tree.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,7 +1,4 @@
|
||||||
[DocumentOrShadowRoot-prototype-elementFromPoint.html]
|
[DocumentOrShadowRoot-prototype-elementFromPoint.html]
|
||||||
[document.elementFromPoint and shadowRoot.elementFromPoint must return the shadow host when the hit-tested text node is assigned to a slot and the host has display: inline]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[document.elementFromPoint and shadowRoot.elementFromPoint must return the element assigned to a slot when hit-tested text node under an element is assigned to a slot in the shadow tree and the shadow host of the slot has display: block]
|
[document.elementFromPoint and shadowRoot.elementFromPoint must return the element assigned to a slot when hit-tested text node under an element is assigned to a slot in the shadow tree and the shadow host of the slot has display: block]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
2
tests/wpt/meta/shadow-dom/focus/focus-pseudo-on-shadow-host-2.html.ini
vendored
Normal file
2
tests/wpt/meta/shadow-dom/focus/focus-pseudo-on-shadow-host-2.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[focus-pseudo-on-shadow-host-2.html]
|
||||||
|
expected: FAIL
|
|
@ -1,6 +0,0 @@
|
||||||
[imperative-slot-fallback-clear.html]
|
|
||||||
[Text node fallback should be cleared in a subsequently layout]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element fallback should be cleared in a subsequent layout]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[imperative-slot-layout-invalidation-001.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[layout-slot-no-longer-fallback.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[slot-fallback-content-001.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[slot-fallback-content-002.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[slot-fallback-content-007.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[reprojection-001.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[shadow-root-002.html]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue