diff options
author | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-25 02:56:57 +0000 |
---|---|---|
committer | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-25 02:56:57 +0000 |
commit | 67fc03984940b07daa38970e6876fcec1fce0e8e (patch) | |
tree | cc4df6d037ecc5e0a479305856fa84137d62af93 /content | |
parent | 31de2b56d10626c2328f43531931bc08348ebad2 (diff) | |
download | chromium_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.cc | 2 | ||||
-rw-r--r-- | content/browser/site_instance.cc | 2 | ||||
-rw-r--r-- | content/browser/tab_contents/render_view_host_manager.cc | 4 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.cc | 2 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.h | 2 | ||||
-rw-r--r-- | content/browser/webui/web_ui.cc | 217 | ||||
-rw-r--r-- | content/browser/webui/web_ui.h | 221 | ||||
-rw-r--r-- | content/browser/webui/web_ui_browsertest.cc | 77 | ||||
-rw-r--r-- | content/browser/webui/web_ui_browsertest.h | 58 | ||||
-rw-r--r-- | content/browser/webui/web_ui_factory.cc | 351 | ||||
-rw-r--r-- | content/browser/webui/web_ui_factory.h | 67 | ||||
-rw-r--r-- | content/browser/webui/web_ui_handler_browsertest.cc | 41 | ||||
-rw-r--r-- | content/browser/webui/web_ui_handler_browsertest.h | 40 | ||||
-rw-r--r-- | content/browser/webui/web_ui_unittest.cc | 199 | ||||
-rw-r--r-- | content/browser/webui/web_ui_util.cc | 64 | ||||
-rw-r--r-- | content/browser/webui/web_ui_util.h | 49 | ||||
-rw-r--r-- | content/content_browser.gypi | 6 |
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(¶ms.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', |