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 Profile::FromWebUI(web_ui()), 116 url, 117 chrome::FAVICON, 118 gfx::kFaviconSize), 119 ui::SCALE_FACTOR_100P, 120 base::Bind(&FaviconWebUIHandler::OnFaviconDataAvailable, 121 base::Unretained(this), 122 id_++), 123 &cancelable_task_tracker_); 124} 125 126void FaviconWebUIHandler::OnFaviconDataAvailable( 127 int id, 128 const chrome::FaviconBitmapResult& bitmap_result) { 129 scoped_ptr<StringValue> color_value; 130 131 if (bitmap_result.is_valid()) 132 color_value.reset(GetDominantColorCssString(bitmap_result.bitmap_data)); 133 else 134 color_value.reset(new StringValue("#919191")); 135 136 StringValue dom_id(dom_id_map_[id]); 137 web_ui()->CallJavascriptFunction("ntp.setFaviconDominantColor", 138 dom_id, *color_value); 139 dom_id_map_.erase(id); 140} 141 142void FaviconWebUIHandler::HandleGetAppIconDominantColor( 143 const ListValue* args) { 144 std::string extension_id; 145 CHECK(args->GetString(0, &extension_id)); 146 147 ExtensionService* extension_service = 148 Profile::FromWebUI(web_ui())->GetExtensionService(); 149 const extensions::Extension* extension = extension_service->GetExtensionById( 150 extension_id, false); 151 if (!extension) 152 return; 153 app_icon_color_manager_->LoadIcon(extension_service->profile(), extension); 154} 155 156void FaviconWebUIHandler::NotifyAppIconReady(const std::string& extension_id) { 157 const SkBitmap& bitmap = app_icon_color_manager_->GetIcon(extension_id); 158 // TODO(estade): would be nice to avoid a round trip through png encoding. 159 std::vector<unsigned char> bits; 160 if (!gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &bits)) 161 return; 162 scoped_refptr<base::RefCountedStaticMemory> bits_mem( 163 new base::RefCountedStaticMemory(&bits.front(), bits.size())); 164 scoped_ptr<StringValue> color_value(GetDominantColorCssString(bits_mem)); 165 StringValue id(extension_id); 166 web_ui()->CallJavascriptFunction( 167 "ntp.setFaviconDominantColor", id, *color_value); 168} 169