Add about:instant for under-the-hood instant settings like animation timing

Patch 1 of 2, wires up the chrome://instant page and associated preferences.  Attaching the prefs to the actual animations will come in a later CL.

This is based on a blend of chrome://inspect, chrome://gesture_config and chrome://gpu-internals.

BUG=none
TEST=navigate to chrome://instant and click reset, then enter some values


Review URL: https://chromiumcodereview.appspot.com/10536206

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@143235 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index da7ea9d..f36ae44 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -76,6 +76,9 @@
       <include name="IDR_INSPECT_CSS" file="resources\inspect\inspect.css" flattenhtml="true" type="BINDATA" />
       <include name="IDR_INSPECT_HTML" file="resources\inspect\inspect.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_INSPECT_JS" file="resources\inspect\inspect.js" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_INSTANT_CSS" file="resources\instant\instant.css" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_INSTANT_HTML" file="resources\instant\instant.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+      <include name="IDR_INSTANT_JS" file="resources\instant\instant.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_MEDIA_INTERNALS_HTML" file="resources\media_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_MEDIA_INTERNALS_JS" file="resources\media_internals\media_internals.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_PREDICTORS_HTML" file="resources\predictors\predictors.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
diff --git a/chrome/browser/instant/instant_controller.cc b/chrome/browser/instant/instant_controller.cc
index ec37f48e..eba6f50 100644
--- a/chrome/browser/instant/instant_controller.cc
+++ b/chrome/browser/instant/instant_controller.cc
@@ -57,6 +57,11 @@
   prefs->RegisterBooleanPref(prefs::kInstantEnabled,
                              false,
                              PrefService::SYNCABLE_PREF);
+
+  // TODO(jamescook): Move this to search controller.
+  prefs->RegisterDoublePref(prefs::kInstantAnimationScaleFactor,
+                            1.0,
+                            PrefService::UNSYNCABLE_PREF);
 }
 
 // static
