aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/script/dom/element.rs196
-rw-r--r--src/components/script/dom/eventtarget.rs7
-rw-r--r--src/components/script/dom/htmlelement.rs9
-rw-r--r--src/components/script/dom/htmliframeelement.rs28
-rw-r--r--src/components/script/dom/htmlimageelement.rs28
-rw-r--r--src/components/script/dom/htmlobjectelement.rs19
-rw-r--r--src/components/script/dom/node.rs25
-rw-r--r--src/components/script/dom/virtualmethods.rs93
-rw-r--r--src/components/script/script.rs1
9 files changed, 266 insertions, 140 deletions
diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs
index 5be2466b80d..b06e3253989 100644
--- a/src/components/script/dom/element.rs
+++ b/src/components/script/dom/element.rs
@@ -7,9 +7,7 @@
use dom::attr::Attr;
use dom::attrlist::AttrList;
use dom::bindings::codegen::ElementBinding;
-use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLImageElementCast};
-use dom::bindings::codegen::InheritTypes::{HTMLIFrameElementCast, NodeCast};
-use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast;
+use dom::bindings::codegen::InheritTypes::{ElementDerived, NodeCast};
use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::bindings::error::{ErrorResult, Fallible, NamespaceError, InvalidCharacter};
@@ -19,11 +17,9 @@ use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::Document;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
-use dom::htmlimageelement::HTMLImageElement;
-use dom::htmliframeelement::HTMLIFrameElement;
-use dom::htmlobjectelement::HTMLObjectElement;
use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node};
use dom::htmlserializer::serialize;
+use dom::virtualmethods::{VirtualMethods, vtable_for};
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
use layout_interface::{MatchSelectorsDocumentDamage};
@@ -202,9 +198,7 @@ pub trait AttributeHandlers {
fn SetAttributeNS(&mut self, namespace_url: Option<DOMString>,
name: DOMString, value: DOMString) -> ErrorResult;
- fn after_set_attr(&mut self, local_name: DOMString, value: DOMString);
fn remove_attribute(&mut self, namespace: Namespace, name: DOMString) -> ErrorResult;
- fn before_remove_attr(&mut self, local_name: DOMString, old_value: DOMString);
fn notify_attribute_changed(&self, local_name: DOMString);
fn has_class(&self, name: &str) -> bool;
@@ -216,14 +210,6 @@ pub trait AttributeHandlers {
fn set_uint_attribute(&mut self, name: &str, value: u32);
}
-pub trait AfterSetAttrListener {
- fn AfterSetAttr(&mut self, name: DOMString, value: DOMString);
-}
-
-pub trait BeforeRemoveAttrListener {
- fn BeforeRemoveAttr(&mut self, name: DOMString);
-}
-
impl AttributeHandlers for JS<Element> {
fn get_attribute(&self, namespace: Namespace, name: &str) -> Option<JS<Attr>> {
if self.get().html_element_in_html_document() {
@@ -273,18 +259,18 @@ impl AttributeHandlers for JS<Element> {
fn do_set_attribute(&mut self, local_name: DOMString, value: DOMString,
name: DOMString, namespace: Namespace,
prefix: Option<DOMString>, cb: |&JS<Attr>| -> bool) {
+ let node: JS<Node> = NodeCast::from(self);
let idx = self.get().attrs.iter().position(cb);
match idx {
Some(idx) => {
if namespace == namespace::Null {
let old_value = self.get().attrs[idx].get().Value();
- self.before_remove_attr(local_name.clone(), old_value);
+ vtable_for(&node).before_remove_attr(local_name.clone(), old_value);
}
self.get_mut().attrs[idx].get_mut().set_value(value.clone());
}
None => {
- let node: JS<Node> = NodeCast::from(self);
let doc = node.get().owner_doc().get();
let new_attr = Attr::new(&doc.window, local_name.clone(), value.clone(),
name, namespace.clone(), prefix);
@@ -293,7 +279,7 @@ impl AttributeHandlers for JS<Element> {
}
if namespace == namespace::Null {
- self.after_set_attr(local_name, value);
+ vtable_for(&node).after_set_attr(local_name, value);
}
}
@@ -379,45 +365,6 @@ impl AttributeHandlers for JS<Element> {
Ok(())
}
- fn after_set_attr(&mut self, local_name: DOMString, value: DOMString) {
- let node: JS<Node> = NodeCast::from(self);
- match local_name.as_slice() {
- "style" => {
- let doc = node.get().owner_doc();
- let base_url = doc.get().url().clone();
- self.get_mut().style_attribute = Some(style::parse_style_attribute(value, &base_url))
- }
- "id" if node.is_in_doc() => {
- // XXX: this dual declaration are workaround to avoid the compile error:
- // "borrowed value does not live long enough"
- let mut doc = node.get().owner_doc().clone();
- let doc = doc.get_mut();
- doc.register_named_element(self, value.clone());
- }
- _ => ()
- }
-
- //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
- // This hardcoding is awful.
- match node.type_id() {
- ElementNodeTypeId(HTMLImageElementTypeId) => {
- let mut elem: JS<HTMLImageElement> = HTMLImageElementCast::to(self).unwrap();
- elem.AfterSetAttr(local_name.clone(), value.clone());
- }
- ElementNodeTypeId(HTMLIFrameElementTypeId) => {
- let mut elem: JS<HTMLIFrameElement> = HTMLIFrameElementCast::to(self).unwrap();
- elem.AfterSetAttr(local_name.clone(), value.clone());
- }
- ElementNodeTypeId(HTMLObjectElementTypeId) => {
- let mut elem: JS<HTMLObjectElement> = HTMLObjectElementCast::to(self).unwrap();
- elem.AfterSetAttr(local_name.clone(), value.clone());
- }
- _ => ()
- }
-
- self.notify_attribute_changed(local_name);
- }
-
fn remove_attribute(&mut self, namespace: Namespace, name: DOMString) -> ErrorResult {
let (_, local_name) = get_attribute_parts(name.clone());
@@ -433,7 +380,7 @@ impl AttributeHandlers for JS<Element> {
Some(idx) => {
if namespace == namespace::Null {
let removed_raw_value = self.get().attrs[idx].get().Value();
- self.before_remove_attr(local_name, removed_raw_value);
+ vtable_for(&node).before_remove_attr(local_name.clone(), removed_raw_value);
}
self.get_mut().attrs.remove(idx);
@@ -443,39 +390,6 @@ impl AttributeHandlers for JS<Element> {
Ok(())
}
- fn before_remove_attr(&mut self, local_name: DOMString, old_value: DOMString) {
- let node: JS<Node> = NodeCast::from(self);
- match local_name.as_slice() {
- "style" => {
- self.get_mut().style_attribute = None
- }
- "id" if node.is_in_doc() => {
- // XXX: this dual declaration are workaround to avoid the compile error:
- // "borrowed value does not live long enough"
- let mut doc = node.get().owner_doc().clone();
- let doc = doc.get_mut();
- doc.unregister_named_element(self, old_value);
- }
- _ => ()
- }
-
- //XXXjdm We really need something like a vtable so we can call BeforeRemoveAttr.
- // This hardcoding is awful.
- match node.type_id() {
- ElementNodeTypeId(HTMLImageElementTypeId) => {
- let mut elem: JS<HTMLImageElement> = HTMLImageElementCast::to(self).unwrap();
- elem.BeforeRemoveAttr(local_name.clone());
- }
- ElementNodeTypeId(HTMLIFrameElementTypeId) => {
- let mut elem: JS<HTMLIFrameElement> = HTMLIFrameElementCast::to(self).unwrap();
- elem.BeforeRemoveAttr(local_name.clone());
- }
- _ => ()
- }
-
- self.notify_attribute_changed(local_name);
- }
-
fn notify_attribute_changed(&self, local_name: DOMString) {
let node: JS<Node> = NodeCast::from(self);
if node.is_in_doc() {
@@ -718,13 +632,81 @@ impl Element {
}
}
-pub trait IElement {
- fn bind_to_tree_impl(&self);
- fn unbind_from_tree_impl(&self);
+pub fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) {
+ //FIXME: Throw for XML-invalid names
+ //FIXME: Throw for XMLNS-invalid names
+ let (prefix, local_name) = if name.contains(":") {
+ let parts: ~[&str] = name.splitn(':', 1).collect();
+ (Some(parts[0].to_owned()), parts[1].to_owned())
+ } else {
+ (None, name)
+ };
+
+ (prefix, local_name)
}
-impl IElement for JS<Element> {
- fn bind_to_tree_impl(&self) {
+impl VirtualMethods for JS<Element> {
+ fn super_type(&self) -> Option<~VirtualMethods:> {
+ let node: JS<Node> = NodeCast::from(self);
+ Some(~node as ~VirtualMethods:)
+ }
+
+ fn after_set_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.after_set_attr(name.clone(), value.clone()),
+ _ => (),
+ }
+
+ let node: JS<Node> = NodeCast::from(self);
+ match name.as_slice() {
+ "style" => {
+ let doc = node.get().owner_doc();
+ let base_url = doc.get().url().clone();
+ self.get_mut().style_attribute = Some(style::parse_style_attribute(value, &base_url))
+ }
+ "id" if node.is_in_doc() => {
+ // XXX: this dual declaration are workaround to avoid the compile error:
+ // "borrowed value does not live long enough"
+ let mut doc = node.get().owner_doc().clone();
+ let doc = doc.get_mut();
+ doc.register_named_element(self, value.clone());
+ }
+ _ => ()
+ }
+
+ self.notify_attribute_changed(name);
+ }
+
+ fn before_remove_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.before_remove_attr(name.clone(), value.clone()),
+ _ => (),
+ }
+
+ let node: JS<Node> = NodeCast::from(self);
+ match name.as_slice() {
+ "style" => {
+ self.get_mut().style_attribute = None
+ }
+ "id" if node.is_in_doc() => {
+ // XXX: this dual declaration are workaround to avoid the compile error:
+ // "borrowed value does not live long enough"
+ let mut doc = node.get().owner_doc().clone();
+ let doc = doc.get_mut();
+ doc.unregister_named_element(self, value);
+ }
+ _ => ()
+ }
+
+ self.notify_attribute_changed(name);
+ }
+
+ fn bind_to_tree(&mut self) {
+ match self.super_type() {
+ Some(ref mut s) => s.bind_to_tree(),
+ _ => (),
+ }
+
match self.get_attribute(Null, "id") {
Some(attr) => {
let mut doc = document_from_node(self);
@@ -734,7 +716,12 @@ impl IElement for JS<Element> {
}
}
- fn unbind_from_tree_impl(&self) {
+ fn unbind_from_tree(&mut self) {
+ match self.super_type() {
+ Some(ref mut s) => s.unbind_from_tree(),
+ _ => (),
+ }
+
match self.get_attribute(Null, "id") {
Some(attr) => {
let mut doc = document_from_node(self);
@@ -744,16 +731,3 @@ impl IElement for JS<Element> {
}
}
}
-
-pub fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) {
- //FIXME: Throw for XML-invalid names
- //FIXME: Throw for XMLNS-invalid names
- let (prefix, local_name) = if name.contains(":") {
- let parts: ~[&str] = name.splitn(':', 1).collect();
- (Some(parts[0].to_owned()), parts[1].to_owned())
- } else {
- (None, name)
- };
-
- (prefix, local_name)
-}
diff --git a/src/components/script/dom/eventtarget.rs b/src/components/script/dom/eventtarget.rs
index 8d622ca0f0a..f953774bb5d 100644
--- a/src/components/script/dom/eventtarget.rs
+++ b/src/components/script/dom/eventtarget.rs
@@ -9,6 +9,7 @@ use dom::bindings::codegen::EventListenerBinding::EventListener;
use dom::event::Event;
use dom::eventdispatcher::dispatch_event;
use dom::node::NodeTypeId;
+use dom::virtualmethods::VirtualMethods;
use servo_util::str::DOMString;
use collections::hashmap::HashMap;
@@ -123,3 +124,9 @@ impl Reflectable for EventTarget {
&mut self.reflector_
}
}
+
+impl VirtualMethods for JS<EventTarget> {
+ fn super_type(&self) -> Option<~VirtualMethods:> {
+ None
+ }
+}
diff --git a/src/components/script/dom/htmlelement.rs b/src/components/script/dom/htmlelement.rs
index 019b531ae38..30f3e7b552c 100644
--- a/src/components/script/dom/htmlelement.rs
+++ b/src/components/script/dom/htmlelement.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::HTMLElementBinding;
+use dom::bindings::codegen::InheritTypes::ElementCast;
use dom::bindings::codegen::InheritTypes::HTMLElementDerived;
use dom::bindings::js::JS;
use dom::bindings::error::{ErrorResult, Fallible};
@@ -10,6 +11,7 @@ use dom::document::Document;
use dom::element::{Element, ElementTypeId, HTMLElementTypeId};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::node::{Node, ElementNodeTypeId};
+use dom::virtualmethods::VirtualMethods;
use js::jsapi::JSContext;
use js::jsval::{JSVal, NullValue};
use servo_util::namespace;
@@ -161,3 +163,10 @@ impl HTMLElement {
0
}
}
+
+impl VirtualMethods for JS<HTMLElement> {
+ fn super_type(&self) -> Option<~VirtualMethods:> {
+ let element: JS<Element> = ElementCast::from(self);
+ Some(~element as ~VirtualMethods:)
+ }
+}
diff --git a/src/components/script/dom/htmliframeelement.rs b/src/components/script/dom/htmliframeelement.rs
index a33e5baf84d..c98634682a6 100644
--- a/src/components/script/dom/htmliframeelement.rs
+++ b/src/components/script/dom/htmliframeelement.rs
@@ -3,15 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::HTMLIFrameElementBinding;
-use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementDerived};
+use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementDerived, HTMLElementCast};
use dom::bindings::js::JS;
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::{HTMLIFrameElementTypeId, Element};
-use dom::element::{AttributeHandlers, AfterSetAttrListener, BeforeRemoveAttrListener};
+use dom::element::AttributeHandlers;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
+use dom::virtualmethods::VirtualMethods;
use dom::windowproxy::WindowProxy;
use servo_util::str::DOMString;
@@ -210,8 +211,18 @@ impl HTMLIFrameElement {
}
}
-impl AfterSetAttrListener for JS<HTMLIFrameElement> {
- fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) {
+impl VirtualMethods for JS<HTMLIFrameElement> {
+ fn super_type(&self) -> Option<~VirtualMethods:> {
+ let htmlelement: JS<HTMLElement> = HTMLElementCast::from(self);
+ Some(~htmlelement as ~VirtualMethods:)
+ }
+
+ fn after_set_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.after_set_attr(name.clone(), value.clone()),
+ _ => (),
+ }
+
if "sandbox" == name {
let mut modes = AllowNothing as u8;
for word in value.split(' ') {
@@ -230,10 +241,13 @@ impl AfterSetAttrListener for JS<HTMLIFrameElement> {
self.get_mut().sandbox = Some(modes);
}
}
-}
-impl BeforeRemoveAttrListener for JS<HTMLIFrameElement> {
- fn BeforeRemoveAttr(&mut self, name: DOMString) {
+ fn before_remove_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.before_remove_attr(name.clone(), value),
+ _ => (),
+ }
+
if "sandbox" == name {
self.get_mut().sandbox = None;
}
diff --git a/src/components/script/dom/htmlimageelement.rs b/src/components/script/dom/htmlimageelement.rs
index 1fcd4a9a0a5..a2937206d03 100644
--- a/src/components/script/dom/htmlimageelement.rs
+++ b/src/components/script/dom/htmlimageelement.rs
@@ -4,15 +4,16 @@
use dom::bindings::codegen::HTMLImageElementBinding;
use dom::bindings::codegen::InheritTypes::{NodeCast, HTMLImageElementDerived};
-use dom::bindings::codegen::InheritTypes::{ElementCast};
+use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::js::JS;
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::{Element, HTMLImageElementTypeId};
-use dom::element::{AttributeHandlers, AfterSetAttrListener, BeforeRemoveAttrListener};
+use dom::element::AttributeHandlers;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId, NodeHelpers, window_from_node};
+use dom::virtualmethods::VirtualMethods;
use servo_util::geometry::to_px;
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
use servo_net::image_cache_task;
@@ -226,18 +227,31 @@ impl HTMLImageElement {
}
}
-impl AfterSetAttrListener for JS<HTMLImageElement> {
- fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) {
+impl VirtualMethods for JS<HTMLImageElement> {
+ fn super_type(&self) -> Option<~VirtualMethods:> {
+ let htmlelement: JS<HTMLElement> = HTMLElementCast::from(self);
+ Some(~htmlelement as ~VirtualMethods:)
+ }
+
+ fn after_set_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.after_set_attr(name.clone(), value.clone()),
+ _ => (),
+ }
+
if "src" == name {
let window = window_from_node(self);
let url = Some(window.get().get_url());
self.get_mut().update_image(Some(value), url);
}
}
-}
-impl BeforeRemoveAttrListener for JS<HTMLImageElement> {
- fn BeforeRemoveAttr(&mut self, name: DOMString) {
+ fn before_remove_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.before_remove_attr(name.clone(), value.clone()),
+ _ => (),
+ }
+
if "src" == name {
self.get_mut().update_image(None, None);
}
diff --git a/src/components/script/dom/htmlobjectelement.rs b/src/components/script/dom/htmlobjectelement.rs
index 03fc8984845..6288dcfc33d 100644
--- a/src/components/script/dom/htmlobjectelement.rs
+++ b/src/components/script/dom/htmlobjectelement.rs
@@ -4,17 +4,18 @@
use dom::bindings::codegen::HTMLObjectElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLObjectElementDerived;
-use dom::bindings::codegen::InheritTypes::ElementCast;
+use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::js::JS;
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::{Element, HTMLObjectElementTypeId};
-use dom::element::{AttributeHandlers, AfterSetAttrListener};
+use dom::element::AttributeHandlers;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::htmlformelement::HTMLFormElement;
use dom::node::{Node, ElementNodeTypeId, NodeHelpers, window_from_node};
use dom::validitystate::ValidityState;
+use dom::virtualmethods::VirtualMethods;
use dom::windowproxy::WindowProxy;
use servo_util::str::DOMString;
@@ -244,8 +245,18 @@ impl HTMLObjectElement {
}
}
-impl AfterSetAttrListener for JS<HTMLObjectElement> {
- fn AfterSetAttr(&mut self, name: DOMString, _value: DOMString) {
+impl VirtualMethods for JS<HTMLObjectElement> {
+ fn super_type(&self) -> Option<~VirtualMethods:> {
+ let htmlelement: JS<HTMLElement> = HTMLElementCast::from(self);
+ Some(~htmlelement as ~VirtualMethods:)
+ }
+
+ fn after_set_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.after_set_attr(name.clone(), value),
+ _ => (),
+ }
+
if "data" == name {
let window = window_from_node(self);
let url = Some(window.get().get_url());
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index d53c23ad5d2..733d1ad7f86 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -8,7 +8,7 @@ use dom::attr::Attr;
use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast};
use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived};
-use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast;
+use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast};
use dom::bindings::codegen::NodeBinding::NodeConstants;
use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
@@ -19,11 +19,12 @@ use dom::comment::Comment;
use dom::document::{Document, HTMLDocument, NonHTMLDocument};
use dom::documentfragment::DocumentFragment;
use dom::documenttype::DocumentType;
-use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId, IElement};
+use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::nodelist::{NodeList};
-use dom::text::Text;
use dom::processinginstruction::ProcessingInstruction;
+use dom::text::Text;
+use dom::virtualmethods::{VirtualMethods, vtable_for};
use dom::window::Window;
use html::hubbub_html_parser::build_element_from_tag;
use layout_interface::{LayoutChan, ReapLayoutDataMsg, UntrustedNodeAddress};
@@ -403,10 +404,7 @@ impl NodeHelpers for JS<Node> {
if self.is_in_doc() {
for node in self.traverse_preorder() {
- if node.is_element() {
- let element: JS<Element> = ElementCast::to(&node).unwrap();
- element.bind_to_tree_impl();
- }
+ vtable_for(&node).bind_to_tree();
}
}
@@ -419,10 +417,8 @@ impl NodeHelpers for JS<Node> {
let document = document_from_node(self);
for node in self.traverse_preorder() {
- if node.is_element() {
- let element: JS<Element> = ElementCast::to(&node).unwrap();
- element.unbind_from_tree_impl();
- }
+ // XXX how about if the node wasn't in the tree in the first place?
+ vtable_for(&node).unbind_from_tree();
}
document.get().content_changed();
@@ -1834,3 +1830,10 @@ pub fn window_from_node<T: NodeBase>(derived: &JS<T>) -> JS<Window> {
let document: JS<Document> = document_from_node(derived);
document.get().window.clone()
}
+
+impl VirtualMethods for JS<Node> {
+ fn super_type(&self) -> Option<~VirtualMethods:> {
+ let eventtarget: JS<EventTarget> = EventTargetCast::from(self);
+ Some(~eventtarget as ~VirtualMethods:)
+ }
+}
diff --git a/src/components/script/dom/virtualmethods.rs b/src/components/script/dom/virtualmethods.rs
new file mode 100644
index 00000000000..866ace84e02
--- /dev/null
+++ b/src/components/script/dom/virtualmethods.rs
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+use dom::bindings::codegen::InheritTypes::ElementCast;
+use dom::bindings::codegen::InheritTypes::HTMLElementCast;
+use dom::bindings::codegen::InheritTypes::HTMLIFrameElementCast;
+use dom::bindings::codegen::InheritTypes::HTMLImageElementCast;
+use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast;
+use dom::bindings::js::JS;
+use dom::element::Element;
+use dom::element::{ElementTypeId, HTMLImageElementTypeId};
+use dom::element::{HTMLIFrameElementTypeId, HTMLObjectElementTypeId};
+use dom::htmlelement::HTMLElement;
+use dom::htmliframeelement::HTMLIFrameElement;
+use dom::htmlimageelement::HTMLImageElement;
+use dom::htmlobjectelement::HTMLObjectElement;
+use dom::node::{Node, ElementNodeTypeId};
+use servo_util::str::DOMString;
+
+/// Trait to allow DOM nodes to opt-in to overriding (or adding to) common
+/// behaviours. Replicates the effect of C++ virtual methods.
+pub trait VirtualMethods {
+ /// Returns self as the superclass of the implementation for this trait,
+ /// if any.
+ fn super_type(&self) -> Option<~VirtualMethods:>;
+
+ /// Called when changing or adding attributes, after the attribute's value
+ /// has been updated.
+ fn after_set_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.after_set_attr(name, value),
+ _ => (),
+ }
+ }
+
+ /// Called when changing or removing attributes, before any modification
+ /// has taken place.
+ fn before_remove_attr(&mut self, name: DOMString, value: DOMString) {
+ match self.super_type() {
+ Some(ref mut s) => s.before_remove_attr(name, value),
+ _ => (),
+ }
+ }
+
+ /// Called when a Node is appended to a tree that is part of a Document.
+ fn bind_to_tree(&mut self) {
+ match self.super_type() {
+ Some(ref mut s) => s.bind_to_tree(),
+ _ => (),
+ }
+ }
+
+ /// Called when a Node is removed from a tree that is part of a Document.
+ fn unbind_from_tree(&mut self) {
+ match self.super_type() {
+ Some(ref mut s) => s.unbind_from_tree(),
+ _ => (),
+ }
+ }
+}
+
+/// Obtain a VirtualMethods instance for a given Node-derived object. Any
+/// method call on the trait object will invoke the corresponding method on the
+/// concrete type, propagating up the parent hierarchy unless otherwise
+/// interrupted.
+pub fn vtable_for<'a>(node: &JS<Node>) -> ~VirtualMethods: {
+ match node.get().type_id {
+ ElementNodeTypeId(HTMLImageElementTypeId) => {
+ let element: JS<HTMLImageElement> = HTMLImageElementCast::to(node).unwrap();
+ ~element as ~VirtualMethods:
+ }
+ ElementNodeTypeId(HTMLIFrameElementTypeId) => {
+ let element: JS<HTMLIFrameElement> = HTMLIFrameElementCast::to(node).unwrap();
+ ~element as ~VirtualMethods:
+ }
+ ElementNodeTypeId(HTMLObjectElementTypeId) => {
+ let element: JS<HTMLObjectElement> = HTMLObjectElementCast::to(node).unwrap();
+ ~element as ~VirtualMethods:
+ }
+ ElementNodeTypeId(ElementTypeId) => {
+ let element: JS<Element> = ElementCast::to(node).unwrap();
+ ~element as ~VirtualMethods:
+ }
+ ElementNodeTypeId(_) => {
+ let element: JS<HTMLElement> = HTMLElementCast::to(node).unwrap();
+ ~element as ~VirtualMethods:
+ }
+ _ => {
+ ~node.clone() as ~VirtualMethods:
+ }
+ }
+}
diff --git a/src/components/script/script.rs b/src/components/script/script.rs
index bb189ad9088..7b9f63c4dc4 100644
--- a/src/components/script/script.rs
+++ b/src/components/script/script.rs
@@ -155,6 +155,7 @@ pub mod dom {
pub mod uievent;
pub mod text;
pub mod validitystate;
+ pub mod virtualmethods;
pub mod window;
pub mod windowproxy;