Commit c3cae2ed authored by pkotwicz@chromium.org's avatar pkotwicz@chromium.org

Refactor SelectFaviconFrames to make it easy to use SelectFaviconFrames on...

Refactor SelectFaviconFrames to make it easy to use SelectFaviconFrames on objects other than SkBitmaps.
Changed the selection and score calculation code to operate on std::vector<gfx::Size> instead of an std::vector<SkBitmap>.

Bug=10802066
Test=SelectFaviconFramesTest.* pass
TBR=thakis

Review URL: https://chromiumcodereview.appspot.com/10872093

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@153590 0039d316-1c4b-4281-b951-d872f2087c98
parent 904f6b29
...@@ -5,17 +5,24 @@ ...@@ -5,17 +5,24 @@
#include "chrome/browser/favicon/select_favicon_frames.h" #include "chrome/browser/favicon/select_favicon_frames.h"
#include "skia/ext/image_operations.h" #include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/size.h"
namespace { namespace {
size_t BiggestCandidate(const std::vector<SkBitmap>& bitmaps) { void SizesFromBitmaps(const std::vector<SkBitmap>& bitmaps,
std::vector<gfx::Size>* sizes) {
for (size_t i = 0; i < bitmaps.size(); ++i)
sizes->push_back(gfx::Size(bitmaps[i].width(), bitmaps[i].height()));
}
size_t BiggestCandidate(const std::vector<gfx::Size>& candidate_sizes) {
size_t max_index = 0; size_t max_index = 0;
int max_area = bitmaps[0].width() * bitmaps[0].height(); int max_area = candidate_sizes[0].GetArea();
for (size_t i = 1; i < bitmaps.size(); ++i) { for (size_t i = 1; i < candidate_sizes.size(); ++i) {
int area = bitmaps[i].width() * bitmaps[i].height(); int area = candidate_sizes[i].GetArea();
if (area > max_area) { if (area > max_area) {
max_area = area; max_area = area;
max_index = i; max_index = i;
...@@ -60,19 +67,29 @@ SkBitmap SampleNearestNeighbor(const SkBitmap& contents, int desired_size) { ...@@ -60,19 +67,29 @@ SkBitmap SampleNearestNeighbor(const SkBitmap& contents, int desired_size) {
return bitmap; return bitmap;
} }
SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps, enum ResizeMethod {
int desired_size, NONE,
ui::ScaleFactor scale_factor, PAD_WITH_BORDER,
float* score) { SAMPLE_NEAREST_NEIGHBOUR,
float scale = GetScaleFactorScale(scale_factor); LANCZOS
};
size_t GetCandidateIndexWithBestScore(
const std::vector<gfx::Size>& candidate_sizes,
ui::ScaleFactor scale_factor,
int desired_size,
float* score,
ResizeMethod* resize_method) {
float scale = ui::GetScaleFactorScale(scale_factor);
desired_size = static_cast<int>(desired_size * scale + 0.5f); desired_size = static_cast<int>(desired_size * scale + 0.5f);
// Try to find an exact match. // Try to find an exact match.
for (size_t i = 0; i < bitmaps.size(); ++i) { for (size_t i = 0; i < candidate_sizes.size(); ++i) {
if (bitmaps[i].width() == desired_size && if (candidate_sizes[i].width() == desired_size &&
bitmaps[i].height() == desired_size) { candidate_sizes[i].height() == desired_size) {
*score = 1; *score = 1;
return bitmaps[i]; *resize_method = NONE;
return i;
} }
} }
...@@ -81,19 +98,21 @@ SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps, ...@@ -81,19 +98,21 @@ SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps,
// a transparent border. // a transparent border.
if (desired_size > 16 * scale && desired_size <= 24 * scale) { if (desired_size > 16 * scale && desired_size <= 24 * scale) {
int source_size = static_cast<int>(16 * scale + 0.5f); int source_size = static_cast<int>(16 * scale + 0.5f);
for (size_t i = 0; i < bitmaps.size(); ++i) { for (size_t i = 0; i < candidate_sizes.size(); ++i) {
if (bitmaps[i].width() == source_size && if (candidate_sizes[i].width() == source_size &&
bitmaps[i].height() == source_size) { candidate_sizes[i].height() == source_size) {
*score = 0.2f; *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. // Try again, with upsizing the base variant.
for (size_t i = 0; i < bitmaps.size(); ++i) { for (size_t i = 0; i < candidate_sizes.size(); ++i) {
if (bitmaps[i].width() * scale == source_size && if (candidate_sizes[i].width() * scale == source_size &&
bitmaps[i].height() * scale == source_size) { candidate_sizes[i].height() * scale == source_size) {
*score = 0.15f; *score = 0.15f;
return PadWithBorder(bitmaps[i], desired_size, source_size); *resize_method = PAD_WITH_BORDER;
return i;
} }
} }
} }
...@@ -101,65 +120,129 @@ SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps, ...@@ -101,65 +120,129 @@ SkBitmap SelectCandidate(const std::vector<SkBitmap>& bitmaps,
// 2. Integer multiples are built using nearest neighbor sampling. // 2. Integer multiples are built using nearest neighbor sampling.
// 3. Else, use Lancosz scaling: // 3. Else, use Lancosz scaling:
// b) If available, from the next bigger variant. // b) If available, from the next bigger variant.
int candidate = -1; int candidate_index = -1;
int min_area = INT_MAX; int min_area = INT_MAX;
for (size_t i = 0; i < bitmaps.size(); ++i) { for (size_t i = 0; i < candidate_sizes.size(); ++i) {
int area = bitmaps[i].width() * bitmaps[i].height(); int area = candidate_sizes[i].GetArea();
if (bitmaps[i].width() > desired_size && if (candidate_sizes[i].width() > desired_size &&
bitmaps[i].height() > desired_size && candidate_sizes[i].height() > desired_size &&
(candidate == -1 || area < min_area)) { (candidate_index == -1 || area < min_area)) {
candidate = i; candidate_index = i;
min_area = area; min_area = area;
} }
} }
*score = 0.1f; *score = 0.1f;
// c) Else, from the biggest smaller variant. // c) Else, from the biggest smaller variant.
if (candidate == -1) { if (candidate_index == -1) {
*score = 0; *score = 0;
candidate = BiggestCandidate(bitmaps); candidate_index = BiggestCandidate(candidate_sizes);
} }
const SkBitmap& bitmap = bitmaps[candidate]; const gfx::Size& candidate_size = candidate_sizes[candidate_index];
bool is_integer_multiple = desired_size % bitmap.width() == 0 && bool is_integer_multiple = desired_size % candidate_size.width() == 0 &&
desired_size % bitmap.height() == 0; desired_size % candidate_size.height() == 0;
if (is_integer_multiple) *resize_method = is_integer_multiple ? SAMPLE_NEAREST_NEIGHBOUR : LANCZOS;
return SampleNearestNeighbor(bitmap, desired_size); return candidate_index;
return skia::ImageOperations::Resize(
bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
desired_size, desired_size);
} }
} // namespace // Represents the index of the best candidate for a |scale_factor| from the
// |candidate_sizes| passed into GetCandidateIndicesWithBestScores().
struct SelectionResult {
// index in |candidate_sizes| of the best candidate.
size_t index;
gfx::ImageSkia SelectFaviconFrames( // The ScaleFactor for which |index| is the best candidate.
const std::vector<SkBitmap>& bitmaps, ui::ScaleFactor scale_factor;
// How the bitmap data that the bitmap with |candidate_sizes[index]| should
// be resized for displaying in the UI.
ResizeMethod resize_method;
};
void GetCandidateIndicesWithBestScores(
const std::vector<gfx::Size>& candidate_sizes,
const std::vector<ui::ScaleFactor>& scale_factors, const std::vector<ui::ScaleFactor>& scale_factors,
int desired_size, int desired_size,
float* match_score) { float* match_score,
gfx::ImageSkia multi_image; std::vector<SelectionResult>* results) {
if (bitmaps.empty()) if (candidate_sizes.empty())
return multi_image; return;
if (desired_size == 0) { if (desired_size == 0) {
// Just return the biggest image available. // Just return the biggest image available.
size_t max_index = BiggestCandidate(bitmaps); SelectionResult result;
multi_image.AddRepresentation( result.index = BiggestCandidate(candidate_sizes);
gfx::ImageSkiaRep(bitmaps[max_index], ui::SCALE_FACTOR_100P)); result.scale_factor = ui::SCALE_FACTOR_100P;
result.resize_method = NONE;
results->push_back(result);
if (match_score) if (match_score)
*match_score = 0.8f; *match_score = 0.8f;
return multi_image; return;
} }
float total_score = 0; float total_score = 0;
for (size_t i = 0; i < scale_factors.size(); ++i) { for (size_t i = 0; i < scale_factors.size(); ++i) {
float score; float score;
multi_image.AddRepresentation(gfx::ImageSkiaRep( SelectionResult result;
SelectCandidate(bitmaps, desired_size, scale_factors[i], &score), result.scale_factor = scale_factors[i];
scale_factors[i])); result.index = GetCandidateIndexWithBestScore(candidate_sizes,
result.scale_factor, desired_size, &score, &result.resize_method);
results->push_back(result);
total_score += score; total_score += score;
} }
if (match_score) if (match_score)
*match_score = total_score / scale_factors.size(); *match_score = total_score / scale_factors.size();
}
// Resize |source_bitmap| using |resize_method|.
SkBitmap GetResizedBitmap(const SkBitmap& source_bitmap,
int desired_size_in_dip,
ui::ScaleFactor scale_factor,
ResizeMethod resize_method) {
float scale = ui::GetScaleFactorScale(scale_factor);
int desired_size_in_pixel = static_cast<int>(
desired_size_in_dip * scale + 0.5f);
switch(resize_method) {
case NONE:
return source_bitmap;
case PAD_WITH_BORDER: {
int inner_border_in_pixel = static_cast<int>(16 * scale + 0.5f);
return PadWithBorder(source_bitmap, desired_size_in_pixel,
inner_border_in_pixel);
}
case SAMPLE_NEAREST_NEIGHBOUR:
return SampleNearestNeighbor(source_bitmap, desired_size_in_pixel);
case LANCZOS:
return skia::ImageOperations::Resize(
source_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
desired_size_in_pixel, desired_size_in_pixel);
}
return source_bitmap;
}
} // namespace
gfx::ImageSkia SelectFaviconFrames(
const std::vector<SkBitmap>& bitmaps,
const std::vector<ui::ScaleFactor>& scale_factors,
int desired_size,
float* match_score) {
std::vector<gfx::Size> candidate_sizes;
SizesFromBitmaps(bitmaps, &candidate_sizes);
std::vector<SelectionResult> results;
GetCandidateIndicesWithBestScores(candidate_sizes, scale_factors,
desired_size, match_score, &results);
gfx::ImageSkia multi_image;
for (size_t i = 0; i < results.size(); ++i) {
const SelectionResult& result = results[i];
SkBitmap resized_bitmap = GetResizedBitmap(bitmaps[result.index],
desired_size, result.scale_factor, result.resize_method);
multi_image.AddRepresentation(
gfx::ImageSkiaRep(resized_bitmap, result.scale_factor));
}
return multi_image; return multi_image;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment