blob: e8d7d3038a1860dfda00ee875bd078a1972a8ea7 [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 "SkAutoPixmapStorage.h"
#include "SkCodecImageGenerator.h"
#include "SkMakeUnique.h"
#include "SkPixmapPriv.h"
#define kMirrorX SkPixmapPriv::kMirrorX
#define kMirrorY SkPixmapPriv::kMirrorY
#define kSwapXY SkPixmapPriv::kSwapXY
const uint8_t gOrientationFlags[] = {
0, // kTopLeft_Origin
kMirrorX, // kTopRight_Origin
kMirrorX | kMirrorY, // kBottomRight_Origin
kMirrorY, // kBottomLeft_Origin
kSwapXY, // kLeftTop_Origin
kMirrorX | kSwapXY, // kRightTop_Origin
kMirrorX | kMirrorY | kSwapXY, // kRightBottom_Origin
kMirrorY | kSwapXY, // kLeftBottom_Origin
};
SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkCodec::Origin o) {
unsigned io = static_cast<int>(o) - 1;
SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags));
return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]);
}
static bool should_swap_width_height(SkCodec::Origin o) {
return SkToBool(SkPixmapPriv::OriginToOrient(o) & kSwapXY);
}
static SkImageInfo swap_width_height(SkImageInfo info) {
return info.makeWH(info.height(), info.width());
}
///////////////////////////////////////////////////////////////////////////////////////////////////
std::unique_ptr<SkImageGenerator> SkCodecImageGenerator::MakeFromEncodedCodec(sk_sp<SkData> data) {
auto codec = SkCodec::MakeFromData(data);
if (nullptr == codec) {
return nullptr;
}
return std::unique_ptr<SkImageGenerator>(new SkCodecImageGenerator(std::move(codec), data));
}
static SkImageInfo adjust_info(SkCodec* codec) {
SkImageInfo info = codec->getInfo();
if (kUnpremul_SkAlphaType == info.alphaType()) {
info = info.makeAlphaType(kPremul_SkAlphaType);
}
if (should_swap_width_height(codec->getOrigin())) {
info = swap_width_height(info);
}
return info;
}
SkCodecImageGenerator::SkCodecImageGenerator(std::unique_ptr<SkCodec> codec, sk_sp<SkData> data)
: INHERITED(adjust_info(codec.get()))
, fCodec(std::move(codec))
, fData(std::move(data))
{}
SkData* SkCodecImageGenerator::onRefEncodedData() {
return SkRef(fData.get());
}
bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& requestInfo, void* requestPixels,
size_t requestRowBytes, const Options& opts) {
const SkCodec::Origin origin = fCodec->getOrigin();
const SkPixmap request(requestInfo, requestPixels, requestRowBytes);
const SkPixmap* codecMap = &request;
SkAutoPixmapStorage storage; // used if we have to post-orient the output from the codec
if (origin != SkCodec::kTopLeft_Origin) {
SkImageInfo info = requestInfo;
if (should_swap_width_height(origin)) {
info = swap_width_height(info);
}
// need a tmp buffer to receive the pixels, so we can post-orient them
if (!storage.tryAlloc(info)) {
return false;
}
codecMap = &storage;
}
SkCodec::Options codecOpts;
codecOpts.fPremulBehavior = opts.fBehavior;
SkCodec::Result result = fCodec->getPixels(*codecMap, &codecOpts);
switch (result) {
case SkCodec::kSuccess:
if (codecMap != &request) {
return SkPixmapPriv::Orient(request, *codecMap,
SkPixmapPriv::OriginToOrient(origin));
}
// fall through
case SkCodec::kIncompleteInput:
case SkCodec::kErrorInInput:
return true;
default:
return false;
}
}
bool SkCodecImageGenerator::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const
{
return fCodec->queryYUV8(sizeInfo, colorSpace);
}
bool SkCodecImageGenerator::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
SkCodec::Result result = fCodec->getYUV8Planes(sizeInfo, planes);
switch (result) {
case SkCodec::kSuccess:
case SkCodec::kIncompleteInput:
case SkCodec::kErrorInInput:
return true;
default:
return false;
}
}