summaryrefslogtreecommitdiffstats
path: root/components/favicon_base
diff options
context:
space:
mode:
Diffstat (limited to 'components/favicon_base')
-rw-r--r--components/favicon_base/BUILD.gn2
-rw-r--r--components/favicon_base/favicon_util.cc255
-rw-r--r--components/favicon_base/favicon_util.h41
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_