Partial ShadowRoot implementation of DocumentOrShadowRoot

This commit is contained in:
Fernando Jiménez Moreno 2019-01-21 20:58:52 +01:00
parent 18ae0fcbd6
commit 4304ee28dc
9 changed files with 161 additions and 54 deletions

View file

@ -43,6 +43,7 @@ use crate::dom::cssstylesheet::CSSStyleSheet;
use crate::dom::customelementregistry::CustomElementDefinition; use crate::dom::customelementregistry::CustomElementDefinition;
use crate::dom::customevent::CustomEvent; use crate::dom::customevent::CustomEvent;
use crate::dom::documentfragment::DocumentFragment; use crate::dom::documentfragment::DocumentFragment;
use crate::dom::documentorshadowroot::DocumentOrShadowRoot;
use crate::dom::documenttype::DocumentType; use crate::dom::documenttype::DocumentType;
use crate::dom::domimplementation::DOMImplementation; use crate::dom::domimplementation::DOMImplementation;
use crate::dom::element::CustomElementCreationMode; use crate::dom::element::CustomElementCreationMode;
@ -486,16 +487,6 @@ impl Document {
self.has_browsing_context 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] #[inline]
pub fn window(&self) -> &Window { pub fn window(&self) -> &Window {
&*self.window &*self.window
@ -2395,21 +2386,6 @@ impl Document {
!self.has_browsing_context || !url_has_network_scheme(&self.url()) !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> /// <https://html.spec.whatwg.org/multipage/#look-up-a-custom-element-definition>
pub fn lookup_custom_element_definition( pub fn lookup_custom_element_definition(
&self, &self,
@ -3270,6 +3246,8 @@ impl Document {
} }
} }
} }
impl_document_or_shadow_root_helpers!();
} }
impl Element { impl Element {
@ -3300,7 +3278,7 @@ impl ProfilerMetadataFactory for Document {
impl DocumentMethods for Document { impl DocumentMethods for Document {
// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin // 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 // https://dom.spec.whatwg.org/#dom-document-implementation
fn Implementation(&self) -> DomRoot<DOMImplementation> { fn Implementation(&self) -> DomRoot<DOMImplementation> {

View 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>>);
}

View file

@ -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)] #[allow(unsafe_code)]
// https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint
fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> { fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
let x = *x as f32; let x = *x as f32;
let y = *y as f32; let y = *y as f32;
let point = &Point2D::new(x, y); let point = &Point2D::new(x, y);
let window = window_from_node(self); let viewport = self.window.window_size().initial_viewport;
let viewport = window.window_size().initial_viewport;
if self.browsing_context().is_none() { if self.browsing_context().is_none() {
return None; return None;
@ -657,7 +685,7 @@ macro_rules! impl_document_or_shadow_root {
.first() .first()
{ {
Some(address) => { 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 node = unsafe { node::from_untrusted_node_address(js_runtime, *address) };
let parent_node = node.GetParentNode().unwrap(); let parent_node = node.GetParentNode().unwrap();
let element_ref = node let element_ref = node
@ -676,8 +704,7 @@ macro_rules! impl_document_or_shadow_root {
let x = *x as f32; let x = *x as f32;
let y = *y as f32; let y = *y as f32;
let point = &Point2D::new(x, y); let point = &Point2D::new(x, y);
let window = window_from_node(self); let viewport = self.window.window_size().initial_viewport;
let viewport = window.window_size().initial_viewport;
if self.browsing_context().is_none() { if self.browsing_context().is_none() {
return vec![]; return vec![];
@ -688,7 +715,7 @@ macro_rules! impl_document_or_shadow_root {
return vec![]; 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 // Step 1 and Step 3
let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All); 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 // https://drafts.csswg.org/cssom/#dom-document-stylesheets
fn StyleSheets(&self) -> DomRoot<StyleSheetList> { fn StyleSheets(&self) -> DomRoot<StyleSheetList> {
self.stylesheet_list 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))))
} }
) );
} );

View file

@ -280,6 +280,7 @@ pub mod dissimilaroriginlocation;
pub mod dissimilaroriginwindow; pub mod dissimilaroriginwindow;
pub mod document; pub mod document;
pub mod documentfragment; pub mod documentfragment;
pub mod documentorshadowroot;
pub mod documenttype; pub mod documenttype;
pub mod domexception; pub mod domexception;
pub mod domimplementation; pub mod domimplementation;

View file

@ -1560,7 +1560,9 @@ impl Node {
) -> ErrorResult { ) -> ErrorResult {
// Step 1. // Step 1.
match parent.type_id() { match parent.type_id() {
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => (), NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
()
},
_ => return Err(Error::HierarchyRequest), _ => return Err(Error::HierarchyRequest),
} }
@ -2248,7 +2250,9 @@ impl NodeMethods for Node {
fn ReplaceChild(&self, node: &Node, child: &Node) -> Fallible<DomRoot<Node>> { fn ReplaceChild(&self, node: &Node, child: &Node) -> Fallible<DomRoot<Node>> {
// Step 1. // Step 1.
match self.type_id() { match self.type_id() {
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => (), NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
()
},
_ => return Err(Error::HierarchyRequest), _ => return Err(Error::HierarchyRequest),
} }
@ -2351,8 +2355,10 @@ impl NodeMethods for Node {
// Step 12. // Step 12.
rooted_vec!(let mut nodes); rooted_vec!(let mut nodes);
let nodes = if node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || let nodes = if node.type_id() ==
node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) { NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
{
nodes.extend(node.children().map(|node| Dom::from_ref(&*node))); nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
nodes.r() nodes.r()
} else { } else {

View file

@ -764,8 +764,11 @@ impl RangeMethods for Range {
// Step 11 // Step 11
let new_offset = new_offset + let new_offset = new_offset +
if node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || if node.type_id() ==
node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) { NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
node.type_id() ==
NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
{
node.len() node.len()
} else { } else {
1 1
@ -880,7 +883,9 @@ impl RangeMethods for Range {
// Step 2. // Step 2.
match new_parent.type_id() { match new_parent.type_id() {
NodeTypeId::Document(_) | NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => { NodeTypeId::Document(_) |
NodeTypeId::DocumentType |
NodeTypeId::DocumentFragment(_) => {
return Err(Error::InvalidNodeType); return Err(Error::InvalidNodeType);
}, },
_ => (), _ => (),

View file

@ -2,19 +2,36 @@
* 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 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::ShadowRootBinding::ShadowRootMethods;
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootMode; 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::document::Document;
use crate::dom::documentfragment::DocumentFragment;
use crate::dom::documentorshadowroot::DocumentOrShadowRoot;
use crate::dom::element::Element; 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 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 // https://dom.spec.whatwg.org/#interface-shadowroot
#[dom_struct] #[dom_struct]
pub struct ShadowRoot { pub struct ShadowRoot {
document_fragment: DocumentFragment, document_fragment: DocumentFragment,
has_browsing_context: bool,
host: Dom<Element>, host: Dom<Element>,
stylesheet_list: MutNullableDom<StyleSheetList>,
window: Dom<Window>,
} }
impl ShadowRoot { impl ShadowRoot {
@ -22,12 +39,43 @@ impl ShadowRoot {
pub fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { pub fn new_inherited(host: &Element, document: &Document) -> ShadowRoot {
ShadowRoot { ShadowRoot {
document_fragment: DocumentFragment::new_inherited(document), document_fragment: DocumentFragment::new_inherited(document),
has_browsing_context: true,
host: Dom::from_ref(host), 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 { 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 /// https://dom.spec.whatwg.org/#dom-shadowroot-mode
fn Mode(&self) -> ShadowRootMode { fn Mode(&self) -> ShadowRootMode {
ShadowRootMode::Closed ShadowRootMode::Closed

View file

@ -5,8 +5,8 @@
use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding; use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding;
use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding::StyleSheetListMethods; use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding::StyleSheetListMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::DomRoot;
use crate::dom::document::Document; use crate::dom::documentorshadowroot::DocumentOrShadowRoot;
use crate::dom::stylesheet::StyleSheet; use crate::dom::stylesheet::StyleSheet;
use crate::dom::window::Window; use crate::dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
@ -14,22 +14,22 @@ use dom_struct::dom_struct;
#[dom_struct] #[dom_struct]
pub struct StyleSheetList { pub struct StyleSheetList {
reflector_: Reflector, reflector_: Reflector,
document: Dom<Document>, document_or_shadow_root: DocumentOrShadowRoot,
} }
impl StyleSheetList { impl StyleSheetList {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
fn new_inherited(doc: Dom<Document>) -> StyleSheetList { fn new_inherited(doc_or_sr: DocumentOrShadowRoot) -> StyleSheetList {
StyleSheetList { StyleSheetList {
reflector_: Reflector::new(), reflector_: Reflector::new(),
document: doc, document_or_shadow_root: doc_or_sr,
} }
} }
#[allow(unrooted_must_root)] #[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( reflect_dom_object(
Box::new(StyleSheetList::new_inherited(document)), Box::new(StyleSheetList::new_inherited(doc_or_sr)),
window, window,
StyleSheetListBinding::Wrap, StyleSheetListBinding::Wrap,
) )
@ -39,14 +39,14 @@ impl StyleSheetList {
impl StyleSheetListMethods for StyleSheetList { impl StyleSheetListMethods for StyleSheetList {
// https://drafts.csswg.org/cssom/#dom-stylesheetlist-length // https://drafts.csswg.org/cssom/#dom-stylesheetlist-length
fn Length(&self) -> u32 { 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 // https://drafts.csswg.org/cssom/#dom-stylesheetlist-item
fn Item(&self, index: u32) -> Option<DomRoot<StyleSheet>> { fn Item(&self, index: u32) -> Option<DomRoot<StyleSheet>> {
// XXXManishearth this doesn't handle the origin clean flag and is a // XXXManishearth this doesn't handle the origin clean flag and is a
// cors vulnerability // cors vulnerability
self.document self.document_or_shadow_root
.stylesheet_at(index as usize) .stylesheet_at(index as usize)
.map(DomRoot::upcast) .map(DomRoot::upcast)
} }

View file

@ -13,3 +13,5 @@ interface ShadowRoot : DocumentFragment {
}; };
enum ShadowRootMode { "open", "closed"}; enum ShadowRootMode { "open", "closed"};
ShadowRoot implements DocumentOrShadowRoot;