diff options
author | pfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-24 13:54:28 +0000 |
---|---|---|
committer | pfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-24 13:54:28 +0000 |
commit | d0ef30f4636680ba1ca213d72bb13540fb5ce7f2 (patch) | |
tree | 5c76b111a2e8a54e7d6343cdf56d6eec4b3cd75b | |
parent | 8ee332ca459d463eecb7807ecd966eda13be0456 (diff) | |
download | chromium_src-d0ef30f4636680ba1ca213d72bb13540fb5ce7f2.zip chromium_src-d0ef30f4636680ba1ca213d72bb13540fb5ce7f2.tar.gz chromium_src-d0ef30f4636680ba1ca213d72bb13540fb5ce7f2.tar.bz2 |
Wire 'Inspect Element' action to the new DevTools (depending on the devtools flag):
- Add new devtools IPC message
- Expose WebView's hit target
- Refactor dom_agent interaction not to send information known to client
- Collect incoming messages on the client until frontend is loaded
- Add Inspect Element scenario into the devtools_host_stub
Review URL: http://codereview.chromium.org/45022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12355 0039d316-1c4b-4281-b951-d872f2087c98
23 files changed, 302 insertions, 164 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 8c7ed5a..eecdd1a 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -16,7 +16,6 @@ #include "chrome/browser/browser_window.h" #include "chrome/browser/character_encoding.h" #include "chrome/browser/debugger/devtools_manager.h" -#include "chrome/browser/debugger/devtools_window.h" #include "chrome/browser/location_bar.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/net/url_fixer_upper.h" @@ -947,14 +946,7 @@ void Browser::OpenDebuggerWindow() { if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableOutOfProcessDevTools)) { DevToolsManager* manager = g_browser_process->devtools_manager(); - DevToolsClientHost* host = manager->GetDevToolsClientHostFor(*wc); - if (!host) { - host = DevToolsWindow::Create(); - manager->RegisterDevToolsClientHostFor(*wc, host); - } - DevToolsWindow* window = host->AsDevToolsWindow(); - if (window) - window->Show(); + manager->OpenDevToolsWindow(wc); } else { // Only one debugger instance can exist at a time right now. // TODO(erikkay): need an alert, dialog, something diff --git a/chrome/browser/debugger/devtools_manager.cc b/chrome/browser/debugger/devtools_manager.cc index 470fb5c..9f63a97 100644 --- a/chrome/browser/debugger/devtools_manager.cc +++ b/chrome/browser/debugger/devtools_manager.cc @@ -11,6 +11,7 @@ #include "chrome/browser/tab_contents/web_contents.h" #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_type.h" +#include "chrome/renderer/devtools_messages.h" DevToolsManager::DevToolsManager() : web_contents_listeners_(NULL) { } @@ -127,6 +128,28 @@ void DevToolsManager::ForwardToDevToolsClient(const RenderViewHost& from, target_host->SendMessageToClient(message); } +void DevToolsManager::OpenDevToolsWindow(WebContents* wc) { + DevToolsClientHost* host = GetDevToolsClientHostFor(*wc); + if (!host) { + host = DevToolsWindow::Create(); + RegisterDevToolsClientHostFor(*wc, host); + } + DevToolsWindow* window = host->AsDevToolsWindow(); + if (window) + window->Show(); +} + +void DevToolsManager::InspectElement(WebContents* wc, int x, int y) { + OpenDevToolsWindow(wc); + RenderViewHost* target_host = wc->render_view_host(); + if (!target_host) { + return; + } + IPC::Message* m = new DevToolsAgentMsg_InspectElement(x, y); + m->set_routing_id(target_host->routing_id()); + target_host->Send(m); +} + void DevToolsManager::ClientHostClosing(DevToolsClientHost* host) { NavigationController* controller = GetDevToolsAgentNavigationController( *host); diff --git a/chrome/browser/debugger/devtools_manager.h b/chrome/browser/debugger/devtools_manager.h index fe1c803..1f9200f 100644 --- a/chrome/browser/debugger/devtools_manager.h +++ b/chrome/browser/debugger/devtools_manager.h @@ -46,6 +46,13 @@ class DevToolsManager : public NotificationObserver, void ForwardToDevToolsClient(const RenderViewHost& from, const IPC::Message& message); + void OpenDevToolsWindow(WebContents* wc); + + // Starts element inspection in the devtools client. + // Creates one by means of OpenDevToolsWindow if no client + // exists. + void InspectElement(WebContents* web_contents, int x, int y); + private: // NotificationObserver override. virtual void Observe(NotificationType type, diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc index 3f94dc7..e6ac8eb 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.cc +++ b/chrome/browser/tab_contents/render_view_context_menu.cc @@ -9,6 +9,7 @@ #include "base/scoped_clipboard_writer.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/debugger/devtools_manager.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url_model.h" @@ -621,7 +622,13 @@ void RenderViewContextMenu::CopyImageAt(int x, int y) { } void RenderViewContextMenu::Inspect(int x, int y) { - source_web_contents_->render_view_host()->InspectElementAt(x, y); + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableOutOfProcessDevTools)) { + g_browser_process->devtools_manager()->InspectElement( + source_web_contents_, x, y); + } else { + source_web_contents_->render_view_host()->InspectElementAt(x, y); + } } void RenderViewContextMenu::WriteTextToClipboard( diff --git a/chrome/renderer/devtools_agent.cc b/chrome/renderer/devtools_agent.cc index 449b250..4d52fca1 100644 --- a/chrome/renderer/devtools_agent.cc +++ b/chrome/renderer/devtools_agent.cc @@ -87,6 +87,7 @@ bool DevToolsAgent::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DebugBreak, OnDebugBreak) IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DebugCommand, OnDebugCommand) IPC_MESSAGE_HANDLER(DevToolsAgentMsg_RpcMessage, OnRpcMessage) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_InspectElement, OnInspectElement) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -175,6 +176,11 @@ void DevToolsAgent::OnRpcMessage(const std::string& raw_msg) { this, &DevToolsAgent::DispatchRpcMessage, raw_msg)); } +void DevToolsAgent::OnInspectElement(int x, int y) { + WebDevToolsAgent* web_agent = view_->webview()->GetWebDevToolsAgent(); + web_agent->InspectElement(x, y); +} + void DevToolsAgent::DispatchRpcMessage(const std::string& raw_msg) { WebDevToolsAgent* web_agent = view_->webview()->GetWebDevToolsAgent(); web_agent->DispatchMessageFromClient(raw_msg); diff --git a/chrome/renderer/devtools_agent.h b/chrome/renderer/devtools_agent.h index f285e69..a0c7bfa 100644 --- a/chrome/renderer/devtools_agent.h +++ b/chrome/renderer/devtools_agent.h @@ -66,6 +66,7 @@ class DevToolsAgent : public IPC::ChannelProxy::MessageFilter, void OnDebugBreak(bool force); void OnDebugCommand(const std::wstring& cmd); void OnRpcMessage(const std::string& raw_msg); + void OnInspectElement(int x, int y); scoped_refptr<DebuggerBridge> debugger_; diff --git a/chrome/renderer/devtools_messages_internal.h b/chrome/renderer/devtools_messages_internal.h index 49eee11..685daa3 100644 --- a/chrome/renderer/devtools_messages_internal.h +++ b/chrome/renderer/devtools_messages_internal.h @@ -83,4 +83,9 @@ IPC_BEGIN_MESSAGES(DevToolsAgent) IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_RpcMessage, std::string /* raw_msg */) + // Inspect element with the given coordinates. + IPC_MESSAGE_CONTROL2(DevToolsAgentMsg_InspectElement, + int /* x */, + int /* y */) + IPC_END_MESSAGES(DevToolsAgent) diff --git a/webkit/glue/devtools/dom_agent.h b/webkit/glue/devtools/dom_agent.h index 3aebf8c..3bd20fa 100644 --- a/webkit/glue/devtools/dom_agent.h +++ b/webkit/glue/devtools/dom_agent.h @@ -13,7 +13,7 @@ // DomAgent's environment is represented with the DomAgentDelegate interface. #define DOM_AGENT_STRUCT(METHOD0, METHOD1, METHOD2, METHOD3) \ /* Requests that the document root element is sent to the delegate. */ \ - METHOD1(GetDocumentElement, int /* call_id */) \ + METHOD0(GetDocumentElement) \ \ /* Requests that the element's children are sent to the client. */ \ METHOD2(GetChildNodes, int /* call_id */, int /* id */) \ @@ -35,17 +35,17 @@ DEFINE_RPC_CLASS(DomAgent, DOM_AGENT_STRUCT) #define DOM_AGENT_DELEGATE_STRUCT(METHOD0, METHOD1, METHOD2, METHOD3) \ - /* Response to GetDocumentElement. */ \ - METHOD2(GetDocumentElementResult, int /* call_id */, Value /* node */) \ - \ /* Response to GetChildNodes. */ \ - METHOD2(GetChildNodesResult, int /* call_id */, Value /* nodes */) \ + METHOD1(DidGetChildNodes, int /* call_id */) \ \ /* Notifies the delegate that element's attributes are updated. */ \ METHOD2(AttributesUpdated, int /* id */, Value /* attributes */) \ \ + /* Sends document element to the delegate. */ \ + METHOD1(SetDocumentElement, Value /* root */) \ + \ /* Notifies the delegate that element's child nodes have been updated. */ \ - METHOD2(ChildNodesUpdated, int /* parent_id */, Value /* nodes */) \ + METHOD2(SetChildNodes, int /* parent_id */, Value /* nodes */) \ \ /* Notifies the delegate that element's 'has children' state has been updated */ \ diff --git a/webkit/glue/devtools/dom_agent_impl.cc b/webkit/glue/devtools/dom_agent_impl.cc index 0170db9..34e1be5 100644 --- a/webkit/glue/devtools/dom_agent_impl.cc +++ b/webkit/glue/devtools/dom_agent_impl.cc @@ -46,7 +46,7 @@ void DomAgentImpl::EventListenerWrapper::handleEvent( DomAgentImpl::DomAgentImpl(DomAgentDelegate* delegate) : delegate_(delegate), last_node_id_(1), - document_element_call_id_(0) { + document_element_requested_(false) { event_listener_ = EventListenerWrapper::Create(this); } @@ -66,9 +66,9 @@ void DomAgentImpl::SetDocument(Document* doc) { if (doc) { StartListening(doc); - if (document_element_call_id_) { - GetDocumentElement(document_element_call_id_); - document_element_call_id_ = 0; + if (document_element_requested_) { + GetDocumentElement(); + document_element_requested_ = false; } } } @@ -128,6 +128,27 @@ void DomAgentImpl::Unbind(Node* node) { } } +void DomAgentImpl::PushDocumentElementToClient() { + Element* doc_elem = (*documents_.begin())->documentElement(); + if (!node_to_id_.contains(doc_elem)) { + OwnPtr<Value> value(BuildValueForNode(doc_elem, 0)); + delegate_->SetDocumentElement(*value.get()); + } +} + +void DomAgentImpl::PushChildNodesToClient(int element_id) { + Node* node = GetNodeForId(element_id); + if (!node || (node->nodeType() != Node::ELEMENT_NODE)) + return; + if (children_requested_.contains(element_id)) + return; + + Element* element = static_cast<Element*>(node); + OwnPtr<Value> children(BuildValueForElementChildren(element, 1)); + children_requested_.add(element_id); + delegate_->SetChildNodes(element_id, *children.get()); +} + void DomAgentImpl::DiscardBindings() { node_to_id_.clear(); id_to_node_.clear(); @@ -208,28 +229,20 @@ void DomAgentImpl::handleEvent(Event* event, bool isWindowEvent) { } } -void DomAgentImpl::GetDocumentElement(int call_id) { +void DomAgentImpl::GetDocumentElement() { if (documents_.size() > 0) { - OwnPtr<Value> value( - BuildValueForNode((*documents_.begin())->documentElement(), 0)); - delegate_->GetDocumentElementResult(call_id, *value.get()); + PushDocumentElementToClient(); } else { - document_element_call_id_ = call_id; + document_element_requested_ = true; } } void DomAgentImpl::GetChildNodes(int call_id, int element_id) { - Node* node = GetNodeForId(element_id); - if (!node || (node->nodeType() != Node::ELEMENT_NODE)) - return; - - Element* element = static_cast<Element*>(node); - OwnPtr<Value> children(BuildValueForElementChildren(element, 1)); - children_requested_.add(element_id); - delegate_->GetChildNodesResult(call_id, *children.get()); + PushChildNodesToClient(element_id); + delegate_->DidGetChildNodes(call_id); } -int DomAgentImpl::GetPathToNode(Node* node_to_select) { +int DomAgentImpl::PushNodePathToClient(Node* node_to_select) { ASSERT(node_to_select); // Invalid input // Return id in case the node is known. @@ -240,6 +253,10 @@ int DomAgentImpl::GetPathToNode(Node* node_to_select) { Element* element = InnerParentElement(node_to_select); ASSERT(element); // Node is detached or is a document itself + // If we are sending information to the client that is currently being + // created. Send root node first. + PushDocumentElementToClient(); + Vector<Element*> path; while (element && !GetIdForNode(element)) { path.append(element); @@ -252,7 +269,7 @@ int DomAgentImpl::GetPathToNode(Node* node_to_select) { for (int i = path.size() - 1; i >= 0; --i) { element = path.at(i); OwnPtr<Value> children(BuildValueForElementChildren(element, 1)); - delegate_->ChildNodesUpdated(GetIdForNode(element), *children.get()); + delegate_->SetChildNodes(GetIdForNode(element), *children.get()); } return GetIdForNode(node_to_select); } diff --git a/webkit/glue/devtools/dom_agent_impl.h b/webkit/glue/devtools/dom_agent_impl.h index 6bc130e..50b2458 100644 --- a/webkit/glue/devtools/dom_agent_impl.h +++ b/webkit/glue/devtools/dom_agent_impl.h @@ -32,7 +32,7 @@ class DomAgentImpl : public DomAgent { virtual ~DomAgentImpl(); // DomAgent implementation. - void GetDocumentElement(int call_id); + void GetDocumentElement(); void GetChildNodes(int call_id, int element_id); void SetAttribute( int element_id, @@ -52,8 +52,8 @@ class DomAgentImpl : public DomAgent { int GetIdForNode(WebCore::Node* node); // Sends path to a given node to the client. Returns node's id according to - // the resulting binding. - int GetPathToNode(WebCore::Node* node); + // the resulting binding. Only sends nodes that are missing on the client. + int PushNodePathToClient(WebCore::Node* node); private: // Convenience EventListner wrapper for cleaner Ref management. @@ -83,6 +83,12 @@ class DomAgentImpl : public DomAgent { // Releases Node to int binding. void Unbind(WebCore::Node* node); + // Pushes document element to the client. + void PushDocumentElementToClient(); + + // Pushes child nodes to the client. + void PushChildNodesToClient(int element_id); + // Serializes given node into the list value. ListValue* BuildValueForNode( WebCore::Node* node, @@ -112,7 +118,7 @@ class DomAgentImpl : public DomAgent { RefPtr<WebCore::EventListener> event_listener_; // Captures pending document element request's call id. // Defaults to 0 meaning no pending request. - int document_element_call_id_; + bool document_element_requested_; DISALLOW_COPY_AND_ASSIGN(DomAgentImpl); }; diff --git a/webkit/glue/devtools/dom_agent_unittest.cc b/webkit/glue/devtools/dom_agent_unittest.cc index 99cbc2c..b88a183 100644 --- a/webkit/glue/devtools/dom_agent_unittest.cc +++ b/webkit/glue/devtools/dom_agent_unittest.cc @@ -97,21 +97,22 @@ class DomAgentTests : public TestShellTest { // version is called. TEST_F(DomAgentTests, GetDocumentElement) { OwnPtr<Value> v(DevToolsRpc::ParseMessage("[1,1,\"HTML\",\"\",[],1]")); - mock_delegate_->GetDocumentElementResult(kCallId1, *v.get()); + mock_delegate_->SetDocumentElement(*v.get()); mock_delegate_->Replay(); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); mock_delegate_->Verify(); } // Requests element's children and tests that the callback with the serialized // version is called. TEST_F(DomAgentTests, GetChildNodes) { - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); mock_delegate_->Reset(); OwnPtr<Value> v(DevToolsRpc::ParseMessage("[[2,1,\"BODY\",\"\",[],0]]")); - mock_delegate_->GetChildNodesResult(kCallId2, *v.get()); + mock_delegate_->SetChildNodes(kHtmlElemId, *v.get()); + mock_delegate_->DidGetChildNodes(kCallId2); mock_delegate_->Replay(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); @@ -120,7 +121,7 @@ TEST_F(DomAgentTests, GetChildNodes) { // Tests that "child node inserted" event is being fired. TEST_F(DomAgentTests, ChildNodeInsertedUnknownParent) { - dom_agent_->GetDocumentElement(1); + dom_agent_->GetDocumentElement(); mock_delegate_->Reset(); // There should be no events fired until parent node is known to client. @@ -132,7 +133,7 @@ TEST_F(DomAgentTests, ChildNodeInsertedUnknownParent) { // Tests that "child node inserted" event is being fired. TEST_F(DomAgentTests, ChildNodeInsertedKnownParent) { - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); mock_delegate_->Reset(); @@ -148,7 +149,7 @@ TEST_F(DomAgentTests, ChildNodeInsertedKnownParent) { // Tests that "child node inserted" event is being fired. TEST_F(DomAgentTests, ChildNodeInsertedKnownChildren) { - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); dom_agent_->GetChildNodes(kCallId3, kBodyElemId); mock_delegate_->Reset(); @@ -170,7 +171,7 @@ TEST_F(DomAgentTests, ChildNodePrepend) { RefPtr<Element> div = document_->createElement("DIV", ec_); body_->appendChild(div, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); dom_agent_->GetChildNodes(kCallId3, kBodyElemId); mock_delegate_->Reset(); @@ -192,7 +193,7 @@ TEST_F(DomAgentTests, ChildNodeAppend) { RefPtr<Element> div = document_->createElement("DIV", ec_); body_->appendChild(div, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); dom_agent_->GetChildNodes(kCallId3, kBodyElemId); mock_delegate_->Reset(); @@ -216,7 +217,7 @@ TEST_F(DomAgentTests, ChildNodeInsert) { RefPtr<Element> div2 = document_->createElement("DIV", ec_); body_->appendChild(div2, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); dom_agent_->GetChildNodes(kCallId3, kBodyElemId); mock_delegate_->Reset(); @@ -238,7 +239,7 @@ TEST_F(DomAgentTests, ChildNodeRemovedUnknownParent) { RefPtr<Element> div = document_->createElement("DIV", ec_); body_->appendChild(div, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); mock_delegate_->Reset(); // There should be no events fired until parent node is known to client. @@ -252,7 +253,7 @@ TEST_F(DomAgentTests, ChildNodeRemovedKnownParent) { RefPtr<Element> div = document_->createElement("DIV", ec_); body_->appendChild(div, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); mock_delegate_->Reset(); @@ -270,7 +271,7 @@ TEST_F(DomAgentTests, ChildNodeRemovedKnownChildren) { RefPtr<Element> div = document_->createElement("DIV", ec_); body_->appendChild(div, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); dom_agent_->GetChildNodes(kCallId3, kBodyElemId); mock_delegate_->Reset(); @@ -284,12 +285,12 @@ TEST_F(DomAgentTests, ChildNodeRemovedKnownChildren) { mock_delegate_->Verify(); } -// Tests that "GetPathToNode" sends all missing events in path. -TEST_F(DomAgentTests, GetPathToKnownNode) { +// Tests that "PushNodePathToClient" sends all missing events in path. +TEST_F(DomAgentTests, PushPathToKnownNode) { RefPtr<Element> div1 = document_->createElement("DIV", ec_); body_->appendChild(div1, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); dom_agent_->GetChildNodes(kCallId3, kBodyElemId); mock_delegate_->Reset(); @@ -297,31 +298,31 @@ TEST_F(DomAgentTests, GetPathToKnownNode) { // We expect no messages - node is already known. mock_delegate_->Replay(); - int id = dom_agent_->GetPathToNode(div1.get()); + int id = dom_agent_->PushNodePathToClient(div1.get()); mock_delegate_->Verify(); EXPECT_EQ(3, id); } -// Tests that "GetPathToNode" sends all missing events in path. -TEST_F(DomAgentTests, GetPathToKnownParent) { +// Tests that "PushNodePathToClient" sends all missing events in path. +TEST_F(DomAgentTests, PushPathToKnownParent) { RefPtr<Element> div1 = document_->createElement("DIV", ec_); body_->appendChild(div1, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); mock_delegate_->Reset(); OwnPtr<Value> v1(DevToolsRpc::ParseMessage("[[3,1,\"DIV\",\"\",[],0]]")); - mock_delegate_->ChildNodesUpdated(kBodyElemId, *v1.get()); + mock_delegate_->SetChildNodes(kBodyElemId, *v1.get()); mock_delegate_->Replay(); - int id = dom_agent_->GetPathToNode(div1.get()); + int id = dom_agent_->PushNodePathToClient(div1.get()); mock_delegate_->Verify(); EXPECT_EQ(3, id); } -// Tests that "GetPathToNode" sends all missing events in path. -TEST_F(DomAgentTests, GetPathToUnknownNode) { +// Tests that "PushNodePathToClient" sends all missing events in path. +TEST_F(DomAgentTests, PushPathToUnknownNode) { RefPtr<Element> div1 = document_->createElement("DIV", ec_); RefPtr<Element> div2 = document_->createElement("DIV", ec_); RefPtr<Element> div3 = document_->createElement("DIV", ec_); @@ -331,7 +332,7 @@ TEST_F(DomAgentTests, GetPathToUnknownNode) { div2->appendChild(div3, ec_); div3->appendChild(div4, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); mock_delegate_->Reset(); @@ -339,13 +340,13 @@ TEST_F(DomAgentTests, GetPathToUnknownNode) { OwnPtr<Value> v2(DevToolsRpc::ParseMessage("[[4,1,\"DIV\",\"\",[],1]]")); OwnPtr<Value> v3(DevToolsRpc::ParseMessage("[[5,1,\"DIV\",\"\",[],1]]")); OwnPtr<Value> v4(DevToolsRpc::ParseMessage("[[6,1,\"DIV\",\"\",[],0]]")); - mock_delegate_->ChildNodesUpdated(kBodyElemId, *v1.get()); - mock_delegate_->ChildNodesUpdated(3, *v2.get()); - mock_delegate_->ChildNodesUpdated(4, *v3.get()); - mock_delegate_->ChildNodesUpdated(5, *v4.get()); + mock_delegate_->SetChildNodes(kBodyElemId, *v1.get()); + mock_delegate_->SetChildNodes(3, *v2.get()); + mock_delegate_->SetChildNodes(4, *v3.get()); + mock_delegate_->SetChildNodes(5, *v4.get()); mock_delegate_->Replay(); - int id = dom_agent_->GetPathToNode(div4.get()); + int id = dom_agent_->PushNodePathToClient(div4.get()); mock_delegate_->Verify(); EXPECT_EQ(6, id); } @@ -355,22 +356,23 @@ TEST_F(DomAgentTests, GetChildNodesOfFrameOwner) { RefPtr<Element> iframe = document_->createElement("IFRAME", ec_); body_->appendChild(iframe, ec_); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); dom_agent_->GetChildNodes(kCallId3, kBodyElemId); mock_delegate_->Reset(); // Expecting HTML child with single (body) child. OwnPtr<Value> v(DevToolsRpc::ParseMessage("[[4,1,\"HTML\",\"\",[],1]]")); - mock_delegate_->GetChildNodesResult(kCallId4, *v.get()); + mock_delegate_->SetChildNodes(3, *v.get()); + mock_delegate_->DidGetChildNodes(kCallId4); mock_delegate_->Replay(); dom_agent_->GetChildNodes(kCallId4, 3); mock_delegate_->Verify(); } -// Tests that "GetPathToNode" crosses frame owner boundaries. -TEST_F(DomAgentTests, GetPathToNodeOverFrameOwner) { +// Tests that "PushNodePathToClient" crosses frame owner boundaries. +TEST_F(DomAgentTests, SendPathToNodeOverFrameOwner) { RefPtr<Element> iframe = document_->createElement("IFRAME", ec_); body_->appendChild(iframe, ec_); HTMLFrameOwnerElement* frame_owner = @@ -378,19 +380,19 @@ TEST_F(DomAgentTests, GetPathToNodeOverFrameOwner) { Node* inner_body = frame_owner->contentDocument()->firstChild()-> firstChild(); - dom_agent_->GetDocumentElement(kCallId1); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallId2, kHtmlElemId); mock_delegate_->Reset(); OwnPtr<Value> v1(DevToolsRpc::ParseMessage("[[3,1,\"IFRAME\",\"\",[],1]]")); OwnPtr<Value> v2(DevToolsRpc::ParseMessage("[[4,1,\"HTML\",\"\",[],1]]")); OwnPtr<Value> v3(DevToolsRpc::ParseMessage("[[5,1,\"BODY\",\"\",[],0]]")); - mock_delegate_->ChildNodesUpdated(2, *v1.get()); - mock_delegate_->ChildNodesUpdated(3, *v2.get()); - mock_delegate_->ChildNodesUpdated(4, *v3.get()); + mock_delegate_->SetChildNodes(2, *v1.get()); + mock_delegate_->SetChildNodes(3, *v2.get()); + mock_delegate_->SetChildNodes(4, *v3.get()); mock_delegate_->Replay(); - dom_agent_->GetPathToNode(inner_body); + dom_agent_->PushNodePathToClient(inner_body); mock_delegate_->Verify(); } @@ -403,7 +405,7 @@ TEST_F(DomAgentTests, ChildNodeInsertUnderFrameOwner) { Node* inner_body = frame_owner->contentDocument()->firstChild()-> firstChild(); - dom_agent_->GetDocumentElement(kCallIdAny); + dom_agent_->GetDocumentElement(); dom_agent_->GetChildNodes(kCallIdAny, kHtmlElemId); dom_agent_->GetChildNodes(kCallIdAny, kBodyElemId); dom_agent_->GetChildNodes(kCallIdAny, 3); // IFrame children diff --git a/webkit/glue/devtools/js/devtools.js b/webkit/glue/devtools/js/devtools.js index 4ef1c14..33d23a9 100644 --- a/webkit/glue/devtools/js/devtools.js +++ b/webkit/glue/devtools/js/devtools.js @@ -13,13 +13,14 @@ goog.require('devtools.DomAgent'); goog.require('devtools.NetAgent'); devtools.ToolsAgent = function() { - + RemoteToolsAgent.UpdateFocusedNode = + goog.bind(this.updateFocusedNode, this); }; // ToolsAgent implementation. devtools.ToolsAgent.prototype.updateFocusedNode = function(node_id) { - var node = dom.getNodeForId(node_id); + var node = domAgent.getNodeForId(node_id); WebInspector.updateFocusedNode(node); }; @@ -49,10 +50,10 @@ WebInspector.loaded = function() { netAgent = new devtools.NetAgent(); toolsAgent = new devtools.ToolsAgent(); - oldLoaded.call(this); Preferences.ignoreWhitespace = false; toolsAgent.setDomAgentEnabled(true); toolsAgent.setNetAgentEnabled(true); + oldLoaded.call(this); domAgent.getDocumentElementAsync(); }; @@ -61,7 +62,8 @@ var webkitUpdateChildren = WebInspector.ElementsTreeElement.prototype.updateChildren; WebInspector.ElementsTreeElement.prototype.updateChildren = function() { - domAgent.getChildNodesAsync( - this.representedObject.id, - goog.bind(webkitUpdateChildren, this)); + var self = this; + domAgent.getChildNodesAsync(this.representedObject.id, function() { + webkitUpdateChildren.call(self); + }); }; diff --git a/webkit/glue/devtools/js/devtools_callback.js b/webkit/glue/devtools/js/devtools_callback.js index c7c1482..0c344d9 100644 --- a/webkit/glue/devtools/js/devtools_callback.js +++ b/webkit/glue/devtools/js/devtools_callback.js @@ -13,7 +13,7 @@ goog.provide('devtools.Callback'); * @constructor */ devtools.Callback = function() { - this.lastCallbackId_ = 0; + this.lastCallbackId_ = 1; this.callbacks_ = {}; }; diff --git a/webkit/glue/devtools/js/devtools_host_stub.js b/webkit/glue/devtools/js/devtools_host_stub.js index f1b10e5..2d51897 100644 --- a/webkit/glue/devtools/js/devtools_host_stub.js +++ b/webkit/glue/devtools/js/devtools_host_stub.js @@ -14,59 +14,68 @@ RemoteDomAgentStub = function() { }; -RemoteDomAgentStub.prototype.GetDocumentElement = function(callId) { - setTimeout(function() { - RemoteDomAgent.GetDocumentElementResult(callId, [ - 1, // id - 1, // type = Node.ELEMENT_NODE, - "HTML", // nodeName - "", // nodeValue - ["foo","bar"], // attributes - 2, // childNodeCount - ]); - }, 0); +RemoteDomAgentStub.sendDocumentElement_ = function() { + RemoteDomAgent.SetDocumentElement([ + 1, // id + 1, // type = Node.ELEMENT_NODE, + "HTML", // nodeName + "", // nodeValue + ["foo","bar"], // attributes + 2, // childNodeCount + ]); }; -RemoteDomAgentStub.prototype.GetChildNodes = function(callId, id) { +RemoteDomAgentStub.sendChildNodes_ = function(id) { if (id == 1) { - setTimeout(function() { - RemoteDomAgent.GetChildNodesResult(callId, + RemoteDomAgent.SetChildNodes(id, + [ [ - [ - 2, // id - 1, // type = Node.ELEMENT_NODE, - "DIV", // nodeName - "", // nodeValue - ["foo","bar"], // attributes - 1, // childNodeCount - ], - [ - 3, // id - 3, // type = Node.TEXT_NODE, - "", // nodeName - "Text", // nodeValue - ] - ]); - }, 0); - } else if (id == 2) { - setTimeout(function() { - RemoteDomAgent.GetChildNodesResult(callId, + 2, // id + 1, // type = Node.ELEMENT_NODE, + "DIV", // nodeName + "", // nodeValue + ["foo","bar"], // attributes + 1, // childNodeCount + ], [ - [ - 4, // id - 1, // type = Node.ELEMENT_NODE, - "span", // nodeName - "", // nodeValue - ["foo","bar"], // attributes - 0, // childNodeCount + 3, // id + 3, // type = Node.TEXT_NODE, + "", // nodeName + "Text", // nodeValue ] ]); - }, 0); + } else if (id == 2) { + RemoteDomAgent.SetChildNodes(id, + [ + [ + 4, // id + 1, // type = Node.ELEMENT_NODE, + "span", // nodeName + "", // nodeValue + ["foo","bar"], // attributes + 0, // childNodeCount + ] + ]); } }; +RemoteDomAgentStub.prototype.GetDocumentElement = function(callId) { + setTimeout(function() { + RemoteDomAgentStub.sendDocumentElement_(); + }, 0); +}; + + +RemoteDomAgentStub.prototype.GetChildNodes = function(callId, id) { + setTimeout(function() { + RemoteDomAgentStub.sendChildNodes_(id); + RemoteDomAgent.DidGetChildNodes(callId); + }, 0); +}; + + RemoteDomAgentStub.prototype.SetAttribute = function() { }; @@ -116,6 +125,14 @@ DevToolsHostStub = function() { }; +DevToolsHostStub.prototype.loaded = function() { + RemoteDomAgentStub.sendDocumentElement_(); + RemoteDomAgentStub.sendChildNodes_(1); + RemoteDomAgentStub.sendChildNodes_(2); + toolsAgent.updateFocusedNode(4); +}; + + if (!window['DevToolsHost']) { window['RemoteDomAgent'] = new RemoteDomAgentStub(); window['RemoteNetAgent'] = new RemoteNetAgentStub(); diff --git a/webkit/glue/devtools/js/dom_agent.js b/webkit/glue/devtools/js/dom_agent.js index bc5c9a1f..5e5693a 100644 --- a/webkit/glue/devtools/js/dom_agent.js +++ b/webkit/glue/devtools/js/dom_agent.js @@ -254,14 +254,14 @@ devtools.DomDocument.prototype.fireDomEvent_ = function(name, event) { devtools.DomAgent = function() { this.document = new devtools.DomDocument(); this.idToDomNode_ = { 0 : this.document }; - RemoteDomAgent.GetDocumentElementResult = - devtools.Callback.processCallback; - RemoteDomAgent.GetChildNodesResult = + RemoteDomAgent.DidGetChildNodes = devtools.Callback.processCallback; RemoteDomAgent.AttributesUpdated = goog.bind(this.attributesUpdated, this); - RemoteDomAgent.ChildNodesUpdated = - goog.bind(this.childNodesUpdated, this); + RemoteDomAgent.SetDocumentElement = + goog.bind(this.setDocumentElement, this); + RemoteDomAgent.SetChildNodes = + goog.bind(this.setChildNodes, this); RemoteDomAgent.HasChildrenUpdated = goog.bind(this.hasChildrenUpdated, this); RemoteDomAgent.ChildNodeInserted = @@ -273,28 +273,12 @@ devtools.DomAgent = function() { /** * Requests that the document element is sent from the agent. - * @param {function(Array.<devtools.DomNode>):undefined} opt_callback Callback - * with the result. */ -devtools.DomAgent.prototype.getDocumentElementAsync = function(opt_callback) { +devtools.DomAgent.prototype.getDocumentElementAsync = function() { if (this.document.documentElement) { - if (opt_callback) { - opt_callback(this.document.documentElement); - } return; } - var self = this; - var mycallback = function(payload) { - self.childNodesUpdated(0, [payload]); - self.document.documentElement = self.document.firstChild; - self.document.documentElement.ownerDocument = self.document; - self.document.fireDomEvent_("DOMContentLoaded"); - if (opt_callback) { - opt_callback(self.document.documentElement); - } - }; - var callId = devtools.Callback.wrap(mycallback); - RemoteDomAgent.GetDocumentElement(callId); + RemoteDomAgent.GetDocumentElement(); }; @@ -312,8 +296,7 @@ devtools.DomAgent.prototype.getChildNodesAsync = function(parentId, return; } var self = this; - var mycallback = function(data) { - self.childNodesUpdated(parentId, data); + var mycallback = function() { if (opt_callback) { opt_callback(self.idToDomNode_[parentId].children); } @@ -334,11 +317,39 @@ devtools.DomAgent.prototype.attributesUpdated = function(nodeId, attrsArray) { /** + * Returns node for id. + * @param {number} nodeId Id to get node for. + * @return {devtools.DomNode} Node with given id. + */ +devtools.DomAgent.prototype.getNodeForId = function(nodeId) { + return this.idToDomNode_[nodeId]; +}; + + +/** * @see DomAgentDelegate. * {@inheritDoc}. */ -devtools.DomAgent.prototype.childNodesUpdated = function(parentId, payloads) { +devtools.DomAgent.prototype.setDocumentElement = function(payload) { + if (this.document.documentElement) { + return; + } + this.setChildNodes(0, [payload]); + this.document.documentElement = this.document.firstChild; + this.document.documentElement.ownerDocument = this.document; + this.document.fireDomEvent_("DOMContentLoaded"); +}; + + +/** + * @see DomAgentDelegate. + * {@inheritDoc}. + */ +devtools.DomAgent.prototype.setChildNodes = function(parentId, payloads) { var parent = this.idToDomNode_[parentId]; + if (parent.children) { + return; + } parent.setChildrenPayload_(payloads); var children = parent.children; for (var i = 0; i < children.length; ++i) { diff --git a/webkit/glue/devtools/js/inspector_controller_impl.js b/webkit/glue/devtools/js/inspector_controller_impl.js index b873a2f..5045a7c 100644 --- a/webkit/glue/devtools/js/inspector_controller_impl.js +++ b/webkit/glue/devtools/js/inspector_controller_impl.js @@ -89,4 +89,11 @@ devtools.InspectorControllerImpl.prototype.inspectedWindow = function() { }; +/** + * {@inheritDoc}. + */ +devtools.InspectorController.prototype.loaded = function() { + DevToolsHost.loaded(); +}; + var InspectorController = new devtools.InspectorControllerImpl(); diff --git a/webkit/glue/webdevtoolsagent.h b/webkit/glue/webdevtoolsagent.h index c6b7650..02600f6 100644 --- a/webkit/glue/webdevtoolsagent.h +++ b/webkit/glue/webdevtoolsagent.h @@ -16,6 +16,8 @@ class WebDevToolsAgent { virtual ~WebDevToolsAgent() {} virtual void DispatchMessageFromClient(const std::string& raw_msg) = 0; + + virtual void InspectElement(int x, int y) = 0; private: DISALLOW_COPY_AND_ASSIGN(WebDevToolsAgent); }; diff --git a/webkit/glue/webdevtoolsagent_impl.cc b/webkit/glue/webdevtoolsagent_impl.cc index bb1dd69..e7c3be5 100644 --- a/webkit/glue/webdevtoolsagent_impl.cc +++ b/webkit/glue/webdevtoolsagent_impl.cc @@ -91,14 +91,6 @@ void WebDevToolsAgentImpl::HideDOMNodeHighlight() { page->inspectorController()->hideHighlight(); } -void WebDevToolsAgentImpl::Inspect(Node* node) { - if (!dom_agent_impl_.get()) - return; - - int node_id = dom_agent_impl_->GetPathToNode(node); - tools_agent_delegate_stub_->UpdateFocusedNode(node_id); -} - void WebDevToolsAgentImpl::DispatchMessageFromClient( const std::string& raw_msg) { OwnPtr<ListValue> message( @@ -112,6 +104,16 @@ void WebDevToolsAgentImpl::DispatchMessageFromClient( ToolsAgentDispatch::Dispatch(this, *message.get()); } +void WebDevToolsAgentImpl::InspectElement(int x, int y) { + Node* node = web_view_impl_->GetNodeForWindowPos(x, y); + if (!node) + return; + + SetDomAgentEnabled(true); + int node_id = dom_agent_impl_->PushNodePathToClient(node); + tools_agent_delegate_stub_->UpdateFocusedNode(node_id); +} + void WebDevToolsAgentImpl::SendRpcMessage(const std::string& raw_msg) { delegate_->SendMessageToClient(raw_msg); } diff --git a/webkit/glue/webdevtoolsagent_impl.h b/webkit/glue/webdevtoolsagent_impl.h index b6ea43d..c06bcd6 100644 --- a/webkit/glue/webdevtoolsagent_impl.h +++ b/webkit/glue/webdevtoolsagent_impl.h @@ -43,13 +43,13 @@ class WebDevToolsAgentImpl // WebDevToolsAgent implementation. virtual void DispatchMessageFromClient(const std::string& raw_msg); + virtual void InspectElement(int x, int y); // DevToolsRpc::Delegate implementation. void SendRpcMessage(const std::string& raw_msg); // Methods called by the glue. void SetMainFrameDocumentReady(bool ready); - void Inspect(WebCore::Node* node); DomAgentImpl* dom_agent_impl() { return dom_agent_impl_.get(); } NetAgentImpl* net_agent_impl() { return net_agent_impl_.get(); } diff --git a/webkit/glue/webdevtoolsclient_impl.cc b/webkit/glue/webdevtoolsclient_impl.cc index 269b159..67b8974 100644 --- a/webkit/glue/webdevtoolsclient_impl.cc +++ b/webkit/glue/webdevtoolsclient_impl.cc @@ -12,6 +12,7 @@ #include "Page.h" #include "PlatformString.h" #include <wtf/OwnPtr.h> +#include <wtf/Vector.h> #undef LOG #include "base/json_reader.h" @@ -54,7 +55,8 @@ WebDevToolsClientImpl::WebDevToolsClientImpl( WebViewImpl* web_view_impl, WebDevToolsClientDelegate* delegate) : web_view_impl_(web_view_impl), - delegate_(delegate) { + delegate_(delegate), + loaded_(false) { WebFrame* frame = web_view_impl_->GetMainFrame(); dom_agent_obj_.set(new JsDomAgentBoundObj(this, frame, L"RemoteDomAgent")); net_agent_obj_.set(new JsNetAgentBoundObj(this, frame, L"RemoteNetAgent")); @@ -62,6 +64,7 @@ WebDevToolsClientImpl::WebDevToolsClientImpl( BindToJavascript(frame, L"DevToolsHost"); BindMethod("addSourceToFrame", &WebDevToolsClientImpl::JsAddSourceToFrame); + BindMethod("loaded", &WebDevToolsClientImpl::JsLoaded); } WebDevToolsClientImpl::~WebDevToolsClientImpl() { @@ -69,6 +72,10 @@ WebDevToolsClientImpl::~WebDevToolsClientImpl() { void WebDevToolsClientImpl::DispatchMessageFromAgent( const std::string& raw_msg) { + if (!loaded_) { + pending_incoming_messages_.append(raw_msg); + return; + } OwnPtr<ListValue> message( static_cast<ListValue*>(DevToolsRpc::ParseMessage(raw_msg))); @@ -106,3 +113,15 @@ void WebDevToolsClientImpl::JsAddSourceToFrame( node); result->SetNull(); } + +void WebDevToolsClientImpl::JsLoaded( + const CppArgumentList& args, + CppVariant* result) { + loaded_ = true; + for (Vector<std::string>::iterator it = pending_incoming_messages_.begin(); + it != pending_incoming_messages_.end(); ++it) { + DispatchMessageFromAgent(*it); + } + pending_incoming_messages_.clear(); + result->SetNull(); +} diff --git a/webkit/glue/webdevtoolsclient_impl.h b/webkit/glue/webdevtoolsclient_impl.h index f05cad6..b2877a9 100644 --- a/webkit/glue/webdevtoolsclient_impl.h +++ b/webkit/glue/webdevtoolsclient_impl.h @@ -40,12 +40,15 @@ class WebDevToolsClientImpl : public WebDevToolsClient, private: void JsAddSourceToFrame(const CppArgumentList& args, CppVariant* result); + void JsLoaded(const CppArgumentList& args, CppVariant* result); WebViewImpl* web_view_impl_; WebDevToolsClientDelegate* delegate_; OwnPtr<JsDomAgentBoundObj> dom_agent_obj_; OwnPtr<JsNetAgentBoundObj> net_agent_obj_; OwnPtr<JsToolsAgentBoundObj> tools_agent_obj_; + bool loaded_; + Vector<std::string> pending_incoming_messages_; DISALLOW_COPY_AND_ASSIGN(WebDevToolsClientImpl); }; diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc index 00bc668..6a0b358 100644 --- a/webkit/glue/webview_impl.cc +++ b/webkit/glue/webview_impl.cc @@ -87,7 +87,6 @@ MSVC_POP_WARNING(); #include "webkit/glue/chrome_client_impl.h" #include "webkit/glue/clipboard_conversion.h" #include "webkit/glue/context_menu_client_impl.h" -#include "webkit/glue/webdevtoolsagent_impl.h" #include "webkit/glue/dragclient_impl.h" #include "webkit/glue/editor_client_impl.h" #include "webkit/glue/event_conversion.h" @@ -96,6 +95,7 @@ MSVC_POP_WARNING(); #include "webkit/glue/image_resource_fetcher.h" #include "webkit/glue/inspector_client_impl.h" #include "webkit/glue/searchable_form_data.h" +#include "webkit/glue/webdevtoolsagent_impl.h" #include "webkit/glue/webdropdata.h" #include "webkit/glue/webhistoryitem_impl.h" #include "webkit/glue/webinputevent.h" @@ -1711,6 +1711,11 @@ void WebViewImpl::HideAutoCompletePopup() { } } +WebCore::Node* WebViewImpl::GetNodeForWindowPos(int x, int y) { + HitTestResult result = HitTestResultForWindowPos(IntPoint(x, y)); + return result.innerNonSharedNode(); +} + void WebViewImpl::HideAutofillPopup() { HideAutoCompletePopup(); } diff --git a/webkit/glue/webview_impl.h b/webkit/glue/webview_impl.h index debc82b..465f174 100644 --- a/webkit/glue/webview_impl.h +++ b/webkit/glue/webview_impl.h @@ -197,6 +197,10 @@ class WebViewImpl : public WebView, public base::RefCounted<WebViewImpl> { // Hides the autocomplete popup if it is showing. void HideAutoCompletePopup(); + // Converts |x|, |y| from window coordinates to contents coordinates and gets + // the underlying Node for them. + WebCore::Node* GetNodeForWindowPos(int x, int y); + protected: friend class WebView; // So WebView::Create can call our constructor friend class base::RefCounted<WebViewImpl>; |