Issue #888 - Node's owner document should never be None.

This commit is contained in:
Ms2ger 2013-10-08 21:12:02 +02:00
parent 59d2d345c8
commit 04319fdb68
18 changed files with 144 additions and 135 deletions

View file

@ -143,7 +143,8 @@ DOMInterfaces = {
'Document': { 'Document': {
'nativeType': 'AbstractDocument', 'nativeType': 'AbstractDocument',
'pointerType': '', 'pointerType': '',
'customTrace': 'trace' 'customTrace': 'trace',
'needsAbstract': ['title', 'createElement', 'createTextNode'],
}, },
'DOMParser': { 'DOMParser': {

View file

@ -6,6 +6,7 @@
use dom::bindings::utils::{DOMString, ErrorResult, Fallible}; use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
use dom::bindings::utils::{BindingObject, Reflectable, Reflector}; use dom::bindings::utils::{BindingObject, Reflectable, Reflector};
use dom::document::AbstractDocument;
use dom::node::{Node, NodeTypeId, ScriptView}; use dom::node::{Node, NodeTypeId, ScriptView};
use js::jsapi::{JSObject, JSContext}; use js::jsapi::{JSObject, JSContext};
@ -15,9 +16,9 @@ pub struct CharacterData {
} }
impl CharacterData { impl CharacterData {
pub fn new(id: NodeTypeId, data: ~str) -> CharacterData { pub fn new(id: NodeTypeId, data: ~str, document: AbstractDocument) -> CharacterData {
CharacterData { CharacterData {
node: Node::new(id), node: Node::new(id, document),
data: data data: data
} }
} }

View file

@ -4,6 +4,7 @@
use dom::bindings::utils::{DOMString, Fallible, null_str_as_empty}; use dom::bindings::utils::{DOMString, Fallible, null_str_as_empty};
use dom::characterdata::CharacterData; use dom::characterdata::CharacterData;
use dom::document::AbstractDocument;
use dom::node::{AbstractNode, ScriptView, CommentNodeTypeId, Node}; use dom::node::{AbstractNode, ScriptView, CommentNodeTypeId, Node};
use dom::window::Window; use dom::window::Window;
@ -14,16 +15,16 @@ pub struct Comment {
impl Comment { impl Comment {
/// Creates a new HTML comment. /// Creates a new HTML comment.
pub fn new(text: ~str) -> Comment { pub fn new(text: ~str, document: AbstractDocument) -> Comment {
Comment { Comment {
element: CharacterData::new(CommentNodeTypeId, text) element: CharacterData::new(CommentNodeTypeId, text, document)
} }
} }
pub fn Constructor(owner: @mut Window, data: &DOMString) -> Fallible<AbstractNode<ScriptView>> { pub fn Constructor(owner: @mut Window, data: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
let s = null_str_as_empty(data); let s = null_str_as_empty(data);
let cx = (*owner.page).js_info.get_ref().js_compartment.cx.ptr; let cx = (*owner.page).js_info.get_ref().js_compartment.cx.ptr;
let comment = @Comment::new(s); let comment = @Comment::new(s, owner.Document());
Ok(unsafe { Node::as_abstract_node(cx, comment) }) Ok(unsafe { Node::as_abstract_node(cx, comment) })
} }
} }

View file

@ -77,9 +77,21 @@ impl AbstractDocument {
} }
} }
pub fn from_box<T>(ptr: *mut Box<T>) -> AbstractDocument {
AbstractDocument {
document: ptr as *Document
}
}
pub fn set_root(&self, root: AbstractNode<ScriptView>) { pub fn set_root(&self, root: AbstractNode<ScriptView>) {
assert!(root.traverse_preorder().all(|node| {
do node.with_base |node| {
node.owner_doc == *self
}
}));
self.with_mut_base(|document| { self.with_mut_base(|document| {
document.root = Some(root); document.root = Some(root);
document.content_changed();
}); });
} }
} }
@ -116,7 +128,7 @@ impl Document {
let document = AbstractDocument::as_abstract(cx, @mut Document::new(None, XML)); let 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", document)
}; };
let root = unsafe { Node::as_abstract_node(cx, root) }; let root = unsafe { Node::as_abstract_node(cx, root) };
document.set_root(root); document.set_root(root);
@ -248,23 +260,23 @@ impl Document {
None None
} }
pub fn CreateElement(&self, local_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> { pub fn CreateElement(&self, abstract_self: AbstractDocument, local_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
let cx = self.get_cx(); let cx = self.get_cx();
let local_name = null_str_as_empty(local_name); let local_name = null_str_as_empty(local_name);
if !is_valid_element_name(local_name) { if !is_valid_element_name(local_name) {
return Err(InvalidCharacter); return Err(InvalidCharacter);
} }
let local_name = local_name.to_ascii_lower(); let local_name = local_name.to_ascii_lower();
Ok(build_element_from_tag(cx, local_name)) Ok(build_element_from_tag(cx, local_name, abstract_self))
} }
pub fn CreateElementNS(&self, _namespace: &DOMString, _qualified_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> { pub fn CreateElementNS(&self, _namespace: &DOMString, _qualified_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
fail!("stub") fail!("stub")
} }
pub fn CreateTextNode(&self, data: &DOMString) -> AbstractNode<ScriptView> { pub fn CreateTextNode(&self, abstract_self: AbstractDocument, data: &DOMString) -> AbstractNode<ScriptView> {
let cx = self.get_cx(); let cx = self.get_cx();
let text = @Text::new(null_str_as_empty(data)); let text = @Text::new(null_str_as_empty(data), abstract_self);
unsafe { Node::as_abstract_node(cx, text) } unsafe { Node::as_abstract_node(cx, text) }
} }
@ -288,7 +300,7 @@ impl Document {
None None
} }
pub fn Title(&self) -> DOMString { pub fn Title(&self, _: AbstractDocument) -> DOMString {
let mut title = ~""; let mut title = ~"";
match self.doctype { match self.doctype {
SVG => { SVG => {
@ -322,7 +334,7 @@ impl Document {
Some(title) Some(title)
} }
pub fn SetTitle(&self, title: &DOMString) -> ErrorResult { pub fn SetTitle(&self, abstract_self: AbstractDocument, title: &DOMString) -> ErrorResult {
match self.doctype { match self.doctype {
SVG => { SVG => {
fail!("no SVG document yet") fail!("no SVG document yet")
@ -345,17 +357,17 @@ impl Document {
for title_child in child.children() { for title_child in child.children() {
child.remove_child(title_child); child.remove_child(title_child);
} }
child.add_child(self.CreateTextNode(title)); child.add_child(self.CreateTextNode(abstract_self, title));
break; break;
} }
if !has_title { if !has_title {
let new_title = @HTMLTitleElement { let new_title = @HTMLTitleElement {
htmlelement: HTMLElement::new(HTMLTitleElementTypeId, ~"title") htmlelement: HTMLElement::new(HTMLTitleElementTypeId, ~"title", abstract_self)
}; };
let new_title = unsafe { let new_title = unsafe {
Node::as_abstract_node(cx, new_title) Node::as_abstract_node(cx, new_title)
}; };
new_title.add_child(self.CreateTextNode(title)); new_title.add_child(self.CreateTextNode(abstract_self, title));
node.add_child(new_title); node.add_child(new_title);
} }
break; break;

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::DOMString; use dom::bindings::utils::DOMString;
use dom::document::AbstractDocument;
use dom::node::{ScriptView, Node, DoctypeNodeTypeId}; use dom::node::{ScriptView, Node, DoctypeNodeTypeId};
/// The `DOCTYPE` tag. /// The `DOCTYPE` tag.
@ -19,10 +20,11 @@ impl DocumentType<ScriptView> {
pub fn new(name: ~str, pub fn new(name: ~str,
public_id: Option<~str>, public_id: Option<~str>,
system_id: Option<~str>, system_id: Option<~str>,
force_quirks: bool) force_quirks: bool,
document: AbstractDocument)
-> DocumentType<ScriptView> { -> DocumentType<ScriptView> {
DocumentType { DocumentType {
node: Node::new(DoctypeNodeTypeId), node: Node::new(DoctypeNodeTypeId, document),
name: name, name: name,
public_id: public_id, public_id: public_id,
system_id: system_id, system_id: system_id,

View file

@ -54,7 +54,7 @@ impl DOMParser {
}; };
let root = @HTMLHtmlElement { let root = @HTMLHtmlElement {
htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html") htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html", document)
}; };
let root = unsafe { Node::as_abstract_node(cx, root) }; let root = unsafe { Node::as_abstract_node(cx, root) };
document.set_root(root); document.set_root(root);

View file

@ -9,6 +9,7 @@ use dom::bindings::utils::{null_str_as_empty, null_str_as_empty_ref};
use dom::htmlcollection::HTMLCollection; use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect; use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList; use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{ElementNodeTypeId, Node, ScriptView, AbstractNode}; use dom::node::{ElementNodeTypeId, Node, ScriptView, AbstractNode};
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery}; use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse}; use layout_interface::{ContentBoxesResponse};
@ -119,9 +120,9 @@ pub enum ElementTypeId {
// //
impl<'self> Element { impl<'self> Element {
pub fn new(type_id: ElementTypeId, tag_name: ~str) -> Element { pub fn new(type_id: ElementTypeId, tag_name: ~str, document: AbstractDocument) -> Element {
Element { Element {
node: Node::new(ElementNodeTypeId(type_id)), node: Node::new(ElementNodeTypeId(type_id), document),
tag_name: tag_name, tag_name: tag_name,
attrs: ~[], attrs: ~[],
style_attribute: None, style_attribute: None,
@ -181,14 +182,15 @@ impl<'self> Element {
_ => () _ => ()
} }
match self.node.owner_doc { if abstract_self.is_in_doc() {
Some(owner) => do owner.with_base |owner| { owner.content_changed() }, do self.node.owner_doc.with_base |owner| {
None => {} owner.content_changed();
}
} }
} }
fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) { fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
let doc = self.node.owner_doc.unwrap(); let doc = self.node.owner_doc;
let win = doc.with_base(|doc| doc.window.unwrap()); let win = doc.with_base(|doc| doc.window.unwrap());
let cx = win.page.js_info.get_ref().js_compartment.cx.ptr; let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
let scope = win.reflector().get_jsobject(); let scope = win.reflector().get_jsobject();
@ -276,7 +278,7 @@ impl Element {
} }
pub fn GetClientRects(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRectList { pub fn GetClientRects(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRectList {
let document = self.node.owner_doc.expect("no document"); let document = self.node.owner_doc;
let win = document.with_base(|doc| doc.window).expect("no window"); let win = document.with_base(|doc| doc.window).expect("no window");
let node = abstract_self; let node = abstract_self;
assert!(node.is_element()); assert!(node.is_element());
@ -304,7 +306,7 @@ impl Element {
} }
pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRect { pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRect {
let document = self.node.owner_doc.expect("no document"); let document = self.node.owner_doc;
let win = document.with_base(|doc| doc.window).expect("no window"); let win = document.with_base(|doc| doc.window).expect("no window");
let page = win.page; let page = win.page;
let node = abstract_self; let node = abstract_self;

View file

@ -14,7 +14,7 @@ pub struct HTMLDataListElement {
impl HTMLDataListElement { impl HTMLDataListElement {
fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) { fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
let doc = self.htmlelement.element.node.owner_doc.unwrap(); let doc = self.htmlelement.element.node.owner_doc;
let win = doc.with_base(|doc| doc.window.unwrap()); let win = doc.with_base(|doc| doc.window.unwrap());
let cx = win.page.js_info.get_ref().js_compartment.cx.ptr; let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
let scope = win.reflector().get_jsobject(); let scope = win.reflector().get_jsobject();

View file

@ -5,6 +5,7 @@
use dom::bindings::codegen::HTMLElementBinding; use dom::bindings::codegen::HTMLElementBinding;
use dom::bindings::utils::{DOMString, ErrorResult, Fallible}; use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
use dom::bindings::utils::{Reflectable, BindingObject, Reflector}; use dom::bindings::utils::{Reflectable, BindingObject, Reflector};
use dom::document::AbstractDocument;
use dom::element::{Element, ElementTypeId}; use dom::element::{Element, ElementTypeId};
use dom::node::{AbstractNode, ScriptView}; use dom::node::{AbstractNode, ScriptView};
use js::jsapi::{JSObject, JSContext, JSVal}; use js::jsapi::{JSObject, JSContext, JSVal};
@ -15,9 +16,9 @@ pub struct HTMLElement {
} }
impl HTMLElement { impl HTMLElement {
pub fn new(type_id: ElementTypeId, tag_name: ~str) -> HTMLElement { pub fn new(type_id: ElementTypeId, tag_name: ~str, document: AbstractDocument) -> HTMLElement {
HTMLElement { HTMLElement {
element: Element::new(type_id, tag_name) element: Element::new(type_id, tag_name, document)
} }
} }
} }

View file

@ -40,7 +40,7 @@ impl HTMLFieldSetElement {
} }
fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) { fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
let doc = self.htmlelement.element.node.owner_doc.unwrap(); let doc = self.htmlelement.element.node.owner_doc;
let win = doc.with_base(|doc| doc.window.unwrap()); let win = doc.with_base(|doc| doc.window.unwrap());
let cx = win.page.js_info.get_ref().js_compartment.cx.ptr; let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
let scope = win.reflector().get_jsobject(); let scope = win.reflector().get_jsobject();

View file

@ -15,7 +15,7 @@ pub struct HTMLFormElement {
impl HTMLFormElement { impl HTMLFormElement {
fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) { fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
let doc = self.htmlelement.element.node.owner_doc.unwrap(); let doc = self.htmlelement.element.node.owner_doc;
let win = doc.with_base(|doc| doc.window.unwrap()); let win = doc.with_base(|doc| doc.window.unwrap());
let cx = win.page.js_info.get_ref().js_compartment.cx.ptr; let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
let scope = win.reflector().get_jsobject(); let scope = win.reflector().get_jsobject();

View file

@ -43,12 +43,10 @@ impl HTMLImageElement {
let name = null_str_as_empty(name); let name = null_str_as_empty(name);
if "src" == name { if "src" == name {
let doc = self.htmlelement.element.node.owner_doc; let doc = self.htmlelement.element.node.owner_doc;
for doc in doc.iter() { do doc.with_base |doc| {
do doc.with_base |doc| { for window in doc.window.iter() {
for window in doc.window.iter() { let url = window.page.url.map(|&(ref url, _)| url.clone());
let url = window.page.url.map(|&(ref url, _)| url.clone()); self.update_image(window.image_cache_task.clone(), url);
self.update_image(window.image_cache_task.clone(), url);
}
} }
} }
} }
@ -102,26 +100,18 @@ impl HTMLImageElement {
pub fn Width(&self, abstract_self: AbstractNode<ScriptView>) -> u32 { pub fn Width(&self, abstract_self: AbstractNode<ScriptView>) -> u32 {
let node = &self.htmlelement.element.node; let node = &self.htmlelement.element.node;
match node.owner_doc { match node.owner_doc.with_base(|doc| doc.window) {
Some(doc) => { Some(win) => {
match doc.with_base(|doc| doc.window) { let page = win.page;
Some(win) => { let (port, chan) = stream();
let page = win.page; match page.query_layout(ContentBoxQuery(abstract_self, chan), port) {
let (port, chan) = stream(); ContentBoxResponse(rect) => {
match page.query_layout(ContentBoxQuery(abstract_self, chan), port) { to_px(rect.size.width) as u32
ContentBoxResponse(rect) => {
to_px(rect.size.width) as u32
}
}
}
None => {
debug!("no window");
0
} }
} }
} }
None => { None => {
debug!("no document"); debug!("no window");
0 0
} }
} }
@ -139,26 +129,18 @@ impl HTMLImageElement {
pub fn Height(&self, abstract_self: AbstractNode<ScriptView>) -> u32 { pub fn Height(&self, abstract_self: AbstractNode<ScriptView>) -> u32 {
let node = &self.htmlelement.element.node; let node = &self.htmlelement.element.node;
match node.owner_doc { match node.owner_doc.with_base(|doc| doc.window) {
Some(doc) => { Some(win) => {
match doc.with_base(|doc| doc.window) { let page = win.page;
Some(win) => { let (port, chan) = stream();
let page = win.page; match page.query_layout(ContentBoxQuery(abstract_self, chan), port) {
let (port, chan) = stream(); ContentBoxResponse(rect) => {
match page.query_layout(ContentBoxQuery(abstract_self, chan), port) { to_px(rect.size.height) as u32
ContentBoxResponse(rect) => {
to_px(rect.size.height) as u32
}
}
}
None => {
debug!("no window");
0
} }
} }
} }
None => { None => {
debug!("no document"); debug!("no window");
0 0
} }
} }

View file

@ -21,7 +21,7 @@ impl HTMLMapElement {
} }
fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) { fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
let doc = self.htmlelement.element.node.owner_doc.unwrap(); let doc = self.htmlelement.element.node.owner_doc;
let win = doc.with_base(|doc| doc.window.unwrap()); let win = doc.with_base(|doc| doc.window.unwrap());
let cx = win.page.js_info.get_ref().js_compartment.cx.ptr; let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
let scope = win.reflector().get_jsobject(); let scope = win.reflector().get_jsobject();

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::{DOMString, ErrorResult}; use dom::bindings::utils::{DOMString, ErrorResult};
use dom::document::AbstractDocument;
use dom::element::ElementTypeId; use dom::element::ElementTypeId;
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
@ -11,9 +12,9 @@ pub struct HTMLMediaElement {
} }
impl HTMLMediaElement { impl HTMLMediaElement {
pub fn new(type_id: ElementTypeId, tag_name: ~str) -> HTMLMediaElement { pub fn new(type_id: ElementTypeId, tag_name: ~str, document: AbstractDocument) -> HTMLMediaElement {
HTMLMediaElement { HTMLMediaElement {
htmlelement: HTMLElement::new(type_id, tag_name) htmlelement: HTMLElement::new(type_id, tag_name, document)
} }
} }
} }

View file

@ -86,7 +86,7 @@ pub struct Node<View> {
prev_sibling: Option<AbstractNode<View>>, prev_sibling: Option<AbstractNode<View>>,
/// The document that this node belongs to. /// The document that this node belongs to.
owner_doc: Option<AbstractDocument>, owner_doc: AbstractDocument,
/// Layout information. Only the layout task may touch this data. /// Layout information. Only the layout task may touch this data.
priv layout_data: LayoutData, priv layout_data: LayoutData,
@ -393,6 +393,32 @@ impl<'self, View> AbstractNode<View> {
current_node: self.first_child(), current_node: self.first_child(),
} }
} }
pub fn is_in_doc(&self) -> bool {
do self.with_base |node| {
do node.owner_doc.with_base |document| {
match document.root {
None => false,
Some(root) => {
let mut node = *self;
let mut in_doc;
loop {
match node.parent_node() {
Some(parent) => {
node = parent;
},
None => {
in_doc = unsafe { node.raw_object() as uint == root.raw_object() as uint };
break;
}
}
}
in_doc
}
}
}
}
}
} }
impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> { impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> {
@ -415,23 +441,22 @@ impl Node<ScriptView> {
pub fn add_to_doc(&mut self, doc: AbstractDocument) { pub fn add_to_doc(&mut self, doc: AbstractDocument) {
let old_doc = self.owner_doc; let old_doc = self.owner_doc;
self.owner_doc = Some(doc); self.owner_doc = doc;
let mut cur_node = self.first_child; let mut cur_node = self.first_child;
while cur_node.is_some() { while cur_node.is_some() {
for node in cur_node.unwrap().traverse_preorder() { for node in cur_node.unwrap().traverse_preorder() {
do node.with_mut_base |node_base| { do node.with_mut_base |node_base| {
node_base.owner_doc = Some(doc); node_base.owner_doc = doc;
} }
}; };
cur_node = cur_node.unwrap().next_sibling(); cur_node = cur_node.unwrap().next_sibling();
} }
// Signal the old document that it needs to update its display // Signal the old document that it needs to update its display
match old_doc { if old_doc != doc {
Some(old_doc) if old_doc != doc => do old_doc.with_base |old_doc| { do old_doc.with_base |old_doc| {
old_doc.content_changed(); old_doc.content_changed();
}, }
_ => ()
} }
// Signal the new document that it needs to update its display // Signal the new document that it needs to update its display
@ -440,30 +465,14 @@ impl Node<ScriptView> {
} }
} }
pub fn remove_from_doc(&mut self) { pub fn remove_from_doc(&self) {
let old_doc = self.owner_doc; // Signal the document that it needs to update its display.
self.owner_doc = None; do self.owner_doc.with_base |doc| {
doc.content_changed();
let mut cur_node = self.first_child;
while cur_node.is_some() {
for node in cur_node.unwrap().traverse_preorder() {
do node.with_mut_base |node_base| {
node_base.owner_doc = None;
}
};
cur_node = cur_node.unwrap().next_sibling();
}
// Signal the old document that it needs to update its display
match old_doc {
Some(doc) => do doc.with_base |doc| {
doc.content_changed();
},
None => ()
} }
} }
pub fn new(type_id: NodeTypeId) -> Node<ScriptView> { pub fn new(type_id: NodeTypeId, doc: AbstractDocument) -> Node<ScriptView> {
Node { Node {
reflector_: Reflector::new(), reflector_: Reflector::new(),
type_id: type_id, type_id: type_id,
@ -476,7 +485,7 @@ impl Node<ScriptView> {
next_sibling: None, next_sibling: None,
prev_sibling: None, prev_sibling: None,
owner_doc: None, owner_doc: doc,
layout_data: LayoutData::new(), layout_data: LayoutData::new(),
} }
@ -616,8 +625,8 @@ impl Node<ScriptView> {
let node = if is_empty { let node = if is_empty {
None None
} else { } else {
let text_node = do self.owner_doc.unwrap().with_base |document| { let text_node = do self.owner_doc.with_base |document| {
document.CreateTextNode(value) document.CreateTextNode(self.owner_doc, value)
}; };
Some(text_node) Some(text_node)
}; };
@ -630,10 +639,8 @@ impl Node<ScriptView> {
characterdata.data = null_str_as_empty(value); characterdata.data = null_str_as_empty(value);
// Notify the document that the content of this node is different // Notify the document that the content of this node is different
for doc in self.owner_doc.iter() { do self.owner_doc.with_base |doc| {
do doc.with_base |doc| { doc.content_changed();
doc.content_changed();
}
} }
} }
} }
@ -647,10 +654,8 @@ impl Node<ScriptView> {
} }
fn wait_until_safe_to_modify_dom(&self) { fn wait_until_safe_to_modify_dom(&self) {
for doc in self.owner_doc.iter() { do self.owner_doc.with_base |doc| {
do doc.with_base |doc| { doc.wait_until_safe_to_modify_dom();
doc.wait_until_safe_to_modify_dom();
}
} }
} }
@ -689,11 +694,8 @@ impl Node<ScriptView> {
// If the node already exists it is removed from current parent node. // If the node already exists it is removed from current parent node.
node.parent_node().map(|parent| parent.remove_child(node)); node.parent_node().map(|parent| parent.remove_child(node));
abstract_self.add_child(node); abstract_self.add_child(node);
match self.owner_doc { do node.with_mut_base |node| {
Some(doc) => do node.with_mut_base |node| { node.add_to_doc(self.owner_doc);
node.add_to_doc(doc);
},
None => ()
} }
Ok(node) Ok(node)
} }

View file

@ -4,6 +4,7 @@
use dom::bindings::utils::{DOMString, Fallible, null_str_as_empty}; use dom::bindings::utils::{DOMString, Fallible, null_str_as_empty};
use dom::characterdata::CharacterData; use dom::characterdata::CharacterData;
use dom::document::AbstractDocument;
use dom::node::{AbstractNode, ScriptView, Node, TextNodeTypeId}; use dom::node::{AbstractNode, ScriptView, Node, TextNodeTypeId};
use dom::window::Window; use dom::window::Window;
@ -14,15 +15,15 @@ pub struct Text {
impl Text { impl Text {
/// Creates a new HTML text node. /// Creates a new HTML text node.
pub fn new(text: ~str) -> Text { pub fn new(text: ~str, document: AbstractDocument) -> Text {
Text { Text {
element: CharacterData::new(TextNodeTypeId, text) element: CharacterData::new(TextNodeTypeId, text, document)
} }
} }
pub fn Constructor(owner: @mut Window, text: &DOMString) -> Fallible<AbstractNode<ScriptView>> { pub fn Constructor(owner: @mut Window, text: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
let cx = owner.page.js_info.get_ref().js_compartment.cx.ptr; let cx = owner.page.js_info.get_ref().js_compartment.cx.ptr;
let text = @Text::new(null_str_as_empty(text)); let text = @Text::new(null_str_as_empty(text), owner.Document());
Ok(unsafe { Node::as_abstract_node(cx, text) }) Ok(unsafe { Node::as_abstract_node(cx, text) })
} }

View file

@ -2,6 +2,7 @@
* 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 http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::document::AbstractDocument;
use dom::element::*; use dom::element::*;
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6}; use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6};
@ -35,7 +36,7 @@ macro_rules! handle_element(
($cx: expr, $tag:expr, $string:expr, $type_id:expr, $ctor:ident, [ $(($field:ident : $field_init:expr)),* ]) => ( ($cx: expr, $tag:expr, $string:expr, $type_id:expr, $ctor:ident, [ $(($field:ident : $field_init:expr)),* ]) => (
if eq_slice($tag, $string) { if eq_slice($tag, $string) {
let _element = @$ctor { let _element = @$ctor {
htmlelement: HTMLElement::new($type_id, ($tag).to_str()), htmlelement: HTMLElement::new($type_id, ($tag).to_str(), document),
$( $(
$field: $field_init, $field: $field_init,
)* )*
@ -49,7 +50,7 @@ macro_rules! handle_element(
macro_rules! handle_htmlelement( macro_rules! handle_htmlelement(
($cx: expr, $tag:expr, $string:expr, $type_id:expr, $ctor:ident) => ( ($cx: expr, $tag:expr, $string:expr, $type_id:expr, $ctor:ident) => (
if eq_slice($tag, $string) { if eq_slice($tag, $string) {
let _element = @HTMLElement::new($type_id, ($tag).to_str()); let _element = @HTMLElement::new($type_id, ($tag).to_str(), document);
unsafe { unsafe {
return Node::as_abstract_node(cx, _element); return Node::as_abstract_node(cx, _element);
} }
@ -60,7 +61,7 @@ macro_rules! handle_htmlmediaelement(
($cx: expr, $tag:expr, $string:expr, $type_id:expr, $ctor:ident) => ( ($cx: expr, $tag:expr, $string:expr, $type_id:expr, $ctor:ident) => (
if eq_slice($tag, $string) { if eq_slice($tag, $string) {
let _element = @$ctor { let _element = @$ctor {
htmlelement: HTMLMediaElement::new($type_id, ($tag).to_str()) htmlelement: HTMLMediaElement::new($type_id, ($tag).to_str(), document)
}; };
unsafe { unsafe {
return Node::as_abstract_node(cx, _element); return Node::as_abstract_node(cx, _element);
@ -209,7 +210,7 @@ fn js_script_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
// Silly macros to handle constructing DOM nodes. This produces bad code and should be optimized // Silly macros to handle constructing DOM nodes. This produces bad code and should be optimized
// via atomization (issue #85). // via atomization (issue #85).
pub fn build_element_from_tag(cx: *JSContext, tag: &str) -> AbstractNode<ScriptView> { pub fn build_element_from_tag(cx: *JSContext, tag: &str, document: AbstractDocument) -> AbstractNode<ScriptView> {
// TODO (Issue #85): use atoms // TODO (Issue #85): use atoms
handle_element!(cx, tag, "a", HTMLAnchorElementTypeId, HTMLAnchorElement, []); handle_element!(cx, tag, "a", HTMLAnchorElementTypeId, HTMLAnchorElement, []);
handle_element!(cx, tag, "applet", HTMLAppletElementTypeId, HTMLAppletElement, []); handle_element!(cx, tag, "applet", HTMLAppletElementTypeId, HTMLAppletElement, []);
@ -292,12 +293,13 @@ pub fn build_element_from_tag(cx: *JSContext, tag: &str) -> AbstractNode<ScriptV
handle_htmlmediaelement!(cx, tag, "video", HTMLVideoElementTypeId, HTMLVideoElement); handle_htmlmediaelement!(cx, tag, "video", HTMLVideoElementTypeId, HTMLVideoElement);
let element = @HTMLUnknownElement { let element = @HTMLUnknownElement {
htmlelement: HTMLElement::new(HTMLUnknownElementTypeId, tag.to_str()) htmlelement: HTMLElement::new(HTMLUnknownElementTypeId, tag.to_str(), document)
}; };
unsafe { Node::as_abstract_node(cx, element) } unsafe { Node::as_abstract_node(cx, element) }
} }
pub fn parse_html(cx: *JSContext, pub fn parse_html(cx: *JSContext,
document: AbstractDocument,
url: Url, url: Url,
resource_task: ResourceTask, resource_task: ResourceTask,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
@ -350,7 +352,7 @@ pub fn parse_html(cx: *JSContext,
let url3 = final_url.clone(); let url3 = final_url.clone();
// Build the root node. // Build the root node.
let root = @HTMLHtmlElement { htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html") }; let root = @HTMLHtmlElement { htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html", document) };
let root = unsafe { Node::as_abstract_node(cx, root) }; let root = unsafe { Node::as_abstract_node(cx, root) };
debug!("created new node"); debug!("created new node");
let mut parser = hubbub::Parser("UTF-8", false); let mut parser = hubbub::Parser("UTF-8", false);
@ -365,7 +367,7 @@ pub fn parse_html(cx: *JSContext,
parser.set_tree_handler(~hubbub::TreeHandler { parser.set_tree_handler(~hubbub::TreeHandler {
create_comment: |data: ~str| { create_comment: |data: ~str| {
debug!("create comment"); debug!("create comment");
let comment = @Comment::new(data); let comment = @Comment::new(data, document);
unsafe { unsafe {
Node::as_abstract_node(cx, comment).to_hubbub_node() Node::as_abstract_node(cx, comment).to_hubbub_node()
} }
@ -379,14 +381,15 @@ pub fn parse_html(cx: *JSContext,
let node = @DocumentType::new(name, let node = @DocumentType::new(name,
public_id, public_id,
system_id, system_id,
force_quirks); force_quirks,
document);
unsafe { unsafe {
Node::as_abstract_node(cx, node).to_hubbub_node() Node::as_abstract_node(cx, node).to_hubbub_node()
} }
}, },
create_element: |tag: ~hubbub::Tag| { create_element: |tag: ~hubbub::Tag| {
debug!("create element"); debug!("create element");
let node = build_element_from_tag(cx, tag.name); let node = build_element_from_tag(cx, tag.name, document);
debug!("-- attach attrs"); debug!("-- attach attrs");
do node.as_mut_element |element| { do node.as_mut_element |element| {
@ -465,7 +468,7 @@ pub fn parse_html(cx: *JSContext,
}, },
create_text: |data: ~str| { create_text: |data: ~str| {
debug!("create text"); debug!("create text");
let text = @Text::new(data); let text = @Text::new(data, document);
unsafe { Node::as_abstract_node(cx, text).to_hubbub_node() } unsafe { Node::as_abstract_node(cx, text).to_hubbub_node() }
}, },
ref_node: |_| {}, ref_node: |_| {},

View file

@ -715,17 +715,18 @@ impl ScriptTask {
// Parse HTML. // Parse HTML.
// //
// Note: We can parse the next document in parallel with any previous documents. // Note: We can parse the next document in parallel with any previous documents.
let document = HTMLDocument::new(Some(window));
let html_parsing_result = hubbub_html_parser::parse_html(cx.ptr, let html_parsing_result = hubbub_html_parser::parse_html(cx.ptr,
document,
url.clone(), url.clone(),
self.resource_task.clone(), self.resource_task.clone(),
self.image_cache_task.clone(), self.image_cache_task.clone(),
page.next_subpage_id.clone(), page.next_subpage_id.clone(),
self.constellation_chan.clone()); self.constellation_chan.clone());
let document = HTMLDocument::new(Some(window));
let HtmlParserResult {root, discovery_port, url: final_url} = html_parsing_result; 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 {
@ -770,9 +771,8 @@ impl ScriptTask {
// of the page. // of the page.
// FIXME: We have no way to ensure that the first reflow performed is a // FIXME: We have no way to ensure that the first reflow performed is a
// ReflowForDisplay operation. // ReflowForDisplay operation.
do root.with_mut_base |base| { document.set_root(root);
base.add_to_doc(document)
}
// No more reflow required // No more reflow required
page.url = Some((url, false)); page.url = Some((url, false));