Reland: Widen internal API to support more complex YUV formats

Bug: skia:7901
Change-Id: Ic83e9f0c2a493335671fe431ffba6f649812d406
Reviewed-on: https://skia-review.googlesource.com/c/163481
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp
index 55a6575..3005ee3 100644
--- a/src/codec/SkCodecImageGenerator.cpp
+++ b/src/codec/SkCodecImageGenerator.cpp
@@ -8,6 +8,7 @@
 #include "SkCodecImageGenerator.h"
 #include "SkMakeUnique.h"
 #include "SkPixmapPriv.h"
+#include "SkYUVAIndex.h"
 
 std::unique_ptr<SkImageGenerator> SkCodecImageGenerator::MakeFromEncodedCodec(sk_sp<SkData> data) {
     auto codec = SkCodec::MakeFromData(data);
@@ -58,13 +59,27 @@
     return SkPixmapPriv::Orient(dst, fCodec->getOrigin(), decode);
 }
 
-bool SkCodecImageGenerator::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const
-{
+bool SkCodecImageGenerator::onQueryYUVA8(SkYUVSizeInfo* sizeInfo,
+                                         SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+                                         SkYUVColorSpace* colorSpace) const {
+    // This image generator always returns 3 separate non-interleaved planes
+    yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
+    yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
+    yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
+    yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
+    yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 2;
+    yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kR;
+    yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
+    yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
+
     return fCodec->queryYUV8(sizeInfo, colorSpace);
 }
 
-bool SkCodecImageGenerator::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
+bool SkCodecImageGenerator::onGetYUVA8Planes(const SkYUVSizeInfo& sizeInfo,
+                                             const SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
+                                             void* planes[]) {
     SkCodec::Result result = fCodec->getYUV8Planes(sizeInfo, planes);
+    // TODO: check indices
 
     switch (result) {
         case SkCodec::kSuccess:
diff --git a/src/codec/SkCodecImageGenerator.h b/src/codec/SkCodecImageGenerator.h
index b9c9d3c..9a64b7c 100644
--- a/src/codec/SkCodecImageGenerator.h
+++ b/src/codec/SkCodecImageGenerator.h
@@ -22,12 +22,14 @@
 protected:
     sk_sp<SkData> onRefEncodedData() override;
 
-    bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options& opts)
-                     override;
+    bool onGetPixels(
+        const SkImageInfo& info, void* pixels, size_t rowBytes, const Options& opts) override;
 
-    bool onQueryYUV8(SkYUVSizeInfo*, SkYUVColorSpace*) const override;
+    bool onQueryYUVA8(
+        SkYUVSizeInfo*, SkYUVAIndex[SkYUVAIndex::kIndexCount], SkYUVColorSpace*) const override;
 
-    bool onGetYUV8Planes(const SkYUVSizeInfo&, void* planes[3]) override;
+    bool onGetYUVA8Planes(const SkYUVSizeInfo&, const SkYUVAIndex[SkYUVAIndex::kIndexCount],
+                          void* planes[]) override;
 
 private:
     /*
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index 257b764..f5c23a2 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -831,11 +831,18 @@
     }
 
     jpeg_component_info * comp_info = dinfo->comp_info;
-    for (auto i : { SkYUVSizeInfo::kY, SkYUVSizeInfo::kU, SkYUVSizeInfo::kV }) {
+    for (auto i : { SkYUVAIndex::kY_Index, SkYUVAIndex::kU_Index, SkYUVAIndex::kV_Index }) {
+        sizeInfo->fColorTypes[i] = kAlpha_8_SkColorType;
         sizeInfo->fSizes[i].set(comp_info[i].downsampled_width, comp_info[i].downsampled_height);
         sizeInfo->fWidthBytes[i] = comp_info[i].width_in_blocks * DCTSIZE;
     }
 
+    // JPEG never has an alpha channel
+    sizeInfo->fColorTypes[SkYUVAIndex::kA_Index] = kUnknown_SkColorType;
+    sizeInfo->fSizes[SkYUVAIndex::kA_Index].fHeight =
+        sizeInfo->fSizes[SkYUVAIndex::kA_Index].fWidth =
+        sizeInfo->fWidthBytes[SkYUVAIndex::kA_Index] = 0;
+
     if (colorSpace) {
         *colorSpace = kJPEG_SkYUVColorSpace;
     }
@@ -843,18 +850,22 @@
     return true;
 }
 
-SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
+SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo,
+                                             void* planes[SkYUVSizeInfo::kMaxCount]) {
     SkYUVSizeInfo defaultInfo;
 
     // This will check is_yuv_supported(), so we don't need to here.
     bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr);
     if (!supportsYUV ||
-            sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeInfo::kY] ||
-            sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeInfo::kU] ||
-            sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeInfo::kV] ||
-            sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kY] ||
-            sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kU] ||
-            sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kV]) {
+            kAlpha_8_SkColorType != sizeInfo.fColorTypes[0] ||
+            kAlpha_8_SkColorType != sizeInfo.fColorTypes[1] ||
+            kAlpha_8_SkColorType != sizeInfo.fColorTypes[2] ||
+            sizeInfo.fSizes[0] != defaultInfo.fSizes[0] ||
+            sizeInfo.fSizes[1] != defaultInfo.fSizes[1] ||
+            sizeInfo.fSizes[2] != defaultInfo.fSizes[2] ||
+            sizeInfo.fWidthBytes[0] < defaultInfo.fWidthBytes[0] ||
+            sizeInfo.fWidthBytes[1] < defaultInfo.fWidthBytes[1] ||
+            sizeInfo.fWidthBytes[2] < defaultInfo.fWidthBytes[2]) {
         return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput);
     }
 
@@ -879,9 +890,9 @@
 
     // Currently, we require that the Y plane dimensions match the image dimensions
     // and that the U and V planes are the same dimensions.
-    SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU] == sizeInfo.fSizes[SkYUVSizeInfo::kV]);
-    SkASSERT((uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].width() == dinfo->output_width &&
-            (uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].height() == dinfo->output_height);
+    SkASSERT(sizeInfo.fSizes[1] == sizeInfo.fSizes[2]);
+    SkASSERT((uint32_t) sizeInfo.fSizes[0].width() == dinfo->output_width &&
+             (uint32_t) sizeInfo.fSizes[0].height() == dinfo->output_height);
 
     // Build a JSAMPIMAGE to handle output from libjpeg-turbo.  A JSAMPIMAGE has
     // a 2-D array of pixels for each of the components (Y, U, V) in the image.
@@ -898,20 +909,19 @@
     // Initialize rowptrs.
     int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
     for (int i = 0; i < numYRowsPerBlock; i++) {
-        rowptrs[i] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kY],
-                i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
+        rowptrs[i] = SkTAddOffset<JSAMPLE>(planes[0], i * sizeInfo.fWidthBytes[0]);
     }
     for (int i = 0; i < DCTSIZE; i++) {
-        rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kU],
-                i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]);
-        rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kV],
-                i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]);
+        rowptrs[i + 2 * DCTSIZE] =
+            SkTAddOffset<JSAMPLE>(planes[1], i * sizeInfo.fWidthBytes[1]);
+        rowptrs[i + 3 * DCTSIZE] =
+            SkTAddOffset<JSAMPLE>(planes[2], i * sizeInfo.fWidthBytes[2]);
     }
 
     // After each loop iteration, we will increment pointers to Y, U, and V.
-    size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY];
-    size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU];
-    size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV];
+    size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[0];
+    size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[1];
+    size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[2];
 
     uint32_t numRowsPerBlock = numYRowsPerBlock;
 
@@ -944,7 +954,7 @@
         // this requirement using a dummy row buffer.
         // FIXME: Should SkCodec have an extra memory buffer that can be shared among
         //        all of the implementations that use temporary/garbage memory?
-        SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
+        SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVAIndex::kY_Index]);
         for (int i = remainingRows; i < numYRowsPerBlock; i++) {
             rowptrs[i] = dummyRow.get();
         }
diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h
index 5eff1d5..c102627 100644
--- a/src/codec/SkJpegCodec.h
+++ b/src/codec/SkJpegCodec.h
@@ -46,7 +46,8 @@
 
     bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override;
 
-    Result onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override;
+    Result onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo,
+                           void* planes[SkYUVSizeInfo::kMaxCount]) override;
 
     SkEncodedImageFormat onGetEncodedFormat() const override {
         return SkEncodedImageFormat::kJPEG;