mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Refactor fragment parsing
This commit is contained in:
parent
ea4fbbc63a
commit
03e04179ae
4 changed files with 67 additions and 46 deletions
|
@ -30,6 +30,7 @@ use dom::bindings::xmlname::XMLName::InvalidXMLName;
|
|||
use dom::characterdata::CharacterData;
|
||||
use dom::create::create_element;
|
||||
use dom::document::{Document, LayoutDocumentHelpers};
|
||||
use dom::documentfragment::DocumentFragment;
|
||||
use dom::domrect::DOMRect;
|
||||
use dom::domrectlist::DOMRectList;
|
||||
use dom::domtokenlist::DOMTokenList;
|
||||
|
@ -61,6 +62,7 @@ use dom::node::{CLICK_IN_PROGRESS, ChildrenMutation, LayoutNodeHelpers, Node};
|
|||
use dom::node::{NodeDamage, SEQUENTIALLY_FOCUSABLE, UnbindContext};
|
||||
use dom::node::{document_from_node, window_from_node};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::servoparser::ServoParser;
|
||||
use dom::text::Text;
|
||||
use dom::validation::Validatable;
|
||||
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
||||
|
@ -1230,6 +1232,37 @@ impl Element {
|
|||
// Step 11
|
||||
win.scroll_node(node.to_trusted_node_address(), x, y, behavior);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/DOM-Parsing/#parsing
|
||||
pub fn parse_fragment(&self, markup: DOMString) -> Fallible<Root<DocumentFragment>> {
|
||||
// Steps 1-2.
|
||||
let context_document = document_from_node(self);
|
||||
let new_children = if context_document.is_html_document() {
|
||||
ServoParser::parse_html_fragment(self, markup)
|
||||
} else {
|
||||
// FIXME: XML case
|
||||
unimplemented!()
|
||||
};
|
||||
// Step 3.
|
||||
let fragment = DocumentFragment::new(&context_document);
|
||||
// Step 4.
|
||||
for child in new_children {
|
||||
fragment.upcast::<Node>().AppendChild(&child).unwrap();
|
||||
}
|
||||
// Step 5.
|
||||
Ok(fragment)
|
||||
}
|
||||
|
||||
pub fn fragment_parsing_context(owner_doc: &Document, element: Option<&Self>) -> Root<Self> {
|
||||
match element {
|
||||
Some(elem) if elem.local_name() != &local_name!("html") || !elem.html_element_in_html_document() => {
|
||||
Root::from_ref(elem)
|
||||
},
|
||||
_ => {
|
||||
Root::upcast(HTMLBodyElement::new(local_name!("body"), None, owner_doc))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementMethods for Element {
|
||||
|
@ -1757,15 +1790,14 @@ impl ElementMethods for Element {
|
|||
|
||||
/// https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML
|
||||
fn SetInnerHTML(&self, value: DOMString) -> ErrorResult {
|
||||
let context_node = self.upcast::<Node>();
|
||||
// Step 1.
|
||||
let frag = try!(context_node.parse_fragment(value));
|
||||
let frag = try!(self.parse_fragment(value));
|
||||
// Step 2.
|
||||
// https://github.com/w3c/DOM-Parsing/issues/1
|
||||
let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
|
||||
Root::upcast(template.Content())
|
||||
} else {
|
||||
Root::from_ref(context_node)
|
||||
Root::from_ref(self.upcast())
|
||||
};
|
||||
Node::replace_all(Some(frag.upcast()), &target);
|
||||
Ok(())
|
||||
|
@ -1776,7 +1808,7 @@ impl ElementMethods for Element {
|
|||
self.serialize(IncludeNode)
|
||||
}
|
||||
|
||||
// https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-outerHTML
|
||||
// https://w3c.github.io/DOM-Parsing/#dom-element-outerhtml
|
||||
fn SetOuterHTML(&self, value: DOMString) -> ErrorResult {
|
||||
let context_document = document_from_node(self);
|
||||
let context_node = self.upcast::<Node>();
|
||||
|
@ -1800,7 +1832,7 @@ impl ElementMethods for Element {
|
|||
ElementCreator::ScriptCreated);
|
||||
Root::upcast(body_elem)
|
||||
},
|
||||
_ => context_node.GetParentNode().unwrap()
|
||||
_ => context_node.GetParentElement().unwrap()
|
||||
};
|
||||
|
||||
// Step 5.
|
||||
|
@ -1957,14 +1989,11 @@ impl ElementMethods for Element {
|
|||
};
|
||||
|
||||
// Step 2.
|
||||
let context = match context.downcast::<Element>() {
|
||||
Some(elem) if elem.local_name() != &local_name!("html") ||
|
||||
!elem.html_element_in_html_document() => Root::from_ref(elem),
|
||||
_ => Root::upcast(HTMLBodyElement::new(local_name!("body"), None, &*context.owner_doc())),
|
||||
};
|
||||
let context = Element::fragment_parsing_context(
|
||||
&context.owner_doc(), context.downcast::<Element>());
|
||||
|
||||
// Step 3.
|
||||
let fragment = try!(context.upcast::<Node>().parse_fragment(text));
|
||||
let fragment = try!(context.parse_fragment(text));
|
||||
|
||||
// Step 4.
|
||||
self.insert_adjacent(position, fragment.upcast()).map(|_| ())
|
||||
|
|
|
@ -51,7 +51,6 @@ use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHel
|
|||
use dom::nodelist::NodeList;
|
||||
use dom::processinginstruction::ProcessingInstruction;
|
||||
use dom::range::WeakRangeVec;
|
||||
use dom::servoparser::ServoParser;
|
||||
use dom::svgsvgelement::{SVGSVGElement, LayoutSVGSVGElementHelpers};
|
||||
use dom::text::Text;
|
||||
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
||||
|
@ -799,19 +798,6 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
// https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#dfn-concept-parse-fragment
|
||||
pub fn parse_fragment(&self, markup: DOMString) -> Fallible<Root<DocumentFragment>> {
|
||||
let context_document = document_from_node(self);
|
||||
let fragment = DocumentFragment::new(&context_document);
|
||||
if context_document.is_html_document() {
|
||||
ServoParser::parse_html_fragment(self.upcast(), markup, fragment.upcast());
|
||||
} else {
|
||||
// FIXME: XML case
|
||||
unimplemented!();
|
||||
}
|
||||
Ok(fragment)
|
||||
}
|
||||
|
||||
/// Used by `HTMLTableSectionElement::InsertRow` and `HTMLTableRowElement::InsertCell`
|
||||
pub fn insert_cell_or_row<F, G, I>(&self, index: i32, get_items: F, new_child: G) -> Fallible<Root<HTMLElement>>
|
||||
where F: Fn() -> Root<HTMLCollection>,
|
||||
|
|
|
@ -22,7 +22,6 @@ use dom::characterdata::CharacterData;
|
|||
use dom::document::Document;
|
||||
use dom::documentfragment::DocumentFragment;
|
||||
use dom::element::Element;
|
||||
use dom::htmlbodyelement::HTMLBodyElement;
|
||||
use dom::htmlscriptelement::HTMLScriptElement;
|
||||
use dom::node::{Node, UnbindContext};
|
||||
use dom::text::Text;
|
||||
|
@ -901,6 +900,7 @@ impl RangeMethods for Range {
|
|||
fn CreateContextualFragment(&self, fragment: DOMString) -> Fallible<Root<DocumentFragment>> {
|
||||
// Step 1.
|
||||
let node = self.StartContainer();
|
||||
let owner_doc = node.owner_doc();
|
||||
let element = match node.type_id() {
|
||||
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment => None,
|
||||
NodeTypeId::Element(_) => Some(Root::downcast::<Element>(node).unwrap()),
|
||||
|
@ -911,15 +911,7 @@ impl RangeMethods for Range {
|
|||
};
|
||||
|
||||
// Step 2.
|
||||
let should_create_body = element.as_ref().map_or(true, |elem| {
|
||||
let elem = elem.downcast::<Element>().unwrap();
|
||||
elem.local_name() == &local_name!("html") && elem.html_element_in_html_document()
|
||||
});
|
||||
let element: Root<Node> = if should_create_body {
|
||||
Root::upcast(HTMLBodyElement::new(local_name!("body"), None, &self.StartContainer().owner_doc()))
|
||||
} else {
|
||||
Root::upcast(element.unwrap())
|
||||
};
|
||||
let element = Element::fragment_parsing_context(&owner_doc, element.r());
|
||||
|
||||
// Step 3.
|
||||
let fragment_node = try!(element.parse_fragment(fragment));
|
||||
|
|
|
@ -14,11 +14,12 @@ use dom::bindings::refcounted::Trusted;
|
|||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::document::{Document, DocumentSource, IsHTMLDocument};
|
||||
use dom::element::Element;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::htmlformelement::HTMLFormElement;
|
||||
use dom::htmlimageelement::HTMLImageElement;
|
||||
use dom::htmlscriptelement::HTMLScriptElement;
|
||||
use dom::node::{Node, document_from_node, window_from_node};
|
||||
use dom::node::{Node, NodeSiblingIterator};
|
||||
use encoding::all::UTF_8;
|
||||
use encoding::types::{DecoderTrap, Encoding};
|
||||
use html5ever::tokenizer::buffer_queue::BufferQueue;
|
||||
|
@ -96,17 +97,15 @@ impl ServoParser {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#parsing-html-fragments
|
||||
pub fn parse_html_fragment(
|
||||
context_node: &Node,
|
||||
input: DOMString,
|
||||
output: &Node) {
|
||||
let window = window_from_node(context_node);
|
||||
let context_document = document_from_node(context_node);
|
||||
pub fn parse_html_fragment(context: &Element, input: DOMString) -> FragmentParsingResult {
|
||||
let context_node = context.upcast::<Node>();
|
||||
let context_document = context_node.owner_doc();
|
||||
let window = context_document.window();
|
||||
let url = context_document.url();
|
||||
|
||||
// Step 1.
|
||||
let loader = DocumentLoader::new(&*context_document.loader());
|
||||
let document = Document::new(&window, None, Some(url.clone()),
|
||||
let document = Document::new(window, None, Some(url.clone()),
|
||||
IsHTMLDocument::HTMLDocument,
|
||||
None, None,
|
||||
DocumentSource::FromParser,
|
||||
|
@ -134,9 +133,7 @@ impl ServoParser {
|
|||
|
||||
// Step 14.
|
||||
let root_element = document.GetDocumentElement().expect("no document element");
|
||||
for child in root_element.upcast::<Node>().children() {
|
||||
output.AppendChild(&child).unwrap();
|
||||
}
|
||||
FragmentParsingResult { inner: root_element.upcast::<Node>().children() }
|
||||
}
|
||||
|
||||
pub fn parse_xml_document(
|
||||
|
@ -349,6 +346,23 @@ impl ServoParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FragmentParsingResult {
|
||||
inner: NodeSiblingIterator,
|
||||
}
|
||||
|
||||
impl Iterator for FragmentParsingResult {
|
||||
type Item = Root<Node>;
|
||||
|
||||
fn next(&mut self) -> Option<Root<Node>> {
|
||||
let next = match self.inner.next() {
|
||||
Some(next) => next,
|
||||
None => return None,
|
||||
};
|
||||
next.remove_self();
|
||||
Some(next)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(HeapSizeOf, JSTraceable)]
|
||||
#[must_root]
|
||||
enum Tokenizer {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue