• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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_ui_bindings.h"
6 
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/chrome_page_zoom.h"
17 #include "chrome/browser/devtools/devtools_target_impl.h"
18 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/infobars/infobar_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/themes/theme_properties.h"
23 #include "chrome/browser/themes/theme_service.h"
24 #include "chrome/browser/themes/theme_service_factory.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_iterator.h"
27 #include "chrome/browser/ui/browser_list.h"
28 #include "chrome/browser/ui/browser_window.h"
29 #include "chrome/browser/ui/tabs/tab_strip_model.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/extensions/manifest_url_handler.h"
32 #include "chrome/common/url_constants.h"
33 #include "chrome/grit/generated_resources.h"
34 #include "components/infobars/core/confirm_infobar_delegate.h"
35 #include "components/infobars/core/infobar.h"
36 #include "content/public/browser/favicon_status.h"
37 #include "content/public/browser/invalidate_type.h"
38 #include "content/public/browser/navigation_controller.h"
39 #include "content/public/browser/navigation_entry.h"
40 #include "content/public/browser/notification_source.h"
41 #include "content/public/browser/render_frame_host.h"
42 #include "content/public/browser/render_view_host.h"
43 #include "content/public/browser/user_metrics.h"
44 #include "content/public/browser/web_contents.h"
45 #include "content/public/browser/web_contents_observer.h"
46 #include "content/public/common/renderer_preferences.h"
47 #include "content/public/common/url_constants.h"
48 #include "extensions/browser/extension_system.h"
49 #include "extensions/common/extension_set.h"
50 #include "extensions/common/permissions/permissions_data.h"
51 #include "ui/base/l10n/l10n_util.h"
52 #include "ui/base/page_transition_types.h"
53 
54 using base::DictionaryValue;
55 using content::BrowserThread;
56 
57 namespace {
58 
59 static const char kFrontendHostId[] = "id";
60 static const char kFrontendHostMethod[] = "method";
61 static const char kFrontendHostParams[] = "params";
62 static const char kTitleFormat[] = "Developer Tools - %s";
63 
64 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList;
65 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
66     LAZY_INSTANCE_INITIALIZER;
67 
SkColorToRGBAString(SkColor color)68 std::string SkColorToRGBAString(SkColor color) {
69   // We avoid StringPrintf because it will use locale specific formatters for
70   // the double (e.g. ',' instead of '.' in German).
71   return "rgba(" + base::IntToString(SkColorGetR(color)) + "," +
72       base::IntToString(SkColorGetG(color)) + "," +
73       base::IntToString(SkColorGetB(color)) + "," +
74       base::DoubleToString(SkColorGetA(color) / 255.0) + ")";
75 }
76 
CreateFileSystemValue(DevToolsFileHelper::FileSystem file_system)77 base::DictionaryValue* CreateFileSystemValue(
78     DevToolsFileHelper::FileSystem file_system) {
79   base::DictionaryValue* file_system_value = new base::DictionaryValue();
80   file_system_value->SetString("fileSystemName", file_system.file_system_name);
81   file_system_value->SetString("rootURL", file_system.root_url);
82   file_system_value->SetString("fileSystemPath", file_system.file_system_path);
83   return file_system_value;
84 }
85 
FindBrowser(content::WebContents * web_contents)86 Browser* FindBrowser(content::WebContents* web_contents) {
87   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
88     int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
89         web_contents);
90     if (tab_index != TabStripModel::kNoTab)
91       return *it;
92   }
93   return NULL;
94 }
95 
96 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
97 
98 typedef base::Callback<void(bool)> InfoBarCallback;
99 
100 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
101  public:
102   // If |infobar_service| is NULL, runs |callback| with a single argument with
103   // value "false".  Otherwise, creates a dev tools confirm infobar and delegate
104   // and adds the infobar to |infobar_service|.
105   static void Create(InfoBarService* infobar_service,
106                      const InfoBarCallback& callback,
107                      const base::string16& message);
108 
109  private:
110   DevToolsConfirmInfoBarDelegate(
111       const InfoBarCallback& callback,
112       const base::string16& message);
113   virtual ~DevToolsConfirmInfoBarDelegate();
114 
115   virtual base::string16 GetMessageText() const OVERRIDE;
116   virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
117   virtual bool Accept() OVERRIDE;
118   virtual bool Cancel() OVERRIDE;
119 
120   InfoBarCallback callback_;
121   const base::string16 message_;
122 
123   DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
124 };
125 
Create(InfoBarService * infobar_service,const InfoBarCallback & callback,const base::string16 & message)126 void DevToolsConfirmInfoBarDelegate::Create(
127     InfoBarService* infobar_service,
128     const InfoBarCallback& callback,
129     const base::string16& message) {
130   if (!infobar_service) {
131     callback.Run(false);
132     return;
133   }
134 
135   infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
136       scoped_ptr<ConfirmInfoBarDelegate>(
137           new DevToolsConfirmInfoBarDelegate(callback, message))));
138 }
139 
DevToolsConfirmInfoBarDelegate(const InfoBarCallback & callback,const base::string16 & message)140 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
141     const InfoBarCallback& callback,
142     const base::string16& message)
143     : ConfirmInfoBarDelegate(),
144       callback_(callback),
145       message_(message) {
146 }
147 
~DevToolsConfirmInfoBarDelegate()148 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
149   if (!callback_.is_null())
150     callback_.Run(false);
151 }
152 
GetMessageText() const153 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
154   return message_;
155 }
156 
GetButtonLabel(InfoBarButton button) const157 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
158     InfoBarButton button) const {
159   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
160       IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
161 }
162 
Accept()163 bool DevToolsConfirmInfoBarDelegate::Accept() {
164   callback_.Run(true);
165   callback_.Reset();
166   return true;
167 }
168 
Cancel()169 bool DevToolsConfirmInfoBarDelegate::Cancel() {
170   callback_.Run(false);
171   callback_.Reset();
172   return true;
173 }
174 
175 // DevToolsUIDefaultDelegate --------------------------------------------------
176 
177 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate {
178  public:
DefaultBindingsDelegate(content::WebContents * web_contents)179   explicit DefaultBindingsDelegate(content::WebContents* web_contents)
180       : web_contents_(web_contents) {}
181 
182  private:
~DefaultBindingsDelegate()183   virtual ~DefaultBindingsDelegate() {}
184 
185   virtual void ActivateWindow() OVERRIDE;
CloseWindow()186   virtual void CloseWindow() OVERRIDE {}
SetInspectedPageBounds(const gfx::Rect & rect)187   virtual void SetInspectedPageBounds(const gfx::Rect& rect) OVERRIDE {}
InspectElementCompleted()188   virtual void InspectElementCompleted() OVERRIDE {}
MoveWindow(int x,int y)189   virtual void MoveWindow(int x, int y) OVERRIDE {}
SetIsDocked(bool is_docked)190   virtual void SetIsDocked(bool is_docked) OVERRIDE {}
191   virtual void OpenInNewTab(const std::string& url) OVERRIDE;
SetWhitelistedShortcuts(const std::string & message)192   virtual void SetWhitelistedShortcuts(const std::string& message) OVERRIDE {}
193 
194   virtual void InspectedContentsClosing() OVERRIDE;
OnLoadCompleted()195   virtual void OnLoadCompleted() OVERRIDE {}
196   virtual InfoBarService* GetInfoBarService() OVERRIDE;
RenderProcessGone()197   virtual void RenderProcessGone() OVERRIDE {}
198 
199   content::WebContents* web_contents_;
200   DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate);
201 };
202 
ActivateWindow()203 void DefaultBindingsDelegate::ActivateWindow() {
204   web_contents_->GetDelegate()->ActivateContents(web_contents_);
205   web_contents_->Focus();
206 }
207 
OpenInNewTab(const std::string & url)208 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) {
209   content::OpenURLParams params(
210       GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
211       ui::PAGE_TRANSITION_LINK, false);
212   Browser* browser = FindBrowser(web_contents_);
213   browser->OpenURL(params);
214 }
215 
InspectedContentsClosing()216 void DefaultBindingsDelegate::InspectedContentsClosing() {
217   web_contents_->GetRenderViewHost()->ClosePage();
218 }
219 
GetInfoBarService()220 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() {
221   return InfoBarService::FromWebContents(web_contents_);
222 }
223 
224 }  // namespace
225 
226 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
227 
228 class DevToolsUIBindings::FrontendWebContentsObserver
229     : public content::WebContentsObserver {
230  public:
231   explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings);
232   virtual ~FrontendWebContentsObserver();
233 
234  private:
235   // contents::WebContentsObserver:
236   virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
237   virtual void AboutToNavigateRenderView(
238       content::RenderViewHost* render_view_host) OVERRIDE;
239   virtual void DocumentOnLoadCompletedInMainFrame() OVERRIDE;
240 
241   DevToolsUIBindings* devtools_bindings_;
242   DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
243 };
244 
FrontendWebContentsObserver(DevToolsUIBindings * devtools_ui_bindings)245 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
246     DevToolsUIBindings* devtools_ui_bindings)
247     : WebContentsObserver(devtools_ui_bindings->web_contents()),
248       devtools_bindings_(devtools_ui_bindings) {
249 }
250 
251 DevToolsUIBindings::FrontendWebContentsObserver::
~FrontendWebContentsObserver()252     ~FrontendWebContentsObserver() {
253 }
254 
RenderProcessGone(base::TerminationStatus status)255 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
256     base::TerminationStatus status) {
257   switch (status) {
258     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
259     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
260     case base::TERMINATION_STATUS_PROCESS_CRASHED:
261       if (devtools_bindings_->agent_host_.get())
262         devtools_bindings_->Detach();
263       break;
264     default:
265       break;
266   }
267   devtools_bindings_->delegate_->RenderProcessGone();
268 }
269 
AboutToNavigateRenderView(content::RenderViewHost * render_view_host)270 void DevToolsUIBindings::FrontendWebContentsObserver::AboutToNavigateRenderView(
271     content::RenderViewHost* render_view_host) {
272   devtools_bindings_->frontend_host_.reset(
273       content::DevToolsFrontendHost::Create(
274           render_view_host, devtools_bindings_));
275 }
276 
277 void DevToolsUIBindings::FrontendWebContentsObserver::
DocumentOnLoadCompletedInMainFrame()278     DocumentOnLoadCompletedInMainFrame() {
279   devtools_bindings_->DocumentOnLoadCompletedInMainFrame();
280 }
281 
282 // DevToolsUIBindings ---------------------------------------------------------
283 
ForWebContents(content::WebContents * web_contents)284 DevToolsUIBindings* DevToolsUIBindings::ForWebContents(
285      content::WebContents* web_contents) {
286  if (g_instances == NULL)
287    return NULL;
288  DevToolsUIBindingsList* instances = g_instances.Pointer();
289  for (DevToolsUIBindingsList::iterator it(instances->begin());
290       it != instances->end(); ++it) {
291    if ((*it)->web_contents() == web_contents)
292      return *it;
293  }
294  return NULL;
295 }
296 
297 // static
ApplyThemeToURL(Profile * profile,const GURL & base_url)298 GURL DevToolsUIBindings::ApplyThemeToURL(Profile* profile,
299                                          const GURL& base_url) {
300   std::string frontend_url = base_url.spec();
301   ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
302   DCHECK(tp);
303   std::string url_string(
304       frontend_url +
305       ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
306       "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
307       "&toolbarColor=" +
308       SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
309       "&textColor=" +
310       SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)));
311   if (CommandLine::ForCurrentProcess()->HasSwitch(
312       switches::kEnableDevToolsExperiments))
313     url_string += "&experiments=true";
314 #if defined(DEBUG_DEVTOOLS)
315   url_string += "&debugFrontend=true";
316 #endif  // defined(DEBUG_DEVTOOLS)
317   return GURL(url_string);
318 }
319 
DevToolsUIBindings(content::WebContents * web_contents)320 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
321     : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
322       web_contents_(web_contents),
323       delegate_(new DefaultBindingsDelegate(web_contents_)),
324       device_count_updates_enabled_(false),
325       devices_updates_enabled_(false),
326       weak_factory_(this) {
327   g_instances.Get().push_back(this);
328   frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
329   web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
330 
331   file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_));
332   file_system_indexer_ = new DevToolsFileSystemIndexer();
333   extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
334       web_contents_);
335 
336   // Wipe out page icon so that the default application icon is used.
337   content::NavigationEntry* entry =
338       web_contents_->GetController().GetActiveEntry();
339   entry->GetFavicon().image = gfx::Image();
340   entry->GetFavicon().valid = true;
341 
342   // Register on-load actions.
343   registrar_.Add(
344       this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
345       content::Source<ThemeService>(
346           ThemeServiceFactory::GetForProfile(profile_)));
347 
348   embedder_message_dispatcher_.reset(
349       DevToolsEmbedderMessageDispatcher::createForDevToolsFrontend(this));
350 
351   frontend_host_.reset(
352       content::DevToolsFrontendHost::Create(
353           web_contents_->GetRenderViewHost(), this));
354 }
355 
~DevToolsUIBindings()356 DevToolsUIBindings::~DevToolsUIBindings() {
357   if (agent_host_.get())
358     agent_host_->DetachClient();
359 
360   for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
361        jobs_it != indexing_jobs_.end(); ++jobs_it) {
362     jobs_it->second->Stop();
363   }
364   indexing_jobs_.clear();
365   SetDeviceCountUpdatesEnabled(false);
366   SetDevicesUpdatesEnabled(false);
367 
368   // Remove self from global list.
369   DevToolsUIBindingsList* instances = g_instances.Pointer();
370   DevToolsUIBindingsList::iterator it(
371       std::find(instances->begin(), instances->end(), this));
372   DCHECK(it != instances->end());
373   instances->erase(it);
374 }
375 
376 // content::NotificationObserver overrides ------------------------------------
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)377 void DevToolsUIBindings::Observe(int type,
378                                  const content::NotificationSource& source,
379                                  const content::NotificationDetails& details) {
380   DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
381   UpdateTheme();
382 }
383 
384 // content::DevToolsFrontendHost::Delegate implementation ---------------------
HandleMessageFromDevToolsFrontend(const std::string & message)385 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
386     const std::string& message) {
387   std::string method;
388   base::ListValue empty_params;
389   base::ListValue* params = &empty_params;
390 
391   base::DictionaryValue* dict = NULL;
392   scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
393   if (!parsed_message ||
394       !parsed_message->GetAsDictionary(&dict) ||
395       !dict->GetString(kFrontendHostMethod, &method) ||
396       (dict->HasKey(kFrontendHostParams) &&
397           !dict->GetList(kFrontendHostParams, &params))) {
398     LOG(ERROR) << "Invalid message was sent to embedder: " << message;
399     return;
400   }
401 
402   int id = 0;
403   dict->GetInteger(kFrontendHostId, &id);
404 
405   std::string error;
406   embedder_message_dispatcher_->Dispatch(method, params, &error);
407   if (id) {
408     base::FundamentalValue id_value(id);
409     base::StringValue error_value(error);
410     CallClientFunction("InspectorFrontendAPI.embedderMessageAck",
411                        &id_value, &error_value, NULL);
412   }
413 }
414 
HandleMessageFromDevToolsFrontendToBackend(const std::string & message)415 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
416     const std::string& message) {
417   if (agent_host_.get())
418     agent_host_->DispatchProtocolMessage(message);
419 }
420 
421 // content::DevToolsAgentHostClient implementation --------------------------
DispatchProtocolMessage(content::DevToolsAgentHost * agent_host,const std::string & message)422 void DevToolsUIBindings::DispatchProtocolMessage(
423     content::DevToolsAgentHost* agent_host, const std::string& message) {
424   DCHECK(agent_host == agent_host_.get());
425   base::StringValue message_value(message);
426   CallClientFunction("InspectorFrontendAPI.dispatchMessage",
427                      &message_value, NULL, NULL);
428 }
429 
AgentHostClosed(content::DevToolsAgentHost * agent_host,bool replaced_with_another_client)430 void DevToolsUIBindings::AgentHostClosed(
431     content::DevToolsAgentHost* agent_host,
432     bool replaced_with_another_client) {
433   DCHECK(agent_host == agent_host_.get());
434   agent_host_ = NULL;
435   delegate_->InspectedContentsClosing();
436 }
437 
438 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
ActivateWindow()439 void DevToolsUIBindings::ActivateWindow() {
440   delegate_->ActivateWindow();
441 }
442 
CloseWindow()443 void DevToolsUIBindings::CloseWindow() {
444   delegate_->CloseWindow();
445 }
446 
SetInspectedPageBounds(const gfx::Rect & rect)447 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) {
448   delegate_->SetInspectedPageBounds(rect);
449 }
450 
MoveWindow(int x,int y)451 void DevToolsUIBindings::MoveWindow(int x, int y) {
452   delegate_->MoveWindow(x, y);
453 }
454 
SetIsDocked(bool dock_requested)455 void DevToolsUIBindings::SetIsDocked(bool dock_requested) {
456   delegate_->SetIsDocked(dock_requested);
457 }
458 
InspectElementCompleted()459 void DevToolsUIBindings::InspectElementCompleted() {
460   delegate_->InspectElementCompleted();
461 }
462 
InspectedURLChanged(const std::string & url)463 void DevToolsUIBindings::InspectedURLChanged(const std::string& url) {
464   content::NavigationController& controller = web_contents()->GetController();
465   content::NavigationEntry* entry = controller.GetActiveEntry();
466   // DevTools UI is not localized.
467   entry->SetTitle(
468       base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
469   web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
470 }
471 
OpenInNewTab(const std::string & url)472 void DevToolsUIBindings::OpenInNewTab(const std::string& url) {
473   delegate_->OpenInNewTab(url);
474 }
475 
SaveToFile(const std::string & url,const std::string & content,bool save_as)476 void DevToolsUIBindings::SaveToFile(const std::string& url,
477                                     const std::string& content,
478                                     bool save_as) {
479   file_helper_->Save(url, content, save_as,
480                      base::Bind(&DevToolsUIBindings::FileSavedAs,
481                                 weak_factory_.GetWeakPtr(), url),
482                      base::Bind(&DevToolsUIBindings::CanceledFileSaveAs,
483                                 weak_factory_.GetWeakPtr(), url));
484 }
485 
AppendToFile(const std::string & url,const std::string & content)486 void DevToolsUIBindings::AppendToFile(const std::string& url,
487                                       const std::string& content) {
488   file_helper_->Append(url, content,
489                        base::Bind(&DevToolsUIBindings::AppendedTo,
490                                   weak_factory_.GetWeakPtr(), url));
491 }
492 
RequestFileSystems()493 void DevToolsUIBindings::RequestFileSystems() {
494   CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
495   file_helper_->RequestFileSystems(base::Bind(
496       &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
497 }
498 
AddFileSystem()499 void DevToolsUIBindings::AddFileSystem() {
500   CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
501   file_helper_->AddFileSystem(
502       base::Bind(&DevToolsUIBindings::FileSystemAdded,
503                  weak_factory_.GetWeakPtr()),
504       base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
505                  weak_factory_.GetWeakPtr()));
506 }
507 
RemoveFileSystem(const std::string & file_system_path)508 void DevToolsUIBindings::RemoveFileSystem(
509     const std::string& file_system_path) {
510   CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
511   file_helper_->RemoveFileSystem(file_system_path);
512   base::StringValue file_system_path_value(file_system_path);
513   CallClientFunction("InspectorFrontendAPI.fileSystemRemoved",
514                      &file_system_path_value, NULL, NULL);
515 }
516 
UpgradeDraggedFileSystemPermissions(const std::string & file_system_url)517 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
518     const std::string& file_system_url) {
519   CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
520   file_helper_->UpgradeDraggedFileSystemPermissions(
521       file_system_url,
522       base::Bind(&DevToolsUIBindings::FileSystemAdded,
523                  weak_factory_.GetWeakPtr()),
524       base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
525                  weak_factory_.GetWeakPtr()));
526 }
527 
IndexPath(int request_id,const std::string & file_system_path)528 void DevToolsUIBindings::IndexPath(int request_id,
529                                    const std::string& file_system_path) {
530   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
531   CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
532   if (!file_helper_->IsFileSystemAdded(file_system_path)) {
533     IndexingDone(request_id, file_system_path);
534     return;
535   }
536   indexing_jobs_[request_id] =
537       scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
538           file_system_indexer_->IndexPath(
539               file_system_path,
540               Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
541                    weak_factory_.GetWeakPtr(),
542                    request_id,
543                    file_system_path),
544               Bind(&DevToolsUIBindings::IndexingWorked,
545                    weak_factory_.GetWeakPtr(),
546                    request_id,
547                    file_system_path),
548               Bind(&DevToolsUIBindings::IndexingDone,
549                    weak_factory_.GetWeakPtr(),
550                    request_id,
551                    file_system_path)));
552 }
553 
StopIndexing(int request_id)554 void DevToolsUIBindings::StopIndexing(int request_id) {
555   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
556   IndexingJobsMap::iterator it = indexing_jobs_.find(request_id);
557   if (it == indexing_jobs_.end())
558     return;
559   it->second->Stop();
560   indexing_jobs_.erase(it);
561 }
562 
SearchInPath(int request_id,const std::string & file_system_path,const std::string & query)563 void DevToolsUIBindings::SearchInPath(int request_id,
564                                       const std::string& file_system_path,
565                                       const std::string& query) {
566   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
567   CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
568   if (!file_helper_->IsFileSystemAdded(file_system_path)) {
569     SearchCompleted(request_id, file_system_path, std::vector<std::string>());
570     return;
571   }
572   file_system_indexer_->SearchInPath(file_system_path,
573                                      query,
574                                      Bind(&DevToolsUIBindings::SearchCompleted,
575                                           weak_factory_.GetWeakPtr(),
576                                           request_id,
577                                           file_system_path));
578 }
579 
SetWhitelistedShortcuts(const std::string & message)580 void DevToolsUIBindings::SetWhitelistedShortcuts(
581     const std::string& message) {
582   delegate_->SetWhitelistedShortcuts(message);
583 }
584 
ZoomIn()585 void DevToolsUIBindings::ZoomIn() {
586   chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_IN);
587 }
588 
ZoomOut()589 void DevToolsUIBindings::ZoomOut() {
590   chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
591 }
592 
ResetZoom()593 void DevToolsUIBindings::ResetZoom() {
594   chrome_page_zoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET);
595 }
596 
InspectTarget(Profile * profile,DevToolsTargetImpl * target)597 static void InspectTarget(Profile* profile, DevToolsTargetImpl* target) {
598   if (target)
599     target->Inspect(profile);
600 }
601 
OpenUrlOnRemoteDeviceAndInspect(const std::string & browser_id,const std::string & url)602 void DevToolsUIBindings::OpenUrlOnRemoteDeviceAndInspect(
603     const std::string& browser_id,
604     const std::string& url) {
605   if (remote_targets_handler_) {
606     remote_targets_handler_->Open(browser_id, url,
607         base::Bind(&InspectTarget, profile_));
608   }
609 }
610 
SetDeviceCountUpdatesEnabled(bool enabled)611 void DevToolsUIBindings::SetDeviceCountUpdatesEnabled(bool enabled) {
612   if (device_count_updates_enabled_ == enabled)
613     return;
614   DevToolsAndroidBridge* adb_bridge =
615       DevToolsAndroidBridge::Factory::GetForProfile(profile_);
616   if (!adb_bridge)
617     return;
618 
619   device_count_updates_enabled_ = enabled;
620   if (enabled)
621     adb_bridge->AddDeviceCountListener(this);
622   else
623     adb_bridge->RemoveDeviceCountListener(this);
624 }
625 
SetDevicesUpdatesEnabled(bool enabled)626 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) {
627   if (devices_updates_enabled_ == enabled)
628     return;
629   devices_updates_enabled_ = enabled;
630   if (enabled) {
631     remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb(
632         base::Bind(&DevToolsUIBindings::DevicesUpdated,
633                    base::Unretained(this)),
634         profile_);
635   } else {
636     remote_targets_handler_.reset();
637   }
638 }
639 
SendMessageToBrowser(const std::string & message)640 void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) {
641   if (agent_host_.get())
642     agent_host_->DispatchProtocolMessage(message);
643 }
644 
DeviceCountChanged(int count)645 void DevToolsUIBindings::DeviceCountChanged(int count) {
646   base::FundamentalValue value(count);
647   CallClientFunction("InspectorFrontendAPI.deviceCountUpdated", &value, NULL,
648                      NULL);
649 }
650 
DevicesUpdated(const std::string & source,const base::ListValue & targets)651 void DevToolsUIBindings::DevicesUpdated(
652     const std::string& source,
653     const base::ListValue& targets) {
654   CallClientFunction("InspectorFrontendAPI.devicesUpdated", &targets, NULL,
655                      NULL);
656 }
657 
FileSavedAs(const std::string & url)658 void DevToolsUIBindings::FileSavedAs(const std::string& url) {
659   base::StringValue url_value(url);
660   CallClientFunction("InspectorFrontendAPI.savedURL", &url_value, NULL, NULL);
661 }
662 
CanceledFileSaveAs(const std::string & url)663 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) {
664   base::StringValue url_value(url);
665   CallClientFunction("InspectorFrontendAPI.canceledSaveURL",
666                      &url_value, NULL, NULL);
667 }
668 
AppendedTo(const std::string & url)669 void DevToolsUIBindings::AppendedTo(const std::string& url) {
670   base::StringValue url_value(url);
671   CallClientFunction("InspectorFrontendAPI.appendedToURL", &url_value, NULL,
672                      NULL);
673 }
674 
FileSystemsLoaded(const std::vector<DevToolsFileHelper::FileSystem> & file_systems)675 void DevToolsUIBindings::FileSystemsLoaded(
676     const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
677   base::ListValue file_systems_value;
678   for (size_t i = 0; i < file_systems.size(); ++i)
679     file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
680   CallClientFunction("InspectorFrontendAPI.fileSystemsLoaded",
681                      &file_systems_value, NULL, NULL);
682 }
683 
FileSystemAdded(const DevToolsFileHelper::FileSystem & file_system)684 void DevToolsUIBindings::FileSystemAdded(
685     const DevToolsFileHelper::FileSystem& file_system) {
686   scoped_ptr<base::StringValue> error_string_value(
687       new base::StringValue(std::string()));
688   scoped_ptr<base::DictionaryValue> file_system_value;
689   if (!file_system.file_system_path.empty())
690     file_system_value.reset(CreateFileSystemValue(file_system));
691   CallClientFunction("InspectorFrontendAPI.fileSystemAdded",
692                      error_string_value.get(), file_system_value.get(), NULL);
693 }
694 
IndexingTotalWorkCalculated(int request_id,const std::string & file_system_path,int total_work)695 void DevToolsUIBindings::IndexingTotalWorkCalculated(
696     int request_id,
697     const std::string& file_system_path,
698     int total_work) {
699   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
700   base::FundamentalValue request_id_value(request_id);
701   base::StringValue file_system_path_value(file_system_path);
702   base::FundamentalValue total_work_value(total_work);
703   CallClientFunction("InspectorFrontendAPI.indexingTotalWorkCalculated",
704                      &request_id_value, &file_system_path_value,
705                      &total_work_value);
706 }
707 
IndexingWorked(int request_id,const std::string & file_system_path,int worked)708 void DevToolsUIBindings::IndexingWorked(int request_id,
709                                         const std::string& file_system_path,
710                                         int worked) {
711   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
712   base::FundamentalValue request_id_value(request_id);
713   base::StringValue file_system_path_value(file_system_path);
714   base::FundamentalValue worked_value(worked);
715   CallClientFunction("InspectorFrontendAPI.indexingWorked", &request_id_value,
716                      &file_system_path_value, &worked_value);
717 }
718 
IndexingDone(int request_id,const std::string & file_system_path)719 void DevToolsUIBindings::IndexingDone(int request_id,
720                                       const std::string& file_system_path) {
721   indexing_jobs_.erase(request_id);
722   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
723   base::FundamentalValue request_id_value(request_id);
724   base::StringValue file_system_path_value(file_system_path);
725   CallClientFunction("InspectorFrontendAPI.indexingDone", &request_id_value,
726                      &file_system_path_value, NULL);
727 }
728 
SearchCompleted(int request_id,const std::string & file_system_path,const std::vector<std::string> & file_paths)729 void DevToolsUIBindings::SearchCompleted(
730     int request_id,
731     const std::string& file_system_path,
732     const std::vector<std::string>& file_paths) {
733   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
734   base::ListValue file_paths_value;
735   for (std::vector<std::string>::const_iterator it(file_paths.begin());
736        it != file_paths.end(); ++it) {
737     file_paths_value.AppendString(*it);
738   }
739   base::FundamentalValue request_id_value(request_id);
740   base::StringValue file_system_path_value(file_system_path);
741   CallClientFunction("InspectorFrontendAPI.searchCompleted", &request_id_value,
742                      &file_system_path_value, &file_paths_value);
743 }
744 
ShowDevToolsConfirmInfoBar(const base::string16 & message,const InfoBarCallback & callback)745 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
746     const base::string16& message,
747     const InfoBarCallback& callback) {
748   DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(),
749       callback, message);
750 }
751 
UpdateTheme()752 void DevToolsUIBindings::UpdateTheme() {
753   ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
754   DCHECK(tp);
755 
756   std::string command("InspectorFrontendAPI.setToolbarColors(\"" +
757       SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
758       "\", \"" +
759       SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
760       "\")");
761   web_contents_->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command));
762 }
763 
AddDevToolsExtensionsToClient()764 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
765   const ExtensionService* extension_service = extensions::ExtensionSystem::Get(
766       profile_->GetOriginalProfile())->extension_service();
767   if (!extension_service)
768     return;
769   const extensions::ExtensionSet* extensions = extension_service->extensions();
770 
771   base::ListValue results;
772   for (extensions::ExtensionSet::const_iterator extension(extensions->begin());
773        extension != extensions->end(); ++extension) {
774     if (extensions::ManifestURL::GetDevToolsPage(extension->get()).is_empty())
775       continue;
776     base::DictionaryValue* extension_info = new base::DictionaryValue();
777     extension_info->Set(
778         "startPage",
779         new base::StringValue(
780             extensions::ManifestURL::GetDevToolsPage(
781                 extension->get()).spec()));
782     extension_info->Set("name", new base::StringValue((*extension)->name()));
783     extension_info->Set("exposeExperimentalAPIs",
784                         new base::FundamentalValue(
785                             (*extension)->permissions_data()->HasAPIPermission(
786                                 extensions::APIPermission::kExperimental)));
787     results.Append(extension_info);
788   }
789   CallClientFunction("WebInspector.addExtensions", &results, NULL, NULL);
790 }
791 
SetDelegate(Delegate * delegate)792 void DevToolsUIBindings::SetDelegate(Delegate* delegate) {
793   delegate_.reset(delegate);
794 }
795 
AttachTo(const scoped_refptr<content::DevToolsAgentHost> & agent_host)796 void DevToolsUIBindings::AttachTo(
797     const scoped_refptr<content::DevToolsAgentHost>& agent_host) {
798   if (agent_host_.get())
799     Detach();
800   agent_host_ = agent_host;
801   agent_host_->AttachClient(this);
802 }
803 
Reattach()804 void DevToolsUIBindings::Reattach() {
805   DCHECK(agent_host_.get());
806   agent_host_->DetachClient();
807   agent_host_->AttachClient(this);
808 }
809 
Detach()810 void DevToolsUIBindings::Detach() {
811   if (agent_host_.get())
812     agent_host_->DetachClient();
813   agent_host_ = NULL;
814 }
815 
IsAttachedTo(content::DevToolsAgentHost * agent_host)816 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) {
817   return agent_host_.get() == agent_host;
818 }
819 
CallClientFunction(const std::string & function_name,const base::Value * arg1,const base::Value * arg2,const base::Value * arg3)820 void DevToolsUIBindings::CallClientFunction(const std::string& function_name,
821                                             const base::Value* arg1,
822                                             const base::Value* arg2,
823                                             const base::Value* arg3) {
824   std::string params;
825   if (arg1) {
826     std::string json;
827     base::JSONWriter::Write(arg1, &json);
828     params.append(json);
829     if (arg2) {
830       base::JSONWriter::Write(arg2, &json);
831       params.append(", " + json);
832       if (arg3) {
833         base::JSONWriter::Write(arg3, &json);
834         params.append(", " + json);
835       }
836     }
837   }
838 
839   base::string16 javascript = base::UTF8ToUTF16(
840       function_name + "(" + params + ");");
841   web_contents_->GetMainFrame()->ExecuteJavaScript(javascript);
842 }
843 
DocumentOnLoadCompletedInMainFrame()844 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
845   // Call delegate first - it seeds importants bit of information.
846   delegate_->OnLoadCompleted();
847 
848   UpdateTheme();
849   AddDevToolsExtensionsToClient();
850 }
851