There is a patch for new resource pak for devtools tab selection page.

We have a generated tab selection page for remote debugging.
It is quite simple and needs to be extended for better discoverability and nice view.
I've splitted it into three parts. Generated one with the list of tabs available
for debugging and two static files devtools_frontend.css and devtools_frontend.js

It was decided to keep these two files separately from the rest of the devtools files.
The first reason: tab selection page can be platform specific.
The second reason: main devtools files can be stored in the cloud.

BUG=none
TEST=none

Review URL: http://codereview.chromium.org/6912023

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84419 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.cc b/chrome/browser/debugger/devtools_http_protocol_handler.cc
index 175de35..6e55da0 100644
--- a/chrome/browser/debugger/devtools_http_protocol_handler.cc
+++ b/chrome/browser/debugger/devtools_http_protocol_handler.cc
@@ -22,11 +22,14 @@
 #include "chrome/common/devtools_messages.h"
 #include "content/browser/browser_thread.h"
 #include "content/browser/tab_contents/tab_contents.h"
+#include "grit/devtools_frontend_resources.h"
 #include "googleurl/src/gurl.h"
+#include "net/base/escape.h"
 #include "net/base/io_buffer.h"
 #include "net/server/http_server_request_info.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "ui/base/resource/resource_bundle.h"
 
 const int kBufferSize = 16 * 1024;
 
@@ -120,18 +123,6 @@
 void DevToolsHttpProtocolHandler::OnHttpRequest(
     int connection_id,
     const net::HttpServerRequestInfo& info) {
-  if (info.path == "" || info.path == "/") {
-    // Pages discovery request.
-    BrowserThread::PostTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        NewRunnableMethod(this,
-                          &DevToolsHttpProtocolHandler::OnRootRequestUI,
-                          connection_id,
-                          info));
-    return;
-  }
-
   if (info.path == "/json") {
     // Pages discovery json request.
     BrowserThread::PostTask(
@@ -144,23 +135,34 @@
     return;
   }
 
-  size_t pos = info.path.find("/devtools/");
-  if (pos != 0) {
-    server_->Send404(connection_id);
-    return;
-  }
-
   // Proxy static files from chrome-devtools://devtools/*.
   if (!Profile::GetDefaultRequestContext()) {
     server_->Send404(connection_id);
     return;
   }
 
+  if (info.path == "" || info.path == "/") {
+    const base::StringPiece frontend_html(
+        ResourceBundle::GetSharedInstance().GetRawDataResource(
+            IDR_DEVTOOLS_FRONTEND_HTML));
+    std::string response(frontend_html.data(), frontend_html.length());
+    server_->Send200(connection_id, response, "text/html; charset=UTF-8");
+    return;
+  }
+
+  net::URLRequest* request;
+
+  if (info.path.find("/devtools/") == 0)
+    request = new net::URLRequest(GURL("chrome-devtools:/" + info.path), this);
+  else if (info.path.find("/thumb/") == 0)
+    request = new net::URLRequest(GURL("chrome:/" + info.path), this);
+  else {
+    server_->Send404(connection_id);
+    return;
+  }
+
   // Make sure DevTools data source is registered.
   DevToolsUI::RegisterDevToolsDataSource();
-
-  net::URLRequest* request = new net::URLRequest(
-      GURL("chrome-devtools:/" + info.path), this);
   Bind(request, connection_id);
   request->set_context(
       Profile::GetDefaultRequestContext()->GetURLRequestContext());
@@ -224,6 +226,7 @@
   std::string url;
   bool attached;
   std::string title;
+  std::string thumbnail_url;
   std::string favicon_url;
 };
 typedef std::vector<PageInfo> PageList;
@@ -253,45 +256,14 @@
     page_info.id = controller.session_id().id();
     page_info.attached = client_host != NULL;
     page_info.url = entry->url().spec();
-    page_info.title = UTF16ToUTF8(entry->title());
+    page_info.title = UTF16ToUTF8(EscapeForHTML(entry->title()));
+    page_info.thumbnail_url = "/thumb/" + entry->url().spec();
     page_info.favicon_url = entry->favicon().url().spec();
     page_list.push_back(page_info);
   }
   return page_list;
 }
 