diff --git a/chrome/browser/resources/instant/instant.css b/chrome/browser/resources/instant/instant.css
new file mode 100644
index 0000000..4ff7a25
--- /dev/null
+++ b/chrome/browser/resources/instant/instant.css
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+body {
+  font-family: Arial, sans-serif;
+  font-size: 12px;
+  margin: 10px;
+  min-width: 47em;
+  padding-bottom: 65px;
+}
+
+img {
+  float: left;
+  height: 16px;
+  padding-right: 5px;
+  width: 16px;
+}
+
+.section {
+  background-color: rgb(235, 239, 249);
+  border-top: 1px solid rgb(181, 199, 222);
+  font-weight: bold;
+  margin: 10px 0 0;
+  padding: 2px 2px;
+}
+
+.row {
+  border-bottom: 1px solid #a0a0a0;
+  padding: 5px;
+}
+
+.url {
+  color: #a0a0a0;
+}
diff --git a/chrome/browser/resources/instant/instant.html b/chrome/browser/resources/instant/instant.html
new file mode 100644
index 0000000..a098f92
--- /dev/null
+++ b/chrome/browser/resources/instant/instant.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Copyright (c) 2012 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.
+-->
+<head>
+<meta charset="utf-8">
+<title>Instant Preferences</title>
+<link rel="stylesheet" href="instant.css"/>
+<script src="instant.js"></script>
+</head>
+<body>
+  <h2>Instant Preferences</h2>
+  <hr>
+  <div id="instant-form"></div>
+  <div class="buttons-pane">
+    <button id="reset-button">Reset</button>
+  </div>
+</body>
+</html>
diff --git a/chrome/browser/resources/instant/instant.js b/chrome/browser/resources/instant/instant.js
new file mode 100644
index 0000000..7932ab18
--- /dev/null
+++ b/chrome/browser/resources/instant/instant.js
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 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.
+
+// Redefine '$' here rather than including 'cr.js', since this is
+// the only function needed.  This allows this file to be loaded
+// in a browser directly for layout and some testing purposes.
+var $ = function(id) { return document.getElementById(id); };
+
+/**
+ * WebUI for configuring instant.* preference values used by
+ * Chrome's instant search system.
+ */
+var instantConfig = (function() {
+  'use strict';
+
+  /** Common prefix of instant preferences. **/
+  /** @const */ var INSTANT_PREFIX = 'instant.';
+
+  /** List of fields used to dynamically build form. **/
+  var FIELDS = [
+    {
+      key: 'animation_scale_factor',
+      label: 'Scale factor used to slow down animations',
+      units: 'no units, range 1.0 to 10.0',
+      default: 1.0
+    }
+  ];
+
+  /**
+   * Returns a DOM element of the given type and class name.
+   */
+  function createElementWithClass(elementType, className) {
+    var element = document.createElement(elementType);
+    element.className = className;
+    return element;
+  }
+
+  /**
+   * Dynamically builds web-form based on FIELDS list.
+   * @return {string} The form's HTML.
+   */
+  function buildForm() {
+    var buf = [];
+
+    for (var i = 0; i < FIELDS.length; i++) {
+      var field = FIELDS[i];
+
+      var row = createElementWithClass('div', 'row');
+      row.id = '';
+
+      var label = createElementWithClass('label', 'row-label');
+      label.setAttribute('for', field.key);
+      label.textContent = field.label;
+      row.appendChild(label);
+
+      var input = createElementWithClass('input', 'row-input');
+      input.type = 'number';
+      input.size = 5;
+      input.id = field.key;
+      input.min = field.min || 0;
+      input.title = "Default Value: " + field.default;
+      if (field.max) input.max = field.max;
+      if (field.step) input.step = field.step;
+      row.appendChild(input);
+
+      var units = createElementWithClass('div', 'row-units');
+      if (field.units)
+        units.innerHTML = field.units;
+      row.appendChild(units);
+
+      $('instant-form').appendChild(row);
+    }
+  }
+
+  /**
+   * Initialize the form by adding 'onChange' listeners to all fields.
+   */
+  function initForm() {
+    for (var i = 0; i < FIELDS.length; i++) {
+      var field = FIELDS[i];
+      $(field.key).onchange = (function(key) {
+        setPreferenceValue(key, $(key).value);
+      }).bind(null, field.key);
+    }
+  }
+
+  /**
+   * Request a preference setting's value.
+   * This method is asynchronous; the result is provided by a call to
+   * getPreferenceValueResult.
+   * @param {string} prefName The name of the preference value being requested.
+   */
+  function getPreferenceValue(prefName) {
+    chrome.send('getPreferenceValue', [INSTANT_PREFIX + prefName]);
+  }
+
+  /**
+   * Handle callback from call to getPreferenceValue.
+   * @param {string} prefName The name of the requested preference value.
+   * @param {value} value The current value associated with prefName.
+   */
+  function getPreferenceValueResult(prefName, value) {
+    prefName = prefName.substring(prefName.indexOf('.') + 1);
+    $(prefName).value = value;
+  }
+
+  /**
+   * Set a preference setting's value.
+   * @param {string} prefName The name of the preference value being set.
+   * @param {value} value The value to be associated with prefName.
+   */
+  function setPreferenceValue(prefName, value) {
+    chrome.send(
+        'setPreferenceValue',
+        [INSTANT_PREFIX + prefName, parseFloat(value)]);
+  }
+
+  /**
+   * Handle processing of "Reset" button.
+   * Causes off form values to be updated based on current preference values.
+   */
+  function onReset() {
+    for (var i = 0; i < FIELDS.length; i++) {
+      var field = FIELDS[i];
+      $(field.key).value = field.default;
+      setPreferenceValue(field.key, field.default);
+    }
+    return false;
+  }
+
+  function loadForm() {
+    for (var i = 0; i < FIELDS.length; i++)
+      getPreferenceValue(FIELDS[i].key);
+  }
+
+  /**
+   * Build and initialize the configuration form.
+   */
+  function initialize() {
+    buildForm();
+    loadForm();
+    initForm();
+
+    $('reset-button').onclick = onReset.bind(this);
+  }
+
+  return {
+    initialize: initialize,
+    getPreferenceValueResult: getPreferenceValueResult
+  };
+})();
+
+document.addEventListener('DOMContentLoaded', instantConfig.initialize);
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index e1764bd..eaec62e3 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ui/webui/help/help_ui.h"
 #include "chrome/browser/ui/webui/history_ui.h"
 #include "chrome/browser/ui/webui/inspect_ui.h"
+#include "chrome/browser/ui/webui/instant_ui.h"
 #include "chrome/browser/ui/webui/media/media_internals_ui.h"
 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
@@ -188,6 +189,8 @@
     return &NewWebUI<GpuInternalsUI>;
   if (url.host() == chrome::kChromeUIHistoryFrameHost)
     return &NewWebUI<HistoryUI>;
