From ea2560ef20ec1116b0897e84fb58eb14a8ea4696 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 9 Apr 2014 23:55:45 +0200 Subject: [PATCH 1/5] Rename before_remove_attr and after_set_attr to allow reusing those names in the next commit. --- src/components/script/dom/element.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index 5be2466b80d..f27655165fb 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -202,9 +202,9 @@ pub trait AttributeHandlers { fn SetAttributeNS(&mut self, namespace_url: Option, name: DOMString, value: DOMString) -> ErrorResult; - fn after_set_attr(&mut self, local_name: DOMString, value: DOMString); + 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 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; @@ -278,7 +278,7 @@ impl AttributeHandlers for JS { Some(idx) => { if namespace == namespace::Null { let old_value = self.get().attrs[idx].get().Value(); - self.before_remove_attr(local_name.clone(), old_value); + self.before_remove_attr_(local_name.clone(), old_value); } self.get_mut().attrs[idx].get_mut().set_value(value.clone()); } @@ -293,7 +293,7 @@ impl AttributeHandlers for JS { } if namespace == namespace::Null { - self.after_set_attr(local_name, value); + self.after_set_attr_(local_name, value); } } @@ -379,7 +379,7 @@ impl AttributeHandlers for JS { Ok(()) } - fn after_set_attr(&mut self, local_name: DOMString, value: DOMString) { + fn after_set_attr_(&mut self, local_name: DOMString, value: DOMString) { let node: JS = NodeCast::from(self); match local_name.as_slice() { "style" => { @@ -433,7 +433,7 @@ impl AttributeHandlers for JS { 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); + self.before_remove_attr_(local_name, removed_raw_value); } self.get_mut().attrs.remove(idx); @@ -443,7 +443,7 @@ impl AttributeHandlers for JS { Ok(()) } - fn before_remove_attr(&mut self, local_name: DOMString, old_value: DOMString) { + fn before_remove_attr_(&mut self, local_name: DOMString, old_value: DOMString) { let node: JS = NodeCast::from(self); match local_name.as_slice() { "style" => { From ca6cfb5bca2ffbb41dd7735557f11fb5726be6e4 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Wed, 9 Apr 2014 20:02:40 +0200 Subject: [PATCH 2/5] Add support for trait-based virtual methods on Nodes, and use it for before_remove_attr and after_set_attr. --- src/components/script/dom/element.rs | 57 +++----------- src/components/script/dom/eventtarget.rs | 7 ++ src/components/script/dom/htmlelement.rs | 9 +++ .../script/dom/htmliframeelement.rs | 28 +++++-- src/components/script/dom/htmlimageelement.rs | 28 +++++-- .../script/dom/htmlobjectelement.rs | 19 ++++- src/components/script/dom/node.rs | 12 ++- src/components/script/dom/virtualmethods.rs | 77 +++++++++++++++++++ src/components/script/script.rs | 1 + 9 files changed, 173 insertions(+), 65 deletions(-) create mode 100644 src/components/script/dom/virtualmethods.rs diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index f27655165fb..f9e3965cd95 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}; @@ -216,14 +212,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 { fn get_attribute(&self, namespace: Namespace, name: &str) -> Option> { if self.get().html_element_in_html_document() { @@ -397,23 +385,7 @@ impl AttributeHandlers for JS { _ => () } - //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 = HTMLImageElementCast::to(self).unwrap(); - elem.AfterSetAttr(local_name.clone(), value.clone()); - } - ElementNodeTypeId(HTMLIFrameElementTypeId) => { - let mut elem: JS = HTMLIFrameElementCast::to(self).unwrap(); - elem.AfterSetAttr(local_name.clone(), value.clone()); - } - ElementNodeTypeId(HTMLObjectElementTypeId) => { - let mut elem: JS = HTMLObjectElementCast::to(self).unwrap(); - elem.AfterSetAttr(local_name.clone(), value.clone()); - } - _ => () - } + vtable_for(&node).after_set_attr(local_name.clone(), value.clone()); self.notify_attribute_changed(local_name); } @@ -454,24 +426,12 @@ impl AttributeHandlers for JS { // "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); + doc.unregister_named_element(self, old_value.clone()); } _ => () } - //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 = HTMLImageElementCast::to(self).unwrap(); - elem.BeforeRemoveAttr(local_name.clone()); - } - ElementNodeTypeId(HTMLIFrameElementTypeId) => { - let mut elem: JS = HTMLIFrameElementCast::to(self).unwrap(); - elem.BeforeRemoveAttr(local_name.clone()); - } - _ => () - } + vtable_for(&node).before_remove_attr(local_name.clone(), old_value); self.notify_attribute_changed(local_name); } @@ -757,3 +717,10 @@ pub fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) { (prefix, local_name) } + +impl VirtualMethods for JS { + fn super_type(&self) -> Option<~VirtualMethods:> { + let node: JS = NodeCast::from(self); + Some(~node as ~VirtualMethods:) + } +} 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 { + fn super_type(&self) -> Option<~VirtualMethods:> { + None + } +} diff --git a/src/components/script/dom/htmlelement.rs b/src/components/script/dom/htmlelement.rs index f8a1cd96a9b..e0a9ccdcc05 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; @@ -160,3 +162,10 @@ impl HTMLElement { 0 } } + +impl VirtualMethods for JS { + fn super_type(&self) -> Option<~VirtualMethods:> { + let element: JS = 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 { - fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) { +impl VirtualMethods for JS { + fn super_type(&self) -> Option<~VirtualMethods:> { + let htmlelement: JS = 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 { self.get_mut().sandbox = Some(modes); } } -} -impl BeforeRemoveAttrListener for JS { - 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 { - fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) { +impl VirtualMethods for JS { + fn super_type(&self) -> Option<~VirtualMethods:> { + let htmlelement: JS = 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 { - 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 { - fn AfterSetAttr(&mut self, name: DOMString, _value: DOMString) { +impl VirtualMethods for JS { + fn super_type(&self) -> Option<~VirtualMethods:> { + let htmlelement: JS = 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..2f3d1c99b67 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}; @@ -22,8 +22,9 @@ use dom::documenttype::DocumentType; use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId, IElement}; 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; use dom::window::Window; use html::hubbub_html_parser::build_element_from_tag; use layout_interface::{LayoutChan, ReapLayoutDataMsg, UntrustedNodeAddress}; @@ -1834,3 +1835,10 @@ pub fn window_from_node(derived: &JS) -> JS { let document: JS = document_from_node(derived); document.get().window.clone() } + +impl VirtualMethods for JS { + fn super_type(&self) -> Option<~VirtualMethods:> { + let eventtarget: JS = 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..f189f0443e8 --- /dev/null +++ b/src/components/script/dom/virtualmethods.rs @@ -0,0 +1,77 @@ +/* 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), + _ => (), + } + } +} + +/// 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) -> ~VirtualMethods: { + match node.get().type_id { + ElementNodeTypeId(HTMLImageElementTypeId) => { + let element: JS = HTMLImageElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(HTMLIFrameElementTypeId) => { + let element: JS = HTMLIFrameElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(HTMLObjectElementTypeId) => { + let element: JS = HTMLObjectElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(ElementTypeId) => { + let element: JS = ElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(_) => { + let element: JS = 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 9ab4c2cc671..523fc790459 100644 --- a/src/components/script/script.rs +++ b/src/components/script/script.rs @@ -153,6 +153,7 @@ pub mod dom { pub mod uievent; pub mod text; pub mod validitystate; + pub mod virtualmethods; pub mod window; pub mod windowproxy; From f5d1907195500aa6785b3c6034058e5d2b66dae7 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 10 Apr 2014 09:03:42 +0200 Subject: [PATCH 3/5] Integrate Element's after_set/remove behaviour into the virtual method hierarchy. --- src/components/script/dom/element.rs | 104 ++++++++++++++------------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index f9e3965cd95..a978ea5d525 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -198,9 +198,7 @@ pub trait AttributeHandlers { fn SetAttributeNS(&mut self, namespace_url: Option, 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; @@ -261,18 +259,18 @@ impl AttributeHandlers for JS { fn do_set_attribute(&mut self, local_name: DOMString, value: DOMString, name: DOMString, namespace: Namespace, prefix: Option, cb: |&JS| -> bool) { + let node: JS = 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 = 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); @@ -281,7 +279,7 @@ impl AttributeHandlers for JS { } if namespace == namespace::Null { - self.after_set_attr_(local_name, value); + vtable_for(&node).after_set_attr(local_name, value); } } @@ -367,29 +365,6 @@ impl AttributeHandlers for JS { Ok(()) } - fn after_set_attr_(&mut self, local_name: DOMString, value: DOMString) { - let node: JS = 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()); - } - _ => () - } - - vtable_for(&node).after_set_attr(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()); @@ -405,7 +380,7 @@ impl AttributeHandlers for JS { 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); @@ -415,27 +390,6 @@ impl AttributeHandlers for JS { Ok(()) } - fn before_remove_attr_(&mut self, local_name: DOMString, old_value: DOMString) { - let node: JS = 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.clone()); - } - _ => () - } - - vtable_for(&node).before_remove_attr(local_name.clone(), old_value); - - self.notify_attribute_changed(local_name); - } - fn notify_attribute_changed(&self, local_name: DOMString) { let node: JS = NodeCast::from(self); if node.is_in_doc() { @@ -723,4 +677,54 @@ impl VirtualMethods for JS { let node: JS = 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 = 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 = 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); + } } From 6388dec9966679202904f2f59d8efe8df7edb9c8 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 13 Feb 2014 08:50:28 +0530 Subject: [PATCH 4/5] Add overridable tree binding/unbinding behaviour. --- src/components/script/dom/element.rs | 18 ++++++++++++++++++ src/components/script/dom/node.rs | 15 +++++---------- src/components/script/dom/virtualmethods.rs | 16 ++++++++++++++++ 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index a978ea5d525..d1b19f41ebe 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -727,4 +727,22 @@ impl VirtualMethods for JS { self.notify_attribute_changed(name); } + + fn bind_to_tree(&mut self) { + match self.super_type() { + Some(ref mut s) => s.bind_to_tree(), + _ => (), + } + + self.bind_to_tree_impl(); + } + + fn unbind_from_tree(&mut self) { + match self.super_type() { + Some(ref mut s) => s.unbind_from_tree(), + _ => (), + } + + self.unbind_from_tree_impl(); + } } diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 2f3d1c99b67..733d1ad7f86 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -19,12 +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::processinginstruction::ProcessingInstruction; use dom::text::Text; -use dom::virtualmethods::VirtualMethods; +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}; @@ -404,10 +404,7 @@ impl NodeHelpers for JS { if self.is_in_doc() { for node in self.traverse_preorder() { - if node.is_element() { - let element: JS = ElementCast::to(&node).unwrap(); - element.bind_to_tree_impl(); - } + vtable_for(&node).bind_to_tree(); } } @@ -420,10 +417,8 @@ impl NodeHelpers for JS { let document = document_from_node(self); for node in self.traverse_preorder() { - if node.is_element() { - let element: JS = 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(); diff --git a/src/components/script/dom/virtualmethods.rs b/src/components/script/dom/virtualmethods.rs index f189f0443e8..866ace84e02 100644 --- a/src/components/script/dom/virtualmethods.rs +++ b/src/components/script/dom/virtualmethods.rs @@ -42,6 +42,22 @@ pub trait VirtualMethods { _ => (), } } + + /// 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 From a3d13c35a2a46fa7a30e705182980fe06aa04e3c Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 10 Apr 2014 09:56:46 +0200 Subject: [PATCH 5/5] Remove the IElement trait. --- src/components/script/dom/element.rs | 43 +++++++++------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index d1b19f41ebe..b06e3253989 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -632,33 +632,6 @@ impl Element { } } -pub trait IElement { - fn bind_to_tree_impl(&self); - fn unbind_from_tree_impl(&self); -} - -impl IElement for JS { - 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 @@ -734,7 +707,13 @@ impl VirtualMethods for JS { _ => (), } - self.bind_to_tree_impl(); + 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) { @@ -743,6 +722,12 @@ impl VirtualMethods for JS { _ => (), } - self.unbind_from_tree_impl(); + 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()); + } + _ => () + } } }