OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "android_webview/browser/aw_devtools_delegate.h" | 5 #include "android_webview/browser/aw_devtools_delegate.h" |
6 | 6 |
| 7 #include "android_webview/browser/browser_view_renderer_impl.h" |
7 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/json/json_writer.h" |
8 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
| 11 #include "base/values.h" |
9 #include "content/public/browser/android/devtools_auth.h" | 12 #include "content/public/browser/android/devtools_auth.h" |
10 #include "content/public/browser/devtools_http_handler.h" | 13 #include "content/public/browser/devtools_http_handler.h" |
11 #include "content/public/browser/web_contents.h" | 14 #include "content/public/browser/web_contents.h" |
12 #include "content/public/common/url_constants.h" | 15 #include "content/public/common/url_constants.h" |
13 #include "net/base/unix_domain_socket_posix.h" | 16 #include "net/base/unix_domain_socket_posix.h" |
14 #include "ui/base/resource/resource_bundle.h" | 17 #include "ui/base/resource/resource_bundle.h" |
15 | 18 |
16 namespace { | 19 namespace { |
17 const char kSocketNameFormat[] = "webview_devtools_remote_%d"; | 20 const char kSocketNameFormat[] = "webview_devtools_remote_%d"; |
18 } | 21 } |
19 | 22 |
20 namespace android_webview { | 23 namespace android_webview { |
21 | 24 |
22 AwDevToolsDelegate::AwDevToolsDelegate(content::BrowserContext* browser_context) | 25 AwDevToolsDelegate::AwDevToolsDelegate(content::BrowserContext* browser_context) |
23 : browser_context_(browser_context) { | 26 : browser_context_(browser_context) { |
24 devtools_http_handler_ = content::DevToolsHttpHandler::Start( | 27 devtools_http_handler_ = content::DevToolsHttpHandler::Start( |
25 new net::UnixDomainSocketWithAbstractNamespaceFactory( | 28 new net::UnixDomainSocketWithAbstractNamespaceFactory( |
26 StringPrintf(kSocketNameFormat, getpid()), | 29 StringPrintf(kSocketNameFormat, getpid()), |
27 base::Bind(&content::CanUserConnectToDevTools)), | 30 base::Bind(&content::CanUserConnectToDevTools)), |
28 "", | 31 "", |
29 this); | 32 this); |
30 } | 33 } |
31 | 34 |
32 AwDevToolsDelegate::~AwDevToolsDelegate() { | 35 AwDevToolsDelegate::~AwDevToolsDelegate() { |
33 } | 36 } |
34 | 37 |
35 void AwDevToolsDelegate::Stop() { | 38 void AwDevToolsDelegate::Stop() { |
36 // The HTTP handler will delete our instance. | |
37 devtools_http_handler_->Stop(); | 39 devtools_http_handler_->Stop(); |
| 40 // WARNING: |this| has now been deleted by the method above. |
38 } | 41 } |
39 | 42 |
40 std::string AwDevToolsDelegate::GetDiscoveryPageHTML() { | 43 std::string AwDevToolsDelegate::GetDiscoveryPageHTML() { |
41 // This is a temporary way of providing the list of inspectable WebViews. | 44 // This is a temporary way of providing the list of inspectable WebViews. |
42 // Since WebView doesn't have its own resources now, it doesn't seem | 45 // Since WebView doesn't have its own resources now, it doesn't seem |
43 // reasonable to create a dedicated .pak file just for this temporary page. | 46 // reasonable to create a dedicated .pak file just for this temporary page. |
44 const char html[] = | 47 const char html[] = |
45 "<html>" | 48 "<html>" |
46 "<head>" | 49 "<head>" |
47 "<title>WebView remote debugging</title>" | 50 "<title>WebView remote debugging</title>" |
48 "<style>" | 51 "<style>" |
49 "</style>" | 52 "</style>" |
50 "<script>" | 53 "<script>" |
51 "function onLoad() {" | 54 "function onLoad() {" |
52 " var tabs_list_request = new XMLHttpRequest();" | 55 " var tabs_list_request = new XMLHttpRequest();" |
53 " tabs_list_request.open(" | 56 " tabs_list_request.open(" |
54 "\"GET\", \"/json/list?t=\" + new Date().getTime(), true);" | 57 " 'GET', '/json/list?t=' + new Date().getTime(), true);" |
55 " tabs_list_request.onreadystatechange = onReady;" | 58 " tabs_list_request.onreadystatechange = onReady;" |
56 " tabs_list_request.send();" | 59 " tabs_list_request.send();" |
57 "}" | 60 "}" |
| 61 "function viewsComparator(v1, v2) {" |
| 62 " if (v1.attached != v2.attached) {" |
| 63 " return v1.attached ? -1 : 1;" |
| 64 " } else if (v1.visible != v2.visible) {" |
| 65 " return v1.visible ? -1 : 1;" |
| 66 " } else if (v1.empty != v2.empty) {" |
| 67 " return v1.empty ? 1 : -1;" |
| 68 " } else if (v1.screenX != v2.screenX) {" |
| 69 " return v1.screenX - v2.screenX;" |
| 70 " } else if (v1.screenY != v2.screenY) {" |
| 71 " return v1.screenY - v2.screenY;" |
| 72 " }" |
| 73 " return 0;" |
| 74 "}" |
| 75 "function processItem(item) {" |
| 76 " var result = JSON.parse(item.description);" |
| 77 " result.debuggable = !!item.devtoolsFrontendUrl;" |
| 78 " result.debugUrl = item.devtoolsFrontendUrl;" |
| 79 " result.title = item.title;" |
| 80 " return result;" |
| 81 "}" |
58 "function onReady() {" | 82 "function onReady() {" |
59 " if(this.readyState == 4 && this.status == 200) {" | 83 " if(this.readyState == 4 && this.status == 200) {" |
60 " if(this.response != null)" | 84 " if(this.response != null)" |
61 " var responseJSON = JSON.parse(this.response);" | 85 " var responseJSON = JSON.parse(this.response);" |
| 86 " var items = [];" |
62 " for (var i = 0; i < responseJSON.length; ++i)" | 87 " for (var i = 0; i < responseJSON.length; ++i)" |
63 " appendItem(responseJSON[i]);" | 88 " items.push(processItem(responseJSON[i]));" |
| 89 " items.sort(viewsComparator);" |
| 90 " for (var i = 0; i < items.length; ++i)" |
| 91 " displayView(items[i]);" |
64 " }" | 92 " }" |
65 "}" | 93 "}" |
66 "function appendItem(item_object) {" | 94 "function addColumn(row, text) {" |
| 95 " var column = document.createElement('td');" |
| 96 " column.innerText = text;" |
| 97 " row.appendChild(column);" |
| 98 "}" |
| 99 "function cutTextIfNeeded(text, maxLen) {" |
| 100 " return text.length <= maxLen ?" |
| 101 " text : text.substr(0, maxLen) + '\u2026';" |
| 102 "}" |
| 103 "function displayView(item) {" |
| 104 " var row = document.createElement('tr');" |
| 105 " var column = document.createElement('td');" |
67 " var frontend_ref;" | 106 " var frontend_ref;" |
68 " if (item_object.devtoolsFrontendUrl) {" | 107 " if (item.debuggable) {" |
69 " frontend_ref = document.createElement(\"a\");" | 108 " frontend_ref = document.createElement('a');" |
70 " frontend_ref.href = item_object.devtoolsFrontendUrl;" | 109 " frontend_ref.href = item.debugUrl;" |
71 " frontend_ref.title = item_object.title;" | 110 " frontend_ref.title = item.title;" |
| 111 " column.appendChild(frontend_ref);" |
72 " } else {" | 112 " } else {" |
73 " frontend_ref = document.createElement(\"div\");" | 113 " frontend_ref = column;" |
74 " frontend_ref.title = " | |
75 "\"The view already has active debugging session\";" | |
76 " }" | 114 " }" |
77 " var text = document.createElement(\"div\");" | 115 " var text = document.createElement('span');" |
78 " if (item_object.title)" | 116 " if (item.title) {" |
79 " text.innerText = item_object.title;" | 117 " text.innerText = cutTextIfNeeded(item.title, 64);" |
80 " else" | 118 " } else {" |
81 " text.innerText = \"(untitled tab)\";" | 119 " text.innerText = '(untitled)';" |
82 " text.style.cssText = " | 120 " }" |
83 "\"background-image:url(\" + item_object.faviconUrl + \")\";" | |
84 " frontend_ref.appendChild(text);" | 121 " frontend_ref.appendChild(text);" |
85 " var item = document.createElement(\"p\");" | 122 " row.appendChild(column);" |
86 " item.appendChild(frontend_ref);" | 123 " addColumn(row, item.attached ? 'Y' : 'N');" |
87 " document.getElementById(\"items\").appendChild(item);" | 124 " addColumn(row, item.visible ? 'Y' : 'N');" |
| 125 " addColumn(row, item.empty ? 'Y' : 'N');" |
| 126 " addColumn(row, item.screenX + ', ' + item.screenY);" |
| 127 " addColumn(row," |
| 128 " !item.empty ? (item.width + '\u00d7' + item.height) : '');" |
| 129 " document.getElementById('items').appendChild(row);" |
88 "}" | 130 "}" |
89 "</script>" | 131 "</script>" |
90 "</head>" | 132 "</head>" |
91 "<body onload='onLoad()'>" | 133 "<body onload='onLoad()'>" |
92 " <div id='caption'>Inspectable WebViews</div>" | 134 " <div id='caption'>Inspectable WebViews</div>" |
93 " <div id='items'></div>" | 135 " <table>" |
| 136 " <tr><th>Title</th><th>Attached</th><th>Visible</th><th>Empty</th>" |
| 137 "<th>Position</th><th>Size</th></tr>" |
| 138 " <tbody id='items'></tbody>" |
| 139 " </table>" |
94 "</body>" | 140 "</body>" |
95 "</html>"; | 141 "</html>"; |
96 return html; | 142 return html; |
97 } | 143 } |
98 | 144 |
99 bool AwDevToolsDelegate::BundlesFrontendResources() { | 145 bool AwDevToolsDelegate::BundlesFrontendResources() { |
100 return true; | 146 return true; |
101 } | 147 } |
102 | 148 |
103 base::FilePath AwDevToolsDelegate::GetDebugFrontendDir() { | 149 base::FilePath AwDevToolsDelegate::GetDebugFrontendDir() { |
104 return base::FilePath(); | 150 return base::FilePath(); |
105 } | 151 } |
106 | 152 |
107 std::string AwDevToolsDelegate::GetPageThumbnailData(const GURL& url) { | 153 std::string AwDevToolsDelegate::GetPageThumbnailData(const GURL& url) { |
108 return ""; | 154 return ""; |
109 } | 155 } |
110 | 156 |
111 content::RenderViewHost* AwDevToolsDelegate::CreateNewTarget() { | 157 content::RenderViewHost* AwDevToolsDelegate::CreateNewTarget() { |
112 return NULL; | 158 return NULL; |
113 } | 159 } |
114 | 160 |
115 content::DevToolsHttpHandlerDelegate::TargetType | 161 content::DevToolsHttpHandlerDelegate::TargetType |
116 AwDevToolsDelegate::GetTargetType(content::RenderViewHost*) { | 162 AwDevToolsDelegate::GetTargetType(content::RenderViewHost*) { |
117 return kTargetTypeTab; | 163 return kTargetTypeTab; |
118 } | 164 } |
119 | 165 |
120 std::string AwDevToolsDelegate::GetViewDescription(content::RenderViewHost*) { | 166 std::string AwDevToolsDelegate::GetViewDescription( |
121 return ""; | 167 content::RenderViewHost* rvh) { |
| 168 content::WebContents* web_contents = |
| 169 content::WebContents::FromRenderViewHost(rvh); |
| 170 if (!web_contents) return ""; |
| 171 BrowserViewRenderer* bvr = |
| 172 BrowserViewRendererImpl::FromWebContents(web_contents); |
| 173 if (!bvr) return ""; |
| 174 base::DictionaryValue description; |
| 175 description.SetBoolean("attached", bvr->IsAttachedToWindow()); |
| 176 description.SetBoolean("visible", bvr->IsViewVisible()); |
| 177 gfx::Rect screen_rect = bvr->GetScreenRect(); |
| 178 description.SetInteger("screenX", screen_rect.x()); |
| 179 description.SetInteger("screenY", screen_rect.y()); |
| 180 description.SetBoolean("empty", screen_rect.size().IsEmpty()); |
| 181 if (!screen_rect.size().IsEmpty()) { |
| 182 description.SetInteger("width", screen_rect.width()); |
| 183 description.SetInteger("height", screen_rect.height()); |
| 184 } |
| 185 std::string json; |
| 186 base::JSONWriter::Write(&description, &json); |
| 187 return json; |
122 } | 188 } |
123 | 189 |
124 } // namespace android_webview | 190 } // namespace android_webview |
OLD | NEW |