+  if (url.host() == chrome::kChromeUIInstantHost)
+    return &NewWebUI<InstantUI>;
   if (url.host() == chrome::kChromeUIMediaInternalsHost)
     return &NewWebUI<MediaInternalsUI>;
   if (url.host() == chrome::kChromeUINetInternalsHost)
diff --git a/chrome/browser/ui/webui/instant_ui.cc b/chrome/browser/ui/webui/instant_ui.cc
new file mode 100644
index 0000000..0233792
--- /dev/null
+++ b/chrome/browser/ui/webui/instant_ui.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 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.
+
+#include "chrome/browser/ui/webui/instant_ui.h"
+
+#include "base/bind.h"
+#include "base/values.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "grit/browser_resources.h"
+
+namespace {
+
+ChromeWebUIDataSource* CreateInstantHTMLSource() {
+  ChromeWebUIDataSource* source =
+      new ChromeWebUIDataSource(chrome::kChromeUIInstantHost);
+
+  source->set_json_path("strings.js");
+  source->add_resource_path("instant.js", IDR_INSTANT_JS);
+  source->add_resource_path("instant.css", IDR_INSTANT_CSS);
+  source->set_default_resource(IDR_INSTANT_HTML);
+  return source;
+}
+
+// This class receives JavaScript messages from the renderer.
+// Note that the WebUI infrastructure runs on the UI thread, therefore all of
+// this class's methods are expected to run on the UI thread.
+class InstantUIMessageHandler
+    : public content::WebUIMessageHandler,
+      public base::SupportsWeakPtr<InstantUIMessageHandler> {
+ public:
+  InstantUIMessageHandler();
+  virtual ~InstantUIMessageHandler();
+
+  // WebUIMessageHandler implementation.
+  virtual void RegisterMessages() OVERRIDE;
+
+ private:
+  void GetPreferenceValue(const base::ListValue* args);
+  void SetPreferenceValue(const base::ListValue* args);
+
+  DISALLOW_COPY_AND_ASSIGN(InstantUIMessageHandler);
+};
+
+InstantUIMessageHandler::InstantUIMessageHandler() {}
+
+InstantUIMessageHandler::~InstantUIMessageHandler() {}
+
+void InstantUIMessageHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "getPreferenceValue",
+      base::Bind(&InstantUIMessageHandler::GetPreferenceValue,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "setPreferenceValue",
+      base::Bind(&InstantUIMessageHandler::SetPreferenceValue,
+                 base::Unretained(this)));
+}
+
+void InstantUIMessageHandler::GetPreferenceValue(const base::ListValue* args) {
+  std::string pref_name;
+
+  if (!args->GetString(0, &pref_name)) return;
+
+  Profile* profile = Profile::FromWebUI(web_ui());
+  PrefService* prefs = profile->GetPrefs();
+
+  base::StringValue arg1(pref_name);
+  base::FundamentalValue arg2(prefs->GetDouble(pref_name.c_str()));
+
+  web_ui()->CallJavascriptFunction(
+      "instant.getPreferenceValueResult",
+      arg1,
+      arg2);
+}
+
+void InstantUIMessageHandler::SetPreferenceValue(const base::ListValue* args) {
+  std::string pref_name;
+  double value;
+  if (!args->GetString(0, &pref_name) || !args->GetDouble(1, &value)) return;
+
+  Profile* profile = Profile::FromWebUI(web_ui());
+  PrefService* prefs = profile->GetPrefs();
+
+  prefs->SetDouble(pref_name.c_str(), value);
+}
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// InstantUI
+
+InstantUI::InstantUI(content::WebUI* web_ui)
+    : WebUIController(web_ui) {
+  web_ui->AddMessageHandler(new InstantUIMessageHandler());
+
+  // Set up the chrome://instant/ source.
+  Profile* profile = Profile::FromWebUI(web_ui);
+  ChromeURLDataManager::AddDataSource(profile, CreateInstantHTMLSource());
+}
diff --git a/chrome/browser/ui/webui/instant_ui.h b/chrome/browser/ui/webui/instant_ui.h
new file mode 100644
index 0000000..0d7a8ac
--- /dev/null
+++ b/chrome/browser/ui/webui/instant_ui.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2012 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.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_INSTANT_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_INSTANT_UI_H_
+#pragma once
+
+#include "content/public/browser/web_ui_controller.h"
+
+// Provides configuration options for instant web search.
+class InstantUI : public content::WebUIController {
+ public:
+  // Constructs an instance using |web_ui| for its data sources and message
+  // handlers.
+  explicit InstantUI(content::WebUI* web_ui);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InstantUI);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_INSTANT_UI_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 4a04447..e3c199e 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3853,6 +3853,8 @@
         'browser/ui/webui/history_ui.h',
         'browser/ui/webui/inspect_ui.cc',
         'browser/ui/webui/inspect_ui.h',
