Merge "Adding force-dark support to RippleDrawable" into sc-dev

This commit is contained in:
Lucas Dupin
2021-05-07 01:08:43 +00:00
committed by Android (Google) Code Review
19 changed files with 177 additions and 182 deletions

View File

@@ -16,6 +16,7 @@
package android.graphics; package android.graphics;
import android.annotation.ColorInt;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.util.Pools.SynchronizedPool; import android.util.Pools.SynchronizedPool;
@@ -227,11 +228,11 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy, public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint, CanvasProperty<Float> radius, CanvasProperty<Paint> paint,
CanvasProperty<Float> progress, CanvasProperty<Float> turbulencePhase, CanvasProperty<Float> progress, CanvasProperty<Float> turbulencePhase,
RuntimeShader shader) { @ColorInt int color, RuntimeShader shader) {
nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
radius.getNativeContainer(), paint.getNativeContainer(), radius.getNativeContainer(), paint.getNativeContainer(),
progress.getNativeContainer(), turbulencePhase.getNativeContainer(), progress.getNativeContainer(), turbulencePhase.getNativeContainer(),
shader.getNativeShaderBuilder()); color, shader.getNativeShaderBuilder());
} }
/** /**
@@ -292,7 +293,7 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
long propCy, long propRadius, long propPaint); long propCy, long propRadius, long propPaint);
@CriticalNative @CriticalNative
private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius, private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius,
long propPaint, long propProgress, long turbulencePhase, long runtimeEffect); long propPaint, long propProgress, long turbulencePhase, int color, long runtimeEffect);
@CriticalNative @CriticalNative
private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
long propRight, long propBottom, long propRx, long propRy, long propPaint); long propRight, long propBottom, long propRx, long propRy, long propPaint);

View File

@@ -19,6 +19,7 @@ package android.graphics.drawable;
import android.animation.Animator; import android.animation.Animator;
import android.animation.TimeInterpolator; import android.animation.TimeInterpolator;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.annotation.ColorInt;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.graphics.Canvas; import android.graphics.Canvas;
@@ -211,6 +212,7 @@ public final class RippleAnimationSession {
CanvasProperty.createFloat(mProperties.getNoisePhase()), CanvasProperty.createFloat(mProperties.getNoisePhase()),
CanvasProperty.createPaint(mProperties.getPaint()), CanvasProperty.createPaint(mProperties.getPaint()),
CanvasProperty.createFloat(mProperties.getProgress()), CanvasProperty.createFloat(mProperties.getProgress()),
mProperties.getColor(),
mProperties.getShader()); mProperties.getShader());
} }
return mCanvasProperties; return mCanvasProperties;
@@ -250,11 +252,12 @@ public final class RippleAnimationSession {
private final FloatType mNoisePhase; private final FloatType mNoisePhase;
private final PaintType mPaint; private final PaintType mPaint;
private final RippleShader mShader; private final RippleShader mShader;
private final @ColorInt int mColor;
private FloatType mX; private FloatType mX;
private FloatType mY; private FloatType mY;
AnimationProperties(FloatType x, FloatType y, FloatType maxRadius, FloatType noisePhase, AnimationProperties(FloatType x, FloatType y, FloatType maxRadius, FloatType noisePhase,
PaintType paint, FloatType progress, RippleShader shader) { PaintType paint, FloatType progress, @ColorInt int color, RippleShader shader) {
mY = y; mY = y;
mX = x; mX = x;
mMaxRadius = maxRadius; mMaxRadius = maxRadius;
@@ -262,6 +265,7 @@ public final class RippleAnimationSession {
mPaint = paint; mPaint = paint;
mShader = shader; mShader = shader;
mProgress = progress; mProgress = progress;
mColor = color;
} }
FloatType getProgress() { FloatType getProgress() {
@@ -296,5 +300,9 @@ public final class RippleAnimationSession {
FloatType getNoisePhase() { FloatType getNoisePhase() {
return mNoisePhase; return mNoisePhase;
} }
@ColorInt int getColor() {
return mColor;
}
} }
} }

View File

@@ -901,7 +901,7 @@ public class RippleDrawable extends LayerDrawable {
yProp = p.getY(); yProp = p.getY();
} }
can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(), can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(),
p.getProgress(), p.getNoisePhase(), p.getShader()); p.getProgress(), p.getNoisePhase(), p.getColor(), p.getShader());
} else { } else {
RippleAnimationSession.AnimationProperties<Float, Paint> p = RippleAnimationSession.AnimationProperties<Float, Paint> p =
s.getProperties(); s.getProperties();
@@ -974,7 +974,7 @@ public class RippleDrawable extends LayerDrawable {
shader.setRadius(radius); shader.setRadius(radius);
shader.setProgress(.0f); shader.setProgress(.0f);
properties = new RippleAnimationSession.AnimationProperties<>( properties = new RippleAnimationSession.AnimationProperties<>(
cx, cy, radius, 0f, p, 0f, shader); cx, cy, radius, 0f, p, 0f, color, shader);
if (mMaskShader == null) { if (mMaskShader == null) {
shader.setShader(null); shader.setShader(null);
} else { } else {

View File

@@ -31,7 +31,7 @@
namespace android::uirenderer { namespace android::uirenderer {
static SkColor makeLight(SkColor color) { SkColor makeLight(SkColor color) {
Lab lab = sRGBToLab(color); Lab lab = sRGBToLab(color);
float invertedL = std::min(110 - lab.L, 100.0f); float invertedL = std::min(110 - lab.L, 100.0f);
if (invertedL > lab.L) { if (invertedL > lab.L) {
@@ -42,7 +42,7 @@ static SkColor makeLight(SkColor color) {
} }
} }
static SkColor makeDark(SkColor color) { SkColor makeDark(SkColor color) {
Lab lab = sRGBToLab(color); Lab lab = sRGBToLab(color);
float invertedL = std::min(110 - lab.L, 100.0f); float invertedL = std::min(110 - lab.L, 100.0f);
if (invertedL < lab.L) { if (invertedL < lab.L) {
@@ -53,7 +53,7 @@ static SkColor makeDark(SkColor color) {
} }
} }
static SkColor transformColor(ColorTransform transform, SkColor color) { SkColor transformColor(ColorTransform transform, SkColor color) {
switch (transform) { switch (transform) {
case ColorTransform::Light: case ColorTransform::Light:
return makeLight(color); return makeLight(color);
@@ -64,6 +64,17 @@ static SkColor transformColor(ColorTransform transform, SkColor color) {
} }
} }
SkColor transformColorInverse(ColorTransform transform, SkColor color) {
switch (transform) {
case ColorTransform::Dark:
return makeLight(color);
case ColorTransform::Light:
return makeDark(color);
default:
return color;
}
}
static void applyColorTransform(ColorTransform transform, SkPaint& paint) { static void applyColorTransform(ColorTransform transform, SkPaint& paint) {
if (transform == ColorTransform::None) return; if (transform == ColorTransform::None) return;

View File

@@ -42,4 +42,7 @@ bool transformPaint(ColorTransform transform, SkPaint* paint);
bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette); bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette);
SkColor transformColor(ColorTransform transform, SkColor color);
SkColor transformColorInverse(ColorTransform transform, SkColor color);
} // namespace android::uirenderer; } // namespace android::uirenderer;

View File

@@ -49,4 +49,5 @@ X(DrawVertices)
X(DrawAtlas) X(DrawAtlas)
X(DrawShadowRec) X(DrawShadowRec)
X(DrawVectorDrawable) X(DrawVectorDrawable)
X(DrawRippleDrawable)
X(DrawWebView) X(DrawWebView)

View File

@@ -36,6 +36,7 @@
#include "SkTextBlob.h" #include "SkTextBlob.h"
#include "SkVertices.h" #include "SkVertices.h"
#include "VectorDrawable.h" #include "VectorDrawable.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/FunctorDrawable.h" #include "pipeline/skia/FunctorDrawable.h"
namespace android { namespace android {
@@ -497,6 +498,18 @@ struct DrawVectorDrawable final : Op {
SkPaint paint; SkPaint paint;
BitmapPalette palette; BitmapPalette palette;
}; };
struct DrawRippleDrawable final : Op {
static const auto kType = Type::DrawRippleDrawable;
DrawRippleDrawable(const skiapipeline::RippleDrawableParams& params) : mParams(params) {}
void draw(SkCanvas* canvas, const SkMatrix&) const {
skiapipeline::AnimatedRippleDrawable::draw(canvas, mParams);
}
skiapipeline::RippleDrawableParams mParams;
};
struct DrawWebView final : Op { struct DrawWebView final : Op {
static const auto kType = Type::DrawWebView; static const auto kType = Type::DrawWebView;
DrawWebView(skiapipeline::FunctorDrawable* drawable) : drawable(sk_ref_sp(drawable)) {} DrawWebView(skiapipeline::FunctorDrawable* drawable) : drawable(sk_ref_sp(drawable)) {}
@@ -721,6 +734,10 @@ void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar
mHasText = true; mHasText = true;
} }
void DisplayListData::drawRippleDrawable(const skiapipeline::RippleDrawableParams& params) {
this->push<DrawRippleDrawable>(0, params);
}
void DisplayListData::drawPatch(const SkPoint points[12], const SkColor colors[4], void DisplayListData::drawPatch(const SkPoint points[12], const SkColor colors[4],
const SkPoint texs[4], SkBlendMode bmode, const SkPaint& paint) { const SkPoint texs[4], SkBlendMode bmode, const SkPaint& paint) {
this->push<DrawPatch>(0, points, colors, texs, bmode, paint); this->push<DrawPatch>(0, points, colors, texs, bmode, paint);
@@ -851,6 +868,16 @@ constexpr color_transform_fn colorTransformForOp<DrawTextBlob>() {
}; };
} }
template <>
constexpr color_transform_fn colorTransformForOp<DrawRippleDrawable>() {
return [](const void* opRaw, ColorTransform transform) {
const DrawRippleDrawable* op = reinterpret_cast<const DrawRippleDrawable*>(opRaw);
// Ripple drawable needs to contrast against the background, so we need the inverse color.
SkColor color = transformColorInverse(transform, op->mParams.color);
const_cast<DrawRippleDrawable*>(op)->mParams.color = color;
};
}
#define X(T) colorTransformForOp<T>(), #define X(T) colorTransformForOp<T>(),
static const color_transform_fn color_transform_fns[] = { static const color_transform_fn color_transform_fns[] = {
#include "DisplayListOps.in" #include "DisplayListOps.in"
@@ -985,6 +1012,10 @@ void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala
fDL->drawTextBlob(blob, x, y, paint); fDL->drawTextBlob(blob, x, y, paint);
} }
void RecordingCanvas::drawRippleDrawable(const skiapipeline::RippleDrawableParams& params) {
fDL->drawRippleDrawable(params);
}
void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y, void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y,
const SkSamplingOptions& sampling, const SkPaint* paint, const SkSamplingOptions& sampling, const SkPaint* paint,
BitmapPalette palette) { BitmapPalette palette) {

View File

@@ -29,6 +29,9 @@
#include "SkPath.h" #include "SkPath.h"
#include "SkRect.h" #include "SkRect.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include <SkRuntimeEffect.h>
#include <vector> #include <vector>
namespace android { namespace android {
@@ -125,6 +128,7 @@ private:
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&); void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&);
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*); SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*);
void drawRippleDrawable(const skiapipeline::RippleDrawableParams& params);
void drawShadowRec(const SkPath&, const SkDrawShadowRec&); void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
void drawVectorDrawable(VectorDrawableRoot* tree); void drawVectorDrawable(VectorDrawableRoot* tree);
void drawWebView(skiapipeline::FunctorDrawable*); void drawWebView(skiapipeline::FunctorDrawable*);
@@ -184,6 +188,7 @@ public:
void drawImage(const sk_sp<SkImage>&, SkScalar left, SkScalar top, const SkSamplingOptions&, void drawImage(const sk_sp<SkImage>&, SkScalar left, SkScalar top, const SkSamplingOptions&,
const SkPaint* paint, BitmapPalette pallete); const SkPaint* paint, BitmapPalette pallete);
void drawRippleDrawable(const skiapipeline::RippleDrawableParams& params);
void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst, void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
const SkSamplingOptions&, const SkPaint*, SrcRectConstraint, BitmapPalette); const SkSamplingOptions&, const SkPaint*, SrcRectConstraint, BitmapPalette);

View File

@@ -815,17 +815,8 @@ void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
mCanvas->drawDrawable(drawable.get()); mCanvas->drawDrawable(drawable.get());
} }
void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x, void SkiaCanvas::drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) {
uirenderer::CanvasPropertyPrimitive* y, uirenderer::skiapipeline::AnimatedRippleDrawable::draw(mCanvas, params);
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) {
sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
turbulencePhase, effectBuilder));
mCanvas->drawDrawable(drawable.get());
} }
void SkiaCanvas::drawPicture(const SkPicture& picture) { void SkiaCanvas::drawPicture(const SkPicture& picture) {

View File

@@ -25,6 +25,7 @@
#include "hwui/Paint.h" #include "hwui/Paint.h"
#include <SkCanvas.h> #include <SkCanvas.h>
#include "pipeline/skia/AnimatedDrawables.h"
#include "src/core/SkArenaAlloc.h" #include "src/core/SkArenaAlloc.h"
#include <cassert> #include <cassert>
@@ -148,13 +149,7 @@ public:
uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) override; uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x, virtual void drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) override;
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) override;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override; virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override; virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;

View File

@@ -43,7 +43,7 @@ enum class CanvasOpType : int8_t {
DrawRoundRectProperty, DrawRoundRectProperty,
DrawDoubleRoundRect, DrawDoubleRoundRect,
DrawCircleProperty, DrawCircleProperty,
DrawRippleProperty, DrawRippleDrawable,
DrawCircle, DrawCircle,
DrawOval, DrawOval,
DrawArc, DrawArc,

View File

@@ -145,73 +145,13 @@ struct CanvasOp<CanvasOpType::DrawCircleProperty> {
ASSERT_DRAWABLE() ASSERT_DRAWABLE()
}; };
template<> template <>
struct CanvasOp<CanvasOpType::DrawRippleProperty> { struct CanvasOp<CanvasOpType::DrawRippleDrawable> {
sp<uirenderer::CanvasPropertyPrimitive> x; skiapipeline::RippleDrawableParams params;
sp<uirenderer::CanvasPropertyPrimitive> y;
sp<uirenderer::CanvasPropertyPrimitive> radius;
sp<uirenderer::CanvasPropertyPaint> paint;
sp<uirenderer::CanvasPropertyPrimitive> progress;
sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase;
sk_sp<SkRuntimeEffect> effect;
const float PI = 3.1415926535897932384626;
const float PI_ROTATE_RIGHT = PI * 0.0078125;
const float PI_ROTATE_LEFT = PI * -0.0078125;
const float SCALE = 1.5;
const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55);
const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55);
const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45);
const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45);
const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35);
const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35);
void draw(SkCanvas* canvas) const { void draw(SkCanvas* canvas) const {
SkRuntimeShaderBuilder runtimeEffectBuilder(effect); skiapipeline::AnimatedRippleDrawable::draw(canvas, params);
setUniform2f(runtimeEffectBuilder, "in_origin", x->value, y->value);
setUniform(runtimeEffectBuilder, "in_radius", radius);
setUniform(runtimeEffectBuilder, "in_progress", progress);
setUniform(runtimeEffectBuilder, "in_turbulencePhase", turbulencePhase);
//
// Keep in sync with:
// frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
//
const float turbulence = turbulencePhase->value;
setUniform2f(runtimeEffectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulence * CIRCLE_X_1),
SCALE * 0.5 + (turbulence * CIRCLE_Y_1));
setUniform2f(runtimeEffectBuilder, "in_tCircle2", SCALE * 0.2 + (turbulence * CIRCLE_X_2),
SCALE * 0.2 + (turbulence * CIRCLE_Y_2));
setUniform2f(runtimeEffectBuilder, "in_tCircle3", SCALE + (turbulence * CIRCLE_X_3),
SCALE + (turbulence * CIRCLE_Y_3));
const float rotation1 = turbulence * PI_ROTATE_RIGHT + 1.7 * PI;
setUniform2f(runtimeEffectBuilder, "in_tRotation1", cos(rotation1), sin(rotation1));
const float rotation2 = turbulence * PI_ROTATE_LEFT + 2 * PI;
setUniform2f(runtimeEffectBuilder, "in_tRotation2", cos(rotation2), sin(rotation2));
const float rotation3 = turbulence * PI_ROTATE_RIGHT + 2.75 * PI;
setUniform2f(runtimeEffectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3));
SkPaint paintMod = paint->value;
paintMod.setShader(runtimeEffectBuilder.makeShader(nullptr, false));
canvas->drawCircle(x->value, y->value, radius->value, paintMod);
} }
void setUniform(SkRuntimeShaderBuilder& effect, std::string name,
sp<uirenderer::CanvasPropertyPrimitive> property) const {
SkRuntimeShaderBuilder::BuilderUniform uniform = effect.uniform(name.c_str());
if (uniform.fVar != nullptr) {
uniform = property->value;
}
}
void setUniform2f(SkRuntimeShaderBuilder effect, std::string name, float a, float b) const {
SkRuntimeShaderBuilder::BuilderUniform uniform = effect.uniform(name.c_str());
if (uniform.fVar != nullptr) {
uniform = SkV2{a, b};
}
}
ASSERT_DRAWABLE() ASSERT_DRAWABLE()
}; };

View File

@@ -22,6 +22,7 @@
#include <androidfw/ResourceTypes.h> #include <androidfw/ResourceTypes.h>
#include "Properties.h" #include "Properties.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include "utils/Macros.h" #include "utils/Macros.h"
#include <SkBitmap.h> #include <SkBitmap.h>
@@ -141,13 +142,7 @@ public:
uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) = 0; uirenderer::CanvasPropertyPaint* paint) = 0;
virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x, virtual void drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) = 0;
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) = 0;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0; virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0; virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;

View File

@@ -144,7 +144,7 @@ static void android_view_DisplayListCanvas_drawCircleProps(CRITICAL_JNI_PARAMS_C
static void android_view_DisplayListCanvas_drawRippleProps( static void android_view_DisplayListCanvas_drawRippleProps(
CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jlong xPropPtr, jlong yPropPtr,
jlong radiusPropPtr, jlong paintPropPtr, jlong progressPropPtr, jlong turbulencePhasePtr, jlong radiusPropPtr, jlong paintPropPtr, jlong progressPropPtr, jlong turbulencePhasePtr,
jlong builderPtr) { jint color, jlong builderPtr) {
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr); CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr); CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
@@ -155,8 +155,12 @@ static void android_view_DisplayListCanvas_drawRippleProps(
CanvasPropertyPrimitive* progressProp = CanvasPropertyPrimitive* progressProp =
reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr); reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(builderPtr); SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(builderPtr);
canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, turbulencePhaseProp,
*builder); const uirenderer::skiapipeline::RippleDrawableParams params =
uirenderer::skiapipeline::RippleDrawableParams{
xProp, yProp, radiusProp, progressProp, turbulencePhaseProp,
(SkColor)color, paintProp, *builder};
canvas->drawRipple(params);
} }
static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) { static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) {
@@ -186,7 +190,7 @@ static JNINativeMethod gMethods[] = {
{"nDrawCircle", "(JJJJJ)V", (void*)android_view_DisplayListCanvas_drawCircleProps}, {"nDrawCircle", "(JJJJJ)V", (void*)android_view_DisplayListCanvas_drawCircleProps},
{"nDrawRoundRect", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRoundRectProps}, {"nDrawRoundRect", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRoundRectProps},
{"nDrawWebViewFunctor", "(JI)V", (void*)android_view_DisplayListCanvas_drawWebViewFunctor}, {"nDrawWebViewFunctor", "(JI)V", (void*)android_view_DisplayListCanvas_drawWebViewFunctor},
{"nDrawRipple", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRippleProps}, {"nDrawRipple", "(JJJJJJJIJ)V", (void*)android_view_DisplayListCanvas_drawRippleProps},
}; };
int register_android_view_DisplayListCanvas(JNIEnv* env) { int register_android_view_DisplayListCanvas(JNIEnv* env) {

View File

@@ -22,6 +22,7 @@
#include <math.h> #include <math.h>
#include <utils/RefBase.h> #include <utils/RefBase.h>
#include "CanvasProperty.h" #include "CanvasProperty.h"
#include "CanvasTransform.h"
namespace android { namespace android {
namespace uirenderer { namespace uirenderer {
@@ -56,89 +57,80 @@ private:
sp<uirenderer::CanvasPropertyPaint> mPaint; sp<uirenderer::CanvasPropertyPaint> mPaint;
}; };
class AnimatedRipple : public SkDrawable { struct RippleDrawableParams {
public: sp<uirenderer::CanvasPropertyPrimitive> x;
AnimatedRipple(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y, sp<uirenderer::CanvasPropertyPrimitive> y;
uirenderer::CanvasPropertyPrimitive* radius, sp<uirenderer::CanvasPropertyPrimitive> radius;
uirenderer::CanvasPropertyPaint* paint, sp<uirenderer::CanvasPropertyPrimitive> progress;
uirenderer::CanvasPropertyPrimitive* progress, sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase;
uirenderer::CanvasPropertyPrimitive* turbulencePhase, SkColor color;
const SkRuntimeShaderBuilder& effectBuilder) sp<uirenderer::CanvasPropertyPaint> paint;
: mX(x) SkRuntimeShaderBuilder effectBuilder;
, mY(y) };
, mRadius(radius)
, mPaint(paint)
, mProgress(progress)
, mTurbulencePhase(turbulencePhase)
, mRuntimeEffectBuilder(effectBuilder) {}
protected: class AnimatedRippleDrawable {
virtual SkRect onGetBounds() override { public:
const float x = mX->value; static void draw(SkCanvas* canvas, const RippleDrawableParams& params) {
const float y = mY->value; auto& effectBuilder = const_cast<SkRuntimeShaderBuilder&>(params.effectBuilder);
const float radius = mRadius->value;
return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius); setUniform2f(effectBuilder, "in_origin", params.x->value, params.y->value);
} setUniform(effectBuilder, "in_radius", params.radius);
virtual void onDraw(SkCanvas* canvas) override { setUniform(effectBuilder, "in_progress", params.progress);
setUniform2f("in_origin", mX->value, mY->value); setUniform(effectBuilder, "in_turbulencePhase", params.turbulencePhase);
setUniform("in_radius", mRadius);
setUniform("in_progress", mProgress); SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform("in_color");
setUniform("in_turbulencePhase", mTurbulencePhase); if (uniform.fVar != nullptr) {
uniform = SkV4{SkColorGetR(params.color) / 255.0f, SkColorGetG(params.color) / 255.0f,
SkColorGetB(params.color) / 255.0f, SkColorGetA(params.color) / 255.0f};
}
const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55);
const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55);
const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45);
const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45);
const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35);
const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35);
// //
// Keep in sync with: // Keep in sync with:
// frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
// //
const float turbulencePhase = mTurbulencePhase->value; const float turbulencePhase = params.turbulencePhase->value;
setUniform2f("in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1), setUniform2f(effectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1),
SCALE * 0.5 + (turbulencePhase * CIRCLE_Y_1)); SCALE * 0.5 + (turbulencePhase * CIRCLE_Y_1));
setUniform2f("in_tCircle2", SCALE * 0.2 + (turbulencePhase * CIRCLE_X_2), setUniform2f(effectBuilder, "in_tCircle2", SCALE * 0.2 + (turbulencePhase * CIRCLE_X_2),
SCALE * 0.2 + (turbulencePhase * CIRCLE_Y_2)); SCALE * 0.2 + (turbulencePhase * CIRCLE_Y_2));
setUniform2f("in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3), setUniform2f(effectBuilder, "in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3),
SCALE + (turbulencePhase * CIRCLE_Y_3)); SCALE + (turbulencePhase * CIRCLE_Y_3));
const float rotation1 = turbulencePhase * PI_ROTATE_RIGHT + 1.7 * PI; const float rotation1 = turbulencePhase * PI_ROTATE_RIGHT + 1.7 * PI;
setUniform2f("in_tRotation1", cos(rotation1), sin(rotation1)); setUniform2f(effectBuilder, "in_tRotation1", cos(rotation1), sin(rotation1));
const float rotation2 = turbulencePhase * PI_ROTATE_LEFT + 2 * PI; const float rotation2 = turbulencePhase * PI_ROTATE_LEFT + 2 * PI;
setUniform2f("in_tRotation2", cos(rotation2), sin(rotation2)); setUniform2f(effectBuilder, "in_tRotation2", cos(rotation2), sin(rotation2));
const float rotation3 = turbulencePhase * PI_ROTATE_RIGHT + 2.75 * PI; const float rotation3 = turbulencePhase * PI_ROTATE_RIGHT + 2.75 * PI;
setUniform2f("in_tRotation3", cos(rotation3), sin(rotation3)); setUniform2f(effectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3));
SkPaint paint = mPaint->value; params.paint->value.setShader(effectBuilder.makeShader(nullptr, false));
paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false)); canvas->drawCircle(params.x->value, params.y->value, params.radius->value,
canvas->drawCircle(mX->value, mY->value, mRadius->value, paint); params.paint->value);
} }
private: private:
sp<uirenderer::CanvasPropertyPrimitive> mX; static constexpr float PI = 3.1415926535897932384626;
sp<uirenderer::CanvasPropertyPrimitive> mY; static constexpr float PI_ROTATE_RIGHT = PI * 0.0078125;
sp<uirenderer::CanvasPropertyPrimitive> mRadius; static constexpr float PI_ROTATE_LEFT = PI * -0.0078125;
sp<uirenderer::CanvasPropertyPaint> mPaint; static constexpr float SCALE = 1.5;
sp<uirenderer::CanvasPropertyPrimitive> mProgress;
sp<uirenderer::CanvasPropertyPrimitive> mTurbulencePhase;
SkRuntimeShaderBuilder mRuntimeEffectBuilder;
const float PI = 3.1415926535897932384626; static void setUniform(SkRuntimeShaderBuilder& effectBuilder, std::string name,
const float PI_ROTATE_RIGHT = PI * 0.0078125; sp<uirenderer::CanvasPropertyPrimitive> property) {
const float PI_ROTATE_LEFT = PI * -0.0078125; SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name.c_str());
const float SCALE = 1.5;
const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55);
const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55);
const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45);
const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45);
const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35);
const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35);
virtual void setUniform(std::string name, sp<uirenderer::CanvasPropertyPrimitive> property) {
SkRuntimeShaderBuilder::BuilderUniform uniform =
mRuntimeEffectBuilder.uniform(name.c_str());
if (uniform.fVar != nullptr) { if (uniform.fVar != nullptr) {
uniform = property->value; uniform = property->value;
} }
} }
virtual void setUniform2f(std::string name, float a, float b) { static void setUniform2f(SkRuntimeShaderBuilder& effectBuilder, std::string name, float a,
SkRuntimeShaderBuilder::BuilderUniform uniform = float b) {
mRuntimeEffectBuilder.uniform(name.c_str()); SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name.c_str());
if (uniform.fVar != nullptr) { if (uniform.fVar != nullptr) {
uniform = SkV2{a, b}; uniform = SkV2{a, b};
} }

View File

@@ -109,15 +109,8 @@ void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint)); drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
} }
void SkiaRecordingCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x, void SkiaRecordingCanvas::drawRipple(const skiapipeline::RippleDrawableParams& params) {
uirenderer::CanvasPropertyPrimitive* y, mRecorder.drawRippleDrawable(params);
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) {
drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
turbulencePhase, effectBuilder));
} }
void SkiaRecordingCanvas::enableZ(bool enableZ) { void SkiaRecordingCanvas::enableZ(bool enableZ) {

View File

@@ -20,6 +20,7 @@
#include "ReorderBarrierDrawables.h" #include "ReorderBarrierDrawables.h"
#include "SkiaCanvas.h" #include "SkiaCanvas.h"
#include "SkiaDisplayList.h" #include "SkiaDisplayList.h"
#include "pipeline/skia/AnimatedDrawables.h"
namespace android { namespace android {
namespace uirenderer { namespace uirenderer {
@@ -70,13 +71,7 @@ public:
uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) override; uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x, virtual void drawRipple(const RippleDrawableParams& params) override;
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override; virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;

View File

@@ -31,6 +31,7 @@
using namespace android; using namespace android;
using namespace android::uirenderer; using namespace android::uirenderer;
using namespace android::uirenderer::skiapipeline;
using namespace android::uirenderer::test; using namespace android::uirenderer::test;
// We lazy // We lazy
@@ -569,6 +570,33 @@ TEST(CanvasOp, simpleDrawPicture) {
EXPECT_EQ(2, canvas.sumTotalDrawCalls()); EXPECT_EQ(2, canvas.sumTotalDrawCalls());
} }
TEST(CanvasOp, simpleDrawRipple) {
CanvasOpBuffer buffer;
EXPECT_EQ(buffer.size(), 0);
const char* sksl =
"half4 main(float2 coord) {"
" return half4(1.);"
"}";
auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(sksl));
auto params = RippleDrawableParams{
.x = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(100)),
.y = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(200)),
.radius = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(50)),
.progress = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(0.5)),
.turbulencePhase = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(1)),
.color = 0xff00ff,
.paint = sp<CanvasPropertyPaint>(new CanvasPropertyPaint(SkPaint{})),
.effectBuilder = SkRuntimeShaderBuilder(effect)};
buffer.push<Op::DrawRippleDrawable>({.params = params});
CallCountingCanvas canvas;
EXPECT_EQ(0, canvas.sumTotalDrawCalls());
rasterizeCanvasBuffer(buffer, &canvas);
EXPECT_EQ(1, canvas.drawOvalCount);
EXPECT_EQ(1, canvas.sumTotalDrawCalls());
}
TEST(CanvasOp, immediateRendering) { TEST(CanvasOp, immediateRendering) {
auto canvas = std::make_shared<CallCountingCanvas>(); auto canvas = std::make_shared<CallCountingCanvas>();

View File

@@ -20,6 +20,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.CanvasProperty; import android.graphics.CanvasProperty;
import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.RecordingCanvas; import android.graphics.RecordingCanvas;
import android.graphics.RuntimeShader; import android.graphics.RuntimeShader;
@@ -48,6 +49,7 @@ public class RippleActivity extends Activity {
static class RippleView extends View { static class RippleView extends View {
static final int DURATION = 1000; static final int DURATION = 1000;
static final int MAX_RADIUS = 250; static final int MAX_RADIUS = 250;
private final int mColor = Color.RED;
private boolean mToggle = false; private boolean mToggle = false;
ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>(); ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
@@ -104,7 +106,7 @@ public class RippleActivity extends Activity {
Paint p = new Paint(); Paint p = new Paint();
p.setAntiAlias(true); p.setAntiAlias(true);
p.setColor(0xFFFF0000); p.setColor(mColor);
mPaint = CanvasProperty.createPaint(p); mPaint = CanvasProperty.createPaint(p);
mRuntimeShader = new RuntimeShader(sSkSL, false); mRuntimeShader = new RuntimeShader(sSkSL, false);
@@ -118,7 +120,7 @@ public class RippleActivity extends Activity {
if (canvas.isHardwareAccelerated()) { if (canvas.isHardwareAccelerated()) {
RecordingCanvas recordingCanvas = (RecordingCanvas) canvas; RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mNoisePhase, recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mNoisePhase,
mRuntimeShader); mColor, mRuntimeShader);
} }
} }