Index: chrome/browser/favicon/select_favicon_frames.cc |
diff --git a/chrome/browser/favicon/select_favicon_frames.cc b/chrome/browser/favicon/select_favicon_frames.cc |
index f06c2c9b58a26e02f7874b2d38f0492de66e8b91..30390c9c24e6ca7563c2146502aad246df1328ac 100644 |
--- a/chrome/browser/favicon/select_favicon_frames.cc |
+++ b/chrome/browser/favicon/select_favicon_frames.cc |
@@ -4,6 +4,9 @@ |
#include "chrome/browser/favicon/select_favicon_frames.h" |
+#include <algorithm> |
+ |
+#include "base/logging.h" |
#include "skia/ext/image_operations.h" |
#include "ui/gfx/image/image.h" |
#include "ui/gfx/image/image_skia.h" |
@@ -11,11 +14,28 @@ |
namespace { |
-size_t BiggestCandidate(const std::vector<SkBitmap>& bitmaps) { |
+void SizesFromBitmaps(const std::vector<SkBitmap>& bitmaps, |
+ std::vector<gfx::Size>* sizes) { |
+ DCHECK(sizes); |
+ sizes->clear(); |
+ for (size_t i = 0; i < bitmaps.size(); ++i) |
+ sizes->push_back(gfx::Size(bitmaps[i].width(), bitmaps[i].height())); |
+} |
+ |
+void SizesFromFaviconBitmapIDSizeListing( |
+ const std::vector<history::FaviconBitmapIDSize> favicon_id_size_listing, |
+ std::vector<gfx::Size>* sizes) { |
+ DCHECK(sizes); |
+ sizes->clear(); |
+ for (size_t i = 0; i < favicon_id_size_listing.size(); ++i) |
+ sizes->push_back(favicon_id_size_listing[i].pixel_size); |
+} |
+ |
+size_t BiggestCandidate(const std::vector<gfx::Size>& candidate_sizes) { |
size_t max_index = 0; |
- int max_area = bitmaps[0].width() * bitmaps[0].height(); |
- for (size_t i = 1; i < bitmaps.size(); ++i) { |
- int area = bitmaps[i].width() * bitmaps[i].height(); |
+ int max_area = candidate_sizes[0].GetArea(); |
+ for (size_t i = 1; i < candidate_sizes.size(); ++i) { |
+ int area = candidate_sizes[i].GetArea(); |
if (area > max_area) { |
max_area = area; |
max_index = i; |
@@ -60,19 +80,28 @@ SkBitmap SampleNearestNeighbor(const SkBitmap& contents, int desired_size) { |
return bitmap; |
} |
-SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps, |
- int desired_size, |
- ui::ScaleFactor scale_factor, |
- float* score) { |
- float scale = GetScaleFactorScale(scale_factor); |
+enum ResizeMethod { |
+NONE, |
+PAD_WITH_BORDER, |
+SAMPLE_NEAREST_NEIGHBOUR, |
+LANCZOS |
+}; |
+ |
+size_t GetCandidateIndexWithBestScore( |
+ const std::vector<gfx::Size>& candidate_sizes, |
+ int desired_size, |
+ float scale, |
+ float* score, |
+ ResizeMethod* resize_method) { |
desired_size = static_cast<int>(desired_size * scale + 0.5f); |
// Try to find an exact match. |
- for (size_t i = 0; i < bitmaps.size(); ++i) { |
- if (bitmaps[i].width() == desired_size && |
- bitmaps[i].height() == desired_size) { |
+ for (size_t i = 0; i < candidate_sizes.size(); ++i) { |
+ if (candidate_sizes[i].width() == desired_size && |
+ candidate_sizes[i].height() == desired_size) { |
*score = 1; |
- return bitmaps[i]; |
+ *resize_method = NONE; |
+ return i; |
} |
} |
@@ -81,19 +110,21 @@ SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps, |
// a transparent border. |
if (desired_size > 16 * scale && desired_size <= 24 * scale) { |
int source_size = static_cast<int>(16 * scale + 0.5f); |
- for (size_t i = 0; i < bitmaps.size(); ++i) { |
- if (bitmaps[i].width() == source_size && |
- bitmaps[i].height() == source_size) { |
+ for (size_t i = 0; i < candidate_sizes.size(); ++i) { |
+ if (candidate_sizes[i].width() == source_size && |
+ candidate_sizes[i].height() == source_size) { |
*score = 0.2f; |
- return PadWithBorder(bitmaps[i], desired_size, source_size); |
+ *resize_method = PAD_WITH_BORDER; |
+ return i; |
} |
} |
// Try again, with upsizing the base variant. |
- for (size_t i = 0; i < bitmaps.size(); ++i) { |
- if (bitmaps[i].width() * scale == source_size && |
- bitmaps[i].height() * scale == source_size) { |
+ for (size_t i = 0; i < candidate_sizes.size(); ++i) { |
+ if (candidate_sizes[i].width() * scale == source_size && |
+ candidate_sizes[i].height() * scale == source_size) { |
*score = 0.15f; |
- return PadWithBorder(bitmaps[i], desired_size, source_size); |
+ *resize_method = PAD_WITH_BORDER; |
+ return i; |
} |
} |
} |
@@ -101,32 +132,65 @@ SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps, |
// 2. Integer multiples are built using nearest neighbor sampling. |
// 3. Else, use Lancosz scaling: |
// b) If available, from the next bigger variant. |
- int candidate = -1; |
+ int candidate_index = -1; |
int min_area = INT_MAX; |
- for (size_t i = 0; i < bitmaps.size(); ++i) { |
- int area = bitmaps[i].width() * bitmaps[i].height(); |
- if (bitmaps[i].width() > desired_size && |
- bitmaps[i].height() > desired_size && |
- (candidate == -1 || area < min_area)) { |
- candidate = i; |
+ for (size_t i = 0; i < candidate_sizes.size(); ++i) { |
+ int area = candidate_sizes[i].GetArea(); |
+ if (candidate_sizes[i].width() > desired_size && |
+ candidate_sizes[i].height() > desired_size && |
+ (candidate_index == -1 || area < min_area)) { |
+ candidate_index = i; |
min_area = area; |
} |
} |
*score = 0.1f; |
// c) Else, from the biggest smaller variant. |
- if (candidate == -1) { |
+ if (candidate_index == -1) { |
*score = 0; |
- candidate = BiggestCandidate(bitmaps); |
+ candidate_index = BiggestCandidate(candidate_sizes); |
} |
- const SkBitmap& bitmap = bitmaps[candidate]; |
- bool is_integer_multiple = desired_size % bitmap.width() == 0 && |
- desired_size % bitmap.height() == 0; |
- if (is_integer_multiple) |
- return SampleNearestNeighbor(bitmap, desired_size); |
- return skia::ImageOperations::Resize( |
- bitmap, skia::ImageOperations::RESIZE_LANCZOS3, |
- desired_size, desired_size); |
+ const gfx::Size& candidate_size = candidate_sizes[candidate_index]; |
+ bool is_integer_multiple = desired_size % candidate_size.width() == 0 && |
+ desired_size % candidate_size.height() == 0; |
+ *resize_method = is_integer_multiple ? SAMPLE_NEAREST_NEIGHBOUR : LANCZOS; |
+ return candidate_index; |
+} |
+ |
+SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps, |
+ int desired_size, |
+ ui::ScaleFactor scale_factor, |
+ float* score) { |
+ std::vector<gfx::Size> candidate_sizes; |
+ SizesFromBitmaps(bitmaps, &candidate_sizes); |
+ |
+ ResizeMethod resize_method = NONE; |
+ float scale = ui::GetScaleFactorScale(scale_factor); |
+ size_t best_candidate = GetCandidateIndexWithBestScore(candidate_sizes, |
+ desired_size, |
+ scale, |
+ score, |
+ &resize_method); |
+ |
+ int scaled_desired_size = static_cast<int>(desired_size * scale + 0.5f); |
+ SkBitmap best_bitmap = bitmaps[best_candidate]; |
+ switch(resize_method) { |
+ case NONE: |
+ return best_bitmap; |
+ case PAD_WITH_BORDER: { |
+ int scaled_16 = static_cast<int>(16 * scale + 0.5f); |
+ return PadWithBorder(best_bitmap, scaled_desired_size, scaled_16); |
+ } |
+ case SAMPLE_NEAREST_NEIGHBOUR: |
+ return SampleNearestNeighbor(best_bitmap, scaled_desired_size); |
+ case LANCZOS: |
+ return skia::ImageOperations::Resize( |
+ best_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, |
+ scaled_desired_size, scaled_desired_size); |
+ default: |
+ NOTREACHED(); |
+ return best_bitmap; |
+ } |
} |
} // namespace |
@@ -142,7 +206,9 @@ gfx::ImageSkia SelectFaviconFrames( |
if (desired_size == 0) { |
// Just return the biggest image available. |
- size_t max_index = BiggestCandidate(bitmaps); |
+ std::vector<gfx::Size> candidate_sizes; |
+ SizesFromBitmaps(bitmaps, &candidate_sizes); |
+ size_t max_index = BiggestCandidate(candidate_sizes); |
multi_image.AddRepresentation( |
gfx::ImageSkiaRep(bitmaps[max_index], ui::SCALE_FACTOR_100P)); |
if (match_score) |
@@ -163,3 +229,52 @@ gfx::ImageSkia SelectFaviconFrames( |
*match_score = total_score / scale_factors.size(); |
return multi_image; |
} |
+ |
+void SelectFaviconBitmapIDs( |
+ const std::vector<history::FaviconBitmapIDSize>& bitmap_id_size_list, |
+ const std::vector<ui::ScaleFactor>& scale_factors, |
+ int desired_size, |
+ std::vector<history::FaviconBitmapID>* filtered_favicon_bitmap_ids, |
+ float* match_score) { |
+ DCHECK(filtered_favicon_bitmap_ids); |
+ filtered_favicon_bitmap_ids->clear(); |
+ |
+ if (bitmap_id_size_list.empty()) |
+ return; |
+ |
+ std::vector<gfx::Size> candidate_sizes; |
+ SizesFromFaviconBitmapIDSizeListing(bitmap_id_size_list, |
+ &candidate_sizes); |
+ |
+ if (desired_size == 0) { |
+ // Just return the FaviconID with the biggest size available. |
+ size_t max_index = BiggestCandidate(candidate_sizes); |
+ filtered_favicon_bitmap_ids->push_back( |
+ bitmap_id_size_list[max_index].bitmap_id); |
+ *match_score = 0.8f; |
+ return; |
+ } |
+ |
+ float total_score = 0; |
+ for (size_t i = 0; i < scale_factors.size(); ++i) { |
+ float score; |
+ ResizeMethod resize_method = NONE; |
+ float scale = ui::GetScaleFactorScale(scale_factors[i]); |
+ size_t best_candidate_index = GetCandidateIndexWithBestScore( |
+ candidate_sizes, desired_size, scale, &score, &resize_method); |
+ filtered_favicon_bitmap_ids->push_back( |
+ bitmap_id_size_list[best_candidate_index].bitmap_id); |
+ total_score += score; |
+ } |
+ |
+ // Remove duplicates. |
+ std::sort(filtered_favicon_bitmap_ids->begin(), |
+ filtered_favicon_bitmap_ids->end()); |
+ filtered_favicon_bitmap_ids->erase(std::unique( |
+ filtered_favicon_bitmap_ids->begin(), |
+ filtered_favicon_bitmap_ids->end()), |
+ filtered_favicon_bitmap_ids->end()); |
+ |
+ if (match_score) |
+ *match_score = total_score / scale_factors.size(); |
+} |