1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/devtools/devtools_embedder_message_dispatcher.h"
6
7#include "base/bind.h"
8#include "base/values.h"
9
10namespace {
11
12bool GetValue(const base::ListValue& list, int pos, std::string& value) {
13  return list.GetString(pos, &value);
14}
15
16bool GetValue(const base::ListValue& list, int pos, int& value) {
17  return list.GetInteger(pos, &value);
18}
19
20bool GetValue(const base::ListValue& list, int pos, bool& value) {
21  return list.GetBoolean(pos, &value);
22}
23
24bool GetValue(const base::ListValue& list, int pos, gfx::Rect& rect) {
25  const base::DictionaryValue* dict;
26  if (!list.GetDictionary(pos, &dict))
27    return false;
28  int x = 0;
29  int y = 0;
30  int width = 0;
31  int height = 0;
32  if (!dict->GetInteger("x", &x) ||
33      !dict->GetInteger("y", &y) ||
34      !dict->GetInteger("width", &width) ||
35      !dict->GetInteger("height", &height))
36    return false;
37  rect.SetRect(x, y, width, height);
38  return true;
39}
40
41template <typename T>
42struct StorageTraits {
43  typedef T StorageType;
44};
45
46template <typename T>
47struct StorageTraits<const T&> {
48  typedef T StorageType;
49};
50
51template <class A>
52class Argument {
53 public:
54  typedef typename StorageTraits<A>::StorageType ValueType;
55
56  Argument(const base::ListValue& list, int pos) {
57    valid_ = GetValue(list, pos, value_);
58  }
59
60  ValueType value() const { return value_; }
61  bool valid() const { return valid_; }
62
63 private:
64  ValueType value_;
65  bool valid_;
66};
67
68bool ParseAndHandle0(const base::Callback<void(void)>& handler,
69                     const base::ListValue& list) {
70  if (list.GetSize() != 0)
71      return false;
72  handler.Run();
73  return true;
74}
75
76template <class A1>
77bool ParseAndHandle1(const base::Callback<void(A1)>& handler,
78                     const base::ListValue& list) {
79  if (list.GetSize() != 1)
80    return false;
81  Argument<A1> arg1(list, 0);
82  if (!arg1.valid())
83    return false;
84  handler.Run(arg1.value());
85  return true;
86}
87
88template <class A1, class A2>
89bool ParseAndHandle2(const base::Callback<void(A1, A2)>& handler,
90                     const base::ListValue& list) {
91  if (list.GetSize() != 2)
92    return false;
93  Argument<A1> arg1(list, 0);
94  if (!arg1.valid())
95    return false;
96  Argument<A2> arg2(list, 1);
97  if (!arg2.valid())
98    return false;
99  handler.Run(arg1.value(), arg2.value());
100  return true;
101}
102
103template <class A1, class A2, class A3>
104bool ParseAndHandle3(const base::Callback<void(A1, A2, A3)>& handler,
105                     const base::ListValue& list) {
106  if (list.GetSize() != 3)
107    return false;
108  Argument<A1> arg1(list, 0);
109  if (!arg1.valid())
110    return false;
111  Argument<A2> arg2(list, 1);
112  if (!arg2.valid())
113    return false;
114  Argument<A3> arg3(list, 2);
115  if (!arg3.valid())
116    return false;
117  handler.Run(arg1.value(), arg2.value(), arg3.value());
118  return true;
119}
120
121template <class A1, class A2, class A3, class A4>
122bool ParseAndHandle4(const base::Callback<void(A1, A2, A3, A4)>& handler,
123                     const base::ListValue& list) {
124  if (list.GetSize() != 4)
125    return false;
126  Argument<A1> arg1(list, 0);
127  if (!arg1.valid())
128    return false;
129  Argument<A2> arg2(list, 1);
130  if (!arg2.valid())
131    return false;
132  Argument<A3> arg3(list, 2);
133  if (!arg3.valid())
134    return false;
135  Argument<A4> arg4(list, 3);
136  if (!arg4.valid())
137    return false;
138  handler.Run(arg1.value(), arg2.value(), arg3.value(), arg4.value());
139  return true;
140}
141
142} // namespace
143
144/**
145 * Dispatcher for messages sent from the frontend running in an
146 * isolated renderer (chrome-devtools:// or chrome://inspect) to the embedder
147 * in the browser.
148 *
149 * The messages are sent via InspectorFrontendHost.sendMessageToEmbedder or
150 * chrome.send method accordingly.
151 */
152class DispatcherImpl : public DevToolsEmbedderMessageDispatcher {
153 public:
154  virtual ~DispatcherImpl() {}
155
156  virtual bool Dispatch(const std::string& method,
157                        const base::ListValue* params,
158                        std::string* error) OVERRIDE {
159    HandlerMap::iterator it = handlers_.find(method);
160    if (it == handlers_.end())
161      return false;
162
163    if (it->second.Run(*params))
164      return true;
165
166    if (error)
167      *error = "Invalid frontend host message parameters: " + method;
168    return false;
169  }
170
171  typedef base::Callback<bool(const base::ListValue&)> Handler;
172  void RegisterHandler(const std::string& method, const Handler& handler) {
173    handlers_[method] = handler;
174  }
175
176  template<class T>
177  void RegisterHandler(const std::string& method,
178                       void (T::*handler)(), T* delegate) {
179    handlers_[method] = base::Bind(&ParseAndHandle0,
180                                   base::Bind(handler,
181                                              base::Unretained(delegate)));
182  }
183
184  template<class T, class A1>
185  void RegisterHandler(const std::string& method,
186                       void (T::*handler)(A1), T* delegate) {
187    handlers_[method] = base::Bind(ParseAndHandle1<A1>,
188                                   base::Bind(handler,
189                                              base::Unretained(delegate)));
190  }
191
192  template<class T, class A1, class A2>
193  void RegisterHandler(const std::string& method,
194                       void (T::*handler)(A1, A2), T* delegate) {
195    handlers_[method] = base::Bind(ParseAndHandle2<A1, A2>,
196                                   base::Bind(handler,
197                                              base::Unretained(delegate)));
198  }
199
200  template<class T, class A1, class A2, class A3>
201  void RegisterHandler(const std::string& method,
202                       void (T::*handler)(A1, A2, A3), T* delegate) {
203    handlers_[method] = base::Bind(ParseAndHandle3<A1, A2, A3>,
204                                   base::Bind(handler,
205                                              base::Unretained(delegate)));
206  }
207
208  template<class T, class A1, class A2, class A3, class A4>
209  void RegisterHandler(const std::string& method,
210                       void (T::*handler)(A1, A2, A3, A4), T* delegate) {
211    handlers_[method] = base::Bind(ParseAndHandle4<A1, A2, A3, A4>,
212                                   base::Bind(handler,
213                                              base::Unretained(delegate)));
214  }
215
216 private:
217  typedef std::map<std::string, Handler> HandlerMap;
218  HandlerMap handlers_;
219};
220
221
222DevToolsEmbedderMessageDispatcher*
223    DevToolsEmbedderMessageDispatcher::createForDevToolsFrontend(
224        Delegate* delegate) {
225  DispatcherImpl* d = new DispatcherImpl();
226
227  d->RegisterHandler("bringToFront", &Delegate::ActivateWindow, delegate);
228  d->RegisterHandler("closeWindow", &Delegate::CloseWindow, delegate);
229  d->RegisterHandler("setInspectedPageBounds",
230                     &Delegate::SetInspectedPageBounds, delegate);
231  d->RegisterHandler("inspectElementCompleted",
232                     &Delegate::InspectElementCompleted, delegate);
233  d->RegisterHandler("inspectedURLChanged",
234                     &Delegate::InspectedURLChanged, delegate);
235  d->RegisterHandler("moveWindowBy", &Delegate::MoveWindow, delegate);
236  d->RegisterHandler("setIsDocked", &Delegate::SetIsDocked, delegate);
237  d->RegisterHandler("openInNewTab", &Delegate::OpenInNewTab, delegate);
238  d->RegisterHandler("save", &Delegate::SaveToFile, delegate);
239  d->RegisterHandler("append", &Delegate::AppendToFile, delegate);
240  d->RegisterHandler("requestFileSystems",
241                     &Delegate::RequestFileSystems, delegate);
242  d->RegisterHandler("addFileSystem", &Delegate::AddFileSystem, delegate);
243  d->RegisterHandler("removeFileSystem", &Delegate::RemoveFileSystem, delegate);
244  d->RegisterHandler("upgradeDraggedFileSystemPermissions",
245                     &Delegate::UpgradeDraggedFileSystemPermissions, delegate);
246  d->RegisterHandler("indexPath", &Delegate::IndexPath, delegate);
247  d->RegisterHandler("stopIndexing", &Delegate::StopIndexing, delegate);
248  d->RegisterHandler("searchInPath", &Delegate::SearchInPath, delegate);
249  d->RegisterHandler("setWhitelistedShortcuts",
250                     &Delegate::SetWhitelistedShortcuts, delegate);
251  d->RegisterHandler("zoomIn", &Delegate::ZoomIn, delegate);
252  d->RegisterHandler("zoomOut", &Delegate::ZoomOut, delegate);
253  d->RegisterHandler("resetZoom", &Delegate::ResetZoom, delegate);
254  d->RegisterHandler("openUrlOnRemoteDeviceAndInspect",
255                     &Delegate::OpenUrlOnRemoteDeviceAndInspect, delegate);
256  d->RegisterHandler("setDeviceCountUpdatesEnabled",
257                     &Delegate::SetDeviceCountUpdatesEnabled, delegate);
258  d->RegisterHandler("setDevicesUpdatesEnabled",
259                     &Delegate::SetDevicesUpdatesEnabled, delegate);
260  d->RegisterHandler("sendMessageToBrowser",
261                     &Delegate::SendMessageToBrowser, delegate);
262  return d;
263}
264