diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs index 7ae4cf89676..c58d7f6373f 100644 --- a/components/devtools/actors/console.rs +++ b/components/devtools/actors/console.rs @@ -237,9 +237,9 @@ impl Actor for ConsoleActor { } else if val.is_infinite() { let mut m = TreeMap::new(); if val < 0. { - m.insert("type".to_string(), "Infinity".to_string().to_json()); - } else { m.insert("type".to_string(), "-Infinity".to_string().to_json()); + } else { + m.insert("type".to_string(), "Infinity".to_string().to_json()); } json::Object(m) } else if val == Float::neg_zero() { diff --git a/components/devtools/actors/inspector.rs b/components/devtools/actors/inspector.rs index ac5608ed63a..5d401e4ea7a 100644 --- a/components/devtools/actors/inspector.rs +++ b/components/devtools/actors/inspector.rs @@ -5,13 +5,15 @@ /// Liberally derived from the [Firefox JS implementation](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/inspector.js). use devtools_traits::{GetRootNode, GetDocumentElement, GetChildren, DevtoolScriptControlMsg}; -use devtools_traits::NodeInfo; +use devtools_traits::{GetLayout, NodeInfo}; use actor::{Actor, ActorRegistry}; use protocol::JsonPacketSender; +use collections::TreeMap; use servo_msg::constellation_msg::PipelineId; use serialize::json; +use serialize::json::ToJson; use std::cell::RefCell; use std::io::TcpStream; @@ -287,6 +289,8 @@ struct PageStyleMsg { struct PageStyleActor { name: String, + script_chan: Sender, + pipeline: PipelineId, } #[deriving(Encodable)] @@ -334,15 +338,31 @@ struct AppliedSheet { ruleCount: uint, } +#[deriving(Encodable)] +struct GetLayoutReply { + width: int, + height: int, + autoMargins: json::Json, + from: String, +} + +#[deriving(Encodable)] +struct AutoMargins { + top: String, + bottom: String, + left: String, + right: String, +} + impl Actor for PageStyleActor { fn name(&self) -> String { self.name.clone() } fn handle_message(&self, - _registry: &ActorRegistry, + registry: &ActorRegistry, msg_type: &String, - _msg: &json::Object, + msg: &json::Object, stream: &mut TcpStream) -> bool { match msg_type.as_slice() { "getApplied" => { @@ -368,7 +388,37 @@ impl Actor for PageStyleActor { } //TODO: query script for box layout properties of node (msg.node) - //"getLayout" => {} + "getLayout" => { + let target = msg.find(&"node".to_string()).unwrap().as_string().unwrap(); + let (tx, rx) = channel(); + self.script_chan.send(GetLayout(self.pipeline, + registry.actor_to_script(target.to_string()), + tx)); + let (width, height) = rx.recv(); + + let auto_margins = msg.find(&"autoMargins".to_string()).unwrap().as_boolean().unwrap(); + + //TODO: the remaining layout properties (margin, border, padding, position) + // as specified in getLayout in http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/styles.js + let msg = GetLayoutReply { + width: width.round() as int, + height: height.round() as int, + autoMargins: if auto_margins { + //TODO: real values like processMargins in http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/styles.js + let mut m = TreeMap::new(); + m.insert("top".to_string(), "auto".to_string().to_json()); + m.insert("bottom".to_string(), "auto".to_string().to_json()); + m.insert("left".to_string(), "auto".to_string().to_json()); + m.insert("right".to_string(), "auto".to_string().to_json()); + json::Object(m) + } else { + json::Null + }, + from: self.name(), + }; + stream.write_json_packet(&msg); + true + } _ => false, } @@ -419,6 +469,8 @@ impl Actor for InspectorActor { if self.pageStyle.borrow().is_none() { let style = PageStyleActor { name: registry.new_name("pageStyle"), + script_chan: self.script_chan.clone(), + pipeline: self.pipeline, }; let mut pageStyle = self.pageStyle.borrow_mut(); *pageStyle = Some(style.name()); diff --git a/components/devtools_traits/lib.rs b/components/devtools_traits/lib.rs index 933b9c9f283..6bba96d81b3 100644 --- a/components/devtools_traits/lib.rs +++ b/components/devtools_traits/lib.rs @@ -70,6 +70,7 @@ pub enum DevtoolScriptControlMsg { GetRootNode(PipelineId, Sender), GetDocumentElement(PipelineId, Sender), GetChildren(PipelineId, String, Sender>), + GetLayout(PipelineId, String, Sender<(f32, f32)>), } /// Messages to instruct devtools server to update its state relating to a particular diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index ebad173edda..61f520821a1 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -2,7 +2,6 @@ * 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 devtools_traits::AttrInfo; use dom::bindings::codegen::Bindings::AttrBinding; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::InheritTypes::NodeCast; @@ -14,6 +13,8 @@ use dom::element::{Element, AttributeHandlers}; use dom::node::Node; use dom::window::Window; use dom::virtualmethods::vtable_for; + +use devtools_traits::AttrInfo; use servo_util::atom::Atom; use servo_util::namespace; use servo_util::namespace::Namespace; @@ -189,7 +190,7 @@ impl<'a> AttrHelpers for JSRef<'a, Attr> { fn summarize(&self) -> AttrInfo { AttrInfo { - namespace: self.GetNamespaceURI().unwrap_or("".to_string()), + namespace: self.namespace.to_str().to_string(), name: self.Name(), value: self.Value(), } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 953036788f4..ab61fc47136 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -10,6 +10,7 @@ use dom::namednodemap::NamedNodeMap; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::Bindings::ElementBinding; use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; +use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods; use dom::bindings::codegen::InheritTypes::{ElementDerived, NodeCast}; use dom::bindings::js::{JS, JSRef, Temporary, TemporaryPushable}; use dom::bindings::js::{OptionalSettable, OptionalRootable, Root}; @@ -30,6 +31,7 @@ use dom::nodelist::NodeList; use dom::virtualmethods::{VirtualMethods, vtable_for}; use layout_interface::ContentChangedDocumentDamage; use layout_interface::MatchSelectorsDocumentDamage; +use devtools_traits::AttrInfo; use style::{matches, parse_selector_list_from_str}; use style; use servo_util::atom::Atom; @@ -239,6 +241,7 @@ pub trait ElementHelpers { fn html_element_in_html_document(&self) -> bool; fn get_local_name<'a>(&'a self) -> &'a Atom; fn get_namespace<'a>(&'a self) -> &'a Namespace; + fn summarize(&self) -> Vec; } impl<'a> ElementHelpers for JSRef<'a, Element> { @@ -254,6 +257,18 @@ impl<'a> ElementHelpers for JSRef<'a, Element> { fn get_namespace<'a>(&'a self) -> &'a Namespace { &self.deref().namespace } + + fn summarize(&self) -> Vec { + let attrs = self.Attributes().root(); + let mut i = 0; + let mut summarized = vec!(); + while i < attrs.Length() { + let attr = attrs.Item(i).unwrap().root(); + summarized.push(attr.summarize()); + i += 1; + } + summarized + } } pub trait AttributeHandlers { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index e58f0e888a6..04d2686df18 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -4,7 +4,6 @@ //! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. -use devtools_traits::NodeInfo; use dom::attr::{Attr, AttrHelpers}; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods; @@ -48,6 +47,7 @@ use geom::rect::Rect; use html::hubbub_html_parser::build_element_from_tag; use layout_interface::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC, LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress, UntrustedNodeAddress}; +use devtools_traits::NodeInfo; use servo_util::geometry::Au; use servo_util::str::{DOMString, null_str_as_empty}; use style::{parse_selector_list_from_str, matches}; @@ -702,7 +702,7 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> { } fn summarize(&self) -> NodeInfo { - if self.unique_id.borrow().as_slice() == "" { + if self.unique_id.borrow().is_empty() { let mut unique_id = self.unique_id.borrow_mut(); *unique_id = uuid::Uuid::new_v4().to_simple_str(); } @@ -710,7 +710,7 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> { NodeInfo { uniqueId: self.unique_id.borrow().clone(), baseURI: self.GetBaseURI().unwrap_or("".to_string()), - parent: self.GetParentNode().root().map(|node| node.unique_id.borrow().clone()).unwrap_or("".to_string()), + parent: self.GetParentNode().root().map(|node| node.get_unique_id()).unwrap_or("".to_string()), nodeType: self.NodeType() as uint, namespaceURI: "".to_string(), //FIXME nodeName: self.NodeName(), @@ -722,16 +722,8 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> { systemId: "".to_string(), attrs: if self.is_element() { - let mut summarized = vec!(); let elem: &JSRef = ElementCast::to_ref(self).unwrap(); - let attrs = elem.Attributes().root(); - let mut i = 0; - while i < attrs.Length() { - let attr = attrs.Item(i).unwrap().root(); - summarized.push(attr.summarize()); - i += 1; - } - summarized + elem.summarize() } else { vec!() }, diff --git a/components/script/script_task.rs b/components/script/script_task.rs index e49350a1942..1dd63abeadd 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -6,7 +6,9 @@ //! and layout tasks. use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; -use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast, EventCast}; +use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods; +use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; +use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast, EventCast, ElementCast}; use dom::bindings::conversions; use dom::bindings::conversions::{FromJSValConvertible, Empty}; use dom::bindings::global::Window; @@ -36,7 +38,7 @@ use page::{Page, IterablePage, Frame}; use devtools_traits; use devtools_traits::{DevtoolsControlChan, DevtoolsControlPort, NewGlobal, NodeInfo, GetRootNode}; use devtools_traits::{DevtoolScriptControlMsg, EvaluateJS, EvaluateJSReply, GetDocumentElement}; -use devtools_traits::{GetChildren}; +use devtools_traits::{GetChildren, GetLayout}; use script_traits::{CompositorEvent, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent}; use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, ScriptTaskFactory}; use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, SendEventMsg, ResizeInactiveMsg}; @@ -506,6 +508,7 @@ impl ScriptTask { FromDevtools(GetRootNode(id, reply)) => self.handle_get_root_node(id, reply), FromDevtools(GetDocumentElement(id, reply)) => self.handle_get_document_element(id, reply), FromDevtools(GetChildren(id, node_id, reply)) => self.handle_get_children(id, node_id, reply), + FromDevtools(GetLayout(id, node_id, reply)) => self.handle_get_layout(id, node_id, reply), } } @@ -554,28 +557,34 @@ impl ScriptTask { reply.send(node.summarize()); } - fn handle_get_children(&self, pipeline: PipelineId, node_id: String, reply: Sender>) { + fn find_node_by_unique_id(&self, pipeline: PipelineId, node_id: String) -> Temporary { let page = get_page(&*self.page.borrow(), pipeline); let frame = page.frame(); let document = frame.get_ref().document.root(); let node: &JSRef = NodeCast::from_ref(&*document); - let mut children = vec!(); - let mut found_parent = false; for candidate in node.traverse_preorder() { if candidate.get_unique_id().as_slice() == node_id.as_slice() { - found_parent = true; - for kid in candidate.children() { - children.push(kid.summarize()); - } - break; + return Temporary::from_rooted(&candidate); } } - assert!(found_parent); + fail!("couldn't find node with unique id {:s}", node_id) + } + + fn handle_get_children(&self, pipeline: PipelineId, node_id: String, reply: Sender>) { + let parent = self.find_node_by_unique_id(pipeline, node_id).root(); + let children = parent.children().map(|child| child.summarize()).collect(); reply.send(children); } + fn handle_get_layout(&self, pipeline: PipelineId, node_id: String, reply: Sender<(f32, f32)>) { + let node = self.find_node_by_unique_id(pipeline, node_id).root(); + let elem: &JSRef = ElementCast::to_ref(&*node).expect("should be getting layout of element"); + let rect = elem.GetBoundingClientRect().root(); + reply.send((rect.Width(), rect.Height())); + } + fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) { debug!("Script: new layout: {:?}", new_layout_info); let NewLayoutInfo {