172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/extensions/extension_web_ui.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set> 821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <vector> 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_bookmark_manager_api.h" 1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/image_loading_tracker.h" 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h" 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/prefs/scoped_user_pref_update.h" 1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h" 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h" 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_switches.h" 224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/extensions/extension.h" 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension_constants.h" 243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/extensions/extension_icon_set.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_resource.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h" 27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_widget_host_view.h" 28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/bindings_policy.h" 30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/page_transition_types.h" 31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/base/file_stream.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h" 3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/codec/png_codec.h" 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/favicon_size.h" 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// De-dupes the items in |list|. Assumes the values are strings. 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CleanUpDuplicates(ListValue* list) { 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<std::string> seen_values; 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Loop backwards as we may be removing items. 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = list->GetSize() - 1; (i + 1) > 0; --i) { 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string value; 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!list->GetString(i, &value)) { 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (seen_values.find(value) == seen_values.end()) 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch seen_values.insert(value); 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch list->Remove(i, NULL); 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Helper class that is used to track the loading of the favicon of an 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// extension. 5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenclass ExtensionWebUIImageLoadingTracker : public ImageLoadingTracker::Observer { 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExtensionWebUIImageLoadingTracker(Profile* profile, 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FaviconService::GetFaviconRequest* request, 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& page_url) 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_(request), 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_(NULL) { 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Even when the extensions service is enabled by default, it's still 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // disabled in incognito mode. 6921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ExtensionService* service = profile->GetExtensionService(); 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (service) 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_ = service->GetExtensionByURL(page_url); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Init() { 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (extension_) { 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionResource icon_resource = 773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick extension_->GetIconResource(Extension::EXTENSION_ICON_BITTY, 783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ExtensionIconSet::MATCH_EXACTLY); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tracker_.LoadImage(extension_, icon_resource, 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gfx::Size(kFaviconSize, kFaviconSize), 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ImageLoadingTracker::DONT_CACHE); 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ForwardResult(NULL); 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void OnImageLoaded(SkBitmap* image, const ExtensionResource& resource, 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (image) { 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<unsigned char> image_data; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!gfx::PNGCodec::EncodeBGRASkBitmap(*image, false, &image_data)) { 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Could not encode extension favicon"; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ForwardResult(RefCountedBytes::TakeVector(&image_data)); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ForwardResult(NULL); 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ~ExtensionWebUIImageLoadingTracker() {} 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Forwards the result on the request. If no favicon was available then 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |icon_data| may be backed by NULL. Once the result has been forwarded the 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // instance is deleted. 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void ForwardResult(scoped_refptr<RefCountedMemory> icon_data) { 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen history::FaviconData favicon; 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen favicon.known_icon = icon_data.get() != NULL && icon_data->size() > 0; 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen favicon.image_data = icon_data; 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen favicon.icon_type = history::FAVICON; 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_->ForwardResultAsync( 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FaviconService::FaviconDataCallback::TupleType(request_->handle(), 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen favicon)); 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete this; 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ImageLoadingTracker tracker_; 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<FaviconService::GetFaviconRequest> request_; 120513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension_; 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DISALLOW_COPY_AND_ASSIGN(ExtensionWebUIImageLoadingTracker); 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst char ExtensionWebUI::kExtensionURLOverrides[] = 1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick "extensions.chrome_url_overrides"; 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionWebUI::ExtensionWebUI(TabContents* tab_contents, const GURL& url) 13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : WebUI(tab_contents), 132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch url_(url) { 13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ExtensionService* service = tab_contents->profile()->GetExtensionService(); 134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension = service->GetExtensionByURL(url); 1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!extension) 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick extension = service->GetExtensionByWebExtent(url); 1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(extension); 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Only hide the url for internal pages (e.g. chrome-extension or packaged 1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // component apps like bookmark manager. 1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick should_hide_url_ = !extension->is_hosted_app(); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bindings_ = BindingsPolicy::EXTENSION; 14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Bind externalHost to Extension WebUI loaded in Chrome Frame. 1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); 1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (browser_command_line.HasSwitch(switches::kChromeFrame)) 1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bindings_ |= BindingsPolicy::EXTERNAL_HOST; 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For chrome:// overrides, some of the defaults are a little different. 1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GURL effective_url = tab_contents->GetURL(); 1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (effective_url.SchemeIs(chrome::kChromeUIScheme) && 1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick effective_url.host() == chrome::kChromeUINewTabHost) { 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_location_bar_by_default_ = true; 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionWebUI::~ExtensionWebUI() {} 156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::ResetExtensionFunctionDispatcher( 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RenderViewHost* render_view_host) { 159513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // TODO(jcivelli): http://crbug.com/60608 we should get the URL out of the 160513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // active entry of the navigation controller. 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_function_dispatcher_.reset( 162513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(extension_function_dispatcher_.get()); 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::ResetExtensionBookmarkManagerEventRouter() { 1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Hack: A few things we specialize just for the bookmark manager. 1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (extension_function_dispatcher_->extension_id() == 1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick extension_misc::kBookmarkManagerId) { 1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick extension_bookmark_manager_event_router_.reset( 1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents())); 1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick link_transition_type_ = PageTransition::AUTO_BOOKMARK; 1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 17772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::RenderViewCreated(RenderViewHost* render_view_host) { 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResetExtensionFunctionDispatcher(render_view_host); 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResetExtensionBookmarkManagerEventRouter(); 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::RenderViewReused(RenderViewHost* render_view_host) { 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResetExtensionFunctionDispatcher(render_view_host); 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResetExtensionBookmarkManagerEventRouter(); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::ProcessWebUIMessage( 188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const ExtensionHostMsg_DomMessage_Params& params) { 1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick extension_function_dispatcher_->HandleRequest(params); 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBrowser* ExtensionWebUI::GetBrowser() { 1934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch TabContents* contents = tab_contents(); 1944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch TabContentsIterator tab_iterator; 1954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch for (; !tab_iterator.done(); ++tab_iterator) { 196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (contents == (*tab_iterator)->tab_contents()) 1974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return tab_iterator.browser(); 1984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return NULL; 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenTabContents* ExtensionWebUI::associated_tab_contents() const { 204731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return tab_contents(); 205731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 206731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 207731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickExtensionBookmarkManagerEventRouter* 20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionWebUI::extension_bookmark_manager_event_router() { 209731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return extension_bookmark_manager_event_router_.get(); 210731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 211731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 21272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsengfx::NativeWindow ExtensionWebUI::GetCustomFrameNativeWindow() { 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GetBrowser()) 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there was no browser associated with the function dispatcher delegate, 21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // then this WebUI may be hosted in an ExternalTabContainer, and a framing 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // window will be accessible through the tab_contents. 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate(); 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_contents_delegate) 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return tab_contents_delegate->GetFrameNativeWindow(); 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsengfx::NativeView ExtensionWebUI::GetNativeViewOfHost() { 227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView(); 228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return rwhv ? rwhv->GetNativeView() : NULL; 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// chrome:// URL overrides 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::RegisterUserPrefs(PrefService* prefs) { 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->RegisterDictionaryPref(kExtensionURLOverrides); 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool ExtensionWebUI::HandleChromeURLOverride(GURL* url, Profile* profile) { 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!url->SchemeIs(chrome::kChromeUIScheme)) 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const DictionaryValue* overrides = 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile->GetPrefs()->GetDictionary(kExtensionURLOverrides); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string page = url->host(); 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ListValue* url_list; 2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!overrides || !overrides->GetList(page, &url_list)) 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 25121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ExtensionService* service = profile->GetExtensionService(); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size_t i = 0; 2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick while (i < url_list->GetSize()) { 2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Value* val = NULL; 2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick url_list->Get(i, &val); 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Verify that the override value is good. If not, unregister it and find 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the next one. 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string override; 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!val->GetAsString(&override)) { 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnregisterChromeURLOverride(page, profile, val); 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL extension_url(override); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!extension_url.is_valid()) { 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnregisterChromeURLOverride(page, profile, val); 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Verify that the extension that's being referred to actually exists. 274513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension = service->GetExtensionByURL(extension_url); 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!extension) { 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This can currently happen if you use --load-extension one run, and 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // then don't use it the next. It could also happen if an extension 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // were deleted directly from the filesystem, etc. 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "chrome URL override present for non-existant extension"; 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnregisterChromeURLOverride(page, profile, val); 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We can't handle chrome-extension URLs in incognito mode unless the 2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // extension uses split mode. 2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool incognito_override_allowed = 2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick extension->incognito_split_mode() && 288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen service->IsIncognitoEnabled(extension->id()); 2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (profile->IsOffTheRecord() && !incognito_override_allowed) { 2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ++i; 2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick continue; 2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *url = extension_url; 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 30172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::RegisterChromeURLOverrides( 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile, const Extension::URLOverrideMap& overrides) { 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (overrides.empty()) 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrefService* prefs = profile->GetPrefs(); 307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DictionaryPrefUpdate update(prefs, kExtensionURLOverrides); 308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DictionaryValue* all_overrides = update.Get(); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For each override provided by the extension, add it to the front of 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the override list if it's not already in the list. 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Extension::URLOverrideMap::const_iterator iter = overrides.begin(); 3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (; iter != overrides.end(); ++iter) { 3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const std::string& key = iter->first; 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ListValue* page_overrides; 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!all_overrides->GetList(key, &page_overrides)) { 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch page_overrides = new ListValue(); 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_overrides->Set(key, page_overrides); 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CleanUpDuplicates(page_overrides); 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Verify that the override isn't already in the list. 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ListValue::iterator i = page_overrides->begin(); 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (; i != page_overrides->end(); ++i) { 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string override_val; 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!(*i)->GetAsString(&override_val)) { 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (override_val == iter->second.spec()) 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This value is already in the list, leave it alone. 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (i != page_overrides->end()) 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Insert the override at the front of the list. Last registered override 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // wins. 3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick page_overrides->Insert(0, new StringValue(iter->second.spec())); 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::UnregisterAndReplaceOverride(const std::string& page, 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile, ListValue* list, Value* override) { 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index = list->Remove(*override); 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index == 0) { 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This is the active override, so we need to find all existing 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tabs for this override and get them to reload the original URL. 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (TabContentsIterator iterator; !iterator.done(); ++iterator) { 351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabContents* tab = (*iterator)->tab_contents(); 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->profile() != profile) 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL url = tab->GetURL(); 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!url.SchemeIs(chrome::kChromeUIScheme) || url.host() != page) 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't use Reload() since |url| isn't the same as the internal URL 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that NavigationController has. 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->controller().LoadURL(url, url, PageTransition::RELOAD); 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 36772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::UnregisterChromeURLOverride(const std::string& page, 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile, Value* override) { 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!override) 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrefService* prefs = profile->GetPrefs(); 372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DictionaryPrefUpdate update(prefs, kExtensionURLOverrides); 373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DictionaryValue* all_overrides = update.Get(); 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ListValue* page_overrides; 3753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!all_overrides->GetList(page, &page_overrides)) { 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If it's being unregistered, it should already be in the list. 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnregisterAndReplaceOverride(page, profile, page_overrides, override); 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::UnregisterChromeURLOverrides( 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile, const Extension::URLOverrideMap& overrides) { 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (overrides.empty()) 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrefService* prefs = profile->GetPrefs(); 390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DictionaryPrefUpdate update(prefs, kExtensionURLOverrides); 391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DictionaryValue* all_overrides = update.Get(); 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Extension::URLOverrideMap::const_iterator iter = overrides.begin(); 3933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (; iter != overrides.end(); ++iter) { 3943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const std::string& page = iter->first; 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ListValue* page_overrides; 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!all_overrides->GetList(page, &page_overrides)) { 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If it's being unregistered, it should already be in the list. 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 4013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick StringValue override(iter->second.spec()); 4023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick UnregisterAndReplaceOverride(iter->first, profile, 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch page_overrides, &override); 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 40972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebUI::GetFaviconForURL(Profile* profile, 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FaviconService::GetFaviconRequest* request, const GURL& page_url) { 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tracker deletes itself when done. 41272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExtensionWebUIImageLoadingTracker* tracker = 41372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen new ExtensionWebUIImageLoadingTracker(profile, request, page_url); 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tracker->Init(); 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 416