Adding force-dark support to RippleDrawable
Add force-dark support to RippleDrawable by modifying the ink color. Test: manual Test: atest CanvasOp Fixes: 186130682 Change-Id: I89eaaf3afa5ec53a74d2d08de8cff6484e55a912
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.graphics;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Pools.SynchronizedPool;
|
||||
@@ -227,11 +228,11 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
|
||||
public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
|
||||
CanvasProperty<Float> radius, CanvasProperty<Paint> paint,
|
||||
CanvasProperty<Float> progress, CanvasProperty<Float> turbulencePhase,
|
||||
RuntimeShader shader) {
|
||||
@ColorInt int color, RuntimeShader shader) {
|
||||
nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
|
||||
radius.getNativeContainer(), paint.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);
|
||||
@CriticalNative
|
||||
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
|
||||
private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
|
||||
long propRight, long propBottom, long propRx, long propRy, long propPaint);
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.graphics.drawable;
|
||||
import android.animation.Animator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.ColorInt;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Canvas;
|
||||
@@ -211,6 +212,7 @@ public final class RippleAnimationSession {
|
||||
CanvasProperty.createFloat(mProperties.getNoisePhase()),
|
||||
CanvasProperty.createPaint(mProperties.getPaint()),
|
||||
CanvasProperty.createFloat(mProperties.getProgress()),
|
||||
mProperties.getColor(),
|
||||
mProperties.getShader());
|
||||
}
|
||||
return mCanvasProperties;
|
||||
@@ -250,11 +252,12 @@ public final class RippleAnimationSession {
|
||||
private final FloatType mNoisePhase;
|
||||
private final PaintType mPaint;
|
||||
private final RippleShader mShader;
|
||||
private final @ColorInt int mColor;
|
||||
private FloatType mX;
|
||||
private FloatType mY;
|
||||
|
||||
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;
|
||||
mX = x;
|
||||
mMaxRadius = maxRadius;
|
||||
@@ -262,6 +265,7 @@ public final class RippleAnimationSession {
|
||||
mPaint = paint;
|
||||
mShader = shader;
|
||||
mProgress = progress;
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
FloatType getProgress() {
|
||||
@@ -296,5 +300,9 @@ public final class RippleAnimationSession {
|
||||
FloatType getNoisePhase() {
|
||||
return mNoisePhase;
|
||||
}
|
||||
|
||||
@ColorInt int getColor() {
|
||||
return mColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -902,7 +902,7 @@ public class RippleDrawable extends LayerDrawable {
|
||||
yProp = p.getY();
|
||||
}
|
||||
can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(),
|
||||
p.getProgress(), p.getNoisePhase(), p.getShader());
|
||||
p.getProgress(), p.getNoisePhase(), p.getColor(), p.getShader());
|
||||
} else {
|
||||
RippleAnimationSession.AnimationProperties<Float, Paint> p =
|
||||
s.getProperties();
|
||||
@@ -975,7 +975,7 @@ public class RippleDrawable extends LayerDrawable {
|
||||
shader.setRadius(radius);
|
||||
shader.setProgress(.0f);
|
||||
properties = new RippleAnimationSession.AnimationProperties<>(
|
||||
cx, cy, radius, 0f, p, 0f, shader);
|
||||
cx, cy, radius, 0f, p, 0f, color, shader);
|
||||
if (mMaskShader == null) {
|
||||
shader.setShader(null);
|
||||
} else {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
namespace android::uirenderer {
|
||||
|
||||
static SkColor makeLight(SkColor color) {
|
||||
SkColor makeLight(SkColor color) {
|
||||
Lab lab = sRGBToLab(color);
|
||||
float invertedL = std::min(110 - lab.L, 100.0f);
|
||||
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);
|
||||
float invertedL = std::min(110 - lab.L, 100.0f);
|
||||
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) {
|
||||
case ColorTransform::Light:
|
||||
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) {
|
||||
if (transform == ColorTransform::None) return;
|
||||
|
||||
|
||||
@@ -42,4 +42,7 @@ bool transformPaint(ColorTransform transform, SkPaint* paint);
|
||||
|
||||
bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette);
|
||||
|
||||
SkColor transformColor(ColorTransform transform, SkColor color);
|
||||
SkColor transformColorInverse(ColorTransform transform, SkColor color);
|
||||
|
||||
} // namespace android::uirenderer;
|
||||
@@ -49,4 +49,5 @@ X(DrawVertices)
|
||||
X(DrawAtlas)
|
||||
X(DrawShadowRec)
|
||||
X(DrawVectorDrawable)
|
||||
X(DrawRippleDrawable)
|
||||
X(DrawWebView)
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "SkTextBlob.h"
|
||||
#include "SkVertices.h"
|
||||
#include "VectorDrawable.h"
|
||||
#include "pipeline/skia/AnimatedDrawables.h"
|
||||
#include "pipeline/skia/FunctorDrawable.h"
|
||||
|
||||
namespace android {
|
||||
@@ -497,6 +498,18 @@ struct DrawVectorDrawable final : Op {
|
||||
SkPaint paint;
|
||||
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 {
|
||||
static const auto kType = Type::DrawWebView;
|
||||
DrawWebView(skiapipeline::FunctorDrawable* drawable) : drawable(sk_ref_sp(drawable)) {}
|
||||
@@ -721,6 +734,10 @@ void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar
|
||||
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],
|
||||
const SkPoint texs[4], SkBlendMode bmode, const SkPaint& 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>(),
|
||||
static const color_transform_fn color_transform_fns[] = {
|
||||
#include "DisplayListOps.in"
|
||||
@@ -985,6 +1012,10 @@ void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala
|
||||
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,
|
||||
const SkSamplingOptions& sampling, const SkPaint* paint,
|
||||
BitmapPalette palette) {
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
#include "SkPath.h"
|
||||
#include "SkRect.h"
|
||||
|
||||
#include "pipeline/skia/AnimatedDrawables.h"
|
||||
|
||||
#include <SkRuntimeEffect.h>
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
@@ -125,6 +128,7 @@ private:
|
||||
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&);
|
||||
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
|
||||
SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*);
|
||||
void drawRippleDrawable(const skiapipeline::RippleDrawableParams& params);
|
||||
void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
|
||||
void drawVectorDrawable(VectorDrawableRoot* tree);
|
||||
void drawWebView(skiapipeline::FunctorDrawable*);
|
||||
@@ -184,6 +188,7 @@ public:
|
||||
|
||||
void drawImage(const sk_sp<SkImage>&, SkScalar left, SkScalar top, const SkSamplingOptions&,
|
||||
const SkPaint* paint, BitmapPalette pallete);
|
||||
void drawRippleDrawable(const skiapipeline::RippleDrawableParams& params);
|
||||
|
||||
void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
|
||||
const SkSamplingOptions&, const SkPaint*, SrcRectConstraint, BitmapPalette);
|
||||
|
||||
@@ -815,17 +815,8 @@ void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
|
||||
mCanvas->drawDrawable(drawable.get());
|
||||
}
|
||||
|
||||
void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
|
||||
uirenderer::CanvasPropertyPrimitive* y,
|
||||
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::drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) {
|
||||
uirenderer::skiapipeline::AnimatedRippleDrawable::draw(mCanvas, params);
|
||||
}
|
||||
|
||||
void SkiaCanvas::drawPicture(const SkPicture& picture) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "hwui/Paint.h"
|
||||
|
||||
#include <SkCanvas.h>
|
||||
#include "pipeline/skia/AnimatedDrawables.h"
|
||||
#include "src/core/SkArenaAlloc.h"
|
||||
|
||||
#include <cassert>
|
||||
@@ -148,13 +149,7 @@ public:
|
||||
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,
|
||||
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
|
||||
const SkRuntimeShaderBuilder& effectBuilder) override;
|
||||
virtual void drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) override;
|
||||
|
||||
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
|
||||
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
|
||||
|
||||
@@ -43,7 +43,7 @@ enum class CanvasOpType : int8_t {
|
||||
DrawRoundRectProperty,
|
||||
DrawDoubleRoundRect,
|
||||
DrawCircleProperty,
|
||||
DrawRippleProperty,
|
||||
DrawRippleDrawable,
|
||||
DrawCircle,
|
||||
DrawOval,
|
||||
DrawArc,
|
||||
|
||||
@@ -145,73 +145,13 @@ struct CanvasOp<CanvasOpType::DrawCircleProperty> {
|
||||
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;
|
||||
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);
|
||||
template <>
|
||||
struct CanvasOp<CanvasOpType::DrawRippleDrawable> {
|
||||
skiapipeline::RippleDrawableParams params;
|
||||
|
||||
void draw(SkCanvas* canvas) const {
|
||||
SkRuntimeShaderBuilder runtimeEffectBuilder(effect);
|
||||
|
||||
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);
|
||||
skiapipeline::AnimatedRippleDrawable::draw(canvas, params);
|
||||
}
|
||||
|
||||
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()
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
#include "Properties.h"
|
||||
#include "pipeline/skia/AnimatedDrawables.h"
|
||||
#include "utils/Macros.h"
|
||||
|
||||
#include <SkBitmap.h>
|
||||
@@ -141,13 +142,7 @@ public:
|
||||
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,
|
||||
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
|
||||
const SkRuntimeShaderBuilder& effectBuilder) = 0;
|
||||
virtual void drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) = 0;
|
||||
|
||||
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
|
||||
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
|
||||
|
||||
@@ -144,7 +144,7 @@ static void android_view_DisplayListCanvas_drawCircleProps(CRITICAL_JNI_PARAMS_C
|
||||
static void android_view_DisplayListCanvas_drawRippleProps(
|
||||
CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jlong xPropPtr, jlong yPropPtr,
|
||||
jlong radiusPropPtr, jlong paintPropPtr, jlong progressPropPtr, jlong turbulencePhasePtr,
|
||||
jlong builderPtr) {
|
||||
jint color, jlong builderPtr) {
|
||||
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
|
||||
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
|
||||
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
|
||||
@@ -155,8 +155,12 @@ static void android_view_DisplayListCanvas_drawRippleProps(
|
||||
CanvasPropertyPrimitive* progressProp =
|
||||
reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
|
||||
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) {
|
||||
@@ -186,7 +190,7 @@ static JNINativeMethod gMethods[] = {
|
||||
{"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", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRippleProps},
|
||||
{"nDrawRipple", "(JJJJJJJIJ)V", (void*)android_view_DisplayListCanvas_drawRippleProps},
|
||||
};
|
||||
|
||||
int register_android_view_DisplayListCanvas(JNIEnv* env) {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <math.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include "CanvasProperty.h"
|
||||
#include "CanvasTransform.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
@@ -56,89 +57,80 @@ private:
|
||||
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,
|
||||
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
|
||||
const SkRuntimeShaderBuilder& effectBuilder)
|
||||
: mX(x)
|
||||
, mY(y)
|
||||
, mRadius(radius)
|
||||
, mPaint(paint)
|
||||
, mProgress(progress)
|
||||
, mTurbulencePhase(turbulencePhase)
|
||||
, mRuntimeEffectBuilder(effectBuilder) {}
|
||||
struct RippleDrawableParams {
|
||||
sp<uirenderer::CanvasPropertyPrimitive> x;
|
||||
sp<uirenderer::CanvasPropertyPrimitive> y;
|
||||
sp<uirenderer::CanvasPropertyPrimitive> radius;
|
||||
sp<uirenderer::CanvasPropertyPrimitive> progress;
|
||||
sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase;
|
||||
SkColor color;
|
||||
sp<uirenderer::CanvasPropertyPaint> paint;
|
||||
SkRuntimeShaderBuilder effectBuilder;
|
||||
};
|
||||
|
||||
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 {
|
||||
setUniform2f("in_origin", mX->value, mY->value);
|
||||
setUniform("in_radius", mRadius);
|
||||
setUniform("in_progress", mProgress);
|
||||
setUniform("in_turbulencePhase", mTurbulencePhase);
|
||||
class AnimatedRippleDrawable {
|
||||
public:
|
||||
static void draw(SkCanvas* canvas, const RippleDrawableParams& params) {
|
||||
auto& effectBuilder = const_cast<SkRuntimeShaderBuilder&>(params.effectBuilder);
|
||||
|
||||
setUniform2f(effectBuilder, "in_origin", params.x->value, params.y->value);
|
||||
setUniform(effectBuilder, "in_radius", params.radius);
|
||||
setUniform(effectBuilder, "in_progress", params.progress);
|
||||
setUniform(effectBuilder, "in_turbulencePhase", params.turbulencePhase);
|
||||
|
||||
SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform("in_color");
|
||||
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:
|
||||
// frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
|
||||
//
|
||||
const float turbulencePhase = mTurbulencePhase->value;
|
||||
setUniform2f("in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1),
|
||||
const float turbulencePhase = params.turbulencePhase->value;
|
||||
setUniform2f(effectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_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));
|
||||
setUniform2f("in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3),
|
||||
setUniform2f(effectBuilder, "in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3),
|
||||
SCALE + (turbulencePhase * CIRCLE_Y_3));
|
||||
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;
|
||||
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;
|
||||
setUniform2f("in_tRotation3", cos(rotation3), sin(rotation3));
|
||||
setUniform2f(effectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3));
|
||||
|
||||
SkPaint paint = mPaint->value;
|
||||
paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false));
|
||||
canvas->drawCircle(mX->value, mY->value, mRadius->value, paint);
|
||||
params.paint->value.setShader(effectBuilder.makeShader(nullptr, false));
|
||||
canvas->drawCircle(params.x->value, params.y->value, params.radius->value,
|
||||
params.paint->value);
|
||||
}
|
||||
|
||||
private:
|
||||
sp<uirenderer::CanvasPropertyPrimitive> mX;
|
||||
sp<uirenderer::CanvasPropertyPrimitive> mY;
|
||||
sp<uirenderer::CanvasPropertyPrimitive> mRadius;
|
||||
sp<uirenderer::CanvasPropertyPaint> mPaint;
|
||||
sp<uirenderer::CanvasPropertyPrimitive> mProgress;
|
||||
sp<uirenderer::CanvasPropertyPrimitive> mTurbulencePhase;
|
||||
SkRuntimeShaderBuilder mRuntimeEffectBuilder;
|
||||
static constexpr float PI = 3.1415926535897932384626;
|
||||
static constexpr float PI_ROTATE_RIGHT = PI * 0.0078125;
|
||||
static constexpr float PI_ROTATE_LEFT = PI * -0.0078125;
|
||||
static constexpr float SCALE = 1.5;
|
||||
|
||||
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);
|
||||
|
||||
virtual void setUniform(std::string name, sp<uirenderer::CanvasPropertyPrimitive> property) {
|
||||
SkRuntimeShaderBuilder::BuilderUniform uniform =
|
||||
mRuntimeEffectBuilder.uniform(name.c_str());
|
||||
static void setUniform(SkRuntimeShaderBuilder& effectBuilder, std::string name,
|
||||
sp<uirenderer::CanvasPropertyPrimitive> property) {
|
||||
SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name.c_str());
|
||||
if (uniform.fVar != nullptr) {
|
||||
uniform = property->value;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setUniform2f(std::string name, float a, float b) {
|
||||
SkRuntimeShaderBuilder::BuilderUniform uniform =
|
||||
mRuntimeEffectBuilder.uniform(name.c_str());
|
||||
static void setUniform2f(SkRuntimeShaderBuilder& effectBuilder, std::string name, float a,
|
||||
float b) {
|
||||
SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name.c_str());
|
||||
if (uniform.fVar != nullptr) {
|
||||
uniform = SkV2{a, b};
|
||||
}
|
||||
|
||||
@@ -109,15 +109,8 @@ void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
|
||||
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,
|
||||
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
|
||||
const SkRuntimeShaderBuilder& effectBuilder) {
|
||||
drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
|
||||
turbulencePhase, effectBuilder));
|
||||
void SkiaRecordingCanvas::drawRipple(const skiapipeline::RippleDrawableParams& params) {
|
||||
mRecorder.drawRippleDrawable(params);
|
||||
}
|
||||
|
||||
void SkiaRecordingCanvas::enableZ(bool enableZ) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "ReorderBarrierDrawables.h"
|
||||
#include "SkiaCanvas.h"
|
||||
#include "SkiaDisplayList.h"
|
||||
#include "pipeline/skia/AnimatedDrawables.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
@@ -70,13 +71,7 @@ public:
|
||||
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,
|
||||
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
|
||||
const SkRuntimeShaderBuilder& effectBuilder) override;
|
||||
virtual void drawRipple(const RippleDrawableParams& params) override;
|
||||
|
||||
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
using namespace android;
|
||||
using namespace android::uirenderer;
|
||||
using namespace android::uirenderer::skiapipeline;
|
||||
using namespace android::uirenderer::test;
|
||||
|
||||
// We lazy
|
||||
@@ -569,6 +570,33 @@ TEST(CanvasOp, simpleDrawPicture) {
|
||||
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) {
|
||||
auto canvas = std::make_shared<CallCountingCanvas>();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.CanvasProperty;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RecordingCanvas;
|
||||
import android.graphics.RuntimeShader;
|
||||
@@ -48,6 +49,7 @@ public class RippleActivity extends Activity {
|
||||
static class RippleView extends View {
|
||||
static final int DURATION = 1000;
|
||||
static final int MAX_RADIUS = 250;
|
||||
private final int mColor = Color.RED;
|
||||
|
||||
private boolean mToggle = false;
|
||||
ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
|
||||
@@ -104,7 +106,7 @@ public class RippleActivity extends Activity {
|
||||
|
||||
Paint p = new Paint();
|
||||
p.setAntiAlias(true);
|
||||
p.setColor(0xFFFF0000);
|
||||
p.setColor(mColor);
|
||||
mPaint = CanvasProperty.createPaint(p);
|
||||
|
||||
mRuntimeShader = new RuntimeShader(sSkSL, false);
|
||||
@@ -118,7 +120,7 @@ public class RippleActivity extends Activity {
|
||||
if (canvas.isHardwareAccelerated()) {
|
||||
RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
|
||||
recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mNoisePhase,
|
||||
mRuntimeShader);
|
||||
mColor, mRuntimeShader);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user