mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Partial ShadowRoot implementation of DocumentOrShadowRoot
This commit is contained in:
parent
18ae0fcbd6
commit
4304ee28dc
9 changed files with 161 additions and 54 deletions
|
@ -43,6 +43,7 @@ use crate::dom::cssstylesheet::CSSStyleSheet;
|
|||
use crate::dom::customelementregistry::CustomElementDefinition;
|
||||
use crate::dom::customevent::CustomEvent;
|
||||
use crate::dom::documentfragment::DocumentFragment;
|
||||
use crate::dom::documentorshadowroot::DocumentOrShadowRoot;
|
||||
use crate::dom::documenttype::DocumentType;
|
||||
use crate::dom::domimplementation::DOMImplementation;
|
||||
use crate::dom::element::CustomElementCreationMode;
|
||||
|
@ -486,16 +487,6 @@ impl Document {
|
|||
self.has_browsing_context
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#concept-document-bc>
|
||||
#[inline]
|
||||
pub fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
|
||||
if self.has_browsing_context {
|
||||
self.window.undiscarded_window_proxy()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn window(&self) -> &Window {
|
||||
&*self.window
|
||||
|
@ -2395,21 +2386,6 @@ impl Document {
|
|||
!self.has_browsing_context || !url_has_network_scheme(&self.url())
|
||||
}
|
||||
|
||||
pub fn nodes_from_point(
|
||||
&self,
|
||||
client_point: &Point2D<f32>,
|
||||
reflow_goal: NodesFromPointQueryType,
|
||||
) -> Vec<UntrustedNodeAddress> {
|
||||
if !self
|
||||
.window
|
||||
.layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal))
|
||||
{
|
||||
return vec![];
|
||||
};
|
||||
|
||||
self.window.layout().nodes_from_point_response()
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#look-up-a-custom-element-definition>
|
||||
pub fn lookup_custom_element_definition(
|
||||
&self,
|
||||
|
@ -3270,6 +3246,8 @@ impl Document {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_document_or_shadow_root_helpers!();
|
||||
}
|
||||
|
||||
impl Element {
|
||||
|
@ -3300,7 +3278,7 @@ impl ProfilerMetadataFactory for Document {
|
|||
|
||||
impl DocumentMethods for Document {
|
||||
// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin
|
||||
impl_document_or_shadow_root!();
|
||||
impl_document_or_shadow_root_methods!(Document);
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-document-implementation
|
||||
fn Implementation(&self) -> DomRoot<DOMImplementation> {
|
||||
|
|
40
components/script/dom/documentorshadowroot.rs
Normal file
40
components/script/dom/documentorshadowroot.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::cssstylesheet::CSSStyleSheet;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::shadowroot::ShadowRoot;
|
||||
|
||||
macro_rules! proxy_call(
|
||||
($fn_name:ident, $return_type:ty) => (
|
||||
pub fn $fn_name(&self) -> $return_type {
|
||||
match self {
|
||||
DocumentOrShadowRoot::Document(doc) => doc.$fn_name(),
|
||||
DocumentOrShadowRoot::ShadowRoot(root) => root.$fn_name(),
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => (
|
||||
pub fn $fn_name(&self, $arg1: $arg1_type) -> $return_type {
|
||||
match self {
|
||||
DocumentOrShadowRoot::Document(doc) => doc.$fn_name($arg1),
|
||||
DocumentOrShadowRoot::ShadowRoot(root) => root.$fn_name($arg1),
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
#[must_root]
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
pub enum DocumentOrShadowRoot {
|
||||
Document(Dom<Document>),
|
||||
ShadowRoot(Dom<ShadowRoot>),
|
||||
}
|
||||
|
||||
impl DocumentOrShadowRoot {
|
||||
proxy_call!(stylesheet_count, usize);
|
||||
proxy_call!(stylesheet_at, index, usize, Option<DomRoot<CSSStyleSheet>>);
|
||||
}
|
|
@ -633,16 +633,44 @@ macro_rules! handle_potential_webgl_error {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_document_or_shadow_root {
|
||||
macro_rules! impl_document_or_shadow_root_helpers(
|
||||
() => (
|
||||
/// <https://html.spec.whatwg.org/multipage/#concept-document-bc>
|
||||
#[inline]
|
||||
pub fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
|
||||
if self.has_browsing_context {
|
||||
self.window.undiscarded_window_proxy()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nodes_from_point(
|
||||
&self,
|
||||
client_point: &Point2D<f32>,
|
||||
reflow_goal: NodesFromPointQueryType,
|
||||
) -> Vec<UntrustedNodeAddress> {
|
||||
if !self
|
||||
.window
|
||||
.layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal))
|
||||
{
|
||||
return vec![];
|
||||
};
|
||||
|
||||
self.window.layout().nodes_from_point_response()
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
macro_rules! impl_document_or_shadow_root_methods(
|
||||
($struct:ident) => (
|
||||
#[allow(unsafe_code)]
|
||||
// https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint
|
||||
fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
|
||||
let x = *x as f32;
|
||||
let y = *y as f32;
|
||||
let point = &Point2D::new(x, y);
|
||||
let window = window_from_node(self);
|
||||
let viewport = window.window_size().initial_viewport;
|
||||
let viewport = self.window.window_size().initial_viewport;
|
||||
|
||||
if self.browsing_context().is_none() {
|
||||
return None;
|
||||
|
@ -657,7 +685,7 @@ macro_rules! impl_document_or_shadow_root {
|
|||
.first()
|
||||
{
|
||||
Some(address) => {
|
||||
let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) };
|
||||
let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) };
|
||||
let node = unsafe { node::from_untrusted_node_address(js_runtime, *address) };
|
||||
let parent_node = node.GetParentNode().unwrap();
|
||||
let element_ref = node
|
||||
|
@ -676,8 +704,7 @@ macro_rules! impl_document_or_shadow_root {
|
|||
let x = *x as f32;
|
||||
let y = *y as f32;
|
||||
let point = &Point2D::new(x, y);
|
||||
let window = window_from_node(self);
|
||||
let viewport = window.window_size().initial_viewport;
|
||||
let viewport = self.window.window_size().initial_viewport;
|
||||
|
||||
if self.browsing_context().is_none() {
|
||||
return vec![];
|
||||
|
@ -688,7 +715,7 @@ macro_rules! impl_document_or_shadow_root {
|
|||
return vec![];
|
||||
}
|
||||
|
||||
let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) };
|
||||
let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) };
|
||||
|
||||
// Step 1 and Step 3
|
||||
let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All);
|
||||
|
@ -730,7 +757,7 @@ macro_rules! impl_document_or_shadow_root {
|
|||
// https://drafts.csswg.org/cssom/#dom-document-stylesheets
|
||||
fn StyleSheets(&self) -> DomRoot<StyleSheetList> {
|
||||
self.stylesheet_list
|
||||
.or_init(|| StyleSheetList::new(&self.window, Dom::from_ref(&self)))
|
||||
.or_init(|| StyleSheetList::new(&self.window, DocumentOrShadowRoot::$struct(Dom::from_ref(self))))
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
);
|
||||
|
|
|
@ -280,6 +280,7 @@ pub mod dissimilaroriginlocation;
|
|||
pub mod dissimilaroriginwindow;
|
||||
pub mod document;
|
||||
pub mod documentfragment;
|
||||
pub mod documentorshadowroot;
|
||||
pub mod documenttype;
|
||||
pub mod domexception;
|
||||
pub mod domimplementation;
|
||||
|
|
|
@ -1560,7 +1560,9 @@ impl Node {
|
|||
) -> ErrorResult {
|
||||
// Step 1.
|
||||
match parent.type_id() {
|
||||
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => (),
|
||||
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
|
||||
()
|
||||
},
|
||||
_ => return Err(Error::HierarchyRequest),
|
||||
}
|
||||
|
||||
|
@ -2248,7 +2250,9 @@ impl NodeMethods for Node {
|
|||
fn ReplaceChild(&self, node: &Node, child: &Node) -> Fallible<DomRoot<Node>> {
|
||||
// Step 1.
|
||||
match self.type_id() {
|
||||
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => (),
|
||||
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
|
||||
()
|
||||
},
|
||||
_ => return Err(Error::HierarchyRequest),
|
||||
}
|
||||
|
||||
|
@ -2351,8 +2355,10 @@ impl NodeMethods for Node {
|
|||
|
||||
// Step 12.
|
||||
rooted_vec!(let mut nodes);
|
||||
let nodes = if node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
|
||||
node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) {
|
||||
let nodes = if node.type_id() ==
|
||||
NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
|
||||
node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
|
||||
{
|
||||
nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
|
||||
nodes.r()
|
||||
} else {
|
||||
|
|
|
@ -764,8 +764,11 @@ impl RangeMethods for Range {
|
|||
|
||||
// Step 11
|
||||
let new_offset = new_offset +
|
||||
if node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
|
||||
node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) {
|
||||
if node.type_id() ==
|
||||
NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
|
||||
node.type_id() ==
|
||||
NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
|
||||
{
|
||||
node.len()
|
||||
} else {
|
||||
1
|
||||
|
@ -880,7 +883,9 @@ impl RangeMethods for Range {
|
|||
|
||||
// Step 2.
|
||||
match new_parent.type_id() {
|
||||
NodeTypeId::Document(_) | NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => {
|
||||
NodeTypeId::Document(_) |
|
||||
NodeTypeId::DocumentType |
|
||||
NodeTypeId::DocumentFragment(_) => {
|
||||
return Err(Error::InvalidNodeType);
|
||||
},
|
||||
_ => (),
|
||||
|
|
|
@ -2,19 +2,36 @@
|
|||
* 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/. */
|
||||
|
||||
use crate::dom::documentfragment::DocumentFragment;
|
||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootMode;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
|
||||
use crate::dom::cssstylesheet::CSSStyleSheet;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::documentfragment::DocumentFragment;
|
||||
use crate::dom::documentorshadowroot::DocumentOrShadowRoot;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::node;
|
||||
use crate::dom::stylesheetlist::StyleSheetList;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::windowproxy::WindowProxy;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::Point2D;
|
||||
use js::jsapi::JS_GetRuntime;
|
||||
use script_layout_interface::message::{NodesFromPointQueryType, QueryMsg};
|
||||
use script_traits::UntrustedNodeAddress;
|
||||
|
||||
// https://dom.spec.whatwg.org/#interface-shadowroot
|
||||
#[dom_struct]
|
||||
pub struct ShadowRoot {
|
||||
document_fragment: DocumentFragment,
|
||||
has_browsing_context: bool,
|
||||
host: Dom<Element>,
|
||||
stylesheet_list: MutNullableDom<StyleSheetList>,
|
||||
window: Dom<Window>,
|
||||
}
|
||||
|
||||
impl ShadowRoot {
|
||||
|
@ -22,12 +39,43 @@ impl ShadowRoot {
|
|||
pub fn new_inherited(host: &Element, document: &Document) -> ShadowRoot {
|
||||
ShadowRoot {
|
||||
document_fragment: DocumentFragment::new_inherited(document),
|
||||
has_browsing_context: true,
|
||||
host: Dom::from_ref(host),
|
||||
stylesheet_list: MutNullableDom::new(None),
|
||||
window: Dom::from_ref(document.window()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_focused_element(&self) -> Option<DomRoot<Element>> {
|
||||
//XXX get retargeted focused element
|
||||
None
|
||||
}
|
||||
|
||||
pub fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn stylesheet_count(&self) -> usize {
|
||||
//XXX handle shadowroot stylesheets
|
||||
0
|
||||
}
|
||||
|
||||
pub fn stylesheet_at(&self, _index: usize) -> Option<DomRoot<CSSStyleSheet>> {
|
||||
//XXX handle shadowroot stylesheets
|
||||
None
|
||||
}
|
||||
|
||||
impl_document_or_shadow_root_helpers!();
|
||||
}
|
||||
|
||||
impl ShadowRootMethods for ShadowRoot {
|
||||
/// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin
|
||||
impl_document_or_shadow_root_methods!(ShadowRoot);
|
||||
|
||||
/// https://dom.spec.whatwg.org/#dom-shadowroot-mode
|
||||
fn Mode(&self) -> ShadowRootMode {
|
||||
ShadowRootMode::Closed
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding;
|
||||
use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding::StyleSheetListMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::documentorshadowroot::DocumentOrShadowRoot;
|
||||
use crate::dom::stylesheet::StyleSheet;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
|
@ -14,22 +14,22 @@ use dom_struct::dom_struct;
|
|||
#[dom_struct]
|
||||
pub struct StyleSheetList {
|
||||
reflector_: Reflector,
|
||||
document: Dom<Document>,
|
||||
document_or_shadow_root: DocumentOrShadowRoot,
|
||||
}
|
||||
|
||||
impl StyleSheetList {
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(doc: Dom<Document>) -> StyleSheetList {
|
||||
fn new_inherited(doc_or_sr: DocumentOrShadowRoot) -> StyleSheetList {
|
||||
StyleSheetList {
|
||||
reflector_: Reflector::new(),
|
||||
document: doc,
|
||||
document_or_shadow_root: doc_or_sr,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, document: Dom<Document>) -> DomRoot<StyleSheetList> {
|
||||
pub fn new(window: &Window, doc_or_sr: DocumentOrShadowRoot) -> DomRoot<StyleSheetList> {
|
||||
reflect_dom_object(
|
||||
Box::new(StyleSheetList::new_inherited(document)),
|
||||
Box::new(StyleSheetList::new_inherited(doc_or_sr)),
|
||||
window,
|
||||
StyleSheetListBinding::Wrap,
|
||||
)
|
||||
|
@ -39,14 +39,14 @@ impl StyleSheetList {
|
|||
impl StyleSheetListMethods for StyleSheetList {
|
||||
// https://drafts.csswg.org/cssom/#dom-stylesheetlist-length
|
||||
fn Length(&self) -> u32 {
|
||||
self.document.stylesheet_count() as u32
|
||||
self.document_or_shadow_root.stylesheet_count() as u32
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#dom-stylesheetlist-item
|
||||
fn Item(&self, index: u32) -> Option<DomRoot<StyleSheet>> {
|
||||
// XXXManishearth this doesn't handle the origin clean flag and is a
|
||||
// cors vulnerability
|
||||
self.document
|
||||
self.document_or_shadow_root
|
||||
.stylesheet_at(index as usize)
|
||||
.map(DomRoot::upcast)
|
||||
}
|
||||
|
|
|
@ -13,3 +13,5 @@ interface ShadowRoot : DocumentFragment {
|
|||
};
|
||||
|
||||
enum ShadowRootMode { "open", "closed"};
|
||||
|
||||
ShadowRoot implements DocumentOrShadowRoot;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue