Provides various implementations of Android's SkBitmapRegionDecoder.

Implements testing in DM for these implementations.

nanobench testing will follow after this.

TBR=scroggo
BUG=skia:

Committed: https://skia.googlesource.com/skia/+/76f755e6d54a32f9887ad254ce59a3a62f28bde4

Review URL: https://codereview.chromium.org/1288963002
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 438868d..981e47d 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -64,6 +64,163 @@
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
+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)
@@ -513,9 +670,8 @@
 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);
 }
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/