Initial framework needed to draw circle with RuntimeShader.

This also adds the ability for RenderThread to animate a few
predefined shader uniforms.

Bug: 177051137
Test: demo in ag/13296877
Change-Id: I6e58e671ad1242a07ecb1cf4cdb48031f85c2088
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index 9f46ceb..49888fd 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -204,6 +204,26 @@
     }
 
     /**
+     * Draws a ripple
+     *
+     * @param cx
+     * @param cy
+     * @param radius
+     * @param paint
+     * @param progress
+     * @param shader
+     *
+     * @hide
+     */
+    public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
+            CanvasProperty<Float> radius, CanvasProperty<Paint> paint,
+            CanvasProperty<Float> progress, RuntimeShader shader) {
+        nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
+                radius.getNativeContainer(), paint.getNativeContainer(),
+                progress.getNativeContainer(), shader.getNativeShaderFactory());
+    }
+
+    /**
      * Draws a round rect
      *
      * @param left
@@ -260,6 +280,9 @@
     private static native void nDrawCircle(long renderer, long propCx,
             long propCy, long propRadius, long propPaint);
     @CriticalNative
+    private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius,
+            long propPaint, long propProgress, long runtimeEffect);
+    @CriticalNative
     private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
             long propRight, long propBottom, long propRx, long propRy, long propPaint);
     @CriticalNative
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index fb0983a..7f2e503 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -115,6 +115,10 @@
                 nativeShaders, colorSpace().getNativeInstance(), mIsOpaque);
     }
 
+    public long getNativeShaderFactory() {
+        return mNativeInstanceRuntimeShaderFactory;
+    }
+
     private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
             long[] shaderInputs, long colorSpaceHandle, boolean isOpaque);
 
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index acb74f4..815ffde 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -814,6 +814,18 @@
     mCanvas->drawDrawable(drawable.get());
 }
 
+void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+                            uirenderer::CanvasPropertyPrimitive* y,
+                            uirenderer::CanvasPropertyPrimitive* radius,
+                            uirenderer::CanvasPropertyPaint* paint,
+                            uirenderer::CanvasPropertyPrimitive* progress,
+                            sk_sp<SkRuntimeEffect> runtimeEffect) {
+    sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
+            new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
+                                                         runtimeEffect));
+    mCanvas->drawDrawable(drawable.get());
+}
+
 void SkiaCanvas::drawPicture(const SkPicture& picture) {
     // TODO: Change to mCanvas->drawPicture()? SkCanvas::drawPicture seems to be
     // where the logic is for playback vs. ref picture. Using picture.playback here
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 591ae5c..1372bc4 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -147,6 +147,12 @@
                             uirenderer::CanvasPropertyPrimitive* y,
                             uirenderer::CanvasPropertyPrimitive* radius,
                             uirenderer::CanvasPropertyPaint* paint) override;
+    virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+                            uirenderer::CanvasPropertyPrimitive* y,
+                            uirenderer::CanvasPropertyPrimitive* radius,
+                            uirenderer::CanvasPropertyPaint* paint,
+                            uirenderer::CanvasPropertyPrimitive* progress,
+                            sk_sp<SkRuntimeEffect> runtimeEffect) override;
 
     virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
     virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
diff --git a/libs/hwui/canvas/CanvasOpTypes.h b/libs/hwui/canvas/CanvasOpTypes.h
index f0aa777..cde50bd 100644
--- a/libs/hwui/canvas/CanvasOpTypes.h
+++ b/libs/hwui/canvas/CanvasOpTypes.h
@@ -42,6 +42,7 @@
     DrawRoundRectProperty,
     DrawDoubleRoundRect,
     DrawCircleProperty,
+    DrawRippleProperty,
     DrawCircle,
     DrawOval,
     DrawArc,
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index 62c26c7..ea9fea97 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -23,6 +23,7 @@
 #include <SkVertices.h>
 #include <SkImage.h>
 #include <SkPicture.h>
+#include <SkRuntimeEffect.h>
 #include <hwui/Bitmap.h>
 #include <log/log.h>
 #include "CanvasProperty.h"
@@ -142,6 +143,42 @@
     ASSERT_DRAWABLE()
 };
 
+template<>
+struct CanvasOp<CanvasOpType::DrawRippleProperty> {
+    sp<uirenderer::CanvasPropertyPrimitive> x;
+    sp<uirenderer::CanvasPropertyPrimitive> y;
+    sp<uirenderer::CanvasPropertyPrimitive> radius;
+    sp<uirenderer::CanvasPropertyPaint> paint;
+    sp<uirenderer::CanvasPropertyPrimitive> progress;
+    sk_sp<SkRuntimeEffect> effect;
+
+    void draw(SkCanvas* canvas) const {
+        SkRuntimeShaderBuilder runtimeEffectBuilder(effect);
+
+        SkRuntimeShaderBuilder::BuilderUniform center = runtimeEffectBuilder.uniform("in_origin");
+        if (center.fVar != nullptr) {
+            center = SkV2{x->value, y->value};
+        }
+
+        SkRuntimeShaderBuilder::BuilderUniform radiusU =
+                runtimeEffectBuilder.uniform("in_maxRadius");
+        if (radiusU.fVar != nullptr) {
+            radiusU = radius->value;
+        }
+
+        SkRuntimeShaderBuilder::BuilderUniform progressU =
+                runtimeEffectBuilder.uniform("in_progress");
+        if (progressU.fVar != nullptr) {
+            progressU = progress->value;
+        }
+
+        SkPaint paintMod = paint->value;
+        paintMod.setShader(runtimeEffectBuilder.makeShader(nullptr, false));
+        canvas->drawCircle(x->value, y->value, radius->value, paintMod);
+    }
+    ASSERT_DRAWABLE()
+};
+
 template <>
 struct CanvasOp<CanvasOpType::DrawColor> {
     SkColor4f color;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 11fa322..d0c996b 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -31,6 +31,7 @@
 
 class SkAnimatedImage;
 class SkCanvasState;
+class SkRuntimeEffect;
 class SkVertices;
 
 namespace minikin {
@@ -133,6 +134,12 @@
                             uirenderer::CanvasPropertyPrimitive* y,
                             uirenderer::CanvasPropertyPrimitive* radius,
                             uirenderer::CanvasPropertyPaint* paint) = 0;
+    virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+                            uirenderer::CanvasPropertyPrimitive* y,
+                            uirenderer::CanvasPropertyPrimitive* radius,
+                            uirenderer::CanvasPropertyPaint* paint,
+                            uirenderer::CanvasPropertyPrimitive* progress,
+                            sk_sp<SkRuntimeEffect> runtimeEffect) = 0;
 
     virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
     virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
index 7c1422d..f4877f4 100644
--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -20,8 +20,8 @@
 #include <utils/Looper.h>
 #endif
 
-#include <SkBitmap.h>
 #include <SkRegion.h>
+#include <SkRuntimeEffect.h>
 
 #include <Rect.h>
 #include <RenderNode.h>
@@ -139,6 +139,21 @@
     canvas->drawCircle(xProp, yProp, radiusProp, paintProp);
 }
 
+static void android_view_DisplayListCanvas_drawRippleProps(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr,
+                                                           jlong xPropPtr, jlong yPropPtr,
+                                                           jlong radiusPropPtr, jlong paintPropPtr,
+                                                           jlong progressPropPtr, jlong effectPtr) {
+    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
+    CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
+    CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
+    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
+    CanvasPropertyPrimitive* progressProp =
+            reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
+    SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(effectPtr);
+    canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, sk_ref_sp(effect));
+}
+
 static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) {
     Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
     canvas->drawWebViewFunctor(functor);
@@ -163,6 +178,7 @@
     { "nDrawCircle",              "(JJJJJ)V",   (void*) android_view_DisplayListCanvas_drawCircleProps },
     { "nDrawRoundRect",           "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps },
     { "nDrawWebViewFunctor",      "(JI)V",      (void*) android_view_DisplayListCanvas_drawWebViewFunctor },
+    { "nDrawRipple",              "(JJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRippleProps },
 };
 
 int register_android_view_DisplayListCanvas(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index bf19655..3142d92 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -18,6 +18,7 @@
 
 #include <SkCanvas.h>
 #include <SkDrawable.h>
+#include <SkRuntimeEffect.h>
 #include <utils/RefBase.h>
 #include "CanvasProperty.h"
 
@@ -54,6 +55,59 @@
     sp<uirenderer::CanvasPropertyPaint> mPaint;
 };
 
+class AnimatedRipple : public SkDrawable {
+public:
+    AnimatedRipple(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
+                   uirenderer::CanvasPropertyPrimitive* radius,
+                   uirenderer::CanvasPropertyPaint* paint,
+                   uirenderer::CanvasPropertyPrimitive* progress,
+                   sk_sp<SkRuntimeEffect> runtimeEffect)
+            : mX(x)
+            , mY(y)
+            , mRadius(radius)
+            , mPaint(paint)
+            , mProgress(progress)
+            , mRuntimeEffectBuilder(std::move(runtimeEffect)) {}
+
+protected:
+    virtual SkRect onGetBounds() override {
+        const float x = mX->value;
+        const float y = mY->value;
+        const float radius = mRadius->value;
+        return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius);
+    }
+    virtual void onDraw(SkCanvas* canvas) override {
+        SkRuntimeShaderBuilder::BuilderUniform center = mRuntimeEffectBuilder.uniform("in_origin");
+        if (center.fVar != nullptr) {
+            center = SkV2{mX->value, mY->value};
+        }
+
+        SkRuntimeShaderBuilder::BuilderUniform radiusU =
+                mRuntimeEffectBuilder.uniform("in_maxRadius");
+        if (radiusU.fVar != nullptr) {
+            radiusU = mRadius->value;
+        }
+
+        SkRuntimeShaderBuilder::BuilderUniform progressU =
+                mRuntimeEffectBuilder.uniform("in_progress");
+        if (progressU.fVar != nullptr) {
+            progressU = mProgress->value;
+        }
+
+        SkPaint paint = mPaint->value;
+        paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false));
+        canvas->drawCircle(mX->value, mY->value, mRadius->value, paint);
+    }
+
+private:
+    sp<uirenderer::CanvasPropertyPrimitive> mX;
+    sp<uirenderer::CanvasPropertyPrimitive> mY;
+    sp<uirenderer::CanvasPropertyPrimitive> mRadius;
+    sp<uirenderer::CanvasPropertyPaint> mPaint;
+    sp<uirenderer::CanvasPropertyPrimitive> mProgress;
+    SkRuntimeShaderBuilder mRuntimeEffectBuilder;
+};
+
 class AnimatedCircle : public SkDrawable {
 public:
     AnimatedCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index e292cbd..f6a60bb 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -85,6 +85,16 @@
     drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
 }
 
+void SkiaRecordingCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+                                     uirenderer::CanvasPropertyPrimitive* y,
+                                     uirenderer::CanvasPropertyPrimitive* radius,
+                                     uirenderer::CanvasPropertyPaint* paint,
+                                     uirenderer::CanvasPropertyPrimitive* progress,
+                                     sk_sp<SkRuntimeEffect> runtimeEffect) {
+    drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
+                                                                runtimeEffect));
+}
+
 void SkiaRecordingCanvas::enableZ(bool enableZ) {
     if (mCurrentBarrier && enableZ) {
         // Already in a re-order section, nothing to do
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 83e9349..622df43 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -66,6 +66,12 @@
                             uirenderer::CanvasPropertyPrimitive* y,
                             uirenderer::CanvasPropertyPrimitive* radius,
                             uirenderer::CanvasPropertyPaint* paint) override;
+    virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+                            uirenderer::CanvasPropertyPrimitive* y,
+                            uirenderer::CanvasPropertyPrimitive* radius,
+                            uirenderer::CanvasPropertyPaint* paint,
+                            uirenderer::CanvasPropertyPrimitive* progress,
+                            sk_sp<SkRuntimeEffect> runtimeEffect) override;
 
     virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;