Make castv2 performance test work.
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_ui_bindings.cc
blob03c3c97ae391af45b3c3c767c4f90f82e9308181
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.
5 #include "chrome/browser/devtools/devtools_ui_bindings.h"
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.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/infobars/infobar_service.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/themes/theme_properties.h"
22 #include "chrome/browser/themes/theme_service.h"
23 #include "chrome/browser/themes/theme_service_factory.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_iterator.h"
26 #include "chrome/browser/ui/browser_list.h"
27 #include "chrome/browser/ui/browser_window.h"
28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/extensions/chrome_manifest_url_handlers.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/grit/generated_resources.h"
33 #include "components/infobars/core/confirm_infobar_delegate.h"
34 #include "components/infobars/core/infobar.h"
35 #include "components/ui/zoom/page_zoom.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_registry.h"
49 #include "extensions/common/permissions/permissions_data.h"
50 #include "net/base/io_buffer.h"
51 #include "net/base/net_errors.h"
52 #include "net/http/http_response_headers.h"
53 #include "net/url_request/url_fetcher.h"
54 #include "net/url_request/url_fetcher_response_writer.h"
55 #include "ui/base/l10n/l10n_util.h"
56 #include "ui/base/page_transition_types.h"
58 using base::DictionaryValue;
59 using content::BrowserThread;
61 namespace content {
62 struct LoadCommittedDetails;
63 struct FrameNavigateParams;
66 namespace {
68 static const char kFrontendHostId[] = "id";
69 static const char kFrontendHostMethod[] = "method";
70 static const char kFrontendHostParams[] = "params";
71 static const char kTitleFormat[] = "Developer Tools - %s";
73 static const char kDevToolsActionTakenHistogram[] = "DevTools.ActionTaken";
74 static const int kDevToolsActionTakenBoundary = 100;
75 static const char kDevToolsPanelShownHistogram[] = "DevTools.PanelShown";
76 static const int kDevToolsPanelShownBoundary = 20;
78 // This constant should be in sync with
79 // the constant at shell_devtools_frontend.cc.
80 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
82 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList;
83 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
84 LAZY_INSTANCE_INITIALIZER;
86 std::string SkColorToRGBAString(SkColor color) {
87 // We avoid StringPrintf because it will use locale specific formatters for
88 // the double (e.g. ',' instead of '.' in German).
89 return "rgba(" + base::IntToString(SkColorGetR(color)) + "," +
90 base::IntToString(SkColorGetG(color)) + "," +
91 base::IntToString(SkColorGetB(color)) + "," +
92 base::DoubleToString(SkColorGetA(color) / 255.0) + ")";
95 base::DictionaryValue* CreateFileSystemValue(
96 DevToolsFileHelper::FileSystem file_system) {
97 base::DictionaryValue* file_system_value = new base::DictionaryValue();
98 file_system_value->SetString("fileSystemName", file_system.file_system_name);
99 file_system_value->SetString("rootURL", file_system.root_url);
100 file_system_value->SetString("fileSystemPath", file_system.file_system_path);
101 return file_system_value;
104 Browser* FindBrowser(content::WebContents* web_contents) {
105 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
106 int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
107 web_contents);
108 if (tab_index != TabStripModel::kNoTab)
109 return *it;
111 return NULL;
114 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
116 typedef base::Callback<void(bool)> InfoBarCallback;
118 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
119 public:
120 // If |infobar_service| is NULL, runs |callback| with a single argument with
121 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
122 // and adds the infobar to |infobar_service|.
123 static void Create(InfoBarService* infobar_service,
124 const InfoBarCallback& callback,
125 const base::string16& message);
127 private:
128 DevToolsConfirmInfoBarDelegate(
129 const InfoBarCallback& callback,
130 const base::string16& message);
131 ~DevToolsConfirmInfoBarDelegate() override;
133 base::string16 GetMessageText() const override;
134 base::string16 GetButtonLabel(InfoBarButton button) const override;
135 bool Accept() override;
136 bool Cancel() override;
138 InfoBarCallback callback_;
139 const base::string16 message_;
141 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
144 void DevToolsConfirmInfoBarDelegate::Create(
145 InfoBarService* infobar_service,
146 const InfoBarCallback& callback,
147 const base::string16& message) {
148 if (!infobar_service) {
149 callback.Run(false);
150 return;
153 infobar_service->AddInfoBar(
154 infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
155 new DevToolsConfirmInfoBarDelegate(callback, message))));
158 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
159 const InfoBarCallback& callback,
160 const base::string16& message)
161 : ConfirmInfoBarDelegate(),
162 callback_(callback),
163 message_(message) {
166 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
167 if (!callback_.is_null())
168 callback_.Run(false);
171 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
172 return message_;
175 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
176 InfoBarButton button) const {
177 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
178 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
181 bool DevToolsConfirmInfoBarDelegate::Accept() {
182 callback_.Run(true);
183 callback_.Reset();
184 return true;
187 bool DevToolsConfirmInfoBarDelegate::Cancel() {
188 callback_.Run(false);
189 callback_.Reset();
190 return true;
193 // DevToolsUIDefaultDelegate --------------------------------------------------
195 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate {
196 public:
197 explicit DefaultBindingsDelegate(content::WebContents* web_contents)
198 : web_contents_(web_contents) {}
200 private:
201 ~DefaultBindingsDelegate() override {}
203 void ActivateWindow() override;
204 void CloseWindow() override {}
205 void SetInspectedPageBounds(const gfx::Rect& rect) override {}
206 void InspectElementCompleted() override {}
207 void SetIsDocked(bool is_docked) override {}
208 void OpenInNewTab(const std::string& url) override;
209 void SetWhitelistedShortcuts(const std::string& message) override {}
211 void InspectedContentsClosing() override;
212 void OnLoadCompleted() override {}
213 InfoBarService* GetInfoBarService() override;
214 void RenderProcessGone(bool crashed) override {}
216 content::WebContents* web_contents_;
217 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate);
220 void DefaultBindingsDelegate::ActivateWindow() {
221 web_contents_->GetDelegate()->ActivateContents(web_contents_);
222 web_contents_->Focus();
225 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) {
226 content::OpenURLParams params(
227 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
228 ui::PAGE_TRANSITION_LINK, false);
229 Browser* browser = FindBrowser(web_contents_);
230 browser->OpenURL(params);
233 void DefaultBindingsDelegate::InspectedContentsClosing() {
234 web_contents_->GetRenderViewHost()->ClosePage();
237 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() {
238 return InfoBarService::FromWebContents(web_contents_);
241 // ResponseWriter -------------------------------------------------------------
243 class ResponseWriter : public net::URLFetcherResponseWriter {
244 public:
245 ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings, int stream_id);
246 ~ResponseWriter() override;
248 // URLFetcherResponseWriter overrides:
249 int Initialize(const net::CompletionCallback& callback) override;
250 int Write(net::IOBuffer* buffer,
251 int num_bytes,
252 const net::CompletionCallback& callback) override;
253 int Finish(const net::CompletionCallback& callback) override;
255 private:
256 base::WeakPtr<DevToolsUIBindings> bindings_;
257 int stream_id_;
259 DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
262 ResponseWriter::ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings,
263 int stream_id)
264 : bindings_(bindings),
265 stream_id_(stream_id) {
268 ResponseWriter::~ResponseWriter() {
271 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
272 return net::OK;
275 int ResponseWriter::Write(net::IOBuffer* buffer,
276 int num_bytes,
277 const net::CompletionCallback& callback) {
278 base::FundamentalValue* id = new base::FundamentalValue(stream_id_);
279 base::StringValue* chunk =
280 new base::StringValue(std::string(buffer->data(), num_bytes));
282 content::BrowserThread::PostTask(
283 content::BrowserThread::UI, FROM_HERE,
284 base::Bind(&DevToolsUIBindings::CallClientFunction,
285 bindings_, "DevToolsAPI.streamWrite",
286 base::Owned(id), base::Owned(chunk), nullptr));
287 return num_bytes;
290 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
291 return net::OK;
294 } // namespace
296 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
298 class DevToolsUIBindings::FrontendWebContentsObserver
299 : public content::WebContentsObserver {
300 public:
301 explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings);
302 ~FrontendWebContentsObserver() override;
304 private:
305 // contents::WebContentsObserver:
306 void RenderProcessGone(base::TerminationStatus status) override;
307 // TODO(creis): Replace with RenderFrameCreated when http://crbug.com/425397
308 // is fixed. See also http://crbug.com/424641.
309 void AboutToNavigateRenderFrame(
310 content::RenderFrameHost* old_host,
311 content::RenderFrameHost* new_host) override;
312 void DocumentOnLoadCompletedInMainFrame() override;
313 void DidNavigateMainFrame(
314 const content::LoadCommittedDetails& details,
315 const content::FrameNavigateParams& params) override;
317 DevToolsUIBindings* devtools_bindings_;
318 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
321 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
322 DevToolsUIBindings* devtools_ui_bindings)
323 : WebContentsObserver(devtools_ui_bindings->web_contents()),
324 devtools_bindings_(devtools_ui_bindings) {
327 DevToolsUIBindings::FrontendWebContentsObserver::
328 ~FrontendWebContentsObserver() {
331 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
332 base::TerminationStatus status) {
333 bool crashed = true;
334 switch (status) {
335 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
336 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
337 case base::TERMINATION_STATUS_PROCESS_CRASHED:
338 if (devtools_bindings_->agent_host_.get())
339 devtools_bindings_->Detach();
340 break;
341 default:
342 crashed = false;
343 break;
345 devtools_bindings_->delegate_->RenderProcessGone(crashed);
348 void DevToolsUIBindings::FrontendWebContentsObserver::
349 AboutToNavigateRenderFrame(content::RenderFrameHost* old_host,
350 content::RenderFrameHost* new_host) {
351 if (new_host->GetParent())
352 return;
353 devtools_bindings_->frontend_host_.reset(
354 content::DevToolsFrontendHost::Create(new_host,
355 devtools_bindings_));
358 void DevToolsUIBindings::FrontendWebContentsObserver::
359 DocumentOnLoadCompletedInMainFrame() {
360 devtools_bindings_->DocumentOnLoadCompletedInMainFrame();
363 void DevToolsUIBindings::FrontendWebContentsObserver::
364 DidNavigateMainFrame(const content::LoadCommittedDetails& details,
365 const content::FrameNavigateParams& params) {
366 devtools_bindings_->DidNavigateMainFrame();
369 // DevToolsUIBindings ---------------------------------------------------------
371 DevToolsUIBindings* DevToolsUIBindings::ForWebContents(
372 content::WebContents* web_contents) {
373 if (g_instances == NULL)
374 return NULL;
375 DevToolsUIBindingsList* instances = g_instances.Pointer();
376 for (DevToolsUIBindingsList::iterator it(instances->begin());
377 it != instances->end(); ++it) {
378 if ((*it)->web_contents() == web_contents)
379 return *it;
381 return NULL;
384 // static
385 GURL DevToolsUIBindings::ApplyThemeToURL(Profile* profile,
386 const GURL& base_url) {
387 std::string frontend_url = base_url.spec();
388 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
389 DCHECK(tp);
390 std::string url_string(
391 frontend_url +
392 ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
393 "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
394 "&toolbarColor=" +
395 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
396 "&textColor=" +
397 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)));
398 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
399 switches::kEnableDevToolsExperiments))
400 url_string += "&experiments=true";
401 #if defined(DEBUG_DEVTOOLS)
402 url_string += "&debugFrontend=true";
403 #endif // defined(DEBUG_DEVTOOLS)
404 return GURL(url_string);
407 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
408 : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
409 android_bridge_(DevToolsAndroidBridge::Factory::GetForProfile(profile_)),
410 web_contents_(web_contents),
411 delegate_(new DefaultBindingsDelegate(web_contents_)),
412 devices_updates_enabled_(false),
413 frontend_loaded_(false),
414 weak_factory_(this) {
415 g_instances.Get().push_back(this);
416 frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
417 web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
419 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_));
420 file_system_indexer_ = new DevToolsFileSystemIndexer();
421 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
422 web_contents_);
424 // Wipe out page icon so that the default application icon is used.
425 content::NavigationEntry* entry =
426 web_contents_->GetController().GetActiveEntry();
427 entry->GetFavicon().image = gfx::Image();
428 entry->GetFavicon().valid = true;
430 // Register on-load actions.
431 registrar_.Add(
432 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
433 content::Source<ThemeService>(
434 ThemeServiceFactory::GetForProfile(profile_)));
436 embedder_message_dispatcher_.reset(
437 DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
439 frontend_host_.reset(content::DevToolsFrontendHost::Create(
440 web_contents_->GetMainFrame(), this));
443 DevToolsUIBindings::~DevToolsUIBindings() {
444 for (const auto& pair : pending_requests_)
445 delete pair.first;
447 if (agent_host_.get())
448 agent_host_->DetachClient();
450 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
451 jobs_it != indexing_jobs_.end(); ++jobs_it) {
452 jobs_it->second->Stop();
454 indexing_jobs_.clear();
455 SetDevicesUpdatesEnabled(false);
457 // Remove self from global list.
458 DevToolsUIBindingsList* instances = g_instances.Pointer();
459 DevToolsUIBindingsList::iterator it(
460 std::find(instances->begin(), instances->end(), this));
461 DCHECK(it != instances->end());
462 instances->erase(it);
465 // content::NotificationObserver overrides ------------------------------------
466 void DevToolsUIBindings::Observe(int type,
467 const content::NotificationSource& source,
468 const content::NotificationDetails& details) {
469 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
470 UpdateTheme();
473 // content::DevToolsFrontendHost::Delegate implementation ---------------------
474 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
475 const std::string& message) {
476 std::string method;
477 base::ListValue empty_params;
478 base::ListValue* params = &empty_params;
480 base::DictionaryValue* dict = NULL;
481 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
482 if (!parsed_message ||
483 !parsed_message->GetAsDictionary(&dict) ||
484 !dict->GetString(kFrontendHostMethod, &method) ||
485 (dict->HasKey(kFrontendHostParams) &&
486 !dict->GetList(kFrontendHostParams, &params))) {
487 LOG(ERROR) << "Invalid message was sent to embedder: " << message;
488 return;
490 int id = 0;
491 dict->GetInteger(kFrontendHostId, &id);
492 embedder_message_dispatcher_->Dispatch(
493 base::Bind(&DevToolsUIBindings::SendMessageAck,
494 weak_factory_.GetWeakPtr(),
495 id),
496 method,
497 params);
500 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
501 const std::string& message) {
502 if (agent_host_.get())
503 agent_host_->DispatchProtocolMessage(message);
506 // content::DevToolsAgentHostClient implementation --------------------------
507 void DevToolsUIBindings::DispatchProtocolMessage(
508 content::DevToolsAgentHost* agent_host, const std::string& message) {
509 DCHECK(agent_host == agent_host_.get());
511 if (message.length() < kMaxMessageChunkSize) {
512 base::string16 javascript = base::UTF8ToUTF16(
513 "DevToolsAPI.dispatchMessage(" + message + ");");
514 web_contents_->GetMainFrame()->ExecuteJavaScript(javascript);
515 return;
518 base::FundamentalValue total_size(static_cast<int>(message.length()));
519 for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
520 base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize));
521 CallClientFunction("DevToolsAPI.dispatchMessageChunk",
522 &message_value, pos ? NULL : &total_size, NULL);
526 void DevToolsUIBindings::AgentHostClosed(
527 content::DevToolsAgentHost* agent_host,
528 bool replaced_with_another_client) {
529 DCHECK(agent_host == agent_host_.get());
530 agent_host_ = NULL;
531 delegate_->InspectedContentsClosing();
534 void DevToolsUIBindings::SendMessageAck(int request_id,
535 const base::Value* arg) {
536 base::FundamentalValue id_value(request_id);
537 CallClientFunction("DevToolsAPI.embedderMessageAck",
538 &id_value, arg, nullptr);
541 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
542 void DevToolsUIBindings::ActivateWindow() {
543 delegate_->ActivateWindow();
546 void DevToolsUIBindings::CloseWindow() {
547 delegate_->CloseWindow();
550 void DevToolsUIBindings::LoadCompleted() {
551 FrontendLoaded();
554 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) {
555 delegate_->SetInspectedPageBounds(rect);
558 void DevToolsUIBindings::SetIsDocked(const DispatchCallback& callback,
559 bool dock_requested) {
560 delegate_->SetIsDocked(dock_requested);
561 callback.Run(nullptr);
564 void DevToolsUIBindings::InspectElementCompleted() {
565 delegate_->InspectElementCompleted();
568 void DevToolsUIBindings::InspectedURLChanged(const std::string& url) {
569 content::NavigationController& controller = web_contents()->GetController();
570 content::NavigationEntry* entry = controller.GetActiveEntry();
571 // DevTools UI is not localized.
572 entry->SetTitle(
573 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
574 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
577 void DevToolsUIBindings::LoadNetworkResource(const DispatchCallback& callback,
578 const std::string& url,
579 const std::string& headers,
580 int stream_id) {
581 GURL gurl(url);
582 if (!gurl.is_valid()) {
583 base::DictionaryValue response;
584 response.SetInteger("statusCode", 404);
585 callback.Run(&response);
586 return;
589 net::URLFetcher* fetcher =
590 net::URLFetcher::Create(gurl, net::URLFetcher::GET, this);
591 pending_requests_[fetcher] = callback;
592 fetcher->SetRequestContext(profile_->GetRequestContext());
593 fetcher->SetExtraRequestHeaders(headers);
594 fetcher->SaveResponseWithWriter(scoped_ptr<net::URLFetcherResponseWriter>(
595 new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
596 fetcher->Start();
599 void DevToolsUIBindings::OpenInNewTab(const std::string& url) {
600 delegate_->OpenInNewTab(url);
603 void DevToolsUIBindings::SaveToFile(const std::string& url,
604 const std::string& content,
605 bool save_as) {
606 file_helper_->Save(url, content, save_as,
607 base::Bind(&DevToolsUIBindings::FileSavedAs,
608 weak_factory_.GetWeakPtr(), url),
609 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs,
610 weak_factory_.GetWeakPtr(), url));
613 void DevToolsUIBindings::AppendToFile(const std::string& url,
614 const std::string& content) {
615 file_helper_->Append(url, content,
616 base::Bind(&DevToolsUIBindings::AppendedTo,
617 weak_factory_.GetWeakPtr(), url));
620 void DevToolsUIBindings::RequestFileSystems() {
621 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
622 file_helper_->RequestFileSystems(base::Bind(
623 &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
626 void DevToolsUIBindings::AddFileSystem() {
627 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
628 file_helper_->AddFileSystem(
629 base::Bind(&DevToolsUIBindings::FileSystemAdded,
630 weak_factory_.GetWeakPtr()),
631 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
632 weak_factory_.GetWeakPtr()));
635 void DevToolsUIBindings::RemoveFileSystem(const std::string& file_system_path) {
636 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
637 file_helper_->RemoveFileSystem(file_system_path);
638 base::StringValue file_system_path_value(file_system_path);
639 CallClientFunction("DevToolsAPI.fileSystemRemoved",
640 &file_system_path_value, NULL, NULL);
643 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
644 const std::string& file_system_url) {
645 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
646 file_helper_->UpgradeDraggedFileSystemPermissions(
647 file_system_url,
648 base::Bind(&DevToolsUIBindings::FileSystemAdded,
649 weak_factory_.GetWeakPtr()),
650 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
651 weak_factory_.GetWeakPtr()));
654 void DevToolsUIBindings::IndexPath(int index_request_id,
655 const std::string& file_system_path) {
656 DCHECK_CURRENTLY_ON(BrowserThread::UI);
657 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
658 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
659 IndexingDone(index_request_id, file_system_path);
660 return;
662 if (indexing_jobs_.count(index_request_id) != 0)
663 return;
664 indexing_jobs_[index_request_id] =
665 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
666 file_system_indexer_->IndexPath(
667 file_system_path,
668 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
669 weak_factory_.GetWeakPtr(),
670 index_request_id,
671 file_system_path),
672 Bind(&DevToolsUIBindings::IndexingWorked,
673 weak_factory_.GetWeakPtr(),
674 index_request_id,
675 file_system_path),
676 Bind(&DevToolsUIBindings::IndexingDone,
677 weak_factory_.GetWeakPtr(),
678 index_request_id,
679 file_system_path)));
682 void DevToolsUIBindings::StopIndexing(int index_request_id) {
683 DCHECK_CURRENTLY_ON(BrowserThread::UI);
684 IndexingJobsMap::iterator it = indexing_jobs_.find(index_request_id);
685 if (it == indexing_jobs_.end())
686 return;
687 it->second->Stop();
688 indexing_jobs_.erase(it);
691 void DevToolsUIBindings::SearchInPath(int search_request_id,
692 const std::string& file_system_path,
693 const std::string& query) {
694 DCHECK_CURRENTLY_ON(BrowserThread::UI);
695 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
696 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
697 SearchCompleted(search_request_id,
698 file_system_path,
699 std::vector<std::string>());
700 return;
702 file_system_indexer_->SearchInPath(file_system_path,
703 query,
704 Bind(&DevToolsUIBindings::SearchCompleted,
705 weak_factory_.GetWeakPtr(),
706 search_request_id,
707 file_system_path));
710 void DevToolsUIBindings::SetWhitelistedShortcuts(const std::string& message) {
711 delegate_->SetWhitelistedShortcuts(message);
714 void DevToolsUIBindings::ZoomIn() {
715 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_IN);
718 void DevToolsUIBindings::ZoomOut() {
719 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
722 void DevToolsUIBindings::ResetZoom() {
723 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET);
726 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) {
727 if (devices_updates_enabled_ == enabled)
728 return;
729 devices_updates_enabled_ = enabled;
730 if (enabled) {
731 remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb(
732 base::Bind(&DevToolsUIBindings::DevicesUpdated,
733 base::Unretained(this)),
734 profile_);
735 } else {
736 remote_targets_handler_.reset();
740 void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) {
741 if (agent_host_.get())
742 agent_host_->DispatchProtocolMessage(message);
745 void DevToolsUIBindings::RecordActionUMA(const std::string& name, int action) {
746 if (name == kDevToolsActionTakenHistogram)
747 UMA_HISTOGRAM_ENUMERATION(name, action, kDevToolsActionTakenBoundary);
748 else if (name == kDevToolsPanelShownHistogram)
749 UMA_HISTOGRAM_ENUMERATION(name, action, kDevToolsPanelShownBoundary);
752 void DevToolsUIBindings::SendJsonRequest(const DispatchCallback& callback,
753 const std::string& browser_id,
754 const std::string& url) {
755 if (!android_bridge_) {
756 callback.Run(nullptr);
757 return;
759 android_bridge_->SendJsonRequest(browser_id, url,
760 base::Bind(&DevToolsUIBindings::JsonReceived,
761 weak_factory_.GetWeakPtr(),
762 callback));
765 void DevToolsUIBindings::JsonReceived(const DispatchCallback& callback,
766 int result,
767 const std::string& message) {
768 if (result != net::OK) {
769 callback.Run(nullptr);
770 return;
772 base::StringValue message_value(message);
773 callback.Run(&message_value);
776 void DevToolsUIBindings::OnURLFetchComplete(const net::URLFetcher* source) {
777 DCHECK(source);
778 PendingRequestsMap::iterator it = pending_requests_.find(source);
779 DCHECK(it != pending_requests_.end());
781 base::DictionaryValue response;
782 base::DictionaryValue* headers = new base::DictionaryValue();
783 net::HttpResponseHeaders* rh = source->GetResponseHeaders();
784 response.SetInteger("statusCode", rh ? rh->response_code() : 200);
785 response.Set("headers", headers);
787 void* iterator = NULL;
788 std::string name;
789 std::string value;
790 while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
791 headers->SetString(name, value);
793 it->second.Run(&response);
794 pending_requests_.erase(it);
795 delete source;
798 void DevToolsUIBindings::DeviceCountChanged(int count) {
799 base::FundamentalValue value(count);
800 CallClientFunction("DevToolsAPI.deviceCountUpdated", &value, NULL,
801 NULL);
804 void DevToolsUIBindings::DevicesUpdated(
805 const std::string& source,
806 const base::ListValue& targets) {
807 CallClientFunction("DevToolsAPI.devicesUpdated", &targets, NULL,
808 NULL);
811 void DevToolsUIBindings::FileSavedAs(const std::string& url) {
812 base::StringValue url_value(url);
813 CallClientFunction("DevToolsAPI.savedURL", &url_value, NULL, NULL);
816 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) {
817 base::StringValue url_value(url);
818 CallClientFunction("DevToolsAPI.canceledSaveURL",
819 &url_value, NULL, NULL);
822 void DevToolsUIBindings::AppendedTo(const std::string& url) {
823 base::StringValue url_value(url);
824 CallClientFunction("DevToolsAPI.appendedToURL", &url_value, NULL,
825 NULL);
828 void DevToolsUIBindings::FileSystemsLoaded(
829 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
830 base::ListValue file_systems_value;
831 for (size_t i = 0; i < file_systems.size(); ++i)
832 file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
833 CallClientFunction("DevToolsAPI.fileSystemsLoaded",
834 &file_systems_value, NULL, NULL);
837 void DevToolsUIBindings::FileSystemAdded(
838 const DevToolsFileHelper::FileSystem& file_system) {
839 scoped_ptr<base::StringValue> error_string_value(
840 new base::StringValue(std::string()));
841 scoped_ptr<base::DictionaryValue> file_system_value;
842 if (!file_system.file_system_path.empty())
843 file_system_value.reset(CreateFileSystemValue(file_system));
844 CallClientFunction("DevToolsAPI.fileSystemAdded",
845 error_string_value.get(), file_system_value.get(), NULL);
848 void DevToolsUIBindings::IndexingTotalWorkCalculated(
849 int request_id,
850 const std::string& file_system_path,
851 int total_work) {
852 DCHECK_CURRENTLY_ON(BrowserThread::UI);
853 base::FundamentalValue request_id_value(request_id);
854 base::StringValue file_system_path_value(file_system_path);
855 base::FundamentalValue total_work_value(total_work);
856 CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
857 &request_id_value, &file_system_path_value,
858 &total_work_value);
861 void DevToolsUIBindings::IndexingWorked(int request_id,
862 const std::string& file_system_path,
863 int worked) {
864 DCHECK_CURRENTLY_ON(BrowserThread::UI);
865 base::FundamentalValue request_id_value(request_id);
866 base::StringValue file_system_path_value(file_system_path);
867 base::FundamentalValue worked_value(worked);
868 CallClientFunction("DevToolsAPI.indexingWorked", &request_id_value,
869 &file_system_path_value, &worked_value);
872 void DevToolsUIBindings::IndexingDone(int request_id,
873 const std::string& file_system_path) {
874 indexing_jobs_.erase(request_id);
875 DCHECK_CURRENTLY_ON(BrowserThread::UI);
876 base::FundamentalValue request_id_value(request_id);
877 base::StringValue file_system_path_value(file_system_path);
878 CallClientFunction("DevToolsAPI.indexingDone", &request_id_value,
879 &file_system_path_value, NULL);
882 void DevToolsUIBindings::SearchCompleted(
883 int request_id,
884 const std::string& file_system_path,
885 const std::vector<std::string>& file_paths) {
886 DCHECK_CURRENTLY_ON(BrowserThread::UI);
887 base::ListValue file_paths_value;
888 for (std::vector<std::string>::const_iterator it(file_paths.begin());
889 it != file_paths.end(); ++it) {
890 file_paths_value.AppendString(*it);
892 base::FundamentalValue request_id_value(request_id);
893 base::StringValue file_system_path_value(file_system_path);
894 CallClientFunction("DevToolsAPI.searchCompleted", &request_id_value,
895 &file_system_path_value, &file_paths_value);
898 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
899 const base::string16& message,
900 const InfoBarCallback& callback) {
901 DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(),
902 callback, message);
905 void DevToolsUIBindings::UpdateTheme() {
906 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
907 DCHECK(tp);
909 std::string command("DevToolsAPI.setToolbarColors(\"" +
910 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
911 "\", \"" +
912 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
913 "\")");
914 web_contents_->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command));
917 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
918 const extensions::ExtensionRegistry* registry =
919 extensions::ExtensionRegistry::Get(profile_->GetOriginalProfile());
920 if (!registry)
921 return;
923 base::ListValue results;
924 for (const scoped_refptr<const extensions::Extension>& extension :
925 registry->enabled_extensions()) {
926 if (extensions::chrome_manifest_urls::GetDevToolsPage(extension.get())
927 .is_empty())
928 continue;
929 base::DictionaryValue* extension_info = new base::DictionaryValue();
930 extension_info->Set(
931 "startPage",
932 new base::StringValue(extensions::chrome_manifest_urls::GetDevToolsPage(
933 extension.get()).spec()));
934 extension_info->Set("name", new base::StringValue(extension->name()));
935 extension_info->Set("exposeExperimentalAPIs",
936 new base::FundamentalValue(
937 extension->permissions_data()->HasAPIPermission(
938 extensions::APIPermission::kExperimental)));
939 results.Append(extension_info);
941 CallClientFunction("DevToolsAPI.addExtensions",
942 &results, NULL, NULL);
945 void DevToolsUIBindings::SetDelegate(Delegate* delegate) {
946 delegate_.reset(delegate);
949 void DevToolsUIBindings::AttachTo(
950 const scoped_refptr<content::DevToolsAgentHost>& agent_host) {
951 if (agent_host_.get())
952 Detach();
953 agent_host_ = agent_host;
954 agent_host_->AttachClient(this);
957 void DevToolsUIBindings::Reattach() {
958 DCHECK(agent_host_.get());
959 agent_host_->DetachClient();
960 agent_host_->AttachClient(this);
963 void DevToolsUIBindings::Detach() {
964 if (agent_host_.get())
965 agent_host_->DetachClient();
966 agent_host_ = NULL;
969 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) {
970 return agent_host_.get() == agent_host;
973 void DevToolsUIBindings::CallClientFunction(const std::string& function_name,
974 const base::Value* arg1,
975 const base::Value* arg2,
976 const base::Value* arg3) {
977 std::string javascript = function_name + "(";
978 if (arg1) {
979 std::string json;
980 base::JSONWriter::Write(arg1, &json);
981 javascript.append(json);
982 if (arg2) {
983 base::JSONWriter::Write(arg2, &json);
984 javascript.append(", ").append(json);
985 if (arg3) {
986 base::JSONWriter::Write(arg3, &json);
987 javascript.append(", ").append(json);
991 javascript.append(");");
992 web_contents_->GetMainFrame()->ExecuteJavaScript(
993 base::UTF8ToUTF16(javascript));
996 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
997 // In the DEBUG_DEVTOOLS mode, the DocumentOnLoadCompletedInMainFrame event
998 // arrives before the LoadCompleted event, thus it should not trigger the
999 // frontend load handling.
1000 #if !defined(DEBUG_DEVTOOLS)
1001 FrontendLoaded();
1002 #endif
1005 void DevToolsUIBindings::DidNavigateMainFrame() {
1006 frontend_loaded_ = false;
1009 void DevToolsUIBindings::FrontendLoaded() {
1010 if (frontend_loaded_)
1011 return;
1012 frontend_loaded_ = true;
1014 // Call delegate first - it seeds importants bit of information.
1015 delegate_->OnLoadCompleted();
1017 UpdateTheme();
1018 AddDevToolsExtensionsToClient();