Commit 11df03ba authored by Mei Liang's avatar Mei Liang Committed by Commit Bot

[native] Integrate the composing favicon logic

The composing favicon logic comes from the explore_sites::ImageHelper.

This CL moves the composing logic to a different class, so it can be
shared with the FaviconHelper. In addition, this CL integrate the
composing logic to FaviconHelper.

Change-Id: I267d5611979875ae28e7df09bf0ef02c2206058e
Bug: 1064153
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2123513
Commit-Queue: Mei Liang <meiliang@chromium.org>
Reviewed-by: default avatarCathy Li <chili@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#757728}
parent 20114fcf
...@@ -2381,6 +2381,8 @@ jumbo_static_library("browser") { ...@@ -2381,6 +2381,8 @@ jumbo_static_library("browser") {
"android/color_helpers.h", "android/color_helpers.h",
"android/component_updater/background_task_update_scheduler.cc", "android/component_updater/background_task_update_scheduler.cc",
"android/component_updater/background_task_update_scheduler.h", "android/component_updater/background_task_update_scheduler.h",
"android/compose_bitmaps_helper.cc",
"android/compose_bitmaps_helper.h",
"android/compositor/compositor_view.cc", "android/compositor/compositor_view.cc",
"android/compositor/compositor_view.h", "android/compositor/compositor_view.h",
"android/compositor/decoration_title.cc", "android/compositor/decoration_title.cc",
......
// Copyright 2020 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 "chrome/browser/android/compose_bitmaps_helper.h"
#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkFilterQuality.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkPixmap.h"
namespace compose_bitmaps_helper {
// Ratio of icon size to the amount of padding between the icons.
const int kIconPaddingScale = 8;
std::unique_ptr<SkBitmap> ComposeBitmaps(const std::vector<SkBitmap>& bitmaps,
int desired_size_in_pixel) {
int num_icons = bitmaps.size();
DVLOG(1) << "num icons: " << num_icons;
if (num_icons == 0) {
return nullptr;
}
DVLOG(1) << "desired_size_in_pixel: " << desired_size_in_pixel;
int icon_padding_pixel_size = desired_size_in_pixel / kIconPaddingScale;
// Offset to write icons out of frame due to padding.
int icon_write_offset = icon_padding_pixel_size / 2;
SkBitmap composite_bitmap;
SkImageInfo image_info =
bitmaps[0]
.info()
.makeWH(desired_size_in_pixel, desired_size_in_pixel)
.makeAlphaType(kPremul_SkAlphaType);
composite_bitmap.setInfo(image_info);
composite_bitmap.allocPixels();
int icon_size = desired_size_in_pixel / 2;
// draw icons in correct areas
switch (num_icons) {
case 1: {
// Centered.
SkBitmap scaledBitmap = ScaleBitmap(icon_size, bitmaps[0]);
if (scaledBitmap.empty()) {
return nullptr;
}
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset,
((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset);
break;
}
case 2: {
// Side by side.
for (int i = 0; i < 2; i++) {
SkBitmap scaledBitmap = ScaleBitmap(icon_size, bitmaps[i]);
if (scaledBitmap.empty()) {
return nullptr;
}
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
(i * (icon_size + icon_padding_pixel_size)) - icon_write_offset,
((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset);
}
break;
}
case 3: {
// Two on top, one on bottom.
for (int i = 0; i < 3; i++) {
SkBitmap scaledBitmap = ScaleBitmap(icon_size, bitmaps[i]);
if (scaledBitmap.empty()) {
return nullptr;
}
switch (i) {
case 0:
composite_bitmap.writePixels(
scaledBitmap.pixmap(), -icon_write_offset, -icon_write_offset);
break;
case 1:
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
(icon_size + icon_padding_pixel_size) - icon_write_offset,
-icon_write_offset);
break;
default:
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset,
(icon_size + icon_padding_pixel_size) - icon_write_offset);
break;
}
}
break;
}
case 4: {
// One in each corner.
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
int index = i + 2 * j;
SkBitmap scaledBitmap = ScaleBitmap(icon_size, bitmaps[index]);
if (scaledBitmap.empty()) {
return nullptr;
}
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
(j * (icon_size + icon_padding_pixel_size)) - icon_write_offset,
(i * (icon_size + icon_padding_pixel_size)) - icon_write_offset);
}
}
break;
}
default:
DLOG(ERROR) << "Invalid number of icons to combine: " << bitmaps.size();
return nullptr;
}
return std::make_unique<SkBitmap>(composite_bitmap);
}
SkBitmap ScaleBitmap(int icon_size, const SkBitmap& bitmap) {
SkBitmap temp_bitmap;
SkImageInfo scaledIconInfo = bitmap.info().makeWH(icon_size, icon_size);
temp_bitmap.setInfo(scaledIconInfo);
temp_bitmap.allocPixels();
bool did_scale =
bitmap.pixmap().scalePixels(temp_bitmap.pixmap(), kHigh_SkFilterQuality);
if (!did_scale) {
DLOG(ERROR) << "Unable to scale icon";
return SkBitmap();
}
return temp_bitmap;
}
} // namespace compose_bitmaps_helper
// Copyright 2020 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 CHROME_BROWSER_ANDROID_COMPOSE_BITMAPS_HELPER_H_
#define CHROME_BROWSER_ANDROID_COMPOSE_BITMAPS_HELPER_H_
#include <vector>
#include "third_party/skia/include/core/SkBitmap.h"
namespace compose_bitmaps_helper {
// This method composes a list of bitmaps, up to four, into one single bitmap.
std::unique_ptr<SkBitmap> ComposeBitmaps(const std::vector<SkBitmap>& bitmaps,
int desired_size_in_pixel);
SkBitmap ScaleBitmap(int icon_size, const SkBitmap& bitmap);
} // namespace compose_bitmaps_helper
#endif // CHROME_BROWSER_ANDROID_COMPOSE_BITMAPS_HELPER_H_
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/android/compose_bitmaps_helper.h"
#include "chrome/browser/android/explore_sites/explore_sites_types.h" #include "chrome/browser/android/explore_sites/explore_sites_types.h"
#include "services/data_decoder/public/cpp/decode_image.h" #include "services/data_decoder/public/cpp/decode_image.h"
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkBitmap.h"
...@@ -18,14 +19,6 @@ ...@@ -18,14 +19,6 @@
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
namespace explore_sites { namespace explore_sites {
namespace {
// Ratio of icon size to the amount of padding between the icons.
const int kIconPaddingScale = 8;
} // namespace
// Class Job is used to manage multiple calls to the ImageHelper. Each request // Class Job is used to manage multiple calls to the ImageHelper. Each request
// to the ImageHelper is handled by a single Job, which is then destroyed after // to the ImageHelper is handled by a single Job, which is then destroyed after
// it is finished. // it is finished.
...@@ -146,123 +139,8 @@ void ImageHelper::Job::OnDecodeCategoryImageDone( ...@@ -146,123 +139,8 @@ void ImageHelper::Job::OnDecodeCategoryImageDone(
} }
} }
SkBitmap ScaleBitmap(int icon_size, SkBitmap* bitmap) {
DCHECK(bitmap);
SkBitmap temp_bitmap;
SkImageInfo scaledIconInfo = bitmap->info().makeWH(icon_size, icon_size);
temp_bitmap.setInfo(scaledIconInfo);
temp_bitmap.allocPixels();
bool did_scale =
bitmap->pixmap().scalePixels(temp_bitmap.pixmap(), kHigh_SkFilterQuality);
if (!did_scale) {
DLOG(ERROR) << "Unable to scale icon for category image.";
return SkBitmap();
}
return temp_bitmap;
}
std::unique_ptr<SkBitmap> ImageHelper::Job::CombineImages() { std::unique_ptr<SkBitmap> ImageHelper::Job::CombineImages() {
DVLOG(1) << "num icons: " << num_icons_; return compose_bitmaps_helper::ComposeBitmaps(bitmaps_, pixel_size_);
if (num_icons_ == 0) {
return nullptr;
}
DVLOG(1) << "pixel_size_: " << pixel_size_;
int icon_padding_pixel_size = pixel_size_ / kIconPaddingScale;
// Offset to write icons out of frame due to padding.
int icon_write_offset = icon_padding_pixel_size / 2;
SkBitmap composite_bitmap;
SkImageInfo image_info = bitmaps_[0]
.info()
.makeWH(pixel_size_, pixel_size_)
.makeAlphaType(kPremul_SkAlphaType);
composite_bitmap.setInfo(image_info);
composite_bitmap.allocPixels();
int icon_size = pixel_size_ / 2;
// draw icons in correct areas
switch (num_icons_) {
case 1: {
// Centered.
SkBitmap scaledBitmap = ScaleBitmap(icon_size, &bitmaps_[0]);
if (scaledBitmap.empty()) {
return nullptr;
}
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset,
((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset);
break;
}
case 2: {
// Side by side.
for (int i = 0; i < 2; i++) {
SkBitmap scaledBitmap = ScaleBitmap(icon_size, &bitmaps_[i]);
if (scaledBitmap.empty()) {
return nullptr;
}
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
(i * (icon_size + icon_padding_pixel_size)) - icon_write_offset,
((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset);
}
break;
}
case 3: {
// Two on top, one on bottom.
for (int i = 0; i < 3; i++) {
SkBitmap scaledBitmap = ScaleBitmap(icon_size, &bitmaps_[i]);
if (scaledBitmap.empty()) {
return nullptr;
}
switch (i) {
case 0:
composite_bitmap.writePixels(
scaledBitmap.pixmap(), -icon_write_offset, -icon_write_offset);
break;
case 1:
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
(icon_size + icon_padding_pixel_size) - icon_write_offset,
-icon_write_offset);
break;
default:
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset,
(icon_size + icon_padding_pixel_size) - icon_write_offset);
break;
}
}
break;
}
case 4: {
// One in each corner.
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
int index = i + 2 * j;
SkBitmap scaledBitmap = ScaleBitmap(icon_size, &bitmaps_[index]);
if (scaledBitmap.empty()) {
return nullptr;
}
composite_bitmap.writePixels(
scaledBitmap.pixmap(),
(j * (icon_size + icon_padding_pixel_size)) - icon_write_offset,
(i * (icon_size + icon_padding_pixel_size)) - icon_write_offset);
}
}
break;
}
default:
DLOG(ERROR) << "Invalid number of icons to combine: " << bitmaps_.size();
return nullptr;
}
return std::make_unique<SkBitmap>(composite_bitmap);
} }
ImageHelper::ImageHelper() : last_used_job_id_(0) {} ImageHelper::ImageHelper() : last_used_job_id_(0) {}
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/android/compose_bitmaps_helper.h"
#include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/favicon/history_ui_favicon_request_handler_factory.h" #include "chrome/browser/favicon/history_ui_favicon_request_handler_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -184,10 +185,13 @@ jboolean FaviconHelper::GetComposedFaviconImage( ...@@ -184,10 +185,13 @@ jboolean FaviconHelper::GetComposedFaviconImage(
if (!favicon_service) if (!favicon_service)
return false; return false;
int desired_size_in_pixel = static_cast<int>(j_desired_size_in_pixel);
favicon_base::FaviconResultsCallback callback_runner = favicon_base::FaviconResultsCallback callback_runner =
base::BindOnce(&FaviconHelper::OnFaviconBitmapResultsAvailable, base::BindOnce(&FaviconHelper::OnFaviconBitmapResultsAvailable,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
ScopedJavaGlobalRef<jobject>(j_favicon_image_callback)); ScopedJavaGlobalRef<jobject>(j_favicon_image_callback),
desired_size_in_pixel);
std::vector<std::string> urls; std::vector<std::string> urls;
base::android::AppendJavaStringArrayToStringVector(env, j_urls, &urls); base::android::AppendJavaStringArrayToStringVector(env, j_urls, &urls);
...@@ -462,12 +466,32 @@ void FaviconHelper::OnFaviconBitmapResultAvailable( ...@@ -462,12 +466,32 @@ void FaviconHelper::OnFaviconBitmapResultAvailable(
void FaviconHelper::OnFaviconBitmapResultsAvailable( void FaviconHelper::OnFaviconBitmapResultsAvailable(
const JavaRef<jobject>& j_favicon_image_callback, const JavaRef<jobject>& j_favicon_image_callback,
const int desired_size_in_pixel,
const std::vector<favicon_base::FaviconRawBitmapResult>& results) { const std::vector<favicon_base::FaviconRawBitmapResult>& results) {
std::vector<SkBitmap> result_bitmaps;
for (size_t i = 0; i < results.size(); i++) {
favicon_base::FaviconRawBitmapResult result = results[i];
if (!result.is_valid())
continue;
SkBitmap favicon_bitmap;
gfx::PNGCodec::Decode(result.bitmap_data->front(),
result.bitmap_data->size(), &favicon_bitmap);
result_bitmaps.push_back(std::move(favicon_bitmap));
}
ScopedJavaLocalRef<jobject> j_favicon_bitmap;
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
// TODO(crbug.com/1064153): Integrate with ImageHelper to compose favicons.
// Convert favicon_image_result to java objects.
ScopedJavaLocalRef<jstring> j_icon_url; ScopedJavaLocalRef<jstring> j_icon_url;
ScopedJavaLocalRef<jobject> j_favicon_bitmap;
if (!result_bitmaps.empty()) {
std::unique_ptr<SkBitmap> composed_bitmap =
compose_bitmaps_helper::ComposeBitmaps(std::move(result_bitmaps),
desired_size_in_pixel);
if (composed_bitmap && !composed_bitmap->isNull()) {
j_favicon_bitmap = gfx::ConvertToJavaBitmap(composed_bitmap.get());
}
}
// Call java side OnFaviconBitmapResultAvailable method. // Call java side OnFaviconBitmapResultAvailable method.
Java_FaviconImageCallback_onFaviconAvailable(env, j_favicon_image_callback, Java_FaviconImageCallback_onFaviconAvailable(env, j_favicon_image_callback,
......
...@@ -111,6 +111,7 @@ class FaviconHelper { ...@@ -111,6 +111,7 @@ class FaviconHelper {
void OnFaviconBitmapResultsAvailable( void OnFaviconBitmapResultsAvailable(
const base::android::JavaRef<jobject>& j_favicon_image_callback, const base::android::JavaRef<jobject>& j_favicon_image_callback,
const int desired_size_in_pixel,
const std::vector<favicon_base::FaviconRawBitmapResult>& result); const std::vector<favicon_base::FaviconRawBitmapResult>& result);
std::unique_ptr<base::CancelableTaskTracker> cancelable_task_tracker_; std::unique_ptr<base::CancelableTaskTracker> cancelable_task_tracker_;
......
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