blob: 4b68ffdd93cc4055f44c2db78840b1ec835563ff [file] [log] [blame]
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkImage_Base.h"
#include "SkCanvas.h"
#include "SkColorSpaceXformCanvas.h"
#include "SkMakeUnique.h"
#include "SkMatrix.h"
#include "SkPaint.h"
#include "SkPicture.h"
#include "SkPictureImageGenerator.h"
#include "SkSurface.h"
std::unique_ptr<SkImageGenerator>
SkPictureImageGenerator::Make(const SkISize& size, sk_sp<SkPicture> picture, const SkMatrix* matrix,
const SkPaint* paint, SkImage::BitDepth bitDepth,
sk_sp<SkColorSpace> colorSpace) {
if (!picture || size.isEmpty()) {
return nullptr;
}
if (SkImage::BitDepth::kF16 == bitDepth && (!colorSpace || !colorSpace->gammaIsLinear())) {
return nullptr;
}
if (colorSpace && (!colorSpace->gammaCloseToSRGB() && !colorSpace->gammaIsLinear())) {
return nullptr;
}
SkColorType colorType = kN32_SkColorType;
if (SkImage::BitDepth::kF16 == bitDepth) {
colorType = kRGBA_F16_SkColorType;
}
SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType,
kPremul_SkAlphaType, std::move(colorSpace));
return std::unique_ptr<SkImageGenerator>(
new SkPictureImageGenerator(info, std::move(picture), matrix, paint));
}
SkPictureImageGenerator::SkPictureImageGenerator(const SkImageInfo& info, sk_sp<SkPicture> picture,
const SkMatrix* matrix, const SkPaint* paint)
: INHERITED(info)
, fPicture(std::move(picture)) {
if (matrix) {
fMatrix = *matrix;
} else {
fMatrix.reset();
}
if (paint) {
fPaint.set(*paint);
}
}
bool SkPictureImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
const Options& opts) {
bool useXformCanvas =
SkTransferFunctionBehavior::kIgnore == opts.fBehavior && info.colorSpace();
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkImageInfo canvasInfo = useXformCanvas ? info.makeColorSpace(nullptr) : info;
std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(canvasInfo, pixels, rowBytes,
&props);
if (!canvas) {
return false;
}
canvas->clear(0);
SkCanvas* canvasPtr = canvas.get();
std::unique_ptr<SkCanvas> xformCanvas;
if (useXformCanvas) {
xformCanvas = SkCreateColorSpaceXformCanvas(canvas.get(), info.refColorSpace());
canvasPtr = xformCanvas.get();
}
canvasPtr->drawPicture(fPicture, &fMatrix, fPaint.getMaybeNull());
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
std::unique_ptr<SkImageGenerator>
SkImageGenerator::MakeFromPicture(const SkISize& size, sk_sp<SkPicture> picture,
const SkMatrix* matrix, const SkPaint* paint,
SkImage::BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) {
// Check this here (rather than in SkPictureImageGenerator::Create) so SkPictureShader
// has a private entry point to create legacy picture backed images.
if (!colorSpace) {
return nullptr;
}
return SkPictureImageGenerator::Make(size, std::move(picture), matrix, paint, bitDepth,
std::move(colorSpace));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
sk_sp<GrTextureProxy> SkPictureImageGenerator::onGenerateTexture(
GrContext* ctx, const SkImageInfo& info, const SkIPoint& origin,
SkTransferFunctionBehavior behavior, bool willNeedMipMaps) {
SkASSERT(ctx);
bool useXformCanvas = SkTransferFunctionBehavior::kIgnore == behavior && info.colorSpace();
//
// TODO: respect the usage, by possibly creating a different (pow2) surface
//
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkImageInfo surfaceInfo = useXformCanvas ? info.makeColorSpace(nullptr) : info;
sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, surfaceInfo,
0, kTopLeft_GrSurfaceOrigin, &props,
willNeedMipMaps));
if (!surface) {
return nullptr;
}
SkCanvas* canvas = surface->getCanvas();
std::unique_ptr<SkCanvas> xformCanvas;
if (useXformCanvas) {
xformCanvas = SkCreateColorSpaceXformCanvas(canvas, info.refColorSpace());
canvas = xformCanvas.get();
}
SkMatrix matrix = fMatrix;
matrix.postTranslate(-origin.x(), -origin.y());
canvas->clear(0); // does NewRenderTarget promise to do this for us?
canvas->drawPicture(fPicture.get(), &matrix, fPaint.getMaybeNull());
sk_sp<SkImage> image(surface->makeImageSnapshot());
if (!image) {
return nullptr;
}
sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef();
SkASSERT(!willNeedMipMaps || GrMipMapped::kYes == proxy->mipMapped());
return proxy;
}
#endif