#include "skia/public/mojom/bitmap_skbitmap_mojom_traits.h"
#include <algorithm>
#include "base/compiler_specific.h"
#include "third_party/skia/include/core/SkPixelRef.h"
namespace mojo {
namespace {
constexpr int kMaxWidth = 64 * 1024;
constexpr int kMaxHeight = 64 * 1024;
class BigBufferPixelRef final : public SkPixelRef {
public:
BigBufferPixelRef(mojo_base::BigBuffer buffer,
int width,
int height,
int row_bytes)
: SkPixelRef(width, height, buffer.data(), row_bytes),
buffer_(std::move(buffer)) {}
~BigBufferPixelRef() override = default;
private:
mojo_base::BigBuffer buffer_;
};
bool CreateSkBitmapForPixelData(SkBitmap* b,
const SkImageInfo& image_info,
base::span<const uint8_t> pixel_data) {
if (image_info.width() > kMaxWidth || image_info.height() > kMaxHeight)
return false;
if (!b->tryAllocPixels(image_info, image_info.minRowBytes()))
return false;
if (image_info.width() == 0 || image_info.height() == 0)
return true;
if (pixel_data.size() != b->computeByteSize())
return false;
std::ranges::copy(pixel_data, static_cast<uint8_t*>(b->getPixels()));
b->notifyPixelsChanged();
return true;
}
}
mojo_base::BigBufferView StructTraits<skia::mojom::BitmapN32DataView,
SkBitmap>::pixel_data(const SkBitmap& b) {
CHECK_EQ(b.rowBytes(), b.info().minRowBytes());
return mojo_base::BigBufferView(UNSAFE_TODO(
base::span(static_cast<uint8_t*>(b.getPixels()), b.computeByteSize())));
}
bool StructTraits<skia::mojom::BitmapN32DataView, SkBitmap>::Read(
skia::mojom::BitmapN32DataView data,
SkBitmap* b) {
SkImageInfo image_info;
if (!data.ReadImageInfo(&image_info))
return false;
mojo_base::BigBufferView pixel_data_view;
if (!data.ReadPixelData(&pixel_data_view))
return false;
return CreateSkBitmapForPixelData(b, std::move(image_info),
pixel_data_view.data());
}
mojo_base::BigBufferView
StructTraits<skia::mojom::BitmapWithArbitraryBppDataView, SkBitmap>::pixel_data(
const SkBitmap& b) {
CHECK_EQ(b.rowBytes(), b.info().minRowBytes());
return mojo_base::BigBufferView(UNSAFE_TODO(
base::span(static_cast<uint8_t*>(b.getPixels()), b.computeByteSize())));
}
bool StructTraits<skia::mojom::BitmapWithArbitraryBppDataView, SkBitmap>::Read(
skia::mojom::BitmapWithArbitraryBppDataView data,
SkBitmap* b) {
SkImageInfo image_info;
if (!data.ReadImageInfo(&image_info))
return false;
mojo_base::BigBufferView pixel_data_view;
if (!data.ReadPixelData(&pixel_data_view))
return false;
return CreateSkBitmapForPixelData(b, std::move(image_info),
pixel_data_view.data());
}
mojo_base::BigBufferView
StructTraits<skia::mojom::BitmapMappedFromTrustedProcessDataView,
SkBitmap>::pixel_data(const SkBitmap& b) {
CHECK_EQ(b.rowBytes(), b.info().minRowBytes());
return mojo_base::BigBufferView(UNSAFE_TODO(
base::span(static_cast<uint8_t*>(b.getPixels()), b.computeByteSize())));
}
bool StructTraits<
skia::mojom::BitmapMappedFromTrustedProcessDataView,
SkBitmap>::Read(skia::mojom::BitmapMappedFromTrustedProcessDataView data,
SkBitmap* b) {
SkImageInfo image_info;
if (!data.ReadImageInfo(&image_info))
return false;
if (image_info.width() > kMaxWidth || image_info.height() > kMaxHeight)
return false;
if (image_info.width() == 0 || image_info.height() == 0)
return b->tryAllocPixels(image_info);
mojo_base::BigBufferView pixel_data_view;
if (!data.ReadPixelData(&pixel_data_view))
return false;
if (!b->setInfo(image_info, image_info.minRowBytes()))
return false;
if (b->computeByteSize() != pixel_data_view.data().size())
return false;
b->setPixelRef(
sk_make_sp<BigBufferPixelRef>(
mojo_base::BigBufferView::ToBigBuffer(std::move(pixel_data_view)),
image_info.width(), image_info.height(), image_info.minRowBytes()),
0, 0);
return true;
}
base::span<const uint8_t>
StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap>::pixel_data(
const SkBitmap& b) {
CHECK_EQ(b.rowBytes(), b.info().minRowBytes());
return UNSAFE_TODO(
base::span(static_cast<uint8_t*>(b.getPixels()), b.computeByteSize()));
}
bool StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap>::Read(
skia::mojom::InlineBitmapDataView data,
SkBitmap* b) {
SkImageInfo image_info;
if (!data.ReadImageInfo(&image_info))
return false;
mojo::ArrayDataView<uint8_t> pixel_data_view;
data.GetPixelDataDataView(&pixel_data_view);
base::span<const uint8_t> UNSAFE_TODO(
pixel_data_bytes(pixel_data_view.data(), pixel_data_view.size()));
return CreateSkBitmapForPixelData(b, std::move(image_info),
std::move(pixel_data_bytes));
}
}