15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_web_ui.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_tab_util.h"
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/extensions/extension_util.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/favicon_base/favicon_util.h"
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_controller.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/bindings_policy.h"
2923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "extensions/browser/extension_registry.h"
306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/image_loader.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/extension_icon_set.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/extension_resource.h"
34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest_handlers/incognito_info.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/file_stream.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/base/page_transition_types.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h"
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/image/image_skia.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::URLOverrides;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// De-dupes the items in |list|. Assumes the values are strings.
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid CleanUpDuplicates(base::ListValue* list) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<std::string> seen_values;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Loop backwards as we may be removing items.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = list->GetSize() - 1; (i + 1) > 0; --i) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string value;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!list->GetString(i, &value)) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (seen_values.find(value) == seen_values.end())
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      seen_values.insert(value);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      list->Remove(i, NULL);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Reloads the page in |web_contents| if it uses the same profile as |profile|
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and if the current URL is a chrome URL.
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UnregisterAndReplaceOverrideForWebContents(const std::string& page,
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                Profile* profile,
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                WebContents* web_contents) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (Profile::FromBrowserContext(web_contents->GetBrowserContext()) != profile)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url = web_contents->GetURL();
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!url.SchemeIs(content::kChromeUIScheme) || url.host() != page)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't use Reload() since |url| isn't the same as the internal URL that
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NavigationController has.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_contents->GetController().LoadURL(
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      url, content::Referrer(url, blink::WebReferrerPolicyDefault),
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ui::PAGE_TRANSITION_RELOAD, std::string());
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Run favicon callbck with image result. If no favicon was available then
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |image| will be empty.
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RunFaviconCallbackAsync(
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const favicon_base::FaviconResultsCallback& callback,
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Image& image) {
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results =
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new std::vector<favicon_base::FaviconRawBitmapResult>();
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::vector<gfx::ImageSkiaRep>& image_reps =
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      image.AsImageSkia().image_reps();
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < image_reps.size(); ++i) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::ImageSkiaRep& image_rep = image_reps[i];
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::RefCountedBytes> bitmap_data(
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new base::RefCountedBytes());
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (gfx::PNGCodec::EncodeBGRASkBitmap(image_rep.sk_bitmap(),
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          false,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          &bitmap_data->data())) {
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      favicon_base::FaviconRawBitmapResult bitmap_result;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bitmap_result.bitmap_data = bitmap_data;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bitmap_result.pixel_size = gfx::Size(image_rep.pixel_width(),
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            image_rep.pixel_height());
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Leave |bitmap_result|'s icon URL as the default of GURL().
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      bitmap_result.icon_type = favicon_base::FAVICON;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_bitmap_results->push_back(bitmap_result);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED() << "Could not encode extension favicon";
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessageLoopProxy::current()->PostTask(
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&FaviconService::FaviconResultsCallbackRunner,
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 callback,
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Owned(favicon_bitmap_results)));
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool ValidateOverrideURL(const base::Value* override_url_value,
12523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         const GURL& source_url,
12623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         const extensions::ExtensionSet& extensions,
12723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         GURL* override_url,
12823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         const Extension** extension) {
12923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::string override;
13023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!override_url_value || !override_url_value->GetAsString(&override)) {
13123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
13223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
13323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!source_url.query().empty())
13423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    override += "?" + source_url.query();
13523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!source_url.ref().empty())
13623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    override += "#" + source_url.ref();
13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  *override_url = GURL(override);
13823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!override_url->is_valid()) {
13923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
14023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
14123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  *extension = extensions.GetByID(override_url->host());
14223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!*extension) {
14323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
14423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return true;
14623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
14723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char ExtensionWebUI::kExtensionURLOverrides[] =
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "extensions.chrome_url_overrides";
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionWebUI::ExtensionWebUI(content::WebUI* web_ui, const GURL& url)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : WebUIController(web_ui),
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_(url) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromWebUI(web_ui);
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const Extension* extension = extensions::ExtensionRegistry::Get(
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      profile)->enabled_extensions().GetExtensionOrAppByURL(url);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(extension);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The base class defaults to enabling WebUI bindings, but we don't need
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // those (this is also reflected in ChromeWebUIControllerFactory::
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // UseWebUIBindingsForURL).
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bindings = 0;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui->SetBindings(bindings);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hack: A few things we specialize just for the bookmark manager.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (extension->id() == extension_misc::kBookmarkManagerId) {
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bookmark_manager_private_drag_event_router_.reset(
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new extensions::BookmarkManagerPrivateDragEventRouter(
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            profile, web_ui->GetWebContents()));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    web_ui->SetLinkTransitionType(ui::PAGE_TRANSITION_AUTO_BOOKMARK);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionWebUI::~ExtensionWebUI() {}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)extensions::BookmarkManagerPrivateDragEventRouter*
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ExtensionWebUI::bookmark_manager_private_drag_event_router() {
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return bookmark_manager_private_drag_event_router_.get();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// chrome:// URL overrides
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ExtensionWebUI::RegisterProfilePrefs(
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registry->RegisterDictionaryPref(
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      kExtensionURLOverrides,
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionWebUI::HandleChromeURLOverride(
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GURL* url,
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    content::BrowserContext* browser_context) {
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!url->SchemeIs(content::kChromeUIScheme))
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(browser_context);
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const base::DictionaryValue* overrides =
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
20523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
20623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::string url_host = url->host();
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const base::ListValue* url_list = NULL;
20823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!overrides || !overrides->GetList(url_host, &url_list))
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  extensions::ExtensionRegistry* registry =
21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      extensions::ExtensionRegistry::Get(browser_context);
21323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const extensions::ExtensionSet& extensions = registry->enabled_extensions();
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GURL component_url;
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool found_component_override = false;
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
21823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Iterate over the URL list looking for a suitable override. If a
21923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // valid non-component override is encountered it is chosen immediately.
22023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (size_t i = 0; i < url_list->GetSize(); ++i) {
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Value* val = NULL;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_list->Get(i, &val);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    GURL override_url;
22523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const Extension* extension;
22623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (!ValidateOverrideURL(
22723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            val, *url, extensions, &override_url, &extension)) {
22823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      LOG(WARNING) << "Invalid chrome URL override";
22923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      UnregisterChromeURLOverride(url_host, profile, val);
23023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      // The above Unregister call will remove this item from url_list.
23123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      --i;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We can't handle chrome-extension URLs in incognito mode unless the
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // extension uses split mode.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool incognito_override_allowed =
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::IncognitoInfo::IsSplitMode(extension) &&
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        extensions::util::IsIncognitoEnabled(extension->id(), profile);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (profile->IsOffTheRecord() && !incognito_override_allowed) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (!extensions::Manifest::IsComponentLocation(extension->location())) {
24523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      *url = override_url;
24623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return true;
24723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
24823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
24923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (!found_component_override) {
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      found_component_override = true;
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      component_url = override_url;
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
25523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // If no other non-component overrides were found, use the first known
25623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // component override, if any.
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (found_component_override) {
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *url = component_url;
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return true;
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionWebUI::HandleChromeURLOverrideReverse(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL* url, content::BrowserContext* browser_context) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(browser_context);
269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const base::DictionaryValue* overrides =
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!overrides)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the reverse mapping based on the given URL. For example this maps the
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // internal URL
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // chrome-extension://eemcgdkfndhakfknompkggombfjjjeno/main.html#1 to
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // chrome://bookmarks/#1 for display in the omnibox.
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (base::DictionaryValue::Iterator it(*overrides); !it.IsAtEnd();
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it.Advance()) {
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::ListValue* url_list = NULL;
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!it.value().GetAsList(&url_list))
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (base::ListValue::const_iterator it2 = url_list->begin();
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it2 != url_list->end(); ++it2) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string override;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!(*it2)->GetAsString(&override))
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (StartsWithASCII(url->spec(), override, true)) {
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        GURL original_url(content::kChromeUIScheme + std::string("://") +
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          it.key() + url->spec().substr(override.length()));
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *url = original_url;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionWebUI::RegisterChromeURLOverrides(
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Profile* profile, const URLOverrides::URLOverrideMap& overrides) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (overrides.empty())
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* prefs = profile->GetPrefs();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* all_overrides = update.Get();
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For each override provided by the extension, add it to the front of
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the override list if it's not already in the list.
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin();
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; iter != overrides.end(); ++iter) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& key = iter->first;
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::ListValue* page_overrides = NULL;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!all_overrides->GetList(key, &page_overrides)) {
318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      page_overrides = new base::ListValue();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_overrides->Set(key, page_overrides);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CleanUpDuplicates(page_overrides);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Verify that the override isn't already in the list.
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::ListValue::iterator i = page_overrides->begin();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (; i != page_overrides->end(); ++i) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string override_val;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!(*i)->GetAsString(&override_val)) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NOTREACHED();
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (override_val == iter->second.spec())
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This value is already in the list, leave it alone.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i != page_overrides->end())
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Insert the override at the front of the list.  Last registered override
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // wins.
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    page_overrides->Insert(0, new base::StringValue(iter->second.spec()));
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionWebUI::UnregisterAndReplaceOverride(const std::string& page,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  Profile* profile,
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                  base::ListValue* list,
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  const base::Value* override) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t index = 0;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool found = list->Remove(*override, &index);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (found && index == 0) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is the active override, so we need to find all existing
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // tabs for this override and get them to reload the original URL.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Callback<void(WebContents*)> callback =
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&UnregisterAndReplaceOverrideForWebContents, page, profile);
356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    extensions::ExtensionTabUtil::ForEachTab(callback);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionWebUI::UnregisterChromeURLOverride(const std::string& page,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 Profile* profile,
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                 const base::Value* override) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!override)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* prefs = profile->GetPrefs();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* all_overrides = update.Get();
369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ListValue* page_overrides = NULL;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!all_overrides->GetList(page, &page_overrides)) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If it's being unregistered, it should already be in the list.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnregisterAndReplaceOverride(page, profile, page_overrides, override);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionWebUI::UnregisterChromeURLOverrides(
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Profile* profile, const URLOverrides::URLOverrideMap& overrides) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (overrides.empty())
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* prefs = profile->GetPrefs();
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* all_overrides = update.Get();
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin();
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; iter != overrides.end(); ++iter) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& page = iter->first;
390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::ListValue* page_overrides = NULL;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!all_overrides->GetList(page, &page_overrides)) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If it's being unregistered, it should already be in the list.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::StringValue override(iter->second.spec());
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UnregisterAndReplaceOverride(iter->first, profile,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   page_overrides, &override);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionWebUI::GetFaviconForURL(
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Profile* profile,
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& page_url,
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const favicon_base::FaviconResultsCallback& callback) {
408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const Extension* extension = extensions::ExtensionRegistry::Get(
409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      profile)->enabled_extensions().GetByID(page_url.host());
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension) {
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RunFaviconCallbackAsync(callback, gfx::Image());
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fetch resources for all supported scale factors for which there are
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // resources. Load image reps for all supported scale factors (in addition to
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // 1x) immediately instead of in an as needed fashion to be consistent with
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // how favicons are requested for chrome:// and page URLs.
4196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const std::vector<float>& favicon_scales = favicon_base::GetFaviconScales();
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
4216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (size_t i = 0; i < favicon_scales.size(); ++i) {
4226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    float scale = favicon_scales[i];
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int pixel_size = static_cast<int>(gfx::kFaviconSize * scale);
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extensions::ExtensionResource icon_resource =
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::IconsInfo::GetIconResource(extension,
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               pixel_size,
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               ExtensionIconSet::MATCH_BIGGER);
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ui::ScaleFactor resource_scale_factor = ui::GetSupportedScaleFactor(scale);
4306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    info_list.push_back(extensions::ImageLoader::ImageRepresentation(
4316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        icon_resource,
4326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
4336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        gfx::Size(pixel_size, pixel_size),
4346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        resource_scale_factor));
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // LoadImagesAsync actually can run callback synchronously. We want to force
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // async.
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extensions::ImageLoader::Get(profile)->LoadImagesAsync(
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension, info_list, base::Bind(&RunFaviconCallbackAsync, callback));
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
442