1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/webui/ntp/favicon_webui_handler.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/strings/string_split.h" 10#include "base/strings/string_util.h" 11#include "base/strings/stringprintf.h" 12#include "base/values.h" 13#include "chrome/browser/extensions/extension_icon_manager.h" 14#include "chrome/browser/favicon/favicon_service.h" 15#include "chrome/browser/favicon/favicon_service_factory.h" 16#include "chrome/browser/history/top_sites.h" 17#include "chrome/browser/profiles/profile.h" 18#include "chrome/common/url_constants.h" 19#include "content/public/browser/web_ui.h" 20#include "extensions/browser/extension_registry.h" 21#include "third_party/skia/include/core/SkBitmap.h" 22#include "ui/base/l10n/l10n_util.h" 23#include "ui/gfx/codec/png_codec.h" 24#include "ui/gfx/color_analysis.h" 25#include "ui/gfx/favicon_size.h" 26 27namespace { 28 29base::StringValue* SkColorToCss(SkColor color) { 30 return new base::StringValue(base::StringPrintf("rgb(%d, %d, %d)", 31 SkColorGetR(color), 32 SkColorGetG(color), 33 SkColorGetB(color))); 34} 35 36base::StringValue* GetDominantColorCssString( 37 scoped_refptr<base::RefCountedMemory> png) { 38 color_utils::GridSampler sampler; 39 SkColor color = color_utils::CalculateKMeanColorOfPNG(png); 40 return SkColorToCss(color); 41} 42 43} // namespace 44 45// Thin inheritance-dependent trampoline to forward notification of app 46// icon loads to the FaviconWebUIHandler. Base class does caching of icons. 47class ExtensionIconColorManager : public ExtensionIconManager { 48 public: 49 explicit ExtensionIconColorManager(FaviconWebUIHandler* handler) 50 : ExtensionIconManager(), 51 handler_(handler) {} 52 virtual ~ExtensionIconColorManager() {} 53 54 virtual void OnImageLoaded(const std::string& extension_id, 55 const gfx::Image& image) OVERRIDE { 56 ExtensionIconManager::OnImageLoaded(extension_id, image); 57 handler_->NotifyAppIconReady(extension_id); 58 } 59 60 private: 61 FaviconWebUIHandler* handler_; 62}; 63 64FaviconWebUIHandler::FaviconWebUIHandler() 65 : id_(0), 66 app_icon_color_manager_(new ExtensionIconColorManager(this)) { 67} 68 69FaviconWebUIHandler::~FaviconWebUIHandler() { 70} 71 72void FaviconWebUIHandler::RegisterMessages() { 73 web_ui()->RegisterMessageCallback("getFaviconDominantColor", 74 base::Bind(&FaviconWebUIHandler::HandleGetFaviconDominantColor, 75 base::Unretained(this))); 76 web_ui()->RegisterMessageCallback("getAppIconDominantColor", 77 base::Bind(&FaviconWebUIHandler::HandleGetAppIconDominantColor, 78 base::Unretained(this))); 79} 80 81void FaviconWebUIHandler::HandleGetFaviconDominantColor( 82 const base::ListValue* args) { 83 std::string path; 84 CHECK(args->GetString(0, &path)); 85 std::string prefix = "chrome://favicon/size/"; 86 DCHECK(StartsWithASCII(path, prefix, false)) << "path is " << path; 87 size_t slash = path.find("/", prefix.length()); 88 path = path.substr(slash + 1); 89 90 std::string dom_id; 91 CHECK(args->GetString(1, &dom_id)); 92 93 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 94 Profile::FromWebUI(web_ui()), Profile::EXPLICIT_ACCESS); 95 if (!favicon_service || path.empty()) 96 return; 97 98 GURL url(path); 99 // Intercept requests for prepopulated pages. 100 for (size_t i = 0; i < arraysize(history::kPrepopulatedPages); i++) { 101 if (url.spec() == 102 l10n_util::GetStringUTF8(history::kPrepopulatedPages[i].url_id)) { 103 base::StringValue dom_id_value(dom_id); 104 scoped_ptr<base::StringValue> color( 105 SkColorToCss(history::kPrepopulatedPages[i].color)); 106 web_ui()->CallJavascriptFunction("ntp.setFaviconDominantColor", 107 dom_id_value, *color); 108 return; 109 } 110 } 111 112 dom_id_map_[id_] = dom_id; 113 favicon_service->GetRawFaviconForPageURL( 114 url, 115 favicon_base::FAVICON, 116 gfx::kFaviconSize, 117 base::Bind(&FaviconWebUIHandler::OnFaviconDataAvailable, 118 base::Unretained(this), 119 id_++), 120 &cancelable_task_tracker_); 121} 122 123void FaviconWebUIHandler::OnFaviconDataAvailable( 124 int id, 125 const favicon_base::FaviconRawBitmapResult& bitmap_result) { 126 scoped_ptr<base::StringValue> color_value; 127 128 if (bitmap_result.is_valid()) 129 color_value.reset(GetDominantColorCssString(bitmap_result.bitmap_data)); 130 else 131 color_value.reset(new base::StringValue("#919191")); 132 133 base::StringValue dom_id(dom_id_map_[id]); 134 web_ui()->CallJavascriptFunction("ntp.setFaviconDominantColor", 135 dom_id, *color_value); 136 dom_id_map_.erase(id); 137} 138 139void FaviconWebUIHandler::HandleGetAppIconDominantColor( 140 const base::ListValue* args) { 141 std::string extension_id; 142 CHECK(args->GetString(0, &extension_id)); 143 144 Profile* profile = Profile::FromWebUI(web_ui()); 145 extensions::ExtensionRegistry* extension_registry = 146 extensions::ExtensionRegistry::Get(profile); 147 const extensions::Extension* extension = 148 extension_registry->enabled_extensions().GetByID(extension_id); 149 if (!extension) 150 return; 151 app_icon_color_manager_->LoadIcon(profile, extension); 152} 153 154void FaviconWebUIHandler::NotifyAppIconReady(const std::string& extension_id) { 155 const SkBitmap& bitmap = app_icon_color_manager_->GetIcon(extension_id); 156 // TODO(estade): would be nice to avoid a round trip through png encoding. 157 std::vector<unsigned char> bits; 158 if (!gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &bits)) 159 return; 160 scoped_refptr<base::RefCountedStaticMemory> bits_mem( 161 new base::RefCountedStaticMemory(&bits.front(), bits.size())); 162 scoped_ptr<base::StringValue> color_value( 163 GetDominantColorCssString(bits_mem)); 164 base::StringValue id(extension_id); 165 web_ui()->CallJavascriptFunction( 166 "ntp.setFaviconDominantColor", id, *color_value); 167} 168