-void DevToolsHttpProtocolHandler::OnRootRequestUI(
-    int connection_id,
-    const net::HttpServerRequestInfo& info) {
-  std::string host = info.headers["Host"];
-  std::string response = "<html><body>";
-  PageList page_list = GeneratePageList(tab_contents_provider_.get(),
-                                        connection_id, info);
-  for (PageList::iterator i = page_list.begin();
-       i != page_list.end(); ++i) {
-
-    std::string frontendURL = StringPrintf("%s?host=%s&page=%d",
-                                           overriden_frontend_url_.c_str(),
-                                           host.c_str(),
-                                           i->id);
-    response += "<div>";
-    response += StringPrintf(
-        "<img style=\"margin-right:5px;width:16px;height:16px\" src=\"%s\">",
-        i->favicon_url.c_str());
-
-    if (i->attached) {
-      response += i->url.c_str();
-    } else {
-      response += StringPrintf("<a href=\"%s\">%s</a><br>",
-                               frontendURL.c_str(),
-                               i->url.c_str());
-    }
-    response += "</div>";
-  }
-  response += "</body></html>";
-  Send200(connection_id, response, "text/html; charset=UTF-8");
-}
-
 void DevToolsHttpProtocolHandler::OnJsonRequestUI(
     int connection_id,
     const net::HttpServerRequestInfo& info) {
@@ -306,6 +278,7 @@
     json_pages_list.Append(page_info);
     page_info->SetString("title", i->title);
     page_info->SetString("url", i->url);
+    page_info->SetString("thumbnailUrl", i->thumbnail_url);
     page_info->SetString("faviconUrl", i->favicon_url);
     if (!i->attached) {
       page_info->SetString("webSocketDebuggerUrl",
diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.h b/chrome/browser/debugger/devtools_http_protocol_handler.h
index 67eadc5..58e3384 100644
--- a/chrome/browser/debugger/devtools_http_protocol_handler.h
+++ b/chrome/browser/debugger/devtools_http_protocol_handler.h
@@ -65,8 +65,6 @@
                                   const std::string& data);
   virtual void OnClose(int connection_id);
 
-  virtual void OnRootRequestUI(int connection_id,
-                             const net::HttpServerRequestInfo& info);
   virtual void OnJsonRequestUI(int connection_id,
                              const net::HttpServerRequestInfo& info);
   virtual void OnWebSocketRequestUI(int connection_id,
diff --git a/chrome/browser/debugger/frontend/devtools_frontend.html b/chrome/browser/debugger/frontend/devtools_frontend.html
new file mode 100644
index 0000000..5191587c
--- /dev/null
+++ b/chrome/browser/debugger/frontend/devtools_frontend.html
@@ -0,0 +1,74 @@
+<html>
+<head>
+<style>
+.item {
+    height: 132px;
+    background-attachment: scroll;
+    background-origin: padding-box;
+    background-repeat: no-repeat;
+    border: 6px solid lightgray;
+    border-radius: 9px;
+    margin-top: 5px;
+}
+
+.item:hover {
+    border-color: gray;
+}
+
+.text {
+    margin-left: 220px;
+}
+</style>
+
+<script>
+function onLoad() {
+  var tabsListRequest = new XMLHttpRequest();
+  tabsListRequest.open("GET", "/json", true);
+  tabsListRequest.onreadystatechange = onReady;
+  tabsListRequest.send();
+}
+
+function onReady() {
+  if(this.readyState == 4 && this.status == 200) {
+    if(this.response != null)
+      var responseJSON = JSON.parse(this.response);
+      for (var i = 0; i < responseJSON.length; ++i)
+        appendItem(responseJSON[i]);
+  }
+}
+
+function appendItem(itemObject) {
+  var frontendRef;
+  if (itemObject.devtoolsFrontendUrl) {
+      frontendRef = document.createElement("a");
+      frontendRef.href = itemObject.devtoolsFrontendUrl;
+  } else {
+      frontendRef = document.createElement("div");
+  }
+
+  var item = document.createElement("div");
+  item.className = "item";
+  item.style.cssText = "background-image:url(" +
+                        itemObject.thumbnailUrl +
+                        ")";
+  frontendRef.appendChild(item);
+
+  var titleElement = document.createElement("div");
+  titleElement.className = "text";
+  titleElement.innerText = itemObject.title;
+  item.appendChild(titleElement);
+
+  var urlElement = document.createElement("div");
+  urlElement.className = "text";
+  urlElement.innerText = itemObject.url;
+  item.appendChild(urlElement);
+
+  document.getElementById("items").appendChild(frontendRef);
+}
+</script>
+</head>
+<body onload='onLoad()'>
+  <div id='items'>
+  </div>
+</body>
+</html>
diff --git a/chrome/browser/debugger/frontend/devtools_frontend_resources.grd b/chrome/browser/debugger/frontend/devtools_frontend_resources.grd
new file mode 100644
index 0000000..0351cac
--- /dev/null
+++ b/chrome/browser/debugger/frontend/devtools_frontend_resources.grd
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit current_release="1" latest_public_release="0">
+  <outputs>
+    <output filename="grit/devtools_frontend_resources.h"
+            type="rc_header">
+      <emit emit_type="prepend"/>
+    </output>
+    <output filename="grit/devtools_frontend_resources_map.cc"
+            type="resource_file_map_source"/>
+    <output filename="grit/devtools_frontend_resources_map.h"
+            type="resource_map_header"/>
+    <output filename="devtools_frontend_resources.pak"
+            type="data_package"/>
+  </outputs>
+  <release seq="1">
+    <includes>
+      <include file="devtools_frontend.html"
+               name="IDR_DEVTOOLS_FRONTEND_HTML"
+               type="BINDATA"/></includes>
+  </release>
+</grit>
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 2af5f7a..4853c01 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -345,6 +345,33 @@
                      '<@(grit_defines)' ],
           'message': 'Generating resources from <(grit_grd_file)',
         },
+        {
+          'action_name': 'devtools_frontend_resources',
+          # This can't use ../build/grit_action.gypi because the grd file
+          # is generated a build time, so the trick of using grit_info to get
+          # the real inputs/outputs at GYP time isn't possible.
+          'variables': {
+            'grit_cmd': ['python', '../tools/grit/grit.py'],
+            'frontend_folder': 'browser/debugger/frontend',
+            'grit_grd_file':
+               '<(frontend_folder)/devtools_frontend_resources.grd',
+          },
+          'inputs': [
+            '<(grit_grd_file)',
+          ],
+          'outputs': [
+            '<(grit_out_dir)/grit/devtools_frontend_resources.h',
+            '<(grit_out_dir)/devtools_frontend_resources.pak',
+            '<(grit_out_dir)/grit/devtools_frontend_resources_map.cc',
+            '<(grit_out_dir)/grit/devtools_frontend_resources_map.h',
+          ],
+          'action': ['<@(grit_cmd)',
+                     '-i', '<(grit_grd_file)', 'build',
+                     '-o', '<(grit_out_dir)',
+                     '-D', 'SHARED_INTERMEDIATE_DIR=<(SHARED_INTERMEDIATE_DIR)',
+                     '<@(grit_defines)' ],
+          'message': 'Generating resources from <(grit_grd_file)',
+        },
       ],
       'includes': [ '../build/grit_target.gypi' ],
     },
