summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authortfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-25 02:56:57 +0000
committertfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-25 02:56:57 +0000
commit67fc03984940b07daa38970e6876fcec1fce0e8e (patch)
treecc4df6d037ecc5e0a479305856fa84137d62af93 /content
parent31de2b56d10626c2328f43531931bc08348ebad2 (diff)
downloadchromium_src-67fc03984940b07daa38970e6876fcec1fce0e8e.zip
chromium_src-67fc03984940b07daa38970e6876fcec1fce0e8e.tar.gz
chromium_src-67fc03984940b07daa38970e6876fcec1fce0e8e.tar.bz2
WebUI: Move the core files of WebUI from chrome/browser/webui to content/browser/webui.
BUG=59946 TEST=trybots Review URL: http://codereview.chromium.org/6575054 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76020 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/browsing_instance.cc2
-rw-r--r--content/browser/site_instance.cc2
-rw-r--r--content/browser/tab_contents/render_view_host_manager.cc4
-rw-r--r--content/browser/tab_contents/tab_contents.cc2
-rw-r--r--content/browser/tab_contents/tab_contents.h2
-rw-r--r--content/browser/webui/web_ui.cc217
-rw-r--r--content/browser/webui/web_ui.h221
-rw-r--r--content/browser/webui/web_ui_browsertest.cc77
-rw-r--r--content/browser/webui/web_ui_browsertest.h58
-rw-r--r--content/browser/webui/web_ui_factory.cc351
-rw-r--r--content/browser/webui/web_ui_factory.h67
-rw-r--r--content/browser/webui/web_ui_handler_browsertest.cc41
-rw-r--r--content/browser/webui/web_ui_handler_browsertest.h40
-rw-r--r--content/browser/webui/web_ui_unittest.cc199
-rw-r--r--content/browser/webui/web_ui_util.cc64
-rw-r--r--content/browser/webui/web_ui_util.h49
-rw-r--r--content/content_browser.gypi6
17 files changed, 1396 insertions, 6 deletions
diff --git a/content/browser/browsing_instance.cc b/content/browser/browsing_instance.cc
index b2c514c..e3efa82 100644
--- a/content/browser/browsing_instance.cc
+++ b/content/browser/browsing_instance.cc
@@ -7,10 +7,10 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/webui/web_ui_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "content/browser/site_instance.h"
+#include "content/browser/webui/web_ui_factory.h"
// static
BrowsingInstance::ProfileSiteInstanceMap
diff --git a/content/browser/site_instance.cc b/content/browser/site_instance.cc
index 6a2ef4a..8f1b53c 100644
--- a/content/browser/site_instance.cc
+++ b/content/browser/site_instance.cc
@@ -6,10 +6,10 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/renderer_host/browser_render_process_host.h"
-#include "chrome/browser/webui/web_ui_factory.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browsing_instance.h"
+#include "content/browser/webui/web_ui_factory.h"
#include "net/base/registry_controlled_domain.h"
// We treat javascript:, about:crash, about:hang, and about:shorthang as the
diff --git a/content/browser/tab_contents/render_view_host_manager.cc b/content/browser/tab_contents/render_view_host_manager.cc
index c31dc76..5c062b2 100644
--- a/content/browser/tab_contents/render_view_host_manager.cc
+++ b/content/browser/tab_contents/render_view_host_manager.cc
@@ -13,8 +13,6 @@
#include "chrome/browser/renderer_host/render_view_host_factory.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/site_instance.h"
-#include "chrome/browser/webui/web_ui.h"
-#include "chrome/browser/webui/web_ui_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
@@ -24,6 +22,8 @@
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/navigation_entry.h"
#include "content/browser/tab_contents/tab_contents_view.h"
+#include "content/browser/webui/web_ui.h"
+#include "content/browser/webui/web_ui_factory.h"
namespace base {
class WaitableEvent;
diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc
index 344e1cb..f710569 100644
--- a/content/browser/tab_contents/tab_contents.cc
+++ b/content/browser/tab_contents/tab_contents.cc
@@ -62,7 +62,6 @@
#include "chrome/browser/tab_contents/thumbnail_generator.h"
#include "chrome/browser/translate/page_translated_details.h"
#include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h"
-#include "chrome/browser/webui/web_ui.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_restriction.h"
@@ -93,6 +92,7 @@
#include "content/browser/tab_contents/tab_contents_delegate.h"
#include "content/browser/tab_contents/tab_contents_observer.h"
#include "content/browser/tab_contents/tab_contents_view.h"
+#include "content/browser/webui/web_ui.h"
#include "net/base/net_util.h"
#include "net/base/registry_controlled_domain.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
diff --git a/content/browser/tab_contents/tab_contents.h b/content/browser/tab_contents/tab_contents.h
index 13ccafd..2390744 100644
--- a/content/browser/tab_contents/tab_contents.h
+++ b/content/browser/tab_contents/tab_contents.h
@@ -22,7 +22,6 @@
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/tab_specific_content_settings.h"
#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
-#include "chrome/browser/webui/web_ui_factory.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/property_bag.h"
#include "chrome/common/renderer_preferences.h"
@@ -34,6 +33,7 @@
#include "content/browser/tab_contents/navigation_entry.h"
#include "content/browser/tab_contents/page_navigator.h"
#include "content/browser/tab_contents/render_view_host_manager.h"
+#include "content/browser/webui/web_ui_factory.h"
#include "net/base/load_states.h"
#include "ui/gfx/native_widget_types.h"
diff --git a/content/browser/webui/web_ui.cc b/content/browser/webui/web_ui.cc
new file mode 100644
index 0000000..11e346e
--- /dev/null
+++ b/content/browser/webui/web_ui.cc
@@ -0,0 +1,217 @@
+// 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.
+
+#include "content/browser/webui/web_ui.h"
+
+#include "base/i18n/rtl.h"
+#include "base/json/json_writer.h"
+#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/webui/generic_handler.h"
+#include "chrome/common/bindings_policy.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+
+namespace {
+
+std::wstring GetJavascript(const std::wstring& function_name,
+ const std::vector<const Value*>& arg_list) {
+ std::wstring parameters;
+ std::string json;
+ for (size_t i = 0; i < arg_list.size(); ++i) {
+ if (i > 0)
+ parameters += L",";
+
+ base::JSONWriter::Write(arg_list[i], false, &json);
+ parameters += UTF8ToWide(json);
+ }
+ return function_name + L"(" + parameters + L");";
+}
+
+} // namespace
+
+WebUI::WebUI(TabContents* contents)
+ : hide_favicon_(false),
+ force_bookmark_bar_visible_(false),
+ focus_location_bar_by_default_(false),
+ should_hide_url_(false),
+ link_transition_type_(PageTransition::LINK),
+ bindings_(BindingsPolicy::WEB_UI),
+ register_callback_overwrites_(false),
+ tab_contents_(contents) {
+ GenericHandler* handler = new GenericHandler();
+ AddMessageHandler(handler->Attach(this));
+}
+
+WebUI::~WebUI() {
+ STLDeleteContainerPairSecondPointers(message_callbacks_.begin(),
+ message_callbacks_.end());
+ STLDeleteContainerPointers(handlers_.begin(), handlers_.end());
+}
+
+// WebUI, public: -------------------------------------------------------------
+
+void WebUI::ProcessWebUIMessage(const ViewHostMsg_DomMessage_Params& params) {
+ // Look up the callback for this message.
+ MessageCallbackMap::const_iterator callback =
+ message_callbacks_.find(params.name);
+ if (callback == message_callbacks_.end())
+ return;
+
+ // Forward this message and content on.
+ callback->second->Run(&params.arguments);
+}
+
+void WebUI::CallJavascriptFunction(const std::wstring& function_name) {
+ std::wstring javascript = function_name + L"();";
+ ExecuteJavascript(javascript);
+}
+
+void WebUI::CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg) {
+ std::vector<const Value*> args;
+ args.push_back(&arg);
+ ExecuteJavascript(GetJavascript(function_name, args));
+}
+
+void WebUI::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const Value& arg1, const Value& arg2) {
+ std::vector<const Value*> args;
+ args.push_back(&arg1);
+ args.push_back(&arg2);
+ ExecuteJavascript(GetJavascript(function_name, args));
+}
+
+void WebUI::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const Value& arg1, const Value& arg2, const Value& arg3) {
+ std::vector<const Value*> args;
+ args.push_back(&arg1);
+ args.push_back(&arg2);
+ args.push_back(&arg3);
+ ExecuteJavascript(GetJavascript(function_name, args));
+}
+
+void WebUI::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const Value& arg1,
+ const Value& arg2,
+ const Value& arg3,
+ const Value& arg4) {
+ std::vector<const Value*> args;
+ args.push_back(&arg1);
+ args.push_back(&arg2);
+ args.push_back(&arg3);
+ args.push_back(&arg4);
+ ExecuteJavascript(GetJavascript(function_name, args));
+}
+
+void WebUI::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const std::vector<const Value*>& args) {
+ ExecuteJavascript(GetJavascript(function_name, args));
+}
+
+ui::ThemeProvider* WebUI::GetThemeProvider() const {
+ return GetProfile()->GetThemeProvider();
+}
+
+void WebUI::RegisterMessageCallback(const std::string &message,
+ MessageCallback *callback) {
+ std::pair<MessageCallbackMap::iterator, bool> result =
+ message_callbacks_.insert(std::make_pair(message, callback));
+
+ // Overwrite preexisting message callback mappings.
+ if (register_callback_overwrites() && !result.second)
+ result.first->second = callback;
+}
+
+Profile* WebUI::GetProfile() const {
+ DCHECK(tab_contents());
+ return tab_contents()->profile();
+}
+
+RenderViewHost* WebUI::GetRenderViewHost() const {
+ DCHECK(tab_contents());
+ return tab_contents()->render_view_host();
+}
+
+// WebUI, protected: ----------------------------------------------------------
+
+void WebUI::AddMessageHandler(WebUIMessageHandler* handler) {
+ handlers_.push_back(handler);
+}
+
+void WebUI::ExecuteJavascript(const std::wstring& javascript) {
+ GetRenderViewHost()->ExecuteJavascriptInWebFrame(string16(),
+ WideToUTF16Hack(javascript));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WebUIMessageHandler
+WebUIMessageHandler::WebUIMessageHandler() : web_ui_(NULL) {
+}
+
+WebUIMessageHandler::~WebUIMessageHandler() {
+}
+
+WebUIMessageHandler* WebUIMessageHandler::Attach(WebUI* web_ui) {
+ web_ui_ = web_ui;
+ RegisterMessages();
+ return this;
+}
+
+// WebUIMessageHandler, protected: ---------------------------------------------
+
+void WebUIMessageHandler::SetURLAndTitle(DictionaryValue* dictionary,
+ string16 title,
+ const GURL& gurl) {
+ dictionary->SetString("url", gurl.spec());
+
+ bool using_url_as_the_title = false;
+ if (title.empty()) {
+ using_url_as_the_title = true;
+ title = UTF8ToUTF16(gurl.spec());
+ }
+
+ // Since the title can contain BiDi text, we need to mark the text as either
+ // RTL or LTR, depending on the characters in the string. If we use the URL
+ // as the title, we mark the title as LTR since URLs are always treated as
+ // left to right strings.
+ string16 title_to_set(title);
+ if (base::i18n::IsRTL()) {
+ if (using_url_as_the_title) {
+ base::i18n::WrapStringWithLTRFormatting(&title_to_set);
+ } else {
+ base::i18n::AdjustStringForLocaleDirection(&title_to_set);
+ }
+ }
+ dictionary->SetString("title", title_to_set);
+}
+
+bool WebUIMessageHandler::ExtractIntegerValue(const ListValue* value,
+ int* out_int) {
+ std::string string_value;
+ if (value->GetString(0, &string_value))
+ return base::StringToInt(string_value, out_int);
+ NOTREACHED();
+ return false;
+}
+
+// TODO(viettrungluu): convert to string16 (or UTF-8 std::string?).
+std::wstring WebUIMessageHandler::ExtractStringValue(const ListValue* value) {
+ string16 string16_value;
+ if (value->GetString(0, &string16_value))
+ return UTF16ToWideHack(string16_value);
+ NOTREACHED();
+ return std::wstring();
+}
diff --git a/content/browser/webui/web_ui.h b/content/browser/webui/web_ui.h
new file mode 100644
index 0000000..0ff0b15
--- /dev/null
+++ b/content/browser/webui/web_ui.h
@@ -0,0 +1,221 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_WEBUI_WEB_UI_H_
+#define CONTENT_BROWSER_WEBUI_WEB_UI_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/string16.h"
+#include "chrome/common/page_transition_types.h"
+
+class DictionaryValue;
+class WebUIMessageHandler;
+class GURL;
+class ListValue;
+class Profile;
+class RenderViewHost;
+class TabContents;
+class Value;
+struct ViewHostMsg_DomMessage_Params;
+
+namespace ui {
+class ThemeProvider;
+}
+
+// A WebUI sets up the datasources and message handlers for a given HTML-based
+// UI. It is contained by a WebUIManager.
+class WebUI {
+ public:
+ explicit WebUI(TabContents* contents);
+ virtual ~WebUI();
+
+ // Called by RenderViewHost when the RenderView is first created. This is
+ // *not* called for every page load because in some cases
+ // RenderViewHostManager will reuse RenderView instances. In those cases,
+ // RenderViewReused will be called instead.
+ virtual void RenderViewCreated(RenderViewHost* render_view_host) {}
+
+ // Called by RenderViewHostManager when a RenderView is reused to display a
+ // page.
+ virtual void RenderViewReused(RenderViewHost* render_view_host) {}
+
+ // Called when this becomes the active WebUI instance for a re-used
+ // RenderView; this is the point at which this WebUI instance will receive
+ // DOM messages instead of the previous WebUI instance.
+ //
+ // If a WebUI instance has code that is usually triggered from a JavaScript
+ // onload handler, this should be overridden to check to see if the web page's
+ // DOM is still intact (e.g., due to a back/forward navigation that remains
+ // within the same page), and if so trigger that code manually since onload
+ // won't be run in that case.
+ virtual void DidBecomeActiveForReusedRenderView() {}
+
+ // Called from TabContents.
+ virtual void ProcessWebUIMessage(const ViewHostMsg_DomMessage_Params& params);
+
+ // Used by WebUIMessageHandlers.
+ typedef Callback1<const ListValue*>::Type MessageCallback;
+ void RegisterMessageCallback(const std::string& message,
+ MessageCallback* callback);
+
+ // Returns true if the favicon should be hidden for the current tab.
+ bool hide_favicon() const {
+ return hide_favicon_;
+ }
+
+ // Returns true if the bookmark bar should be forced to being visible,
+ // overriding the user's preference.
+ bool force_bookmark_bar_visible() const {
+ return force_bookmark_bar_visible_;
+ }
+
+ // Returns true if the location bar should be focused by default rather than
+ // the page contents. Some pages will want to use this to encourage the user
+ // to type in the URL bar.
+ bool focus_location_bar_by_default() const {
+ return focus_location_bar_by_default_;
+ }
+
+ // Returns true if the page's URL should be hidden. Some Web UI pages
+ // like the new tab page will want to hide it.
+ bool should_hide_url() const {
+ return should_hide_url_;
+ }
+
+ // Gets a custom tab title provided by the Web UI. If there is no title
+ // override, the string will be empty which should trigger the default title
+ // behavior for the tab.
+ const string16& overridden_title() const {
+ return overridden_title_;
+ }
+
+ // Returns the transition type that should be used for link clicks on this
+ // Web UI. This will default to LINK but may be overridden.
+ PageTransition::Type link_transition_type() const {
+ return link_transition_type_;
+ }
+
+ int bindings() const {
+ return bindings_;
+ }
+
+ // Indicates whether RegisterMessageCallback() will overwrite an existing
+ // message callback mapping. Serves as the hook for test mocks.
+ bool register_callback_overwrites() const {
+ return register_callback_overwrites_;
+ }
+
+ void register_callback_overwrites(bool value) {
+ register_callback_overwrites_ = value;
+ }
+
+ // Call a Javascript function by sending its name and arguments down to
+ // the renderer. This is asynchronous; there's no way to get the result
+ // of the call, and should be thought of more like sending a message to
+ // the page.
+ // There are variants for calls with more arguments.
+ void CallJavascriptFunction(const std::wstring& function_name);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg1,
+ const Value& arg2);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg1,
+ const Value& arg2,
+ const Value& arg3);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg1,
+ const Value& arg2,
+ const Value& arg3,
+ const Value& arg4);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const std::vector<const Value*>& args);
+
+ ui::ThemeProvider* GetThemeProvider() const;
+
+ // May be overridden by WebUI's which do not have a tab contents.
+ virtual Profile* GetProfile() const;
+
+ // May be overridden by WebUI's which do not have a tab contents.
+ virtual RenderViewHost* GetRenderViewHost() const;
+
+ TabContents* tab_contents() const { return tab_contents_; }
+
+ protected:
+ void AddMessageHandler(WebUIMessageHandler* handler);
+
+ // Execute a string of raw Javascript on the page. Overridable for
+ // testing purposes.
+ virtual void ExecuteJavascript(const std::wstring& javascript);
+
+ // Options that may be overridden by individual Web UI implementations. The
+ // bool options default to false. See the public getters for more information.
+ bool hide_favicon_;
+ bool force_bookmark_bar_visible_;
+ bool focus_location_bar_by_default_;
+ bool should_hide_url_;
+ string16 overridden_title_; // Defaults to empty string.
+ PageTransition::Type link_transition_type_; // Defaults to LINK.
+ int bindings_; // The bindings from BindingsPolicy that should be enabled for
+ // this page.
+
+ // Used by test mocks. See the public getters for more information.
+ bool register_callback_overwrites_; // Defaults to false.
+
+ // The WebUIMessageHandlers we own.
+ std::vector<WebUIMessageHandler*> handlers_;
+
+ // Non-owning pointer to the TabContents this WebUI is associated with.
+ TabContents* tab_contents_;
+
+ private:
+ // A map of message name -> message handling callback.
+ typedef std::map<std::string, MessageCallback*> MessageCallbackMap;
+ MessageCallbackMap message_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebUI);
+};
+
+// Messages sent from the DOM are forwarded via the WebUI to handler
+// classes. These objects are owned by WebUI and destroyed when the
+// host is destroyed.
+class WebUIMessageHandler {
+ public:
+ WebUIMessageHandler();
+ virtual ~WebUIMessageHandler();
+
+ // Attaches |this| to |web_ui| in order to handle messages from it. Declared
+ // virtual so that subclasses can do special init work as soon as the web_ui
+ // is provided. Returns |this| for convenience.
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui);
+
+ protected:
+ // Adds "url" and "title" keys on incoming dictionary, setting title
+ // as the url as a fallback on empty title.
+ static void SetURLAndTitle(DictionaryValue* dictionary,
+ string16 title,
+ const GURL& gurl);
+
+ // This is where subclasses specify which messages they'd like to handle.
+ virtual void RegisterMessages() = 0;
+
+ // Extract an integer value from a list Value.
+ bool ExtractIntegerValue(const ListValue* value, int* out_int);
+
+ // Extract a string value from a list Value.
+ std::wstring ExtractStringValue(const ListValue* value);
+
+ WebUI* web_ui_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebUIMessageHandler);
+};
+
+#endif // CONTENT_BROWSER_WEBUI_WEB_UI_H_
diff --git a/content/browser/webui/web_ui_browsertest.cc b/content/browser/webui/web_ui_browsertest.cc
new file mode 100644
index 0000000..18836c3
--- /dev/null
+++ b/content/browser/webui/web_ui_browsertest.cc
@@ -0,0 +1,77 @@
+// 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.
+
+#include "content/browser/webui/web_ui_browsertest.h"
+
+#include "base/path_service.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/ui_test_utils.h"
+#include "ui/base/resource/resource_bundle.h"
+
+static const FilePath::CharType* kWebUILibraryJS =
+ FILE_PATH_LITERAL("test_api.js");
+static const FilePath::CharType* kWebUITestFolder = FILE_PATH_LITERAL("webui");
+
+WebUIBrowserTest::~WebUIBrowserTest() {}
+
+bool WebUIBrowserTest::RunWebUITest(const FilePath::CharType* src_path) {
+ std::string content;
+ BuildJavaScriptTest(FilePath(src_path), &content);
+ SetupHandlers();
+ return test_handler_->Execute(content);
+}
+
+WebUIBrowserTest::WebUIBrowserTest()
+ : test_handler_(new WebUIHandlerBrowserTest()) {}
+
+void WebUIBrowserTest::SetUpInProcessBrowserTestFixture() {
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_));
+ test_data_directory_ = test_data_directory_.Append(kWebUITestFolder);
+
+ // TODO(dtseng): should this be part of every BrowserTest or just WebUI test.
+ FilePath resources_pack_path;
+ PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
+ ResourceBundle::AddDataPackToSharedInstance(resources_pack_path);
+}
+
+WebUIMessageHandler* WebUIBrowserTest::GetMockMessageHandler() {
+ return NULL;
+}
+
+void WebUIBrowserTest::BuildJavaScriptTest(const FilePath& src_path,
+ std::string* content) {
+ ASSERT_TRUE(content != NULL);
+ std::string library_content, src_content;
+ ASSERT_TRUE(file_util::ReadFileToString(
+ test_data_directory_.Append(FilePath(kWebUILibraryJS)),
+ &library_content));
+ ASSERT_TRUE(file_util::ReadFileToString(
+ test_data_directory_.Append(src_path), &src_content));
+
+ content->append(library_content);
+ content->append(";\n");
+ content->append(src_content);
+}
+
+void WebUIBrowserTest::SetupHandlers() {
+ WebUI* web_ui_instance =
+ browser()->GetSelectedTabContents()->web_ui();
+ ASSERT_TRUE(web_ui_instance != NULL);
+ web_ui_instance->register_callback_overwrites(true);
+ test_handler_->Attach(web_ui_instance);
+
+ if (GetMockMessageHandler())
+ GetMockMessageHandler()->Attach(web_ui_instance);
+}
+
+IN_PROC_BROWSER_TEST_F(WebUIBrowserTest, TestSamplePass) {
+ // Navigate to UI.
+ // TODO(dtseng): make accessor for subclasses to return?
+ ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL));
+
+ ASSERT_TRUE(RunWebUITest(FILE_PATH_LITERAL("sample_downloads.js")));
+}
diff --git a/content/browser/webui/web_ui_browsertest.h b/content/browser/webui/web_ui_browsertest.h
new file mode 100644
index 0000000..000fbde
--- /dev/null
+++ b/content/browser/webui/web_ui_browsertest.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_WEBUI_WEB_UI_BROWSERTEST_H_
+#define CONTENT_BROWSER_WEBUI_WEB_UI_BROWSERTEST_H_
+#pragma once
+
+#include <string>
+
+#include "base/file_path.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "content/browser/webui/web_ui_handler_browsertest.h"
+
+class WebUIMessageHandler;
+
+// The runner of WebUI javascript based tests.
+// See chrome/test/data/webui/test_api.js for the javascript side test API's.
+//
+// These tests should follow the form given in:
+// chrome/test/data/webui/sample_downloads.js.
+// and the lone test within this class.
+class WebUIBrowserTest : public InProcessBrowserTest {
+ public:
+ virtual ~WebUIBrowserTest();
+
+ bool RunWebUITest(const FilePath::CharType* src_path);
+
+ protected:
+ WebUIBrowserTest();
+
+ // Setup test path.
+ virtual void SetUpInProcessBrowserTestFixture();
+
+ // Returns a mock WebUI object under test (if any).
+ virtual WebUIMessageHandler* GetMockMessageHandler();
+
+ private:
+ // Builds a javascript test in the form:
+ // <js_library> ...
+ // <src_path> ...
+ // runTests(function test1() {...},
+ // ...
+ // );
+ void BuildJavaScriptTest(const FilePath& src_path,
+ std::string* content);
+
+ // Attaches mock and test handlers.
+ void SetupHandlers();
+
+ // Handles test framework messages.
+ scoped_ptr<WebUIHandlerBrowserTest> test_handler_;
+
+ // Location of test data (currently test/data/webui).
+ FilePath test_data_directory_;
+};
+
+#endif // CONTENT_BROWSER_WEBUI_WEB_UI_BROWSERTEST_H_
diff --git a/content/browser/webui/web_ui_factory.cc b/content/browser/webui/web_ui_factory.cc
new file mode 100644
index 0000000..f73a516
--- /dev/null
+++ b/content/browser/webui/web_ui_factory.cc
@@ -0,0 +1,351 @@
+// 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.
+
+#include "content/browser/webui/web_ui_factory.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/about_flags.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_web_ui.h"
+#include "chrome/browser/extensions/extensions_ui.h"
+#include "chrome/browser/printing/print_dialog_cloud.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/webui/bookmarks_ui.h"
+#include "chrome/browser/webui/bug_report_ui.h"
+#include "chrome/browser/webui/constrained_html_ui.h"
+#include "chrome/browser/webui/crashes_ui.h"
+#include "chrome/browser/webui/devtools_ui.h"
+#include "chrome/browser/webui/downloads_ui.h"
+#include "chrome/browser/webui/flags_ui.h"
+#include "chrome/browser/webui/gpu_internals_ui.h"
+#include "chrome/browser/webui/history2_ui.h"
+#include "chrome/browser/webui/history_ui.h"
+#include "chrome/browser/webui/html_dialog_ui.h"
+#include "chrome/browser/webui/net_internals_ui.h"
+#include "chrome/browser/webui/new_tab_ui.h"
+#include "chrome/browser/webui/options/options_ui.h"
+#include "chrome/browser/webui/plugins_ui.h"
+#include "chrome/browser/webui/print_preview_ui.h"
+#include "chrome/browser/webui/remoting_ui.h"
+#include "chrome/browser/webui/slideshow_ui.h"
+#include "chrome/browser/webui/sync_internals_ui.h"
+#include "chrome/browser/webui/textfields_ui.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/webui/imageburner_ui.h"
+#include "chrome/browser/chromeos/webui/keyboard_overlay_ui.h"
+#include "chrome/browser/chromeos/webui/menu_ui.h"
+#include "chrome/browser/chromeos/webui/mobile_setup_ui.h"
+#include "chrome/browser/chromeos/webui/network_menu_ui.h"
+#include "chrome/browser/chromeos/webui/register_page_ui.h"
+#include "chrome/browser/chromeos/webui/system_info_ui.h"
+#include "chrome/browser/chromeos/webui/wrench_menu_ui.h"
+#include "chrome/browser/webui/filebrowse_ui.h"
+#include "chrome/browser/webui/mediaplayer_ui.h"
+#endif
+
+#if defined(TOUCH_UI)
+#include "chrome/browser/webui/keyboard_ui.h"
+#endif
+
+#if defined(TOUCH_UI) && defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/webui/login/login_ui.h"
+#endif
+
+#if defined(OS_WIN)
+#include "chrome/browser/webui/conflicts_ui.h"
+#endif
+
+const WebUITypeID WebUIFactory::kNoWebUI = NULL;
+
+// A function for creating a new WebUI. The caller owns the return value, which
+// may be NULL (for example, if the URL refers to an non-existent extension).
+typedef WebUI* (*WebUIFactoryFunction)(TabContents* tab_contents,
+ const GURL& url);
+
+// Template for defining WebUIFactoryFunction.
+template<class T>
+WebUI* NewWebUI(TabContents* contents, const GURL& url) {
+ return new T(contents);
+}
+
+// Special case for extensions.
+template<>
+WebUI* NewWebUI<ExtensionWebUI>(TabContents* contents, const GURL& url) {
+ // Don't use a WebUI for incognito tabs because we require extensions to run
+ // within a single process.
+ ExtensionService* service = contents->profile()->GetExtensionService();
+ if (service &&
+ service->ExtensionBindingsAllowed(url)) {
+ return new ExtensionWebUI(contents, url);
+ }
+ return NULL;
+}
+
+// Returns a function that can be used to create the right type of WebUI for a
+// tab, based on its URL. Returns NULL if the URL doesn't have WebUI associated
+// with it. Even if the factory function is valid, it may yield a NULL WebUI
+// when invoked for a particular tab - see NewWebUI<ExtensionWebUI>.
+static WebUIFactoryFunction GetWebUIFactoryFunction(Profile* profile,
+ const GURL& url) {
+ // Currently, any gears: URL means an HTML dialog.
+ if (url.SchemeIs(chrome::kGearsScheme))
+ return &NewWebUI<HtmlDialogUI>;
+
+ if (url.host() == chrome::kChromeUIDialogHost)
+ return &NewWebUI<ConstrainedHtmlUI>;
+
+ ExtensionService* service = profile ? profile->GetExtensionService() : NULL;
+ if (service && service->ExtensionBindingsAllowed(url))
+ return &NewWebUI<ExtensionWebUI>;
+
+ // All platform builds of Chrome will need to have a cloud printing
+ // dialog as backup. It's just that on Chrome OS, it's the only
+ // print dialog.
+ if (url.host() == chrome::kCloudPrintResourcesHost)
+ return &NewWebUI<ExternalHtmlDialogUI>;
+
+ // This will get called a lot to check all URLs, so do a quick check of other
+ // schemes (gears was handled above) to filter out most URLs.
+ if (!url.SchemeIs(chrome::kChromeDevToolsScheme) &&
+ !url.SchemeIs(chrome::kChromeInternalScheme) &&
+ !url.SchemeIs(chrome::kChromeUIScheme))
+ return NULL;
+
+ if (url.host() == chrome::kChromeUISyncResourcesHost ||
+ url.host() == chrome::kChromeUIRemotingResourcesHost ||
+ url.host() == chrome::kCloudPrintSetupHost)
+ return &NewWebUI<HtmlDialogUI>;
+
+ // Special case the new tab page. In older versions of Chrome, the new tab
+ // page was hosted at chrome-internal:<blah>. This might be in people's saved
+ // sessions or bookmarks, so we say any URL with that scheme triggers the new
+ // tab page.
+ if (url.host() == chrome::kChromeUINewTabHost ||
+ url.SchemeIs(chrome::kChromeInternalScheme))
+ return &NewWebUI<NewTabUI>;
+
+ // Give about:about a generic Web UI so it can navigate to pages with Web UIs.
+ if (url.spec() == chrome::kChromeUIAboutAboutURL)
+ return &NewWebUI<WebUI>;
+
+ // We must compare hosts only since some of the Web UIs append extra stuff
+ // after the host name.
+ if (url.host() == chrome::kChromeUIBookmarksHost)
+ return &NewWebUI<BookmarksUI>;
+ if (url.host() == chrome::kChromeUIBugReportHost)
+ return &NewWebUI<BugReportUI>;
+ if (url.host() == chrome::kChromeUICrashesHost)
+ return &NewWebUI<CrashesUI>;
+ if (url.host() == chrome::kChromeUIDevToolsHost)
+ return &NewWebUI<DevToolsUI>;
+#if defined(OS_WIN)
+ if (url.host() == chrome::kChromeUIConflictsHost)
+ return &NewWebUI<ConflictsUI>;
+#endif
+ if (url.host() == chrome::kChromeUIDownloadsHost)
+ return &NewWebUI<DownloadsUI>;
+ if (url.host() == chrome::kChromeUITextfieldsHost)
+ return &NewWebUI<TextfieldsUI>;
+ if (url.host() == chrome::kChromeUIExtensionsHost)
+ return &NewWebUI<ExtensionsUI>;
+ if (url.host() == chrome::kChromeUIHistoryHost)
+ return &NewWebUI<HistoryUI>;
+ if (url.host() == chrome::kChromeUIHistory2Host)
+ return &NewWebUI<HistoryUI2>;
+ if (url.host() == chrome::kChromeUIFlagsHost)
+ return &NewWebUI<FlagsUI>;
+#if defined(TOUCH_UI)
+ if (url.host() == chrome::kChromeUIKeyboardHost)
+ return &NewWebUI<KeyboardUI>;
+#endif
+ if (url.host() == chrome::kChromeUIGpuInternalsHost)
+ return &NewWebUI<GpuInternalsUI>;
+ if (url.host() == chrome::kChromeUINetInternalsHost)
+ return &NewWebUI<NetInternalsUI>;
+ if (url.host() == chrome::kChromeUIPluginsHost)
+ return &NewWebUI<PluginsUI>;
+ if (url.host() == chrome::kChromeUISyncInternalsHost)
+ return &NewWebUI<SyncInternalsUI>;
+#if defined(ENABLE_REMOTING)
+ if (url.host() == chrome::kChromeUIRemotingHost) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableRemoting)) {
+ return &NewWebUI<RemotingUI>;
+ }
+ }
+#endif
+
+#if defined(OS_CHROMEOS)
+ if (url.host() == chrome::kChromeUIFileBrowseHost)
+ return &NewWebUI<FileBrowseUI>;
+ if (url.host() == chrome::kChromeUIImageBurnerHost)
+ return &NewWebUI<ImageBurnUI>;
+ if (url.host() == chrome::kChromeUIKeyboardOverlayHost)
+ return &NewWebUI<KeyboardOverlayUI>;
+ if (url.host() == chrome::kChromeUIMediaplayerHost)
+ return &NewWebUI<MediaplayerUI>;
+ if (url.host() == chrome::kChromeUIMobileSetupHost)
+ return &NewWebUI<MobileSetupUI>;
+ if (url.host() == chrome::kChromeUIRegisterPageHost)
+ return &NewWebUI<RegisterPageUI>;
+ if (url.host() == chrome::kChromeUISettingsHost)
+ return &NewWebUI<OptionsUI>;
+ if (url.host() == chrome::kChromeUISlideshowHost)
+ return &NewWebUI<SlideshowUI>;
+ if (url.host() == chrome::kChromeUISystemInfoHost)
+ return &NewWebUI<SystemInfoUI>;
+ if (url.host() == chrome::kChromeUIMenu)
+ return &NewWebUI<chromeos::MenuUI>;
+ if (url.host() == chrome::kChromeUIWrenchMenu)
+ return &NewWebUI<chromeos::WrenchMenuUI>;
+ if (url.host() == chrome::kChromeUINetworkMenu)
+ return &NewWebUI<chromeos::NetworkMenuUI>;
+#else
+ if (url.host() == chrome::kChromeUISettingsHost) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableTabbedOptions)) {
+ return &NewWebUI<OptionsUI>;
+ }
+ }
+ if (url.host() == chrome::kChromeUIPrintHost) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnablePrintPreview)) {
+ return &NewWebUI<PrintPreviewUI>;
+ }
+ }
+#endif // defined(OS_CHROMEOS)
+
+#if defined(TOUCH_UI) && defined(OS_CHROMEOS)
+ if (url.host() == chrome::kChromeUILoginHost)
+ return &NewWebUI<chromeos::LoginUI>;
+#endif
+
+ if (url.spec() == chrome::kChromeUIConstrainedHTMLTestURL)
+ return &NewWebUI<ConstrainedHtmlUI>;
+
+ return NULL;
+}
+
+// static
+WebUITypeID WebUIFactory::GetWebUIType(Profile* profile, const GURL& url) {
+ WebUIFactoryFunction function = GetWebUIFactoryFunction(profile, url);
+ return function ? reinterpret_cast<WebUITypeID>(function) : kNoWebUI;
+}
+
+// static
+bool WebUIFactory::HasWebUIScheme(const GURL& url) {
+ return url.SchemeIs(chrome::kChromeDevToolsScheme) ||
+ url.SchemeIs(chrome::kChromeInternalScheme) ||
+ url.SchemeIs(chrome::kChromeUIScheme) ||
+ url.SchemeIs(chrome::kExtensionScheme);
+}
+
+// static
+bool WebUIFactory::UseWebUIForURL(Profile* profile, const GURL& url) {
+ return GetWebUIFactoryFunction(profile, url) != NULL;
+}
+
+// static
+bool WebUIFactory::IsURLAcceptableForWebUI(Profile* profile, const GURL& url) {
+ return UseWebUIForURL(profile, url) ||
+ // javacsript: URLs are allowed to run in Web UI pages
+ url.SchemeIs(chrome::kJavaScriptScheme) ||
+ // It's possible to load about:blank in a Web UI renderer.
+ // See http://crbug.com/42547
+ url.spec() == chrome::kAboutBlankURL ||
+ // about:crash, about:kill, about:hang, and about:shorthang are allowed.
+ url.spec() == chrome::kAboutCrashURL ||
+ url.spec() == chrome::kAboutKillURL ||
+ url.spec() == chrome::kAboutHangURL ||
+ url.spec() == chrome::kAboutShorthangURL;
+}
+
+// static
+WebUI* WebUIFactory::CreateWebUIForURL(TabContents* tab_contents,
+ const GURL& url) {
+ WebUIFactoryFunction function = GetWebUIFactoryFunction(
+ tab_contents->profile(), url);
+ if (!function)
+ return NULL;
+ return (*function)(tab_contents, url);
+}
+
+// static
+void WebUIFactory::GetFaviconForURL(Profile* profile,
+ FaviconService::GetFaviconRequest* request,
+ const GURL& page_url) {
+ // All extensions but the bookmark manager get their favicon from the icons
+ // part of the manifest.
+ if (page_url.SchemeIs(chrome::kExtensionScheme) &&
+ page_url.host() != extension_misc::kBookmarkManagerId) {
+ ExtensionWebUI::GetFaviconForURL(profile, request, page_url);
+ } else {
+ scoped_refptr<RefCountedMemory> icon_data(
+ WebUIFactory::GetFaviconResourceBytes(profile, page_url));
+ bool know_icon = icon_data.get() != NULL && icon_data->size() > 0;
+ request->ForwardResultAsync(
+ FaviconService::FaviconDataCallback::TupleType(request->handle(),
+ know_icon, icon_data, false, GURL()));
+ }
+}
+
+// static
+RefCountedMemory* WebUIFactory::GetFaviconResourceBytes(Profile* profile,
+ const GURL& page_url) {
+ // The bookmark manager is a chrome extension, so we have to check for it
+ // before we check for extension scheme.
+ if (page_url.host() == extension_misc::kBookmarkManagerId)
+ return BookmarksUI::GetFaviconResourceBytes();
+
+ // The extension scheme is handled in GetFaviconForURL.
+ if (page_url.SchemeIs(chrome::kExtensionScheme)) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ if (!HasWebUIScheme(page_url))
+ return NULL;
+
+#if defined(OS_WIN)
+ if (page_url.host() == chrome::kChromeUIConflictsHost)
+ return ConflictsUI::GetFaviconResourceBytes();
+#endif
+
+ if (page_url.host() == chrome::kChromeUICrashesHost)
+ return CrashesUI::GetFaviconResourceBytes();
+
+ if (page_url.host() == chrome::kChromeUIDownloadsHost)
+ return DownloadsUI::GetFaviconResourceBytes();
+
+ if (page_url.host() == chrome::kChromeUIExtensionsHost)
+ return ExtensionsUI::GetFaviconResourceBytes();
+
+ if (page_url.host() == chrome::kChromeUIHistoryHost)
+ return HistoryUI::GetFaviconResourceBytes();
+
+ if (page_url.host() == chrome::kChromeUIHistory2Host)
+ return HistoryUI2::GetFaviconResourceBytes();
+
+ if (page_url.host() == chrome::kChromeUIFlagsHost)
+ return FlagsUI::GetFaviconResourceBytes();
+
+ if (page_url.host() == chrome::kChromeUISettingsHost)
+ return OptionsUI::GetFaviconResourceBytes();
+
+ if (page_url.host() == chrome::kChromeUIPluginsHost)
+ return PluginsUI::GetFaviconResourceBytes();
+
+#if defined(ENABLE_REMOTING)
+ if (page_url.host() == chrome::kChromeUIRemotingHost)
+ return RemotingUI::GetFaviconResourceBytes();
+#endif
+
+ return NULL;
+}
diff --git a/content/browser/webui/web_ui_factory.h b/content/browser/webui/web_ui_factory.h
new file mode 100644
index 0000000..2be656a
--- /dev/null
+++ b/content/browser/webui/web_ui_factory.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_WEBUI_WEB_UI_FACTORY_H_
+#define CONTENT_BROWSER_WEBUI_WEB_UI_FACTORY_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "chrome/browser/favicon_service.h"
+
+class WebUI;
+class GURL;
+class Profile;
+class RefCountedMemory;
+class TabContents;
+
+// An opaque identifier used to identify a WebUI. This can only be compared to
+// kNoWebUI or other WebUI types. See GetWebUIType.
+typedef void* WebUITypeID;
+
+class WebUIFactory {
+ public:
+ // A special WebUI type that signifies that a given page would not use the
+ // Web UI system.
+ static const WebUITypeID kNoWebUI;
+
+ // Returns a type identifier indicating what WebUI we would use for the
+ // given URL. This is useful for comparing the potential WebUIs for two URLs.
+ // Returns kNoWebUI if the given URL will not use the Web UI system.
+ static WebUITypeID GetWebUIType(Profile* profile, const GURL& url);
+
+ // Returns true if the given URL's scheme would trigger the Web UI system.
+ // This is a less precise test than UseDONUIForURL, which tells you whether
+ // that specific URL matches a known one. This one is faster and can be used
+ // to determine security policy.
+ static bool HasWebUIScheme(const GURL& url);
+
+ // Returns true if the given URL must use the Web UI system.
+ static bool UseWebUIForURL(Profile* profile, const GURL& url);
+
+ // Returns true if the given URL can be loaded by Web UI system. This
+ // includes URLs that can be loaded by normal tabs as well, such as
+ // javascript: URLs or about:hang.
+ static bool IsURLAcceptableForWebUI(Profile* profile, const GURL& url);
+
+ // Allocates a new WebUI object for the given URL, and returns it. If the URL
+ // is not a Web UI URL, then it will return NULL. When non-NULL, ownership of
+ // the returned pointer is passed to the caller.
+ static WebUI* CreateWebUIForURL(TabContents* tab_contents, const GURL& url);
+
+ // Get the favicon for |page_url| and forward the result to the |request|
+ // when loaded.
+ static void GetFaviconForURL(Profile* profile,
+ FaviconService::GetFaviconRequest* request,
+ const GURL& page_url);
+
+ private:
+ // Gets the data for the favicon for a WebUI page. Returns NULL if the WebUI
+ // does not have a favicon.
+ static RefCountedMemory* GetFaviconResourceBytes(Profile* profile,
+ const GURL& page_url);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(WebUIFactory);
+};
+
+#endif // CONTENT_BROWSER_WEBUI_WEB_UI_FACTORY_H_
diff --git a/content/browser/webui/web_ui_handler_browsertest.cc b/content/browser/webui/web_ui_handler_browsertest.cc
new file mode 100644
index 0000000..ab580ee
--- /dev/null
+++ b/content/browser/webui/web_ui_handler_browsertest.cc
@@ -0,0 +1,41 @@
+// 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.
+
+#include "content/browser/webui/web_ui_handler_browsertest.h"
+
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/test/ui_test_utils.h"
+
+bool WebUIHandlerBrowserTest::Execute(const std::string& js_test) {
+ web_ui_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
+ string16(), UTF8ToUTF16(js_test));
+ return WaitForResult();
+}
+
+void WebUIHandlerBrowserTest::HandlePass(const ListValue* args) {
+ test_succeeded_ = true;
+ if (is_waiting_)
+ MessageLoopForUI::current()->Quit();
+}
+
+void WebUIHandlerBrowserTest::HandleFail(const ListValue* args) {
+ test_succeeded_ = false;
+ if (is_waiting_)
+ MessageLoopForUI::current()->Quit();
+}
+
+void WebUIHandlerBrowserTest::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("Pass",
+ NewCallback(this, &WebUIHandlerBrowserTest::HandlePass));
+ web_ui_->RegisterMessageCallback("Fail",
+ NewCallback(this, &WebUIHandlerBrowserTest::HandleFail));
+}
+
+bool WebUIHandlerBrowserTest::WaitForResult() {
+ is_waiting_ = true;
+ ui_test_utils::RunMessageLoop();
+ is_waiting_ = false;
+ return test_succeeded_;
+}
diff --git a/content/browser/webui/web_ui_handler_browsertest.h b/content/browser/webui/web_ui_handler_browsertest.h
new file mode 100644
index 0000000..b19484a
--- /dev/null
+++ b/content/browser/webui/web_ui_handler_browsertest.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_WEBUI_WEB_UI_HANDLER_BROWSERTEST_H_
+#define CONTENT_BROWSER_WEBUI_WEB_UI_HANDLER_BROWSERTEST_H_
+#pragma once
+
+#include <string>
+
+#include "content/browser/webui/web_ui.h"
+
+// This class registers test framework specific handlers on WebUI objects.
+class WebUIHandlerBrowserTest : public WebUIMessageHandler {
+ public:
+ // Executes a string of javascript. Returns pass fail.
+ bool Execute(const std::string& js_test);
+
+ protected:
+ // WebUI handlers which deliver results to any waiting message loops.
+ // |args| is currently ignored.
+ void HandlePass(const ListValue* args);
+ void HandleFail(const ListValue* args);
+
+ // WebUIMessageHandler overrides.
+ // Add test handlers to the current WebUI object.
+ virtual void RegisterMessages();
+
+ private:
+ // Runs a message loop until test finishes. Returns the result of the test.
+ bool WaitForResult();
+
+ // Pass fail result of current tests.
+ bool test_succeeded_;
+
+ // Waiting for a test to finish.
+ bool is_waiting_;
+};
+
+#endif // CONTENT_BROWSER_WEBUI_WEB_UI_HANDLER_BROWSERTEST_H_
diff --git a/content/browser/webui/web_ui_unittest.cc b/content/browser/webui/web_ui_unittest.cc
new file mode 100644
index 0000000..4c5b48b
--- /dev/null
+++ b/content/browser/webui/web_ui_unittest.cc
@@ -0,0 +1,199 @@
+// 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.
+
+#include "chrome/browser/webui/new_tab_ui.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_profile.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/renderer_host/test_render_view_host.h"
+#include "content/browser/site_instance.h"
+#include "content/browser/tab_contents/navigation_controller.h"
+#include "content/browser/tab_contents/test_tab_contents.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class WebUITest : public RenderViewHostTestHarness {
+ public:
+ WebUITest() : ui_thread_(BrowserThread::UI, MessageLoop::current()) {}
+
+ // Tests navigating with a Web UI from a fresh (nothing pending or committed)
+ // state, through pending, committed, then another navigation. The first page
+ // ID that we should use is passed as a parameter. We'll use the next two
+ // values. This must be increasing for the life of the tests.
+ static void DoNavigationTest(TabContents* contents, int page_id) {
+ NavigationController* controller = &contents->controller();
+
+ // Start a pending load.
+ GURL new_tab_url(chrome::kChromeUINewTabURL);
+ controller->LoadURL(new_tab_url, GURL(), PageTransition::LINK);
+
+ // The navigation entry should be pending with no committed entry.
+ ASSERT_TRUE(controller->pending_entry());
+ ASSERT_FALSE(controller->GetLastCommittedEntry());
+
+ // Check the things the pending Web UI should have set.
+ EXPECT_FALSE(contents->ShouldDisplayURL());
+ EXPECT_FALSE(contents->ShouldDisplayFavIcon());
+ EXPECT_TRUE(contents->ShouldShowBookmarkBar());
+ EXPECT_TRUE(contents->FocusLocationBarByDefault());
+
+ // Now commit the load.
+ static_cast<TestRenderViewHost*>(
+ contents->render_view_host())->SendNavigate(page_id, new_tab_url);
+
+ // The same flags should be set as before now that the load has committed.
+ EXPECT_FALSE(contents->ShouldDisplayURL());
+ EXPECT_FALSE(contents->ShouldDisplayFavIcon());
+ EXPECT_TRUE(contents->ShouldShowBookmarkBar());
+ EXPECT_TRUE(contents->FocusLocationBarByDefault());
+
+ // Start a pending navigation to a regular page.
+ GURL next_url("http://google.com/");
+ controller->LoadURL(next_url, GURL(), PageTransition::LINK);
+
+ // Check the flags. Some should reflect the new page (URL, title), some
+ // should reflect the old one (bookmark bar) until it has committed.
+ EXPECT_TRUE(contents->ShouldDisplayURL());
+ EXPECT_TRUE(contents->ShouldDisplayFavIcon());
+ EXPECT_TRUE(contents->ShouldShowBookmarkBar());
+ EXPECT_FALSE(contents->FocusLocationBarByDefault());
+
+ // Commit the regular page load. Note that we must send it to the "pending"
+ // RenderViewHost if there is one, since this transition will also cause a
+ // process transition, and our RVH pointer will be the "committed" one.
+ // In the second call to this function from WebUIToStandard, it won't
+ // actually be pending, which is the point of this test.
+ if (contents->render_manager()->pending_render_view_host()) {
+ static_cast<TestRenderViewHost*>(
+ contents->render_manager()->pending_render_view_host())->SendNavigate(
+ page_id + 1, next_url);
+ } else {
+ static_cast<TestRenderViewHost*>(
+ contents->render_view_host())->SendNavigate(page_id + 1, next_url);
+ }
+
+ // The state should now reflect a regular page.
+ EXPECT_TRUE(contents->ShouldDisplayURL());
+ EXPECT_TRUE(contents->ShouldDisplayFavIcon());
+ EXPECT_FALSE(contents->ShouldShowBookmarkBar());
+ EXPECT_FALSE(contents->FocusLocationBarByDefault());
+ }
+
+ private:
+ BrowserThread ui_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebUITest);
+};
+
+// Tests that the New Tab Page flags are correctly set and propogated by
+// TabContents when we first navigate to a Web UI page, then to a standard
+// non-DOM-UI page.
+TEST_F(WebUITest, WebUIToStandard) {
+ DoNavigationTest(contents(), 1);
+
+ // Test the case where we're not doing the initial navigation. This is
+ // slightly different than the very-first-navigation case since the
+ // SiteInstance will be the same (the original TabContents must still be
+ // alive), which will trigger different behavior in RenderViewHostManager.
+ TestTabContents contents2(profile_.get(), NULL);
+
+ DoNavigationTest(&contents2, 101);
+}
+
+TEST_F(WebUITest, WebUIToWebUI) {
+ // Do a load (this state is tested above).
+ GURL new_tab_url(chrome::kChromeUINewTabURL);
+ controller().LoadURL(new_tab_url, GURL(), PageTransition::LINK);
+ rvh()->SendNavigate(1, new_tab_url);
+
+ // Start another pending load of the new tab page.
+ controller().LoadURL(new_tab_url, GURL(), PageTransition::LINK);
+ rvh()->SendNavigate(2, new_tab_url);
+
+ // The flags should be the same as the non-pending state.
+ EXPECT_FALSE(contents()->ShouldDisplayURL());
+ EXPECT_FALSE(contents()->ShouldDisplayFavIcon());
+ EXPECT_TRUE(contents()->ShouldShowBookmarkBar());
+ EXPECT_TRUE(contents()->FocusLocationBarByDefault());
+}
+
+TEST_F(WebUITest, StandardToWebUI) {
+ // Start a pending navigation to a regular page.
+ GURL std_url("http://google.com/");
+
+ controller().LoadURL(std_url, GURL(), PageTransition::LINK);
+
+ // The state should now reflect the default.
+ EXPECT_TRUE(contents()->ShouldDisplayURL());
+ EXPECT_TRUE(contents()->ShouldDisplayFavIcon());
+ EXPECT_FALSE(contents()->ShouldShowBookmarkBar());
+ EXPECT_FALSE(contents()->FocusLocationBarByDefault());
+
+ // Commit the load, the state should be the same.
+ rvh()->SendNavigate(1, std_url);
+ EXPECT_TRUE(contents()->ShouldDisplayURL());
+ EXPECT_TRUE(contents()->ShouldDisplayFavIcon());
+ EXPECT_FALSE(contents()->ShouldShowBookmarkBar());
+ EXPECT_FALSE(contents()->FocusLocationBarByDefault());
+
+ // Start a pending load for a WebUI.
+ GURL new_tab_url(chrome::kChromeUINewTabURL);
+ controller().LoadURL(new_tab_url, GURL(), PageTransition::LINK);
+ EXPECT_FALSE(contents()->ShouldDisplayURL());
+ EXPECT_TRUE(contents()->ShouldDisplayFavIcon());
+ EXPECT_FALSE(contents()->ShouldShowBookmarkBar());
+ EXPECT_TRUE(contents()->FocusLocationBarByDefault());
+
+ // Committing Web UI is tested above.
+}
+
+class TabContentsForFocusTest : public TestTabContents {
+ public:
+ TabContentsForFocusTest(Profile* profile, SiteInstance* instance)
+ : TestTabContents(profile, instance), focus_called_(0) {
+ }
+
+ virtual void SetFocusToLocationBar(bool select_all) { ++focus_called_; }
+ int focus_called() const { return focus_called_; }
+
+ private:
+ int focus_called_;
+};
+
+TEST_F(WebUITest, FocusOnNavigate) {
+ // Setup. |tc| will be used to track when we try to focus the location bar.
+ TabContentsForFocusTest* tc = new TabContentsForFocusTest(
+ contents()->profile(),
+ SiteInstance::CreateSiteInstance(contents()->profile()));
+ tc->controller().CopyStateFrom(controller());
+ scoped_ptr<TestTabContents> tc_scoped_ptr(tc);
+ contents_.swap(tc_scoped_ptr);
+ int page_id = 200;
+
+ // Load the NTP.
+ GURL new_tab_url(chrome::kChromeUINewTabURL);
+ controller().LoadURL(new_tab_url, GURL(), PageTransition::LINK);
+ rvh()->SendNavigate(page_id, new_tab_url);
+
+ // Navigate to another page.
+ GURL next_url("http://google.com/");
+ int next_page_id = page_id + 1;
+ controller().LoadURL(next_url, GURL(), PageTransition::LINK);
+ pending_rvh()->SendNavigate(next_page_id, next_url);
+
+ // Navigate back. Should focus the location bar.
+ int focus_called = tc->focus_called();
+ ASSERT_TRUE(controller().CanGoBack());
+ controller().GoBack();
+ pending_rvh()->SendNavigate(page_id, new_tab_url);
+ EXPECT_LT(focus_called, tc->focus_called());
+
+ // Navigate forward. Shouldn't focus the location bar.
+ focus_called = tc->focus_called();
+ ASSERT_TRUE(controller().CanGoForward());
+ controller().GoForward();
+ pending_rvh()->SendNavigate(next_page_id, next_url);
+ EXPECT_EQ(focus_called, tc->focus_called());
+
+ contents_.swap(tc_scoped_ptr);
+}
diff --git a/content/browser/webui/web_ui_util.cc b/content/browser/webui/web_ui_util.cc
new file mode 100644
index 0000000..e76aaef
--- /dev/null
+++ b/content/browser/webui/web_ui_util.cc
@@ -0,0 +1,64 @@
+// 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.
+
+#include "content/browser/webui/web_ui_util.h"
+
+#include <vector>
+
+#include "base/base64.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace web_ui_util {
+
+std::string GetJsonResponseFromFirstArgumentInList(const ListValue* args) {
+ return GetJsonResponseFromArgumentList(args, 0);
+}
+
+std::string GetJsonResponseFromArgumentList(const ListValue* args,
+ size_t list_index) {
+ std::string result;
+ if (args->GetSize() <= list_index) {
+ NOTREACHED();
+ return result;
+ }
+
+ Value* value = NULL;
+ if (args->Get(list_index, &value))
+ value->GetAsString(&result);
+ else
+ NOTREACHED();
+
+ return result;
+}
+
+std::string GetImageDataUrl(const SkBitmap& bitmap) {
+ std::vector<unsigned char> output;
+ gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &output);
+ std::string str_url;
+ std::copy(output.begin(), output.end(),
+ std::back_inserter(str_url));
+ base::Base64Encode(str_url, &str_url);
+ str_url.insert(0, "data:image/png;base64,");
+ return str_url;
+}
+
+std::string GetImageDataUrlFromResource(int res) {
+ // Load resource icon and covert to base64 encoded data url
+ RefCountedStaticMemory* icon_data =
+ ResourceBundle::GetSharedInstance().LoadDataResourceBytes(res);
+ if (!icon_data)
+ return std::string();
+ scoped_refptr<RefCountedMemory> raw_icon(icon_data);
+ std::string str_url;
+ std::copy(raw_icon->front(), raw_icon->front() + raw_icon->size(),
+ std::back_inserter(str_url));
+ base::Base64Encode(str_url, &str_url);
+ str_url.insert(0, "data:image/png;base64,");
+ return str_url;
+}
+
+} // namespace web_ui_util
diff --git a/content/browser/webui/web_ui_util.h b/content/browser/webui/web_ui_util.h
new file mode 100644
index 0000000..d7034dc
--- /dev/null
+++ b/content/browser/webui/web_ui_util.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_WEBUI_WEB_UI_UTIL_H_
+#define CONTENT_BROWSER_WEBUI_WEB_UI_UTIL_H_
+#pragma once
+
+#include <string>
+
+class ListValue;
+class SkBitmap;
+
+namespace web_ui_util {
+
+// Convenience routine to get the response string from an argument
+// list. Typically used when supporting a WebUI and getting calls
+// from the hosted code. Content must be a ListValue with at least
+// one entry in it, and that first entry must be a string, which is
+// returned. The parameter is a Value for convenience. Returns an
+// empty string on error or if the parameter is not a ListValue.
+std::string GetJsonResponseFromFirstArgumentInList(const ListValue* args);
+
+// Convenience routine to get one of the response strings from an
+// argument list. content must be a ListValue, with at least
+// (list_index+1) entries in it. list_index is the 0-based index of
+// the entry to pull from that list, and that entry must be a string,
+// which is returned. The parameter is a Value for convenience.
+// Returns an empty string on error or if the parameter is not a
+// ListValue.
+std::string GetJsonResponseFromArgumentList(const ListValue* args,
+ size_t list_index);
+
+
+// Convenience routine to convert SkBitmap object to data url
+// so that it can be used in WebUI.
+std::string GetImageDataUrl(const SkBitmap& bitmap);
+
+// Convenience routine to get data url that corresponds to given
+// resource_id as an image. This function does not check if the
+// resource for the |resource_id| is an image, therefore it is the
+// caller's responsibility to make sure the resource is indeed an
+// image. Returns empty string if a resource does not exist for given
+// |resource_id|.
+std::string GetImageDataUrlFromResource(int resource_id);
+
+} // namespace web_ui_util
+
+#endif // CONTENT_BROWSER_WEBUI_WEB_UI_UTIL_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 9e7837e..3ca1baa 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -221,6 +221,12 @@
'browser/tab_contents/tab_contents_observer.h',
'browser/tab_contents/tab_contents_view.cc',
'browser/tab_contents/tab_contents_view.h',
+ 'browser/webui/web_ui.cc',
+ 'browser/webui/web_ui.h',
+ 'browser/webui/web_ui_factory.cc',
+ 'browser/webui/web_ui_factory.h',
+ 'browser/webui/web_ui_util.cc',
+ 'browser/webui/web_ui_util.h',
'browser/zygote_host_linux.cc',
'browser/zygote_host_linux.h',
'browser/zygote_main_linux.cc',