Skip to content

Commit 9b4f780

Browse files
committed
servo: Merge #7531 - Implement <template> (from nox:template); r=Ms2ger
All tests using iframes can't currently pass, same for innerHTML-related tests with <template> elements. The latter contradicts the spec, see the links below. Apart from this, they work, AFAICT. servo/html5ever#164 https://www.w3.org/Bugs/Public/show_bug.cgi?id=27314 Source-Repo: https://github.com/servo/servo Source-Revision: 5a0be12e43f92fc64b1d8f5d35f9dadaa4b53521 UltraBlame original commit: f773205ecd62d34bff8f4c6325ef72b5841266f5
1 parent 7b79893 commit 9b4f780

File tree

10 files changed

+144
-42
lines changed

10 files changed

+144
-42
lines changed

servo/components/script/dom/document.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ pub struct Document {
155155
reflow_timeout: Cell<Option<u64>>,
156156

157157
base_element: MutNullableHeap<JS<HTMLBaseElement>>,
158+
159+
160+
appropriate_template_contents_owner_document: MutNullableHeap<JS<Document>>,
158161
}
159162

160163
impl PartialEq for Document {
@@ -1058,6 +1061,7 @@ impl Document {
10581061
current_parser: Default::default(),
10591062
reflow_timeout: Cell::new(None),
10601063
base_element: Default::default(),
1064+
appropriate_template_contents_owner_document: Default::default(),
10611065
}
10621066
}
10631067

@@ -1106,6 +1110,23 @@ impl Document {
11061110
.and_then(HTMLHtmlElementCast::to_ref)
11071111
.map(Root::from_ref)
11081112
}
1113+
1114+
/// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document
1115+
pub fn appropriate_template_contents_owner_document(&self) -> Root<Document> {
1116+
self.appropriate_template_contents_owner_document.or_init(|| {
1117+
let doctype = if self.is_html_document {
1118+
IsHTMLDocument::HTMLDocument
1119+
} else {
1120+
IsHTMLDocument::NonHTMLDocument
1121+
};
1122+
let new_doc = Document::new(
1123+
&*self.window(), None, doctype, None, None,
1124+
DocumentSource::NotFromParser, DocumentLoader::new(&self.loader()));
1125+
new_doc.appropriate_template_contents_owner_document.set(
1126+
Some(JS::from_ref(&*new_doc)));
1127+
new_doc
1128+
})
1129+
}
11091130
}
11101131

11111132

servo/components/script/dom/element.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,18 @@ use dom::bindings::codegen::Bindings::ElementBinding;
1313
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
1414
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
1515
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
16+
use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
1617
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
1718
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
18-
use dom::bindings::codegen::InheritTypes::CharacterDataCast;
19-
use dom::bindings::codegen::InheritTypes::DocumentDerived;
20-
use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast;
21-
use dom::bindings::codegen::InheritTypes::TextCast;
22-
use dom::bindings::codegen::InheritTypes::{ElementCast, ElementDerived, EventTargetCast};
19+
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, DocumentDerived, ElementCast};
20+
use dom::bindings::codegen::InheritTypes::{ElementDerived, EventTargetCast, HTMLAnchorElementCast};
2321
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLFontElementDerived};
2422
use dom::bindings::codegen::InheritTypes::{HTMLIFrameElementDerived, HTMLInputElementCast};
2523
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLTableElementCast};
2624
use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, HTMLTableCellElementDerived};
27-
use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived, HTMLTextAreaElementDerived};
28-
use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast};
25+
use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived, HTMLTableSectionElementDerived};
26+
use dom::bindings::codegen::InheritTypes::{HTMLTemplateElementCast, HTMLTextAreaElementDerived};
27+
use dom::bindings::codegen::InheritTypes::{NodeCast, TextCast};
2928
use dom::bindings::codegen::UnionTypes::NodeOrString;
3029
use dom::bindings::error::Error::NoModificationAllowed;
3130
use dom::bindings::error::Error::{InvalidCharacter, Syntax};
@@ -1280,19 +1279,25 @@ impl ElementMethods for Element {
12801279
node.get_client_rect().size.height
12811280
}
12821281

1283-
// https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-innerHTML
1282+
/// https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML
12841283
fn GetInnerHTML(&self) -> Fallible<DOMString> {
12851284
//XXX TODO: XML case
12861285
self.serialize(ChildrenOnly)
12871286
}
12881287

