blob: 8905485f8a88632e4b4e541b81cc68de4a0ba576 [file] [log] [blame]
// 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