#include <string>
+#include "base/base64.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_target.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "grit/xwalk_resources.h"
#include "net/socket/tcp_listen_socket.h"
#include "ui/base/resource/resource_bundle.h"
-#include "xwalk/runtime/browser/runtime.h"
+#include "ui/snapshot/snapshot.h"
using content::DevToolsAgentHost;
using content::RenderViewHost;
+using content::RenderWidgetHostView;
using content::WebContents;
namespace {
const char kTargetTypePage[] = "page";
+const char kTargetTypeServiceWorker[] = "service_worker";
+const char kTargetTypeOther[] = "other";
class Target : public content::DevToolsTarget {
public:
- explicit Target(WebContents* web_contents);
+ explicit Target(scoped_refptr<content::DevToolsAgentHost> agent_host);
- virtual std::string GetId() const OVERRIDE { return id_; }
- virtual std::string GetType() const OVERRIDE { return kTargetTypePage; }
- virtual std::string GetTitle() const OVERRIDE { return title_; }
+ virtual std::string GetId() const OVERRIDE { return agent_host_->GetId(); }
+ virtual std::string GetType() const OVERRIDE {
+ switch (agent_host_->GetType()) {
+ case content::DevToolsAgentHost::TYPE_WEB_CONTENTS:
+ return kTargetTypePage;
+ case content::DevToolsAgentHost::TYPE_SERVICE_WORKER:
+ return kTargetTypeServiceWorker;
+ default:
+ break;
+ }
+ return kTargetTypeOther;
+ }
+ virtual std::string GetTitle() const OVERRIDE {
+ return agent_host_->GetTitle();
+ }
virtual std::string GetDescription() const OVERRIDE { return std::string(); }
- virtual GURL GetURL() const OVERRIDE { return url_; }
+ virtual GURL GetURL() const OVERRIDE { return agent_host_->GetURL(); }
virtual GURL GetFaviconURL() const OVERRIDE { return favicon_url_; }
virtual base::TimeTicks GetLastActivityTime() const OVERRIDE {
return last_activity_time_;
virtual bool Close() const OVERRIDE;
private:
+ GURL GetFaviconDataURL(WebContents* web_contents) const;
+
scoped_refptr<DevToolsAgentHost> agent_host_;
std::string id_;
std::string title_;
- GURL url_;
GURL favicon_url_;
base::TimeTicks last_activity_time_;
};
-Target::Target(WebContents* web_contents) {
- agent_host_ =
- DevToolsAgentHost::GetOrCreateFor(web_contents);
- id_ = agent_host_->GetId();
- title_ = base::UTF16ToUTF8(web_contents->GetTitle());
- url_ = web_contents->GetURL();
- content::NavigationController& controller = web_contents->GetController();
- content::NavigationEntry* entry = controller.GetActiveEntry();
- if (entry != NULL && entry->GetURL().is_valid())
- favicon_url_ = entry->GetFavicon().url;
- last_activity_time_ = web_contents->GetLastActiveTime();
+Target::Target(scoped_refptr<content::DevToolsAgentHost> agent_host)
+ : agent_host_(agent_host) {
+ if (content::WebContents* web_contents = agent_host_->GetWebContents()) {
+ content::NavigationController& controller = web_contents->GetController();
+ content::NavigationEntry* entry = controller.GetActiveEntry();
+ if (entry != NULL && entry->GetURL().is_valid())
+ favicon_url_ = entry->GetFavicon().url;
+ if (favicon_url_.is_empty())
+ favicon_url_ = GetFaviconDataURL(web_contents);
+ last_activity_time_ = web_contents->GetLastActiveTime();
+ }
+}
+
+GURL Target::GetFaviconDataURL(WebContents* web_contents) const {
+ // Convert icon image to "data:" url.
+#if defined(OS_ANDROID)
+ // TODO(YangangHan): Add a new base parent class of WebContents
+ // for both Tizen and Android, so we can remove the current macro
+ // in the future.
+ return GURL();
+#endif
+ xwalk::Runtime* runtime =
+ static_cast<xwalk::Runtime*>(web_contents->GetDelegate());
+ if (!runtime || runtime->app_icon().IsEmpty())
+ return GURL();
+ scoped_refptr<base::RefCountedMemory> icon_bytes =
+ runtime->app_icon().Copy1xPNGBytes();
+ std::string str_url;
+ str_url.append(reinterpret_cast<const char*>(icon_bytes->front()),
+ icon_bytes->size());
+ base::Base64Encode(str_url, &str_url);
+ str_url.insert(0, "data:image/png;base64,");
+ return GURL(str_url);
}
bool Target::Activate() const {
- WebContents* web_contents = agent_host_->GetWebContents();
- if (!web_contents)
- return false;
- web_contents->GetDelegate()->ActivateContents(web_contents);
- return true;
+ return agent_host_->Activate();
}
bool Target::Close() const {
- RenderViewHost* rvh = agent_host_->GetWebContents()->GetRenderViewHost();
- if (!rvh)
- return false;
- rvh->ClosePage();
- return true;
+ return agent_host_->Close();
}
} // namespace
namespace xwalk {
-XWalkDevToolsDelegate::XWalkDevToolsDelegate(RuntimeContext* runtime_context)
- : runtime_context_(runtime_context) {
+namespace {
+Runtime* CreateWithDefaultWindow(
+ XWalkBrowserContext* browser_context, const GURL& url,
+ Runtime::Observer* observer) {
+ Runtime* runtime = Runtime::Create(browser_context);
+ runtime->set_observer(observer);
+ runtime->LoadURL(url);
+#if !defined(OS_ANDROID)
+ runtime->set_ui_delegate(DefaultRuntimeUIDelegate::Create(runtime));
+ runtime->Show();
+#endif
+ return runtime;
}
+} // namespace
-XWalkDevToolsDelegate::~XWalkDevToolsDelegate() {
+XWalkDevToolsHttpHandlerDelegate::XWalkDevToolsHttpHandlerDelegate() {
+}
+
+XWalkDevToolsHttpHandlerDelegate::~XWalkDevToolsHttpHandlerDelegate() {
}
-std::string XWalkDevToolsDelegate::GetDiscoveryPageHTML() {
+std::string XWalkDevToolsHttpHandlerDelegate::GetDiscoveryPageHTML() {
return ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_DEVTOOLS_FRONTEND_PAGE_HTML).as_string();
}
-bool XWalkDevToolsDelegate::BundlesFrontendResources() {
+void XWalkDevToolsDelegate::ProcessAndSaveThumbnail(
+ const GURL& url,
+ scoped_refptr<base::RefCountedBytes> png) {
+ const std::vector<unsigned char>& png_data = png->data();
+ std::string png_string_data(reinterpret_cast<const char*>(&png_data[0]),
+ png_data.size());
+ thumbnail_map_[url] = png_string_data;
+}
+
+bool XWalkDevToolsHttpHandlerDelegate::BundlesFrontendResources() {
return true;
}
-base::FilePath XWalkDevToolsDelegate::GetDebugFrontendDir() {
+base::FilePath XWalkDevToolsHttpHandlerDelegate::GetDebugFrontendDir() {
return base::FilePath();
}
+scoped_ptr<net::StreamListenSocket>
+XWalkDevToolsHttpHandlerDelegate::CreateSocketForTethering(
+ net::StreamListenSocket::Delegate* delegate,
+ std::string* name) {
+ return scoped_ptr<net::StreamListenSocket>();
+}
+
+XWalkDevToolsDelegate::XWalkDevToolsDelegate(XWalkBrowserContext* context)
+ : browser_context_(context),
+ weak_factory_(this) {
+}
+
+XWalkDevToolsDelegate::~XWalkDevToolsDelegate() {
+}
+
+base::DictionaryValue* XWalkDevToolsDelegate::HandleCommand(
+ content::DevToolsAgentHost* agent_host,
+ base::DictionaryValue* command_dict) {
+ return NULL;
+}
+
std::string XWalkDevToolsDelegate::GetPageThumbnailData(const GURL& url) {
+ if (thumbnail_map_.find(url) != thumbnail_map_.end())
+ return thumbnail_map_[url];
+ // TODO(YangangHan): Support real time thumbnail.
+ content::DevToolsAgentHost::List agents =
+ content::DevToolsAgentHost::GetOrCreateAll();
+ for (auto& it : agents) {
+ WebContents* web_contents = it.get()->GetWebContents();
+ if (web_contents && web_contents->GetURL() == url) {
+ RenderWidgetHostView* render_widget_host_view =
+ web_contents->GetRenderWidgetHostView();
+ if (!render_widget_host_view)
+ continue;
+ gfx::Rect snapshot_bounds(
+ render_widget_host_view->GetViewBounds().size());
+ ui::GrabViewSnapshotAsync(
+ render_widget_host_view->GetNativeView(),
+ snapshot_bounds,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&XWalkDevToolsDelegate::ProcessAndSaveThumbnail,
+ weak_factory_.GetWeakPtr(),
+ url));
+ break;
+ }
+ }
return std::string();
}
scoped_ptr<content::DevToolsTarget>
XWalkDevToolsDelegate::CreateNewTarget(const GURL& url) {
- Runtime* runtime = Runtime::CreateWithDefaultWindow(
- runtime_context_, GURL(url::kAboutBlankURL));
+ Runtime* runtime = CreateWithDefaultWindow(
+ browser_context_, GURL(url::kAboutBlankURL), this);
return scoped_ptr<content::DevToolsTarget>(
- new Target(runtime->web_contents()));
+ new Target(DevToolsAgentHost::GetOrCreateFor(runtime->web_contents())));
}
void XWalkDevToolsDelegate::EnumerateTargets(TargetCallback callback) {
TargetList targets;
- std::vector<WebContents*> web_contents_list =
- content::DevToolsAgentHost::GetInspectableWebContents();
- for (std::vector<WebContents*>::iterator it = web_contents_list.begin();
- it != web_contents_list.end();
- ++it) {
- Runtime* runtime = static_cast<Runtime*>((*it)->GetDelegate());
+ content::DevToolsAgentHost::List agents =
+ content::DevToolsAgentHost::GetOrCreateAll();
+ for (content::DevToolsAgentHost::List::iterator it = agents.begin();
+ it != agents.end(); ++it) {
+#if !defined(OS_ANDROID)
+ Runtime* runtime =
+ static_cast<Runtime*>((*it)->GetWebContents()->GetDelegate());
if (runtime && runtime->remote_debugging_enabled())
+#endif
targets.push_back(new Target(*it));
}
callback.Run(targets);
}
-scoped_ptr<net::StreamListenSocket>
-XWalkDevToolsDelegate::CreateSocketForTethering(
- net::StreamListenSocket::Delegate* delegate,
- std::string* name) {
- return scoped_ptr<net::StreamListenSocket>();
+void XWalkDevToolsDelegate::OnNewRuntimeAdded(Runtime* runtime) {
+ runtime->set_observer(this);
+ runtime->set_ui_delegate(DefaultRuntimeUIDelegate::Create(runtime));
+ runtime->Show();
+}
+
+void XWalkDevToolsDelegate::OnRuntimeClosed(Runtime* runtime) {
+ delete runtime;
}
} // namespace xwalk