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/favicon/favicon_util.h" 6 7#include "chrome/browser/history/select_favicon_frames.h" 8#include "chrome/common/favicon/favicon_types.h" 9#include "skia/ext/image_operations.h" 10#include "third_party/skia/include/core/SkBitmap.h" 11#include "ui/gfx/codec/png_codec.h" 12#include "ui/gfx/favicon_size.h" 13#include "ui/gfx/image/image_png_rep.h" 14#include "ui/gfx/image/image_skia.h" 15#include "ui/gfx/size.h" 16 17#if defined(OS_MACOSX) && !defined(OS_IOS) 18#include "base/mac/mac_util.h" 19#endif // defined(OS_MACOSX) && !defined(OS_IOS) 20 21namespace { 22 23// Creates image reps of DIP size |favicon_size| for the subset of 24// |scale_factors| for which the image reps can be created without resizing 25// or decoding the bitmap data. 26std::vector<gfx::ImagePNGRep> SelectFaviconFramesFromPNGsWithoutResizing( 27 const std::vector<chrome::FaviconBitmapResult>& png_data, 28 const std::vector<ui::ScaleFactor>& scale_factors, 29 int favicon_size) { 30 std::vector<gfx::ImagePNGRep> png_reps; 31 if (png_data.empty()) 32 return png_reps; 33 34 // A |favicon_size| of 0 indicates that the largest frame is desired. 35 if (favicon_size == 0 && scale_factors.size() == 1) { 36 int maximum_area = 0; 37 scoped_refptr<base::RefCountedMemory> best_candidate; 38 for (size_t i = 0; i < png_data.size(); ++i) { 39 int area = png_data[i].pixel_size.GetArea(); 40 if (area > maximum_area) { 41 maximum_area = area; 42 best_candidate = png_data[i].bitmap_data; 43 } 44 } 45 png_reps.push_back(gfx::ImagePNGRep(best_candidate, 46 scale_factors[0])); 47 return png_reps; 48 } 49 50 // Cache the scale factor for each pixel size as |scale_factors| may contain 51 // any of GetFaviconScaleFactors() which may include scale factors not 52 // supported by the platform. (ui::GetScaleFactorFromScale() cannot be used.) 53 std::map<int, ui::ScaleFactor> desired_pixel_sizes; 54 for (size_t i = 0; i < scale_factors.size(); ++i) { 55 int pixel_size = floor(favicon_size * 56 ui::GetScaleFactorScale(scale_factors[i])); 57 desired_pixel_sizes[pixel_size] = scale_factors[i]; 58 } 59 60 for (size_t i = 0; i < png_data.size(); ++i) { 61 if (!png_data[i].is_valid()) 62 continue; 63 64 const gfx::Size& pixel_size = png_data[i].pixel_size; 65 if (pixel_size.width() != pixel_size.height()) 66 continue; 67 68 std::map<int, ui::ScaleFactor>::iterator it = desired_pixel_sizes.find( 69 pixel_size.width()); 70 if (it == desired_pixel_sizes.end()) 71 continue; 72 73 png_reps.push_back(gfx::ImagePNGRep(png_data[i].bitmap_data, it->second)); 74 } 75 76 return png_reps; 77} 78 79} // namespace 80 81// static 82std::vector<ui::ScaleFactor> FaviconUtil::GetFaviconScaleFactors() { 83 const float kScale1x = ui::GetScaleFactorScale(ui::SCALE_FACTOR_100P); 84 std::vector<ui::ScaleFactor> favicon_scale_factors = 85 ui::GetSupportedScaleFactors(); 86 87 // The scale factors returned from ui::GetSupportedScaleFactors() are sorted. 88 // Insert the 1x scale factor such that GetFaviconScaleFactors() is sorted as 89 // well. 90 size_t insert_index = favicon_scale_factors.size(); 91 for (size_t i = 0; i < favicon_scale_factors.size(); ++i) { 92 float scale = ui::GetScaleFactorScale(favicon_scale_factors[i]); 93 if (scale == kScale1x) { 94 return favicon_scale_factors; 95 } else if (scale > kScale1x) { 96 insert_index = i; 97 break; 98 } 99 } 100 // TODO(ios): 100p should not be necessary on iOS retina devices. However 101 // the sync service only supports syncing 100p favicons. Until sync supports 102 // other scales 100p is needed in the list of scale factors to retrieve and 103 // store the favicons in both 100p for sync and 200p for display. cr/160503. 104 favicon_scale_factors.insert(favicon_scale_factors.begin() + insert_index, 105 ui::SCALE_FACTOR_100P); 106 return favicon_scale_factors; 107} 108 109// static 110void FaviconUtil::SetFaviconColorSpace(gfx::Image* image) { 111#if defined(OS_MACOSX) && !defined(OS_IOS) 112 image->SetSourceColorSpace(base::mac::GetSystemColorSpace()); 113#endif // defined(OS_MACOSX) && !defined(OS_IOS) 114} 115 116// static 117gfx::Image FaviconUtil::SelectFaviconFramesFromPNGs( 118 const std::vector<chrome::FaviconBitmapResult>& png_data, 119 const std::vector<ui::ScaleFactor>& scale_factors, 120 int favicon_size) { 121 // Create image reps for as many scale factors as possible without resizing 122 // the bitmap data or decoding it. FaviconHandler stores already resized 123 // favicons into history so no additional resizing should be needed in the 124 // common case. 125 // Creating the gfx::Image from |png_data| without resizing or decoding if 126 // possible is important because: 127 // - Sync does a byte-to-byte comparison of gfx::Image::As1xPNGBytes() to 128 // the data it put into the database in order to determine whether any 129 // updates should be pushed to sync. 130 // - The decoding occurs on the UI thread and the decoding can be a 131 // significant performance hit if a user has many bookmarks. 132 // TODO(pkotwicz): Move the decoding off the UI thread. 133 std::vector<gfx::ImagePNGRep> png_reps = 134 SelectFaviconFramesFromPNGsWithoutResizing(png_data, scale_factors, 135 favicon_size); 136 137 std::vector<ui::ScaleFactor> scale_factors_to_generate = scale_factors; 138 for (size_t i = 0; i < png_reps.size(); ++i) { 139 std::vector<ui::ScaleFactor>::iterator it = std::find( 140 scale_factors_to_generate.begin(), 141 scale_factors_to_generate.end(), 142 png_reps[i].scale_factor); 143 CHECK(it != scale_factors_to_generate.end()); 144 scale_factors_to_generate.erase(it); 145 } 146 147 if (scale_factors_to_generate.empty()) 148 return gfx::Image(png_reps); 149 150 std::vector<SkBitmap> bitmaps; 151 for (size_t i = 0; i < png_data.size(); ++i) { 152 if (!png_data[i].is_valid()) 153 continue; 154 155 SkBitmap bitmap; 156 if (gfx::PNGCodec::Decode(png_data[i].bitmap_data->front(), 157 png_data[i].bitmap_data->size(), 158 &bitmap)) { 159 bitmaps.push_back(bitmap); 160 } 161 } 162 163 if (bitmaps.empty()) 164 return gfx::Image(); 165 166 gfx::ImageSkia resized_image_skia = SelectFaviconFrames(bitmaps, 167 scale_factors_to_generate, favicon_size, NULL); 168 169 if (png_reps.empty()) 170 return gfx::Image(resized_image_skia); 171 172 std::vector<gfx::ImageSkiaRep> resized_image_skia_reps = 173 resized_image_skia.image_reps(); 174 for (size_t i = 0; i < resized_image_skia_reps.size(); ++i) { 175 scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes()); 176 if (gfx::PNGCodec::EncodeBGRASkBitmap( 177 resized_image_skia_reps[i].sk_bitmap(), false, &png_bytes->data())) { 178 png_reps.push_back(gfx::ImagePNGRep(png_bytes, 179 resized_image_skia_reps[i].scale_factor())); 180 } 181 } 182 183 return gfx::Image(png_reps); 184} 185 186// static 187size_t FaviconUtil::SelectBestFaviconFromBitmaps( 188 const std::vector<SkBitmap>& bitmaps, 189 const std::vector<ui::ScaleFactor>& scale_factors, 190 int desired_size) { 191 std::vector<gfx::Size> sizes; 192 for (size_t i = 0; i < bitmaps.size(); ++i) 193 sizes.push_back(gfx::Size(bitmaps[i].width(), bitmaps[i].height())); 194 std::vector<size_t> selected_bitmap_indices; 195 SelectFaviconFrameIndices(sizes, scale_factors, desired_size, 196 &selected_bitmap_indices, NULL); 197 DCHECK_EQ(1u, selected_bitmap_indices.size()); 198 return selected_bitmap_indices[0]; 199} 200