aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Paris <cap@chrisparis.org>2015-03-20 22:37:05 -1000
committerChris Paris <cap@chrisparis.org>2015-04-06 12:54:58 -1000
commit63ced23fca19a75aa02a2d1ba11e1df8cd60ea05 (patch)
tree224998328d226e342ae532afeab3aff7e733eccd
parent3c5c2f416b6a0584758ac98c3d984288cad80aba (diff)
downloadservo-63ced23fca19a75aa02a2d1ba11e1df8cd60ea05.tar.gz
servo-63ced23fca19a75aa02a2d1ba11e1df8cd60ea05.zip
Refactor fragment parsing
-rw-r--r--components/script/dom/element.rs62
-rw-r--r--components/script/dom/node.rs23
-rw-r--r--components/script/parse/html.rs44
3 files changed, 74 insertions, 55 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 544aa918c6d..66ca145d623 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -10,13 +10,11 @@ use dom::attr::AttrValue;
use dom::namednodemap::NamedNodeMap;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
-use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
-use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, ElementDerived, EventTargetCast};
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLInputElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLTableElementCast};
@@ -24,7 +22,6 @@ use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, HTMLTableCel
use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived, HTMLTextAreaElementDerived};
use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast};
use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast;
-use dom::bindings::codegen::InheritTypes::HTMLFormElementDerived;
use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::error::Error;
use dom::bindings::error::Error::{InvalidCharacter, Syntax};
@@ -37,7 +34,6 @@ use dom::create::create_element;
use dom::domrect::DOMRect;
use dom::domrectlist::DOMRectList;
use dom::document::{Document, DocumentHelpers, LayoutDocumentHelpers};
-use dom::document::{DocumentSource, IsHTMLDocument};
use dom::domtokenlist::DOMTokenList;
use dom::event::{Event, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetTypeId};
@@ -55,10 +51,9 @@ use dom::node::{CLICK_IN_PROGRESS, LayoutNodeHelpers, Node, NodeHelpers, NodeTyp
use dom::node::{document_from_node, NodeDamage};
use dom::node::{window_from_node};
use dom::nodelist::NodeList;
-use dom::servohtmlparser::FragmentContext;
use dom::virtualmethods::{VirtualMethods, vtable_for};
use devtools_traits::AttrInfo;
-use parse::html::{HTMLInput, parse_html};
+use parse::html::HTMLInput;
use style::legacy::{SimpleColorAttribute, UnsignedIntegerAttribute, IntegerAttribute, LengthAttribute};
use selectors::matching::matches;
use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, parse_style_attribute};
@@ -1169,61 +1164,20 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
rect.origin.x + rect.size.width)
}
+ // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#extensions-to-the-element-interface
fn GetInnerHTML(self) -> Fallible<DOMString> {
//XXX TODO: XML case
self.serialize(ChildrenOnly)
}
fn SetInnerHTML(self, value: DOMString) -> Fallible<()> {
- let window = window_from_node(self).root();
- let context_document = document_from_node(self).root();
+ // 1. Let fragment be the result of invoking the fragment parsing algorithm
+ // with the new value as markup, and the context object as the context element.
+ // 2. Replace all with fragment within the context object.
let context_node: JSRef<Node> = NodeCast::from_ref(self);
- let url = context_document.r().url();
-
- // Follows https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments
-
- // 1. Create a new Document node, and mark it as being an HTML document.
- let document = Document::new(window.r(), Some(url.clone()),
- IsHTMLDocument::HTMLDocument,
- None, None,
- DocumentSource::FromParser).root();
-
- // 2. If the node document of the context element is in quirks mode,
- // then let the Document be in quirks mode. Otherwise,
- // the node document of the context element is in limited-quirks mode,
- // then let the Document be in limited-quirks mode. Otherwise,
- // leave the Document in no-quirks mode.
- document.r().set_quirks_mode(context_document.r().quirks_mode());
-
- // 11. Set the parser's form element pointer to the nearest node to
- // the context element that is a form element (going straight up
- // the ancestor chain, and including the element itself, if it
- // is a form element), if any. (If there is no such form element,
- // the form element pointer keeps its initial value, null.)
- let form = context_node.inclusive_ancestors()
- .find(|element| element.is_htmlformelement());
- let fragment_context = FragmentContext {
- context_elem: context_node,
- form_elem: form,
- };
- parse_html(document.r(), HTMLInput::InputString(value), &url, Some(fragment_context));
-
- // "14. Return the child nodes of root, in tree order."
- // We do this by deleting all nodes of the context node,
- // and then moving all nodes parsed into the new root_node
- // into the context node.
- while let Some(child) = context_node.GetFirstChild() {
- try!(context_node.RemoveChild(child.root().r()));
- }
- let root_element = document.r().GetDocumentElement().expect("no document element").root();
- let root_node: JSRef<Node> = NodeCast::from_ref(root_element.r());
- while let Some(child) = root_node.GetFirstChild() {
- let child = child.root();
- try!(root_node.RemoveChild(child.r()));
- try!(context_node.AppendChild(child.r()));
- }
-
- Ok(())
+ context_node.parse_fragment(HTMLInput::InputString(value))
+ .and_then(|frag| Ok(Node::replace_all(Some(NodeCast::from_ref(frag.root().r())),
+ context_node)))
}
fn GetOuterHTML(self) -> Fallible<DOMString> {
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 6d69e4cf7e5..9bc8e9879a4 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -46,6 +46,7 @@ use dom::window::{Window, WindowHelpers};
use geom::rect::Rect;
use layout_interface::{LayoutChan, Msg};
use devtools_traits::NodeInfo;
+use parse::html::{HTMLInput, parse_html_fragment};
use script_traits::UntrustedNodeAddress;
use util::geometry::Au;
use util::str::{DOMString, null_str_as_empty};
@@ -502,6 +503,8 @@ pub trait NodeHelpers<'a> {
fn summarize(self) -> NodeInfo;
fn teardown(self);
+
+ fn parse_fragment(self, markup: HTMLInput) -> Fallible<Temporary<DocumentFragment>>;
}
impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
@@ -929,6 +932,24 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
}
}
+ // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#dfn-concept-parse-fragment
+ fn parse_fragment(self, markup: HTMLInput) -> Fallible<Temporary<DocumentFragment>> {
+ let context_node: JSRef<Node> = NodeCast::from_ref(self);
+ let context_document = document_from_node(self).root();
+ let new_children =
+ if context_document.r().is_html_document() {
+ parse_html_fragment(context_node, markup)
+ } else {
+ // FIXME: XML case
+ unimplemented!()
+ };
+ let fragment = DocumentFragment::new(context_document.r()).root();
+ let fragment_node: JSRef<Node> = NodeCast::from_ref(fragment.r());
+ for node in new_children {
+ try!(fragment_node.AppendChild(node.root().r()));
+ }
+ Ok(Temporary::from_rooted(fragment.r()))
+ }
}
/// If the given untrusted node address represents a valid DOM node in the given runtime,
@@ -1456,7 +1477,7 @@ impl Node {
}
// http://dom.spec.whatwg.org/#concept-node-replace-all
- fn replace_all(node: Option<JSRef<Node>>, parent: JSRef<Node>) {
+ pub fn replace_all(node: Option<JSRef<Node>>, parent: JSRef<Node>) {
// Step 1.
match node {
Some(node) => {
diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs
index 794c6824ba8..1667afe288d 100644
--- a/components/script/parse/html.rs
+++ b/components/script/parse/html.rs
@@ -5,18 +5,22 @@
#![allow(unsafe_code, unrooted_must_root)]
use dom::attr::AttrHelpers;
+use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, HTMLScriptElementCast};
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, TextCast, CommentCast};
use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast;
+use dom::bindings::codegen::InheritTypes::HTMLFormElementDerived;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root};
use dom::comment::Comment;
use dom::document::{Document, DocumentHelpers};
+use dom::document::{DocumentSource, IsHTMLDocument};
use dom::documenttype::DocumentType;
use dom::element::{Element, AttributeHandlers, ElementHelpers, ElementCreator};
use dom::htmlscriptelement::HTMLScriptElement;
use dom::htmlscriptelement::HTMLScriptElementHelpers;
use dom::node::{Node, NodeHelpers, NodeTypeId};
+use dom::node::{document_from_node, window_from_node};
use dom::processinginstruction::ProcessingInstruction;
use dom::servohtmlparser;
use dom::servohtmlparser::{ServoHTMLParser, FragmentContext};
@@ -324,3 +328,43 @@ pub fn parse_html(document: JSRef<Document>,
debug!("finished parsing");
}
+
+// https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments
+pub fn parse_html_fragment(context_node: JSRef<Node>, input: HTMLInput) -> Vec<Temporary<Node>> {
+ let window = window_from_node(context_node).root();
+ let context_document = document_from_node(context_node).root();
+ let url = context_document.r().url();
+
+ // 1. Create a new Document node, and mark it as being an HTML document.
+ let document = Document::new(window.r(), Some(url.clone()),
+ IsHTMLDocument::HTMLDocument,
+ None, None,
+ DocumentSource::FromParser).root();
+
+ // 2. If the node document of the context element is in quirks mode,
+ // then let the Document be in quirks mode. Otherwise,
+ // the node document of the context element is in limited-quirks mode,
+ // then let the Document be in limited-quirks mode. Otherwise,
+ // leave the Document in no-quirks mode.
+ document.r().set_quirks_mode(context_document.r().quirks_mode());
+
+ // 11. Set the parser's form element pointer to the nearest node to
+ // the context element that is a form element (going straight up
+ // the ancestor chain, and including the element itself, if it
+ // is a form element), if any. (If there is no such form element,
+ // the form element pointer keeps its initial value, null.)
+ let form = context_node.inclusive_ancestors()
+ .find(|element| element.is_htmlformelement());
+ let fragment_context = FragmentContext {
+ context_elem: context_node,
+ form_elem: form,
+ };
+ parse_html(document.r(), input, &url, Some(fragment_context));
+
+ // "14. Return the child nodes of root, in tree order."
+ let root_element = document.r().GetDocumentElement().expect("no document element").root();
+ let root_node: JSRef<Node> = NodeCast::from_ref(root_element.r());
+ root_node.children()
+ .map(|node| Temporary::from_rooted(node))
+ .collect()
+}