1289-
// https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-innerHTML
1288+
/// https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML
12901289
fn SetInnerHTML(&self, value: DOMString) -> Fallible<()> {
12911290
let context_node = NodeCast::from_ref(self);
12921291
// Step 1.
12931292
let frag = try!(context_node.parse_fragment(value));
12941293
// Step 2.
1295-
Node::replace_all(Some(NodeCast::from_ref(frag.r())), context_node);
1294+
// https://github.com/w3c/DOM-Parsing/issues/1
1295+
let target = if let Some(template) = HTMLTemplateElementCast::to_ref(self) {
1296+
NodeCast::from_root(template.Content())
1297+
} else {
1298+
Root::from_ref(context_node)
1299+
};
1300+
Node::replace_all(Some(NodeCast::from_ref(&*frag)), &target);
12961301
Ok(())
12971302
}
12981303

servo/components/script/dom/htmltemplateelement.rs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,28 @@
22

33

44

5+
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
56
use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding;
6-
use dom::bindings::codegen::InheritTypes::HTMLTemplateElementDerived;
7-
use dom::bindings::js::Root;
7+
use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
8+
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
9+
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTemplateElementCast};
10+
use dom::bindings::codegen::InheritTypes::{HTMLTemplateElementDerived, NodeCast};
11+
use dom::bindings::js::{JS, MutNullableHeap, Root};
812
use dom::document::Document;
13+
use dom::documentfragment::DocumentFragment;
914
use dom::element::ElementTypeId;
1015
use dom::eventtarget::{EventTarget, EventTargetTypeId};
1116
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
12-
use dom::node::{Node, NodeTypeId};
17+
use dom::node::{CloneChildrenFlag, Node, NodeTypeId, document_from_node};
18+
use dom::virtualmethods::VirtualMethods;
1319
use util::str::DOMString;
1420

1521
#[dom_struct]
1622
pub struct HTMLTemplateElement {
1723
htmlelement: HTMLElement,
24+
25+
26+
contents: MutNullableHeap<JS<DocumentFragment>>,
1827
}
1928

2029
impl HTMLTemplateElementDerived for EventTarget {
@@ -31,7 +40,8 @@ impl HTMLTemplateElement {
3140
document: &Document) -> HTMLTemplateElement {
3241
HTMLTemplateElement {
3342
htmlelement:
34-
HTMLElement::new_inherited(HTMLElementTypeId::HTMLTemplateElement, localName, prefix, document)
43+
HTMLElement::new_inherited(HTMLElementTypeId::HTMLTemplateElement, localName, prefix, document),
44+
contents: MutNullableHeap::new(None),
3545
}
3646
}
3747

@@ -43,3 +53,47 @@ impl HTMLTemplateElement {
4353
Node::reflect_node(box element, document, HTMLTemplateElementBinding::Wrap)
4454
}
4555
}
56+
57+
impl HTMLTemplateElementMethods for HTMLTemplateElement {
58+
59+
fn Content(&self) -> Root<DocumentFragment> {
60+
self.contents.or_init(|| {
61+
let doc = document_from_node(self);
62+
doc.appropriate_template_contents_owner_document().CreateDocumentFragment()
63+
})
64+
}
65+
}
66+
67+
impl VirtualMethods for HTMLTemplateElement {
68+
fn super_type(&self) -> Option<&VirtualMethods> {
69+
Some(HTMLElementCast::from_ref(self) as &VirtualMethods)
70+
}
71+
72+
73+
fn adopting_steps(&self, old_doc: &Document) {
74+
self.super_type().unwrap().adopting_steps(old_doc);
75+
76+
let doc = document_from_node(self).appropriate_template_contents_owner_document();
77+
78+
Node::adopt(NodeCast::from_ref(&*self.Content()), &doc);
79+
}
80+
81+
82+
fn cloning_steps(&self, copy: &Node, maybe_doc: Option<&Document>,
83+
clone_children: CloneChildrenFlag) {
84+
self.super_type().unwrap().cloning_steps(copy, maybe_doc, clone_children);
85+
if clone_children == CloneChildrenFlag::DoNotCloneChildren {
86+
87+
return;
88+
}
89+
let copy = HTMLTemplateElementCast::to_ref(copy).unwrap();
90+
91+
let copy_contents = NodeCast::from_root(copy.Content());
92+
let copy_contents_doc = copy_contents.owner_doc();
93+
for child in NodeCast::from_root(self.Content()).children() {
94+
let copy_child = Node::clone(
95+
&child, Some(&copy_contents_doc), CloneChildrenFlag::CloneChildren);
96+
copy_contents.AppendChild(&copy_child).unwrap();
97+
}
98+
}
99+
}

