SkCrabbyAvifCodec: Support subsets

Add support in SkCrabbyAvifCodec for decoding subsets of an
image. It takes the same path as images with crop rectangle
specified.

Change-Id: I2d87725ae7572f3bba1957b3cb31f59274530bc7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/938239
Auto-Submit: Vignesh Venkat <vigneshv@google.com>
Commit-Queue: Vignesh Venkat <vigneshv@google.com>
Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
Commit-Queue: Jorge Betancourt <jmbetancourt@google.com>
diff --git a/src/codec/SkCrabbyAvifCodec.cpp b/src/codec/SkCrabbyAvifCodec.cpp
index 6d17fe9..e4cffb7 100644
--- a/src/codec/SkCrabbyAvifCodec.cpp
+++ b/src/codec/SkCrabbyAvifCodec.cpp
@@ -313,10 +313,6 @@
                                                size_t dstRowBytes,
                                                const Options& options,
                                                int* rowsDecoded) {
-    if (options.fSubset) {
-        return kUnimplemented;
-    }
-
     switch (dstInfo.colorType()) {
         case kRGBA_8888_SkColorType:
         case kRGB_565_SkColorType:
@@ -346,7 +342,7 @@
             std::unique_ptr<crabbyavif::avifImage, decltype(&crabbyavif::crabby_avifImageDestroy)>;
 
     AvifImagePtr scaled_image{nullptr, crabbyavif::crabby_avifImageDestroy};
-    if (this->dimensions() != dstInfo.dimensions()) {
+    if (this->dimensions() != dstInfo.dimensions() && !options.fSubset) {
         // |image| contains plane pointers which point to Android MediaCodec's buffers. Those
         // buffers are read-only and hence we cannot scale in place. Make a copy of the image and
         // scale the copied image.
@@ -380,6 +376,21 @@
         }
     }
 
+    AvifImagePtr subset_image{nullptr, crabbyavif::crabby_avifImageDestroy};
+    if (options.fSubset) {
+        const crabbyavif::avifCropRect rect{
+                .x = static_cast<uint32_t>(options.fSubset->x()),
+                .y = static_cast<uint32_t>(options.fSubset->y()),
+                .width = static_cast<uint32_t>(options.fSubset->width()),
+                .height = static_cast<uint32_t>(options.fSubset->height())};
+        subset_image.reset(crabbyavif::crabby_avifImageCreateEmpty());
+        result = crabbyavif::crabby_avifImageSetViewRect(subset_image.get(), image, &rect);
+        if (result != crabbyavif::AVIF_RESULT_OK) {
+            return kInvalidInput;
+        }
+        image = subset_image.get();
+    }
+
     crabbyavif::avifRGBImage rgbImage;
     crabbyavif::avifRGBImageSetDefaults(&rgbImage, image);
 
diff --git a/src/codec/SkCrabbyAvifCodec.h b/src/codec/SkCrabbyAvifCodec.h
index df31de1..56ecf56 100644
--- a/src/codec/SkCrabbyAvifCodec.h
+++ b/src/codec/SkCrabbyAvifCodec.h
@@ -63,6 +63,7 @@
     const SkFrameHolder* getFrameHolder() const override { return &fFrameHolder; }
     bool conversionSupported(const SkImageInfo&, bool, bool) override;
     bool onGetGainmapCodec(SkGainmapInfo* info, std::unique_ptr<SkCodec>* gainmapCodec) override;
+    bool onGetValidSubset(SkIRect*) const override { return true; }
 
 private:
     SkCrabbyAvifCodec(SkEncodedInfo&&,