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