@@ -1175,6 +1202,7 @@
               'variables': {
                 'pak_inputs': [
                   '<(grit_out_dir)/component_extension_resources.pak',
+                  '<(grit_out_dir)/devtools_frontend_resources.pak',
                   '<(grit_out_dir)/devtools_resources.pak',
                   '<(grit_out_dir)/net_internals_resources.pak',
                   '<(grit_out_dir)/shared_resources.pak',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 9ace239..34a4378 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3458,6 +3458,7 @@
 
         # These files are generated by GRIT.
         '<(grit_out_dir)/grit/component_extension_resources_map.cc',
+        '<(grit_out_dir)/grit/devtools_frontend_resources_map.cc',
         '<(grit_out_dir)/grit/devtools_resources_map.cc',
         '<(grit_out_dir)/grit/shared_resources_map.cc',
         '<(grit_out_dir)/grit/theme_resources_map.cc',
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi
index c3a0b05..8381331 100644
--- a/chrome/chrome_dll.gypi
+++ b/chrome/chrome_dll.gypi
@@ -390,6 +390,7 @@
                   'variables': {
                     'pak_inputs': [
                       '<(grit_out_dir)/component_extension_resources.pak',
+                      '<(grit_out_dir)/devtools_frontend_resources.pak',
                       '<(grit_out_dir)/devtools_resources.pak',
                       '<(grit_out_dir)/net_internals_resources.pak',
                       '<(grit_out_dir)/shared_resources.pak',
diff --git a/tools/grit/resource_ids b/tools/grit/resource_ids
index c871600..0b4c334 100644
--- a/tools/grit/resource_ids
+++ b/tools/grit/resource_ids
@@ -1,4 +1,4 @@
-# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 #
@@ -138,4 +138,8 @@
   "chrome/app/theme/theme_resources_large.grd": {
     "includes": [21000],
   },
+  # This file is generated during the build.
+  "chrome/browser/debugger/frontend/devtools_frontend_resources.grd": {
+    "includes": [21500],
+  },
 }