diff options
Diffstat (limited to 'chromium/third_party/skia/client_utils')
4 files changed, 297 insertions, 0 deletions
diff --git a/chromium/third_party/skia/client_utils/android/BRDAllocator.h b/chromium/third_party/skia/client_utils/android/BRDAllocator.h new file mode 100644 index 00000000000..904676d2889 --- /dev/null +++ b/chromium/third_party/skia/client_utils/android/BRDAllocator.h @@ -0,0 +1,35 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef BRDAllocator_DEFINED +#define BRDAllocator_DEFINED + +#include "include/codec/SkCodec.h" +#include "include/core/SkBitmap.h" + +namespace android { +namespace skia { + +/** + * Abstract subclass of SkBitmap's allocator. + * Allows the allocator to indicate if the memory it allocates + * is zero initialized. + */ +class BRDAllocator : public SkBitmap::Allocator { +public: + + /** + * Indicates if the memory allocated by this allocator is + * zero initialized. + */ + virtual SkCodec::ZeroInitialized zeroInit() const = 0; +}; + +} // namespace skia +} // namespace android + +#endif // BRDAllocator_DEFINED diff --git a/chromium/third_party/skia/client_utils/android/BitmapRegionDecoder.cpp b/chromium/third_party/skia/client_utils/android/BitmapRegionDecoder.cpp new file mode 100644 index 00000000000..8727a0bd8ab --- /dev/null +++ b/chromium/third_party/skia/client_utils/android/BitmapRegionDecoder.cpp @@ -0,0 +1,151 @@ +/* + * 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 "client_utils/android/BitmapRegionDecoder.h" +#include "client_utils/android/BitmapRegionDecoderPriv.h" +#include "include/codec/SkAndroidCodec.h" +#include "src/codec/SkCodecPriv.h" + +namespace android { +namespace skia { + +std::unique_ptr<BitmapRegionDecoder> BitmapRegionDecoder::Make(sk_sp<SkData> data) { + auto codec = SkAndroidCodec::MakeFromData(std::move(data)); + if (nullptr == codec) { + SkCodecPrintf("Error: Failed to create codec.\n"); + return nullptr; + } + + switch (codec->getEncodedFormat()) { + case SkEncodedImageFormat::kJPEG: + case SkEncodedImageFormat::kPNG: + case SkEncodedImageFormat::kWEBP: + case SkEncodedImageFormat::kHEIF: + break; + default: + return nullptr; + } + + return std::unique_ptr<BitmapRegionDecoder>(new BitmapRegionDecoder(std::move(codec))); +} + +BitmapRegionDecoder::BitmapRegionDecoder(std::unique_ptr<SkAndroidCodec> codec) + : fCodec(std::move(codec)) +{} + +int BitmapRegionDecoder::width() const { + return fCodec->getInfo().width(); +} + +int BitmapRegionDecoder::height() const { + return fCodec->getInfo().height(); +} + +bool BitmapRegionDecoder::decodeRegion(SkBitmap* bitmap, BRDAllocator* allocator, + const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType, + bool requireUnpremul, sk_sp<SkColorSpace> dstColorSpace) { + + // Fix the input sampleSize if necessary. + if (sampleSize < 1) { + sampleSize = 1; + } + + // The size of the output bitmap is determined by the size of the + // requested subset, not by the size of the intersection of the subset + // and the image dimensions. + // If inputX is negative, we will need to place decoded pixels into the + // output bitmap starting at a left offset. Call this outX. + // If outX is non-zero, subsetX must be zero. + // If inputY is negative, we will need to place decoded pixels into the + // output bitmap starting at a top offset. Call this outY. + // If outY is non-zero, subsetY must be zero. + int outX; + int outY; + SkIRect subset = desiredSubset; + SubsetType type = adjust_subset_rect(fCodec->getInfo().dimensions(), &subset, &outX, &outY); + if (SubsetType::kOutside_SubsetType == type) { + return false; + } + + // Ask the codec for a scaled subset + if (!fCodec->getSupportedSubset(&subset)) { + SkCodecPrintf("Error: Could not get subset.\n"); + return false; + } + SkISize scaledSize = fCodec->getSampledSubsetDimensions(sampleSize, subset); + + // Create the image info for the decode + SkAlphaType dstAlphaType = fCodec->computeOutputAlphaType(requireUnpremul); + SkImageInfo decodeInfo = + SkImageInfo::Make(scaledSize, dstColorType, dstAlphaType, dstColorSpace); + + // Initialize the destination bitmap + int scaledOutX = 0; + int scaledOutY = 0; + int scaledOutWidth = scaledSize.width(); + int scaledOutHeight = scaledSize.height(); + if (SubsetType::kPartiallyInside_SubsetType == type) { + scaledOutX = outX / sampleSize; + scaledOutY = outY / sampleSize; + // We need to be safe here because getSupportedSubset() may have modified the subset. + const int extraX = std::max(0, desiredSubset.width() - outX - subset.width()); + const int extraY = std::max(0, desiredSubset.height() - outY - subset.height()); + const int scaledExtraX = extraX / sampleSize; + const int scaledExtraY = extraY / sampleSize; + scaledOutWidth += scaledOutX + scaledExtraX; + scaledOutHeight += scaledOutY + scaledExtraY; + } + SkImageInfo outInfo = decodeInfo.makeWH(scaledOutWidth, scaledOutHeight); + if (kGray_8_SkColorType == dstColorType) { + // The legacy implementations of BitmapFactory and BitmapRegionDecoder + // used kAlpha8 for grayscale images (before kGray8 existed). While + // the codec recognizes kGray8, we need to decode into a kAlpha8 + // bitmap in order to avoid a behavior change. + outInfo = outInfo.makeColorType(kAlpha_8_SkColorType).makeAlphaType(kPremul_SkAlphaType); + } + bitmap->setInfo(outInfo); + if (!bitmap->tryAllocPixels(allocator)) { + SkCodecPrintf("Error: Could not allocate pixels.\n"); + return false; + } + + // Zero the bitmap if the region is not completely within the image. + // TODO (msarett): Can we make this faster by implementing it to only + // zero parts of the image that we won't overwrite with + // pixels? + SkCodec::ZeroInitialized zeroInit = allocator ? allocator->zeroInit() : + SkCodec::kNo_ZeroInitialized; + if (SubsetType::kPartiallyInside_SubsetType == type && + SkCodec::kNo_ZeroInitialized == zeroInit) { + void* pixels = bitmap->getPixels(); + size_t bytes = outInfo.computeByteSize(bitmap->rowBytes()); + memset(pixels, 0, bytes); + } + + // Decode into the destination bitmap + SkAndroidCodec::AndroidOptions options; + options.fSampleSize = sampleSize; + options.fSubset = ⊂ + options.fZeroInitialized = zeroInit; + void* dst = bitmap->getAddr(scaledOutX, scaledOutY); + + SkCodec::Result result = fCodec->getAndroidPixels(decodeInfo, dst, bitmap->rowBytes(), + &options); + switch (result) { + case SkCodec::kSuccess: + case SkCodec::kIncompleteInput: + case SkCodec::kErrorInInput: + return true; + default: + SkCodecPrintf("Error: Could not get pixels with message \"%s\".\n", + SkCodec::ResultToString(result)); + return false; + } +} + +} // namespace skia +} // namespace android diff --git a/chromium/third_party/skia/client_utils/android/BitmapRegionDecoder.h b/chromium/third_party/skia/client_utils/android/BitmapRegionDecoder.h new file mode 100644 index 00000000000..2996df3aee6 --- /dev/null +++ b/chromium/third_party/skia/client_utils/android/BitmapRegionDecoder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef BitmapRegionDecoder_DEFINED +#define BitmapRegionDecoder_DEFINED + +#include "client_utils/android/BRDAllocator.h" +#include "include/codec/SkAndroidCodec.h" +#include "include/core/SkBitmap.h" +#include "include/core/SkData.h" + +namespace android { +namespace skia { + +class BitmapRegionDecoder final { +public: + static std::unique_ptr<BitmapRegionDecoder> Make(sk_sp<SkData> data); + + bool decodeRegion(SkBitmap* bitmap, BRDAllocator* allocator, + const SkIRect& desiredSubset, int sampleSize, + SkColorType colorType, bool requireUnpremul, + sk_sp<SkColorSpace> prefColorSpace); + + SkEncodedImageFormat getEncodedFormat() { return fCodec->getEncodedFormat(); } + + SkColorType computeOutputColorType(SkColorType requestedColorType) { + return fCodec->computeOutputColorType(requestedColorType); + } + + sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType, + sk_sp<SkColorSpace> prefColorSpace = nullptr) { + return fCodec->computeOutputColorSpace(outputColorType, prefColorSpace); + } + + int width() const; + int height() const; + +private: + BitmapRegionDecoder(std::unique_ptr<SkAndroidCodec> codec); + + std::unique_ptr<SkAndroidCodec> fCodec; +}; + +} // namespace skia +} // namespace android +#endif // BitmapRegionDecoder_DEFINED diff --git a/chromium/third_party/skia/client_utils/android/BitmapRegionDecoderPriv.h b/chromium/third_party/skia/client_utils/android/BitmapRegionDecoderPriv.h new file mode 100644 index 00000000000..d63d4ef47c8 --- /dev/null +++ b/chromium/third_party/skia/client_utils/android/BitmapRegionDecoderPriv.h @@ -0,0 +1,61 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef BitmapRegionDecoderPriv_DEFINED +#define BitmapRegionDecoderPriv_DEFINED + +#include "include/core/SkRect.h" + +enum SubsetType { + kFullyInside_SubsetType, + kPartiallyInside_SubsetType, + kOutside_SubsetType, +}; + +/* + * Corrects image subset offsets and dimensions in order to perform a valid decode. + * Also indicates if the image subset should be placed at an offset within the + * output bitmap. + * + * Values of output variables are undefined if the SubsetType is kInvalid. + * + * @param imageDims Original image dimensions. + * @param subset As input, the subset that the client requested. + * As output, the image subset that we will decode. + * @param outX The left offset of the image subset within the output bitmap. + * @param outY The top offset of the image subset within the output bitmap. + * + * @return An indication of how the subset is contained in the image. + * If the return value is kInvalid, values of output variables are undefined. + */ +inline SubsetType adjust_subset_rect(const SkISize& imageDims, SkIRect* subset, int* outX, + int* outY) { + // These must be at least zero, we can't start decoding the image at a negative coordinate. + int left = std::max(0, subset->fLeft); + int top = std::max(0, subset->fTop); + + // If input offsets are less than zero, we decode to an offset location in the output bitmap. + *outX = left - subset->fLeft; + *outY = top - subset->fTop; + + // Make sure we don't decode pixels past the edge of the image or past the edge of the subset. + int width = std::min(imageDims.width() - left, subset->width() - *outX); + int height = std::min(imageDims.height() - top, subset->height() - *outY); + if (width <= 0 || height <= 0) { + return SubsetType::kOutside_SubsetType; + } + + subset->setXYWH(left, top, width, height); + if ((*outX != 0) || (*outY != 0) || (width != subset->width()) || + (height != subset->height())) { + return SubsetType::kPartiallyInside_SubsetType; + } + + return SubsetType::kFullyInside_SubsetType; +} + +#endif // BitmapRegionDecoderPriv_DEFINED |