Don't require passing a root element to Document::new (needed for issue #888).

This commit is contained in:
Ms2ger 2013-10-05 21:42:13 +02:00
parent f13438d012
commit c93d13b0da
4 changed files with 183 additions and 127 deletions

View file

@ -76,6 +76,12 @@ impl AbstractDocument {
_ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument") _ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument")
} }
} }
pub fn set_root(&mut self, root: AbstractNode<ScriptView>) {
self.with_mut_base(|document| {
document.set_root(root);
});
}
} }
pub enum DocumentType { pub enum DocumentType {
@ -85,7 +91,7 @@ pub enum DocumentType {
} }
pub struct Document { pub struct Document {
root: AbstractNode<ScriptView>, root: Option<AbstractNode<ScriptView>>,
wrapper: WrapperCache, wrapper: WrapperCache,
window: Option<@mut Window>, window: Option<@mut Window>,
doctype: DocumentType, doctype: DocumentType,
@ -94,9 +100,9 @@ pub struct Document {
impl Document { impl Document {
#[fixed_stack_segment] #[fixed_stack_segment]
pub fn new(root: AbstractNode<ScriptView>, window: Option<@mut Window>, doctype: DocumentType) -> Document { pub fn new(window: Option<@mut Window>, doctype: DocumentType) -> Document {
Document { Document {
root: root, root: None,
wrapper: WrapperCache::new(), wrapper: WrapperCache::new(),
window: window, window: window,
doctype: doctype, doctype: doctype,
@ -104,14 +110,22 @@ impl Document {
} }
} }
pub fn set_root(&mut self, root: AbstractNode<ScriptView>) {
self.root = Some(root);
}
pub fn Constructor(owner: @mut Window) -> Fallible<AbstractDocument> { pub fn Constructor(owner: @mut Window) -> Fallible<AbstractDocument> {
let cx = owner.page.js_info.get_ref().js_compartment.cx.ptr;
let mut document = AbstractDocument::as_abstract(cx, @mut Document::new(None, XML));
let root = @HTMLHtmlElement { let root = @HTMLHtmlElement {
htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html") htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html")
}; };
let cx = owner.page.js_info.get_ref().js_compartment.cx.ptr;
let root = unsafe { Node::as_abstract_node(cx, root) }; let root = unsafe { Node::as_abstract_node(cx, root) };
Ok(AbstractDocument::as_abstract(cx, @mut Document::new(root, None, XML))) document.set_root(root);
Ok(document)
} }
} }
@ -208,7 +222,7 @@ impl Document {
} }
pub fn GetDocumentElement(&self) -> Option<AbstractNode<ScriptView>> { pub fn GetDocumentElement(&self) -> Option<AbstractNode<ScriptView>> {
Some(self.root) self.root
} }
fn get_cx(&self) -> *JSContext { fn get_cx(&self) -> *JSContext {
@ -288,20 +302,25 @@ impl Document {
fail!("no SVG document yet") fail!("no SVG document yet")
}, },
_ => { _ => {
let _ = for node in self.root.traverse_preorder() { match self.root {
if node.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) { None => {},
loop; Some(root) => {
} let _ = for node in root.traverse_preorder() {
for child in node.children() { if node.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) {
if child.is_text() { loop;
do child.with_imm_text() |text| {
let s = text.element.Data();
title = title + null_str_as_empty(&s);
} }
} for child in node.children() {
if child.is_text() {
do child.with_imm_text() |text| {
let s = text.element.Data();
title = title + null_str_as_empty(&s);
}
}
}
break;
};
} }
break; }
};
} }
} }
let v: ~[&str] = title.word_iter().collect(); let v: ~[&str] = title.word_iter().collect();
@ -317,34 +336,39 @@ impl Document {
}, },
_ => { _ => {
let (_scope, cx) = self.get_scope_and_cx(); let (_scope, cx) = self.get_scope_and_cx();
let _ = for node in self.root.traverse_preorder() { match self.root {
if node.type_id() != ElementNodeTypeId(HTMLHeadElementTypeId) { None => {},
loop; Some(root) => {
} let _ = for node in root.traverse_preorder() {
let mut has_title = false; if node.type_id() != ElementNodeTypeId(HTMLHeadElementTypeId) {
for child in node.children() { loop;
if child.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) { }
loop; let mut has_title = false;
} for child in node.children() {
has_title = true; if child.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) {
for title_child in child.children() { loop;
child.remove_child(title_child); }
} has_title = true;
child.add_child(self.CreateTextNode(title)); for title_child in child.children() {
break; child.remove_child(title_child);
} }
if !has_title { child.add_child(self.CreateTextNode(title));
let new_title = @HTMLTitleElement { break;
htmlelement: HTMLElement::new(HTMLTitleElementTypeId, ~"title") }
if !has_title {
let new_title = @HTMLTitleElement {
htmlelement: HTMLElement::new(HTMLTitleElementTypeId, ~"title")
};
let new_title = unsafe {
Node::as_abstract_node(cx, new_title)
};
new_title.add_child(self.CreateTextNode(title));
node.add_child(new_title);
}
break;
}; };
let new_title = unsafe {
Node::as_abstract_node(cx, new_title)
};
new_title.add_child(self.CreateTextNode(title));
node.add_child(new_title);
} }
break; }
};
} }
} }
Ok(()) Ok(())
@ -440,15 +464,20 @@ impl Document {
pub fn createHTMLCollection(&self, callback: &fn(elem: &Element) -> bool) -> @mut HTMLCollection { pub fn createHTMLCollection(&self, callback: &fn(elem: &Element) -> bool) -> @mut HTMLCollection {
let mut elements = ~[]; let mut elements = ~[];
let _ = for child in self.root.traverse_preorder() { match self.root {
if child.is_element() { None => {},
do child.with_imm_element |elem| { Some(root) => {
if callback(elem) { let _ = for child in root.traverse_preorder() {
elements.push(child); if child.is_element() {
do child.with_imm_element |elem| {
if callback(elem) {
elements.push(child);
}
}
} }
} };
} }
}; }
let (scope, cx) = self.get_scope_and_cx(); let (scope, cx) = self.get_scope_and_cx();
HTMLCollection::new(elements, cx, scope) HTMLCollection::new(elements, cx, scope)
} }
@ -469,16 +498,21 @@ impl Document {
impl Traceable for Document { impl Traceable for Document {
#[fixed_stack_segment] #[fixed_stack_segment]
fn trace(&self, tracer: *mut JSTracer) { fn trace(&self, tracer: *mut JSTracer) {
unsafe { match self.root {
(*tracer).debugPrinter = ptr::null(); None => {},
(*tracer).debugPrintIndex = -1; Some(root) => {
do "root".to_c_str().with_ref |name| { unsafe {
(*tracer).debugPrintArg = name as *libc::c_void; (*tracer).debugPrinter = ptr::null();
debug!("tracing root node"); (*tracer).debugPrintIndex = -1;
do self.root.with_base |node| { do "root".to_c_str().with_ref |name| {
JS_CallTracer(tracer as *JSTracer, (*tracer).debugPrintArg = name as *libc::c_void;
node.wrapper.wrapper, debug!("tracing root node");
JSTRACE_OBJECT as u32); do root.with_base |node| {
JS_CallTracer(tracer as *JSTracer,
node.wrapper.wrapper,
JSTRACE_OBJECT as u32);
}
}
} }
} }
} }

View file

@ -41,26 +41,26 @@ impl DOMParser {
_s: &DOMString, _s: &DOMString,
ty: DOMParserBinding::SupportedType) ty: DOMParserBinding::SupportedType)
-> Fallible<AbstractDocument> { -> Fallible<AbstractDocument> {
unsafe { let cx = (*self.owner.page).js_info.get_ref().js_compartment.cx.ptr;
let root = @HTMLHtmlElement { let mut document = match ty {
htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html") Text_html => {
}; HTMLDocument::new(None)
let root = Node::as_abstract_node((*self.owner.page).js_info.get_ref().js_compartment.cx.ptr, root);
let cx = (*self.owner.page).js_info.get_ref().js_compartment.cx.ptr;
match ty {
Text_html => {
Ok(HTMLDocument::new(root, None))
}
Text_xml => {
Ok(AbstractDocument::as_abstract(cx, @mut Document::new(root, None, XML)))
}
_ => {
fail!("unsupported document type")
}
} }
} Text_xml => {
AbstractDocument::as_abstract(cx, @mut Document::new(None, XML))
}
_ => {
fail!("unsupported document type")
}
};
let root = @HTMLHtmlElement {
htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html")
};
let root = unsafe { Node::as_abstract_node(cx, root) };
document.set_root(root);
Ok(document)
} }
} }

View file

@ -24,9 +24,9 @@ pub struct HTMLDocument {
} }
impl HTMLDocument { impl HTMLDocument {
pub fn new(root: AbstractNode<ScriptView>, window: Option<@mut Window>) -> AbstractDocument { pub fn new(window: Option<@mut Window>) -> AbstractDocument {
let doc = @mut HTMLDocument { let doc = @mut HTMLDocument {
parent: Document::new(root, window, HTML) parent: Document::new(window, HTML)
}; };
let compartment = window.get_ref().page.js_info.get_ref().js_compartment; let compartment = window.get_ref().page.js_info.get_ref().js_compartment;
@ -70,14 +70,19 @@ impl HTMLDocument {
} }
pub fn GetHead(&self) -> Option<AbstractNode<ScriptView>> { pub fn GetHead(&self) -> Option<AbstractNode<ScriptView>> {
let mut headNode: Option<AbstractNode<ScriptView>> = None; match self.parent.root {
let _ = for child in self.parent.root.traverse_preorder() { None => None,
if child.type_id() == ElementNodeTypeId(HTMLHeadElementTypeId) { Some(root) => {
headNode = Some(child); let mut headNode: Option<AbstractNode<ScriptView>> = None;
break; let _ = for child in root.traverse_preorder() {
if child.type_id() == ElementNodeTypeId(HTMLHeadElementTypeId) {
headNode = Some(child);
break;
}
};
headNode
} }
}; }
headNode
} }
pub fn Images(&self) -> @mut HTMLCollection { pub fn Images(&self) -> @mut HTMLCollection {

View file

@ -217,20 +217,26 @@ impl<'self> Iterator<@mut Page> for PageTreeIterator<'self> {
impl Page { impl Page {
/// Adds the given damage. /// Adds the given damage.
fn damage(&mut self, level: DocumentDamageLevel) { fn damage(&mut self, level: DocumentDamageLevel) {
match self.damage { let root = do self.frame.get_ref().document.with_base |doc| { doc.root };
None => {} match root {
Some(ref mut damage) => { None => {},
// FIXME(pcwalton): This is wrong. We should trace up to the nearest ancestor. Some(root) => {
damage.root = do self.frame.get_ref().document.with_base |doc| { doc.root }; match self.damage {
damage.level.add(level); None => {}
return Some(ref mut damage) => {
} // FIXME(pcwalton): This is wrong. We should trace up to the nearest ancestor.
} damage.root = root;
damage.level.add(level);
return
}
}
self.damage = Some(DocumentDamage { self.damage = Some(DocumentDamage {
root: do self.frame.get_ref().document.with_base |doc| { doc.root }, root: root,
level: level, level: level,
}) })
}
};
} }
/// Sends a ping to layout and waits for the response. The response will arrive when the /// Sends a ping to layout and waits for the response. The response will arrive when the
@ -269,27 +275,34 @@ impl Page {
/// ///
/// This function fails if there is no root frame. /// This function fails if there is no root frame.
fn reflow(&mut self, goal: ReflowGoal, script_chan: ScriptChan, compositor: @ScriptListener) { fn reflow(&mut self, goal: ReflowGoal, script_chan: ScriptChan, compositor: @ScriptListener) {
let root = match self.frame {
debug!("script: performing reflow for goal %?", goal);
// Now, join the layout so that they will see the latest changes we have made.
self.join_layout();
// Tell the user that we're performing layout.
compositor.set_ready_state(PerformingLayout);
// Layout will let us know when it's done.
let (join_port, join_chan) = comm::stream();
self.layout_join_port = Some(join_port);
self.last_reflow_id += 1;
match self.frame {
None => fail!(~"Tried to relayout with no root frame!"), None => fail!(~"Tried to relayout with no root frame!"),
Some(ref frame) => { Some(ref frame) => {
do frame.document.with_base |doc| {
doc.root
}
}
};
match root {
None => {},
Some(root) => {
debug!("script: performing reflow for goal %?", goal);
// Now, join the layout so that they will see the latest changes we have made.
self.join_layout();
// Tell the user that we're performing layout.
compositor.set_ready_state(PerformingLayout);
// Layout will let us know when it's done.
let (join_port, join_chan) = comm::stream();
self.layout_join_port = Some(join_port);
self.last_reflow_id += 1;
// Send new document and relevant styles to layout. // Send new document and relevant styles to layout.
let reflow = ~Reflow { let reflow = ~Reflow {
document_root: do frame.document.with_base |doc| { doc.root }, document_root: root,
url: self.url.get_ref().first().clone(), url: self.url.get_ref().first().clone(),
goal: goal, goal: goal,
window_size: self.window_size.get(), window_size: self.window_size.get(),
@ -299,11 +312,11 @@ impl Page {
id: self.last_reflow_id, id: self.last_reflow_id,
}; };
self.layout_chan.send(ReflowMsg(reflow)) self.layout_chan.send(ReflowMsg(reflow));
debug!("script: layout forked")
} }
} }
debug!("script: layout forked")
} }
/// Reflows the entire document. /// Reflows the entire document.
@ -709,9 +722,10 @@ impl ScriptTask {
page.next_subpage_id.clone(), page.next_subpage_id.clone(),
self.constellation_chan.clone()); self.constellation_chan.clone());
let HtmlParserResult {root, discovery_port, url: final_url} = html_parsing_result; let mut document = HTMLDocument::new(Some(window));
let document = HTMLDocument::new(root, Some(window)); let HtmlParserResult {root, discovery_port, url: final_url} = html_parsing_result;
document.set_root(root);
// Create the root frame. // Create the root frame.
page.frame = Some(Frame { page.frame = Some(Frame {
@ -817,8 +831,11 @@ impl ScriptTask {
let root = do page.frame.expect("root frame is None").document.with_base |doc| { let root = do page.frame.expect("root frame is None").document.with_base |doc| {
doc.root doc.root
}; };
if root.is_none() {
return;
}
let (port, chan) = comm::stream(); let (port, chan) = comm::stream();
match page.query_layout(HitTestQuery(root, point, chan), port) { match page.query_layout(HitTestQuery(root.unwrap(), point, chan), port) {
Ok(node) => match node { Ok(node) => match node {
HitTestResponse(node) => { HitTestResponse(node) => {
debug!("clicked on %s", node.debug_str()); debug!("clicked on %s", node.debug_str());