diff options
author | 2015-09-04 13:00:49 -0700 | |
---|---|---|
committer | 2015-09-04 13:00:50 -0700 | |
commit | 76f755e6d54a32f9887ad254ce59a3a62f28bde4 (patch) | |
tree | 9fd2954a383da06941f9448c57c8bddb8378e84e /dm/DMSrcSink.cpp | |
parent | c3470340b6658dea7baa3ac90d3b716c0afd7051 (diff) |
Provides various implementations of Android's SkBitmapRegionDecoder.
Implements testing in DM for these implementations.
nanobench testing will follow after this.
BUG=skia:
Review URL: https://codereview.chromium.org/1288963002
Diffstat (limited to 'dm/DMSrcSink.cpp')
-rw-r--r-- | dm/DMSrcSink.cpp | 160 |
1 files changed, 158 insertions, 2 deletions
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index 2c80fac6be..e31a249f70 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -64,6 +64,163 @@ void GMSrc::modifyGrContextOptions(GrContextOptions* options) const { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +BRDSrc::BRDSrc(Path path, SkBitmapRegionDecoderInterface::Strategy strategy, Mode mode, + CodecSrc::DstColorType dstColorType, uint32_t sampleSize) + : fPath(path) + , fStrategy(strategy) + , fMode(mode) + , fDstColorType(dstColorType) + , fSampleSize(sampleSize) +{} + +bool BRDSrc::veto(SinkFlags flags) const { + // No need to test to non-raster or indirect backends. + return flags.type != SinkFlags::kRaster + || flags.approach != SinkFlags::kDirect; +} + +static SkBitmapRegionDecoderInterface* create_brd(Path path, + SkBitmapRegionDecoderInterface::Strategy strategy) { + SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str())); + if (!encoded) { + return NULL; + } + return SkBitmapRegionDecoderInterface::CreateBitmapRegionDecoder(new SkMemoryStream(encoded), + strategy); +} + +Error BRDSrc::draw(SkCanvas* canvas) const { + SkColorType colorType = canvas->imageInfo().colorType(); + if (kRGB_565_SkColorType == colorType && + CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) { + return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); + } + switch (fDstColorType) { + case CodecSrc::kGetFromCanvas_DstColorType: + break; + case CodecSrc::kIndex8_Always_DstColorType: + colorType = kIndex_8_SkColorType; + break; + case CodecSrc::kGrayscale_Always_DstColorType: + colorType = kGray_8_SkColorType; + break; + } + + SkAutoTDelete<SkBitmapRegionDecoderInterface> brd(create_brd(fPath, fStrategy)); + if (nullptr == brd.get()) { + return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str())); + } + + const uint32_t width = brd->width(); + const uint32_t height = brd->height(); + // Visually inspecting very small output images is not necessary. + if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) { + return Error::Nonfatal("Scaling very small images is uninteresting."); + } + switch (fMode) { + case kFullImage_Mode: { + SkAutoTDelete<SkBitmap> bitmap(brd->decodeRegion(0, 0, width, height, fSampleSize, + colorType)); + if (nullptr == bitmap.get() || colorType != bitmap->colorType()) { + return Error::Nonfatal("Cannot convert to color type.\n"); + } + canvas->drawBitmap(*bitmap, 0, 0); + return ""; + } + case kDivisor_Mode: { + const uint32_t divisor = 2; + if (width < divisor || height < divisor) { + return Error::Nonfatal("Divisor is larger than image dimension.\n"); + } + + // Use a border to test subsets that extend outside the image. + // We will not allow the border to be larger than the image dimensions. Allowing + // these large borders causes off by one errors that indicate a problem with the + // test suite, not a problem with the implementation. + const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor); + const uint32_t scaledBorder = SkTMin(5u, maxBorder); + const uint32_t unscaledBorder = scaledBorder * fSampleSize; + + // We may need to clear the canvas to avoid uninitialized memory. + // Assume we are scaling a 780x780 image with sampleSize = 8. + // The output image should be 97x97. + // Each subset will be 390x390. + // Each scaled subset be 48x48. + // Four scaled subsets will only fill a 96x96 image. + // The bottom row and last column will not be touched. + // This is an unfortunate result of our rounding rules when scaling. + // Maybe we need to consider testing scaled subsets without trying to + // combine them to match the full scaled image? Or maybe this is the + // best we can do? + canvas->clear(0); + + for (uint32_t x = 0; x < divisor; x++) { + for (uint32_t y = 0; y < divisor; y++) { + // Calculate the subset dimensions + uint32_t subsetWidth = width / divisor; + uint32_t subsetHeight = height / divisor; + const int left = x * subsetWidth; + const int top = y * subsetHeight; + + // Increase the size of the last subset in each row or column, when the + // divisor does not divide evenly into the image dimensions + subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; + subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; + + // Increase the size of the subset in order to have a border on each side + const int decodeLeft = left - unscaledBorder; + const int decodeTop = top - unscaledBorder; + const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2; + const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2; + SkAutoTDelete<SkBitmap> bitmap(brd->decodeRegion(decodeLeft, + decodeTop, decodeWidth, decodeHeight, fSampleSize, colorType)); + if (nullptr == bitmap.get() || colorType != bitmap->colorType()) { + return Error::Nonfatal("Cannot convert to color type.\n"); + } + + canvas->drawBitmapRect(*bitmap, + SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder, + (SkScalar) (subsetWidth / fSampleSize), + (SkScalar) (subsetHeight / fSampleSize)), + SkRect::MakeXYWH((SkScalar) (left / fSampleSize), + (SkScalar) (top / fSampleSize), + (SkScalar) (subsetWidth / fSampleSize), + (SkScalar) (subsetHeight / fSampleSize)), + nullptr); + } + } + return ""; + } + default: + SkASSERT(false); + return "Error: Should not be reached.\n"; + } +} + +SkISize BRDSrc::size() const { + SkAutoTDelete<SkBitmapRegionDecoderInterface> brd(create_brd(fPath, fStrategy)); + if (brd) { + return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize), + SkTMax(1, brd->height() / (int) fSampleSize)); + } + return SkISize::Make(0, 0); +} + +static SkString get_scaled_name(const Path& path, float scale) { + return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale); +} + +Name BRDSrc::name() const { + // We will replicate the names used by CodecSrc so that images can + // be compared in Gold. + if (1 == fSampleSize) { + return SkOSPath::Basename(fPath.c_str()); + } + return get_scaled_name(fPath, BRDSrc::GetScale(fSampleSize)); +} + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, float scale) : fPath(path) , fMode(mode) @@ -493,9 +650,8 @@ SkISize CodecSrc::size() const { Name CodecSrc::name() const { if (1.0f == fScale) { return SkOSPath::Basename(fPath.c_str()); - } else { - return SkStringPrintf("%s_%.3f", SkOSPath::Basename(fPath.c_str()).c_str(), fScale); } + return get_scaled_name(fPath, fScale); } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |