Added BlurShader API

Created BlurShader framework API along with
native implementation as an implementation of
the Shader wrapper that maps to either
SkShader or SkImageFilter

Bug: 143468037
Test: Added CTS test to verify BlurShader

Change-Id: I05fcf7ba79e9d552f8b0738f7382f7826cd94e21
This commit is contained in:
Nader Jawad 2020-08-17 17:15:54 -07:00
parent fc42a99ea5
commit 322cb9c4e8
10 changed files with 299 additions and 1 deletions

View File

@ -14250,6 +14250,10 @@ package android.graphics {
enum_constant public static final android.graphics.BlurMaskFilter.Blur SOLID;
}
public final class BlurShader extends android.graphics.Shader {
ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
}
public class Camera {
ctor public Camera();
method public void applyToCanvas(android.graphics.Canvas);

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.graphics;
import android.annotation.Nullable;
/**
* A subclass of shader that blurs input from another {@link android.graphics.Shader} instance
* or all the drawing commands with the {@link android.graphics.Paint} that this shader is
* attached to.
*/
public final class BlurShader extends Shader {
private final float mRadiusX;
private final float mRadiusY;
private final Shader mInputShader;
private long mNativeInputShader = 0;
/**
* Create a {@link BlurShader} that blurs the contents of the optional input shader
* with the specified radius along the x and y axis. If no input shader is provided
* then all drawing commands issued with a {@link android.graphics.Paint} that this
* shader is installed in will be blurred
* @param radiusX Radius of blur along the X axis
* @param radiusY Radius of blur along the Y axis
* @param inputShader Input shader that provides the content to be blurred
*/
public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader) {
mRadiusX = radiusX;
mRadiusY = radiusY;
mInputShader = inputShader;
}
/** @hide **/
@Override
protected long createNativeInstance(long nativeMatrix) {
mNativeInputShader = mInputShader != null ? mInputShader.getNativeInstance() : 0;
return nativeCreate(nativeMatrix, mRadiusX, mRadiusY, mNativeInputShader);
}
/** @hide **/
@Override
protected boolean shouldDiscardNativeInstance() {
long currentNativeInstance = mInputShader != null ? mInputShader.getNativeInstance() : 0;
return mNativeInputShader != currentNativeInstance;
}
private static native long nativeCreate(long nativeMatrix, float radiusX, float radiusY,
long inputShader);
}

View File

@ -464,6 +464,7 @@ cc_defaults {
"RootRenderNode.cpp",
"shader/Shader.cpp",
"shader/BitmapShader.cpp",
"shader/BlurShader.cpp",
"shader/ComposeShader.cpp",
"shader/LinearGradientShader.cpp",
"shader/RadialGradientShader.cpp",

View File

@ -7,6 +7,7 @@
#include "include/effects/SkRuntimeEffect.h"
#include "shader/Shader.h"
#include "shader/BitmapShader.h"
#include "shader/BlurShader.h"
#include "shader/ComposeShader.h"
#include "shader/LinearGradientShader.h"
#include "shader/RadialGradientShader.h"
@ -222,6 +223,22 @@ static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong BlurShader_create(JNIEnv* env , jobject o, jlong matrixPtr, jfloat sigmaX,
jfloat sigmaY, jlong shaderHandle) {
auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
auto* inputShader = reinterpret_cast<Shader*>(shaderHandle);
auto* blurShader = new BlurShader(
sigmaX,
sigmaY,
inputShader,
matrix
);
return reinterpret_cast<jlong>(blurShader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
auto* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
@ -273,6 +290,10 @@ static const JNINativeMethod gBitmapShaderMethods[] = {
{ "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor },
};
static const JNINativeMethod gBlurShaderMethods[] = {
{ "nativeCreate", "(JFFJ)J", (void*)BlurShader_create }
};
static const JNINativeMethod gLinearGradientMethods[] = {
{ "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
};
@ -304,6 +325,8 @@ int register_android_graphics_Shader(JNIEnv* env)
NELEM(gShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
NELEM(gBitmapShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/BlurShader", gBlurShaderMethods,
NELEM(gBlurShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
NELEM(gLinearGradientMethods));
android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "BlurShader.h"
#include "SkImageFilters.h"
#include "SkRefCnt.h"
#include "utils/Blur.h"
namespace android::uirenderer {
BlurShader::BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix)
: Shader(matrix)
, skImageFilter(
SkImageFilters::Blur(
Blur::convertRadiusToSigma(radiusX),
Blur::convertRadiusToSigma(radiusY),
inputShader ? inputShader->asSkImageFilter() : nullptr)
) { }
sk_sp<SkImageFilter> BlurShader::makeSkImageFilter() {
return skImageFilter;
}
BlurShader::~BlurShader() {}
} // namespace android::uirenderer

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "Shader.h"
namespace android::uirenderer {
/**
* Shader implementation that blurs another Shader instance or the source bitmap
*/
class BlurShader : public Shader {
public:
/**
* Creates a BlurShader instance with the provided radius values to blur along the x and y
* axis accordingly.
*
* This will blur the contents of the provided input shader if it is non-null, otherwise
* the source bitmap will be blurred instead.
*/
BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix);
~BlurShader() override;
protected:
sk_sp<SkImageFilter> makeSkImageFilter() override;
private:
sk_sp<SkImageFilter> skImageFilter;
};
} // namespace android::uirenderer

View File

@ -32,7 +32,9 @@ namespace android::uirenderer {
class Shader: public SkRefCnt {
public:
/**
* Creates a Shader instance with an optional transformation matrix
* Creates a Shader instance with an optional transformation matrix. The transformation matrix
* is copied internally and ownership is unchanged. It is the responsibility of the caller to
* deallocate it appropriately.
* @param matrix Optional matrix to transform the underlying SkShader or SkImageFilter
*/
Shader(const SkMatrix* matrix);

View File

@ -14250,6 +14250,10 @@ package android.graphics {
enum_constant public static final android.graphics.BlurMaskFilter.Blur SOLID;
}
public final class BlurShader extends android.graphics.Shader {
ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
}
public class Camera {
ctor public Camera();
method public void applyToCanvas(android.graphics.Canvas);

View File

@ -744,6 +744,15 @@
</intent-filter>
</activity>
<activity android:name="BlurActivity"
android:label="Shaders/Blur"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
<activity android:name="TextActivity"
android:label="Text/Simple Text"
android:theme="@android:style/Theme.NoTitleBar"

View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.hwui;
import android.app.Activity;
import android.content.Context;
import android.graphics.BlurShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
@SuppressWarnings({"UnusedDeclaration"})
public class BlurActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
layout.setClipChildren(false);
layout.setGravity(Gravity.CENTER);
layout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500, 500);
params.bottomMargin = 100;
layout.addView(new BlurGradientView(this), params);
layout.addView(new BlurView(this), params);
setContentView(layout);
}
public static class BlurGradientView extends View {
private BlurShader mBlurShader = null;
private Paint mPaint;
public BlurGradientView(Context c) {
super(c);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed || mBlurShader == null) {
LinearGradient gradient = new LinearGradient(
0f,
0f,
right - left,
bottom - top,
Color.CYAN,
Color.YELLOW,
Shader.TileMode.CLAMP
);
mBlurShader = new BlurShader(30f, 40f, gradient);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(mBlurShader);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
}
}
public static class BlurView extends View {
private final BlurShader mBlurShader;
private final Paint mPaint;
public BlurView(Context c) {
super(c);
mBlurShader = new BlurShader(20f, 20f, null);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(mBlurShader);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.BLUE);
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
mPaint.setColor(Color.RED);
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, 50f, mPaint);
}
}
}