mirror of
https://github.com/servo/servo.git
synced 2025-06-24 17:14:33 +01:00
auto merge of #2087 : Ms2ger/servo/vtable2, r=jdm
Fixes #1527. Does *not* include the code for #1528. (Originally by @jdm in #1688 and #1866.)
This commit is contained in:
commit
9d2a6b7824
9 changed files with 274 additions and 148 deletions
|
@ -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,33 +632,6 @@ impl Element {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait IElement {
|
||||
fn bind_to_tree_impl(&self);
|
||||
fn unbind_from_tree_impl(&self);
|
||||
}
|
||||
|
||||
impl IElement for JS<Element> {
|
||||
fn bind_to_tree_impl(&self) {
|
||||
match self.get_attribute(Null, "id") {
|
||||
Some(attr) => {
|
||||
let mut doc = document_from_node(self);
|
||||
doc.get_mut().register_named_element(self, attr.get().Value());
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn unbind_from_tree_impl(&self) {
|
||||
match self.get_attribute(Null, "id") {
|
||||
Some(attr) => {
|
||||
let mut doc = document_from_node(self);
|
||||
doc.get_mut().unregister_named_element(self, attr.get().Value());
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) {
|
||||
//FIXME: Throw for XML-invalid names
|
||||
//FIXME: Throw for XMLNS-invalid names
|
||||
|
@ -757,3 +644,90 @@ pub fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) {
|
|||
|
||||
(prefix, local_name)
|
||||
}
|
||||
|
||||
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);
|
||||
doc.get_mut().register_named_element(self, attr.get().Value());
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
doc.get_mut().unregister_named_element(self, attr.get().Value());
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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:)
|
||||
}
|
||||
}
|
||||
|
|
93
src/components/script/dom/virtualmethods.rs
Normal file
93
src/components/script/dom/virtualmethods.rs
Normal file
|
@ -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:
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue