Make experimental_drawImageSet support per-quad alpha.

The V0 version of this will use the product of the "global" and per-quad
alpha.

A new V1 version is added that does not take a global alpha.

The V0 version will be removed once SkiaRenderer no longer uses it.


Bug: skia:8563
Change-Id: Iace3dff6c4f1fd1a5c6c30eb8226f4815c58e0ed
Reviewed-on: https://skia-review.googlesource.com/c/172146
Commit-Queue: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Auto-Submit: Brian Salomon <bsalomon@google.com>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index e8fa60a..0ff997c 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -57,6 +57,23 @@
 #define RETURN_ON_FALSE(pred)   do { if (!(pred)) return; } while (0)
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
+                                       const SkRect& dstRect, unsigned aaFlags)
+        : fImage(std::move(image))
+        , fSrcRect(srcRect)
+        , fDstRect(dstRect)
+        , fAlpha(1.f)
+        , fAAFlags(aaFlags) {}
+
+SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
+                                       const SkRect& dstRect, float alpha, unsigned aaFlags)
+        : fImage(std::move(image))
+        , fSrcRect(srcRect)
+        , fDstRect(dstRect)
+        , fAlpha(alpha)
+        , fAAFlags(aaFlags) {}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
 /*
  *  Return true if the drawing this rect would hit every pixels in the canvas.
@@ -1803,6 +1820,15 @@
     this->onDrawImageSet(imageSet, cnt, alpha, filterQuality, mode);
 }
 
+void SkCanvas::experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
+                                           SkFilterQuality filterQuality, SkBlendMode mode) {
+    TRACE_EVENT0("skia", TRACE_FUNC);
+    RETURN_ON_NULL(imageSet);
+    RETURN_ON_FALSE(cnt);
+
+    this->onDrawImageSet(imageSet, cnt, 1.f, filterQuality, mode);
+}
+
 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
     TRACE_EVENT0("skia", TRACE_FUNC);
     if (bitmap.drawsNothing()) {
diff --git a/src/core/SkColorSpaceXformCanvas.cpp b/src/core/SkColorSpaceXformCanvas.cpp
index 9ae9cb7..1e33ba7 100644
--- a/src/core/SkColorSpaceXformCanvas.cpp
+++ b/src/core/SkColorSpaceXformCanvas.cpp
@@ -178,6 +178,7 @@
             xformedSet[i].fImage = this->prepareImage(set[i].fImage.get());
             xformedSet[i].fSrcRect = set[i].fSrcRect;
             xformedSet[i].fDstRect = set[i].fDstRect;
+            xformedSet[i].fAlpha = set[i].fAlpha;
             xformedSet[i].fAAFlags = set[i].fAAFlags;
         }
         fTarget->experimental_DrawImageSetV0(xformedSet.get(), count, alpha, filterQuality, mode);
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 8b5a890..f93eb2c 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -207,13 +207,14 @@
                                 SkFilterQuality filterQuality, SkBlendMode mode) {
     SkPaint paint;
     paint.setFilterQuality(SkTPin(filterQuality, kNone_SkFilterQuality, kLow_SkFilterQuality));
-    paint.setAlpha(SkToUInt(SkTClamp(SkScalarRoundToInt(alpha * 255), 0, 255)));
     paint.setBlendMode(mode);
     for (int i = 0; i < count; ++i) {
         // TODO: Handle per-edge AA. Right now this mirrors the SkiaRenderer component of Chrome
         // which turns off antialiasing unless all four edges should be antialiased. This avoids
         // seaming in tiled composited layers.
         paint.setAntiAlias(images[i].fAAFlags == SkCanvas::kAll_QuadAAFlags);
+        paint.setAlpha(
+                SkToUInt(SkTClamp(SkScalarRoundToInt(images[i].fAlpha * alpha * 255), 0, 255)));
         this->drawImageRect(images[i].fImage.get(), &images[i].fSrcRect, images[i].fDstRect, paint,
                             SkCanvas::kFast_SrcRectConstraint);
     }
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index caa3763..7c1a556 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -362,6 +362,7 @@
                 set[i].fImage = sk_ref_sp(fPictureData->getImage(reader));
                 reader->readRect(&set[i].fSrcRect);
                 reader->readRect(&set[i].fDstRect);
+                set[i].fAlpha = reader->readScalar();
                 set[i].fAAFlags = reader->readUInt();
             }
             BREAK_ON_READ_ERROR(reader);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 8c3ad22..5c2945e 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -544,9 +544,9 @@
 
 void SkPictureRecord::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha,
                                      SkFilterQuality filterQuality, SkBlendMode mode) {
-    // op + count + alpha + fq + mode + (image index, src rect, dst rect, aa flags) * cnt
-    size_t size =
-            4 * kUInt32Size + sizeof(SkScalar) + (2 * kUInt32Size + 2 * sizeof(SkRect)) * count;
+    // op + count + alpha + fq + mode + (image index, src rect, dst rect, alpha, aa flags) * cnt
+    size_t size = 4 * kUInt32Size + sizeof(SkScalar) +
+                  (2 * kUInt32Size + 2 * sizeof(SkRect) + sizeof(SkScalar)) * count;
     size_t initialOffset = this->addDraw(DRAW_IMAGE_SET, &size);
     this->addInt(count);
     this->addScalar(SkFloatToScalar(alpha));
@@ -556,6 +556,7 @@
         this->addImage(set[i].fImage.get());
         this->addRect(set[i].fSrcRect);
         this->addRect(set[i].fDstRect);
+        this->addScalar(set[i].fAlpha);
         this->addInt((int)set[i].fAAFlags);
     }
     this->validate(initialOffset, size);
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index df2ea29..b26ff20 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -143,6 +143,7 @@
         sk_sp<GrTextureProxy> fProxy;
         SkRect fSrcRect;
         SkRect fDstRect;
+        float fAlpha;
         GrQuadAAFlags fAAFlags;
     };
     /**
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index e36b0ce..66688bf 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1506,6 +1506,7 @@
         }
         textures[i].fSrcRect = set[i].fSrcRect;
         textures[i].fDstRect = set[i].fDstRect;
+        textures[i].fAlpha = set[i].fAlpha;
         textures[i].fAAFlags = SkToGrQuadAAFlags(set[i].fAAFlags);
         if (n > 0 &&
             (textures[i].fProxy->textureType() != textures[base].fProxy->textureType() ||
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 953b9bf..22ef9fc 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -376,7 +376,8 @@
                 mustFilter = quadType != GrQuadType::kRect ||
                              filter_has_effect_for_rect_stays_rect(quad, set[p].fSrcRect);
             }
-            SkPMColor4f color{alpha, alpha, alpha, alpha};
+            float quadAlpha = SkTPin(set[p].fAlpha, 0.f, 1.f) * alpha;
+            SkPMColor4f color{quadAlpha, quadAlpha, quadAlpha, quadAlpha};
             fQuads.emplace_back(set[p].fSrcRect, quad, aaFlags, SkCanvas::kFast_SrcRectConstraint,
                                 color);
         }