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/extensions/extension_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 "grit/ui_resources.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 29StringValue* SkColorToCss(SkColor color) { 30 return new 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 = 40 color_utils::CalculateKMeanColorOfPNG(png, 100, 665, &sampler); 41 return SkColorToCss(color); 42} 43 44} // namespace 45 46// Thin inheritance-dependent trampoline to forward notification of app 47// icon loads to the FaviconWebUIHandler. Base class does caching of icons. 48class ExtensionIconColorManager : public ExtensionIconManager { 49 public: 50 explicit ExtensionIconColorManager(FaviconWebUIHandler* handler) 51 : ExtensionIconManager(), 52 handler_(handler) {} 53 virtual ~ExtensionIconColorManager() {} 54 55 virtual void OnImageLoaded(const std::string& extension_id, 56 const gfx::Image& image) OVERRIDE { 57 ExtensionIconManager::OnImageLoaded(extension_id, image); 58 handler_->NotifyAppIconReady(extension_id); 59 } 60 61 private: 62 FaviconWebUIHandler* handler_; 63}; 64 65FaviconWebUIHandler::FaviconWebUIHandler() 66 : id_(0), 67 app_icon_color_manager_(new ExtensionIconColorManager(this)) { 68} 69 70FaviconWebUIHandler::~FaviconWebUIHandler() { 71} 72 73void FaviconWebUIHandler::RegisterMessages() { 74 web_ui()->RegisterMessageCallback("getFaviconDominantColor", 75 base::Bind(&FaviconWebUIHandler::HandleGetFaviconDominantColor, 76 base::Unretained(this))); 77 web_ui()->RegisterMessageCallback("getAppIconDominantColor", 78 base::Bind(&FaviconWebUIHandler::HandleGetAppIconDominantColor, 79 base::Unretained(this))); 80} 81 82void FaviconWebUIHandler::HandleGetFaviconDominantColor(const 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 StringValue dom_id_value(dom_id); 104 scoped_ptr<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->GetRawFaviconForURL( 114 FaviconService::FaviconForURLParams( 115 url, 116 chrome::FAVICON, 117 gfx::kFaviconSize), 118 ui::SCALE_FACTOR_100P, 119 base::Bind(&FaviconWebUIHandler::OnFaviconDataAvailable, 120 base::Unretained(this), 121 id_++), 122 &cancelable_task_tracker_); 123} 124 125void FaviconWebUIHandler::OnFaviconDataAvailable( 126 int id, 127 const chrome::FaviconBitmapResult& bitmap_result) { 128 scoped_ptr<StringValue> color_value; 129 130 if (bitmap_result.is_valid()) 131 color_value.reset(GetDominantColorCssString(bitmap_result.bitmap_data)); 132 else 133 color_value.reset(new StringValue("#919191")); 134 135 StringValue dom_id(dom_id_map_[id]); 136 web_ui()->CallJavascriptFunction("ntp.setFaviconDominantColor", 137 dom_id, *color_value); 138 dom_id_map_.erase(id); 139} 140 141void FaviconWebUIHandler::HandleGetAppIconDominantColor( 142 const ListValue* args) { 143 std::string extension_id; 144 CHECK(args->GetString(0, &extension_id)); 145 146 ExtensionService* extension_service = 147 Profile::FromWebUI(web_ui())->GetExtensionService(); 148 const extensions::Extension* extension = extension_service->GetExtensionById( 149 extension_id, false); 150 if (!extension) 151 return; 152 app_icon_color_manager_->LoadIcon(extension_service->profile(), extension); 153} 154 155void FaviconWebUIHandler::NotifyAppIconReady(const std::string& extension_id) { 156 const SkBitmap& bitmap = app_icon_color_manager_->GetIcon(extension_id); 157 // TODO(estade): would be nice to avoid a round trip through png encoding. 158 std::vector<unsigned char> bits; 159 if (!gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &bits)) 160 return; 161 scoped_refptr<base::RefCountedStaticMemory> bits_mem( 162 new base::RefCountedStaticMemory(&bits.front(), bits.size())); 163 scoped_ptr<StringValue> color_value(GetDominantColorCssString(bits_mem)); 164 StringValue id(extension_id); 165 web_ui()->CallJavascriptFunction( 166 "ntp.setFaviconDominantColor", id, *color_value); 167} 168