diff options
Diffstat (limited to 'components/favicon_base')
-rw-r--r-- | components/favicon_base/BUILD.gn | 2 | ||||
-rw-r--r-- | components/favicon_base/favicon_util.cc | 255 | ||||
-rw-r--r-- | components/favicon_base/favicon_util.h | 41 |
3 files changed, 298 insertions, 0 deletions
diff --git a/components/favicon_base/BUILD.gn b/components/favicon_base/BUILD.gn index 3d4f638..6e40b06 100644 --- a/components/favicon_base/BUILD.gn +++ b/components/favicon_base/BUILD.gn @@ -7,6 +7,8 @@ source_set("favicon_base") { "favicon_callback.h", "favicon_types.cc", "favicon_types.h", + "favicon_util.cc", + "favicon_util.h", "select_favicon_frames.cc", "select_favicon_frames.h", ] diff --git a/components/favicon_base/favicon_util.cc b/components/favicon_base/favicon_util.cc new file mode 100644 index 0000000..0a3f0a2 --- /dev/null +++ b/components/favicon_base/favicon_util.cc @@ -0,0 +1,255 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/favicon_base/favicon_util.h" + +#include "components/favicon_base/favicon_types.h" +#include "components/favicon_base/select_favicon_frames.h" +#include "skia/ext/image_operations.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/favicon_size.h" +#include "ui/gfx/image/image_png_rep.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/size.h" + +#if defined(OS_MACOSX) && !defined(OS_IOS) +#include "base/mac/mac_util.h" +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + +namespace favicon_base { +namespace { + +// Creates image reps of DIP size |favicon_size| for the subset of +// |scale_factors| for which the image reps can be created without resizing +// or decoding the bitmap data. +std::vector<gfx::ImagePNGRep> SelectFaviconFramesFromPNGsWithoutResizing( + const std::vector<favicon_base::FaviconRawBitmapResult>& png_data, + const std::vector<ui::ScaleFactor>& scale_factors, + int favicon_size) { + std::vector<gfx::ImagePNGRep> png_reps; + if (png_data.empty()) + return png_reps; + + // A |favicon_size| of 0 indicates that the largest frame is desired. + if (favicon_size == 0) { + int maximum_area = 0; + scoped_refptr<base::RefCountedMemory> best_candidate; + for (size_t i = 0; i < png_data.size(); ++i) { + int area = png_data[i].pixel_size.GetArea(); + if (area > maximum_area) { + maximum_area = area; + best_candidate = png_data[i].bitmap_data; + } + } + png_reps.push_back(gfx::ImagePNGRep(best_candidate, 1.0f)); + return png_reps; + } + + // Cache the scale factor for each pixel size as |scale_factors| may contain + // any of GetFaviconScaleFactors() which may include scale factors not + // supported by the platform. (ui::GetSupportedScaleFactor() cannot be used.) + std::map<int, ui::ScaleFactor> desired_pixel_sizes; + for (size_t i = 0; i < scale_factors.size(); ++i) { + int pixel_size = + floor(favicon_size * ui::GetScaleForScaleFactor(scale_factors[i])); + desired_pixel_sizes[pixel_size] = scale_factors[i]; + } + + for (size_t i = 0; i < png_data.size(); ++i) { + if (!png_data[i].is_valid()) + continue; + + const gfx::Size& pixel_size = png_data[i].pixel_size; + if (pixel_size.width() != pixel_size.height()) + continue; + + std::map<int, ui::ScaleFactor>::iterator it = + desired_pixel_sizes.find(pixel_size.width()); + if (it == desired_pixel_sizes.end()) + continue; + + png_reps.push_back(gfx::ImagePNGRep( + png_data[i].bitmap_data, ui::GetScaleForScaleFactor(it->second))); + } + + return png_reps; +} + +// Returns a resampled bitmap of +// |desired_size_in_pixel| x |desired_size_in_pixel| by resampling the best +// bitmap out of |input_bitmaps|. ResizeBitmapByDownsamplingIfPossible() is +// similar to SelectFaviconFrames() but it operates on bitmaps which have +// already been resampled via SelectFaviconFrames(). +SkBitmap ResizeBitmapByDownsamplingIfPossible( + const std::vector<SkBitmap>& input_bitmaps, + int desired_size_in_pixel) { + DCHECK(!input_bitmaps.empty()); + DCHECK_NE(desired_size_in_pixel, 0); + + SkBitmap best_bitmap; + for (size_t i = 0; i < input_bitmaps.size(); ++i) { + const SkBitmap& input_bitmap = input_bitmaps[i]; + if (input_bitmap.width() == desired_size_in_pixel && + input_bitmap.height() == desired_size_in_pixel) { + return input_bitmap; + } else if (best_bitmap.isNull()) { + best_bitmap = input_bitmap; + } else if (input_bitmap.width() >= best_bitmap.width() && + input_bitmap.height() >= best_bitmap.height()) { + if (best_bitmap.width() < desired_size_in_pixel || + best_bitmap.height() < desired_size_in_pixel) { + best_bitmap = input_bitmap; + } + } else { + if (input_bitmap.width() >= desired_size_in_pixel && + input_bitmap.height() >= desired_size_in_pixel) { + best_bitmap = input_bitmap; + } + } + } + + if (desired_size_in_pixel % best_bitmap.width() == 0 && + desired_size_in_pixel % best_bitmap.height() == 0) { + // Use nearest neighbour resampling if upsampling by an integer. This + // makes the result look similar to the result of SelectFaviconFrames(). + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, + desired_size_in_pixel, + desired_size_in_pixel); + bitmap.allocPixels(); + if (!best_bitmap.isOpaque()) + bitmap.eraseARGB(0, 0, 0, 0); + + SkCanvas canvas(bitmap); + SkRect dest(SkRect::MakeWH(desired_size_in_pixel, desired_size_in_pixel)); + canvas.drawBitmapRect(best_bitmap, NULL, dest); + return bitmap; + } + return skia::ImageOperations::Resize(best_bitmap, + skia::ImageOperations::RESIZE_LANCZOS3, + desired_size_in_pixel, + desired_size_in_pixel); +} + +} // namespace + +std::vector<ui::ScaleFactor> GetFaviconScaleFactors() { + const float kScale1x = 1.0f; + std::vector<ui::ScaleFactor> favicon_scale_factors = + ui::GetSupportedScaleFactors(); + + // The scale factors returned from ui::GetSupportedScaleFactors() are sorted. + // Insert the 1x scale factor such that GetFaviconScaleFactors() is sorted as + // well. + size_t insert_index = favicon_scale_factors.size(); + for (size_t i = 0; i < favicon_scale_factors.size(); ++i) { + float scale = ui::GetScaleForScaleFactor(favicon_scale_factors[i]); + if (scale == kScale1x) { + return favicon_scale_factors; + } else if (scale > kScale1x) { + insert_index = i; + break; + } + } + // TODO(ios): 100p should not be necessary on iOS retina devices. However + // the sync service only supports syncing 100p favicons. Until sync supports + // other scales 100p is needed in the list of scale factors to retrieve and + // store the favicons in both 100p for sync and 200p for display. cr/160503. + favicon_scale_factors.insert(favicon_scale_factors.begin() + insert_index, + ui::SCALE_FACTOR_100P); + return favicon_scale_factors; +} + +void SetFaviconColorSpace(gfx::Image* image) { +#if defined(OS_MACOSX) && !defined(OS_IOS) + image->SetSourceColorSpace(base::mac::GetSystemColorSpace()); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) +} + +gfx::Image SelectFaviconFramesFromPNGs( + const std::vector<favicon_base::FaviconRawBitmapResult>& png_data, + const std::vector<ui::ScaleFactor>& scale_factors, + int favicon_size) { + // Create image reps for as many scale factors as possible without resizing + // the bitmap data or decoding it. FaviconHandler stores already resized + // favicons into history so no additional resizing should be needed in the + // common case. + // Creating the gfx::Image from |png_data| without resizing or decoding if + // possible is important because: + // - Sync does a byte-to-byte comparison of gfx::Image::As1xPNGBytes() to + // the data it put into the database in order to determine whether any + // updates should be pushed to sync. + // - The decoding occurs on the UI thread and the decoding can be a + // significant performance hit if a user has many bookmarks. + // TODO(pkotwicz): Move the decoding off the UI thread. + std::vector<gfx::ImagePNGRep> png_reps = + SelectFaviconFramesFromPNGsWithoutResizing( + png_data, scale_factors, favicon_size); + + // SelectFaviconFramesFromPNGsWithoutResizing() should have selected the + // largest favicon if |favicon_size| == 0. + if (favicon_size == 0) + return gfx::Image(png_reps); + + std::vector<ui::ScaleFactor> scale_factors_to_generate = scale_factors; + for (size_t i = 0; i < png_reps.size(); ++i) { + for (int j = static_cast<int>(scale_factors_to_generate.size()) - 1; j >= 0; + --j) { + if (png_reps[i].scale == + ui::GetScaleForScaleFactor(scale_factors_to_generate[j])) { + scale_factors_to_generate.erase(scale_factors_to_generate.begin() + j); + } + } + } + + if (scale_factors_to_generate.empty()) + return gfx::Image(png_reps); + + std::vector<SkBitmap> bitmaps; + for (size_t i = 0; i < png_data.size(); ++i) { + if (!png_data[i].is_valid()) + continue; + + SkBitmap bitmap; + if (gfx::PNGCodec::Decode(png_data[i].bitmap_data->front(), + png_data[i].bitmap_data->size(), + &bitmap)) { + bitmaps.push_back(bitmap); + } + } + + if (bitmaps.empty()) + return gfx::Image(); + + gfx::ImageSkia resized_image_skia; + for (size_t i = 0; i < scale_factors_to_generate.size(); ++i) { + float scale = ui::GetScaleForScaleFactor(scale_factors_to_generate[i]); + int desired_size_in_pixel = ceil(favicon_size * scale); + SkBitmap bitmap = + ResizeBitmapByDownsamplingIfPossible(bitmaps, desired_size_in_pixel); + resized_image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale)); + } + + if (png_reps.empty()) + return gfx::Image(resized_image_skia); + + std::vector<gfx::ImageSkiaRep> resized_image_skia_reps = + resized_image_skia.image_reps(); + for (size_t i = 0; i < resized_image_skia_reps.size(); ++i) { + scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes()); + if (gfx::PNGCodec::EncodeBGRASkBitmap( + resized_image_skia_reps[i].sk_bitmap(), + false, + &png_bytes->data())) { + png_reps.push_back( + gfx::ImagePNGRep(png_bytes, resized_image_skia_reps[i].scale())); + } + } + + return gfx::Image(png_reps); +} + +} // namespace favicon_base diff --git a/components/favicon_base/favicon_util.h b/components/favicon_base/favicon_util.h new file mode 100644 index 0000000..ee59428 --- /dev/null +++ b/components/favicon_base/favicon_util.h @@ -0,0 +1,41 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_FAVICON_BASE_FAVICON_UTIL_H_ +#define COMPONENTS_FAVICON_BASE_FAVICON_UTIL_H_ + +#include <vector> + +#include "components/favicon_base/favicon_types.h" +#include "ui/base/layout.h" + +namespace gfx { +class Image; +} + +namespace favicon_base { + +// Returns the scale factors at which favicons should be fetched. This is +// different from ui::GetSupportedScaleFactors() because clients which do +// not support 1x should still fetch a favicon for 1x to push to sync. This +// guarantees that the clients receiving sync updates pushed by this client +// receive a favicon (potentially of the wrong scale factor) and do not show +// the default favicon. +std::vector<ui::ScaleFactor> GetFaviconScaleFactors(); + +// Sets the color space used for converting |image| to an NSImage to the +// system colorspace. This makes the favicon look the same in the browser UI +// as it does in the renderer. +void SetFaviconColorSpace(gfx::Image* image); + +// Takes a vector of png-encoded frames, decodes them, and converts them to +// a favicon of size favicon_size (in DIPs) at the desired ui scale factors. +gfx::Image SelectFaviconFramesFromPNGs( + const std::vector<favicon_base::FaviconRawBitmapResult>& png_data, + const std::vector<ui::ScaleFactor>& scale_factors, + int favicon_size); + +} // namspace favicon_base + +#endif // COMPONENTS_FAVICON_BASE_FAVICON_UTIL_H_ |