+        'browser/ui/webui/instant_ui.cc',
+        'browser/ui/webui/instant_ui.h',
         'browser/ui/webui/media/media_internals_handler.cc',
         'browser/ui/webui/media/media_internals_handler.h',
         'browser/ui/webui/media/media_internals_proxy.cc',
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 09d2e57..a2a1d75 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -447,6 +447,10 @@
 // Allows access to the listed host patterns, as exceptions to the blacklist.
 const char kUrlWhitelist[] = "policy.url_whitelist";
 
+// Double pref for a scaling factor used to slow down animations.
+const char kInstantAnimationScaleFactor[] =
+    "instant.animation_scale_factor";
+
 // Boolean pref indicating whether the instant confirm dialog has been shown.
 const char kInstantConfirmDialogShown[] = "instant.confirm_dialog_shown";
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index e1cde1f..50b94b7 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -172,6 +172,7 @@
 extern const char kDisabledSchemes[];
 extern const char kUrlBlacklist[];
 extern const char kUrlWhitelist[];
+extern const char kInstantAnimationScaleFactor[];
 extern const char kInstantConfirmDialogShown[];
 extern const char kInstantEnabled[];
 extern const char kMultipleProfilePrefMigration[];
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index ebef3d8b..25ae4a4 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -48,6 +48,7 @@
 const char kChromeUIHistoryFrameURL[] = "chrome://history-frame/";
 const char kChromeUIInputWindowDialogURL[] = "chrome://input-window-dialog/";
 const char kChromeUIInspectURL[] = "chrome://inspect/";
+const char kChromeUIInstantURL[] = "chrome://instant/";
 const char kChromeUIIPCURL[] = "chrome://ipc/";
 const char kChromeUIKeyboardURL[] = "chrome://keyboard/";
 const char kChromeUIMemoryRedirectURL[] = "chrome://memory-redirect/";
@@ -157,6 +158,7 @@
 const char kChromeUIHistoryFrameHost[] = "history-frame";
 const char kChromeUIInputWindowDialogHost[] = "input-window-dialog";
 const char kChromeUIInspectHost[] = "inspect";
+const char kChromeUIInstantHost[] = "instant";
 const char kChromeUIIPCHost[] = "ipc";
 const char kChromeUIKeyboardHost[] = "keyboard";
 const char kChromeUIKillHost[] = "kill";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index d6804b0..a908144 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -44,6 +44,7 @@
 extern const char kChromeUIHistoryFrameURL[];
 extern const char kChromeUIInputWindowDialogURL[];
 extern const char kChromeUIInspectURL[];
+extern const char kChromeUIInstantURL[];
 extern const char kChromeUIIPCURL[];
 extern const char kChromeUIKeyboardURL[];
 extern const char kChromeUIMemoryRedirectURL[];
@@ -149,6 +150,7 @@
 extern const char kChromeUIHistoryFrameHost[];
 extern const char kChromeUIInputWindowDialogHost[];
 extern const char kChromeUIInspectHost[];
+extern const char kChromeUIInstantHost[];
 extern const char kChromeUIIPCHost[];
 extern const char kChromeUIKeyboardHost[];
 extern const char kChromeUIKillHost[];
diff --git a/ui/base/native_theme/native_theme_aura.cc b/ui/base/native_theme/native_theme_aura.cc
index c31e2ec8..06618f0ff 100644
--- a/ui/base/native_theme/native_theme_aura.cc
+++ b/ui/base/native_theme/native_theme_aura.cc
@@ -227,7 +227,8 @@
                                        const gfx::Rect& rect,
                                        Part part,
                                        State state) const {
-  DCHECK(rect.IsEmpty());
+  // TODO(jamescook): Should this paint something?  We used to DCHECK() here
+  // that the rect was empty, but that was failing on about: UI pages.
 }
 
 void NativeThemeAura::PaintScrollbarThumb(SkCanvas* canvas,