servo/components/script/dom/node.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,24 +1415,19 @@ impl Node {
14151415

14161416
pub fn adopt(node: &Node, document: &Document) {
14171417

1418-
let parent_node = node.GetParentNode();
1419-
match parent_node {
1420-
Some(ref parent) => {
1421-
Node::remove(node, parent, SuppressObserver::Unsuppressed);
1422-
}
1423-
None => (),
1424-
}
1425-
1418+
let old_doc = node.owner_doc();
14261419

1427-
let node_doc = document_from_node(node);
1428-
if node_doc.r() != document {
1420+
node.remove_self();
1421+
if &*old_doc != document {
1422+
1423+
for descendant in node.traverse_preorder() {
1424+
descendant.set_owner_doc(document);
1425+
}
1426+
14291427
for descendant in node.traverse_preorder() {
1430-
descendant.r().set_owner_doc(document);
1428+
vtable_for(&descendant).adopting_steps(&old_doc);
14311429
}
14321430
}
1433-
1434-
1435-
14361431
}
14371432

14381433

servo/components/script/dom/virtualmethods.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast;
3030
use dom::bindings::codegen::InheritTypes::HTMLTableElementCast;
3131
use dom::bindings::codegen::InheritTypes::HTMLTableRowElementCast;
3232
use dom::bindings::codegen::InheritTypes::HTMLTableSectionElementCast;
33+
use dom::bindings::codegen::InheritTypes::HTMLTemplateElementCast;
3334
use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast;
3435
use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast;
3536
use dom::document::Document;
@@ -99,6 +100,13 @@ pub trait VirtualMethods {
99100
}
100101

101102

103+
fn adopting_steps(&self, old_doc: &Document) {
104+
if let Some(ref s) = self.super_type() {
105+
s.adopting_steps(old_doc);
106+
}
107+
}
108+
109+
102110
fn cloning_steps(&self, copy: &Node, maybe_doc: Option<&Document>,
103111
clone_children: CloneChildrenFlag) {
104112
if let Some(ref s) = self.super_type() {
@@ -216,6 +224,9 @@ pub fn vtable_for<'a>(node: &'a Node) -> &'a (VirtualMethods + 'a) {
216224
HTMLTableSectionElementCast::to_ref(node).unwrap();
217225
element as &'a (VirtualMethods + 'a)
218226
}
227+
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTemplateElement)) => {
228+
HTMLTemplateElementCast::to_ref(node).unwrap() as &'a (VirtualMethods + 'a)
229+
}
219230
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) => {
220231
let element = HTMLTextAreaElementCast::to_ref(node).unwrap();
221232
element as &'a (VirtualMethods + 'a)

servo/components/script/dom/webidls/HTMLTemplateElement.webidl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55

66
// https://www.whatwg.org/html/#htmltemplateelement
77
interface HTMLTemplateElement : HTMLElement {
8-
//readonly attribute DocumentFragment content;
8+
readonly attribute DocumentFragment content;
99
};

servo/components/script/parse/html.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66

77
use document_loader::DocumentLoader;
88
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
9+
use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
910
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
10-
use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast;
1111
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, DocumentTypeCast};
12-
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLScriptElementCast};
13-
use dom::bindings::codegen::InheritTypes::{HTMLFormElementDerived, NodeCast};
12+
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFormElementDerived};
13+
use dom::bindings::codegen::InheritTypes::{HTMLScriptElementCast, HTMLTemplateElementCast};
14+
use dom::bindings::codegen::InheritTypes::{NodeCast, ProcessingInstructionCast};
1415
use dom::bindings::js::{JS, Root};
1516
use dom::bindings::js::{RootedReference};
1617
use dom::characterdata::CharacterDataTypeId;
@@ -43,12 +44,20 @@ use util::str::DOMString;
4344

4445
impl<'a> TreeSink for servohtmlparser::Sink {
4546
type Handle = JS<Node>;
47+
4648
fn get_document(&mut self) -> JS<Node> {
4749
let doc = self.document.root();
4850
let node = NodeCast::from_ref(doc.r());
4951
JS::from_ref(node)
5052
}
5153

54+
fn get_template_contents(&self, target: JS<Node>) -> JS<Node> {
55+
let target = target.root();
56+
let template = HTMLTemplateElementCast::to_ref(&*target)
57+
.expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing");
58+
JS::from_ref(NodeCast::from_ref(&*template.Content()))
59+
}
60+
5261
fn same_node(&self, x: JS<Node>, y: JS<Node>) -> bool {
5362
x == y
5463
}
@@ -194,7 +203,14 @@ impl<'a> Serializable for &'a Node {
194203
try!(serializer.start_elem(name.clone(), attr_refs));
195204
}
196205

197-
for handle in node.children() {
206+
let children = if let Some(tpl) = HTMLTemplateElementCast::to_ref(node) {
207+
208+
NodeCast::from_ref(&*tpl.Content()).children()
209+
} else {
210+
node.children()
211+
};
212+
213+
for handle in children {
198214
try!(handle.r().serialize(serializer, IncludeNode));
199215
}
200216

servo/components/servo/Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

servo/ports/cef/Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

servo/ports/gonk/Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)