blob: d43e33d3851df459d24dfc34848d1ad1dfab8942 [file] [log] [blame]
// Copyright 2014 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 "platform/graphics/StaticBitmapImage.h"
#include "platform/graphics/AcceleratedStaticBitmapImage.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageObserver.h"
#include "platform/graphics/UnacceleratedStaticBitmapImage.h"
#include "platform/graphics/paint/PaintImage.h"
#include "platform/wtf/CheckedNumeric.h"
#include "platform/wtf/typed_arrays/ArrayBufferContents.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPaint.h"
namespace blink {
scoped_refptr<StaticBitmapImage> StaticBitmapImage::Create(
sk_sp<SkImage> image,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>
context_provider_wrapper) {
if (image->isTextureBacked()) {
CHECK(context_provider_wrapper);
return AcceleratedStaticBitmapImage::CreateFromSkImage(
image, std::move(context_provider_wrapper));
}
return UnacceleratedStaticBitmapImage::Create(image);
}
scoped_refptr<StaticBitmapImage> StaticBitmapImage::Create(PaintImage image) {
DCHECK(!image.GetSkImage()->isTextureBacked());
return UnacceleratedStaticBitmapImage::Create(std::move(image));
}
scoped_refptr<StaticBitmapImage> StaticBitmapImage::Create(
scoped_refptr<Uint8Array>&& image_pixels,
const SkImageInfo& info) {
SkPixmap pixmap(info, image_pixels->Data(), info.minRowBytes());
Uint8Array* pixels = image_pixels.get();
if (pixels) {
pixels->AddRef();
image_pixels = nullptr;
}
return Create(SkImage::MakeFromRaster(
pixmap,
[](const void*, void* p) { static_cast<Uint8Array*>(p)->Release(); },
pixels));
}
scoped_refptr<StaticBitmapImage> StaticBitmapImage::Create(
WTF::ArrayBufferContents& contents,
const SkImageInfo& info) {
SkPixmap pixmap(info, contents.Data(), info.minRowBytes());
return Create(SkImage::MakeFromRaster(pixmap, nullptr, nullptr));
}
void StaticBitmapImage::DrawHelper(PaintCanvas* canvas,
const PaintFlags& flags,
const FloatRect& dst_rect,
const FloatRect& src_rect,
ImageClampingMode clamp_mode,
const PaintImage& image) {
FloatRect adjusted_src_rect = src_rect;
adjusted_src_rect.Intersect(SkRect::MakeWH(image.width(), image.height()));
if (dst_rect.IsEmpty() || adjusted_src_rect.IsEmpty())
return; // Nothing to draw.
canvas->drawImageRect(image, adjusted_src_rect, dst_rect, &flags,
WebCoreClampingModeToSkiaRectConstraint(clamp_mode));
}
scoped_refptr<StaticBitmapImage> StaticBitmapImage::ConvertToColorSpace(
sk_sp<SkColorSpace> target,
SkTransferFunctionBehavior transfer_function_behavior) {
sk_sp<SkImage> skia_image = PaintImageForCurrentFrame().GetSkImage();
sk_sp<SkColorSpace> src_color_space = skia_image->refColorSpace();
if (!src_color_space.get())
src_color_space = SkColorSpace::MakeSRGB();
sk_sp<SkColorSpace> dst_color_space = target;
if (!dst_color_space.get())
dst_color_space = SkColorSpace::MakeSRGB();
if (SkColorSpace::Equals(src_color_space.get(), dst_color_space.get()))
return this;
sk_sp<SkImage> converted_skia_image =
skia_image->makeColorSpace(dst_color_space, transfer_function_behavior);
DCHECK(converted_skia_image.get());
DCHECK(skia_image.get() != converted_skia_image.get());
return StaticBitmapImage::Create(converted_skia_image,
ContextProviderWrapper());
}
bool StaticBitmapImage::ConvertToArrayBufferContents(
scoped_refptr<StaticBitmapImage> src_image,
WTF::ArrayBufferContents& dest_contents,
const IntRect& rect,
const CanvasColorParams& color_params,
bool is_accelerated) {
uint8_t bytes_per_pixel = color_params.BytesPerPixel();
CheckedNumeric<int> data_size = bytes_per_pixel;
data_size *= rect.Size().Area();
if (!data_size.IsValid() ||
data_size.ValueOrDie() > v8::TypedArray::kMaxLength)
return false;
size_t alloc_size_in_bytes = rect.Size().Area() * bytes_per_pixel;
if (!src_image) {
auto data = WTF::ArrayBufferContents::CreateDataHandle(
alloc_size_in_bytes, WTF::ArrayBufferContents::kZeroInitialize);
if (!data)
return false;
WTF::ArrayBufferContents result(std::move(data), alloc_size_in_bytes,
WTF::ArrayBufferContents::kNotShared);
result.Transfer(dest_contents);
return true;
}
const bool may_have_stray_area =
is_accelerated // GPU readback may fail silently
|| rect.X() < 0 || rect.Y() < 0 ||
rect.MaxX() > src_image->Size().Width() ||
rect.MaxY() > src_image->Size().Height();
WTF::ArrayBufferContents::InitializationPolicy initialization_policy =
may_have_stray_area ? WTF::ArrayBufferContents::kZeroInitialize
: WTF::ArrayBufferContents::kDontInitialize;
auto data = WTF::ArrayBufferContents::CreateDataHandle(alloc_size_in_bytes,
initialization_policy);
if (!data)
return false;
WTF::ArrayBufferContents result(std::move(data), alloc_size_in_bytes,
WTF::ArrayBufferContents::kNotShared);
SkColorType color_type =
(color_params.GetSkColorType() == kRGBA_F16_SkColorType)
? kRGBA_F16_SkColorType
: kRGBA_8888_SkColorType;
SkImageInfo info = SkImageInfo::Make(rect.Width(), rect.Height(), color_type,
kUnpremul_SkAlphaType);
sk_sp<SkImage> sk_image = src_image->PaintImageForCurrentFrame().GetSkImage();
bool read_pixels_successful = sk_image->readPixels(
info, result.Data(), info.minRowBytes(), rect.X(), rect.Y());
DCHECK(read_pixels_successful ||
!sk_image->bounds().intersect(SkIRect::MakeXYWH(
rect.X(), rect.Y(), info.width(), info.height())));
result.Transfer(dest_contents);
return true;
}
const gpu::SyncToken& StaticBitmapImage::GetSyncToken() const {
static const gpu::SyncToken sync_token;
return sync_token;
}
} // namespace blink