Merge "Introduce more RenderEffect APIs"

This commit is contained in:
Nader Jawad
2020-11-06 21:16:25 +00:00
committed by Android (Google) Code Review
5 changed files with 258 additions and 6 deletions

View File

@@ -15610,6 +15610,19 @@ package android.graphics {
method public final boolean next(android.graphics.Rect);
}
public final class RenderEffect {
method @NonNull public static android.graphics.RenderEffect createBitmapEffect(@NonNull android.graphics.Bitmap);
method @NonNull public static android.graphics.RenderEffect createBitmapEffect(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @NonNull android.graphics.Rect);
method @NonNull public static android.graphics.RenderEffect createBlendModeEffect(@NonNull android.graphics.RenderEffect, @NonNull android.graphics.RenderEffect, @NonNull android.graphics.BlendMode);
method @NonNull public static android.graphics.RenderEffect createBlurEffect(float, float, @NonNull android.graphics.RenderEffect, @NonNull android.graphics.Shader.TileMode);
method @NonNull public static android.graphics.RenderEffect createBlurEffect(float, float, @NonNull android.graphics.Shader.TileMode);
method @NonNull public static android.graphics.RenderEffect createChainEffect(@NonNull android.graphics.RenderEffect, @NonNull android.graphics.RenderEffect);
method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter, @NonNull android.graphics.RenderEffect);
method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter);
method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float);
method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float, @NonNull android.graphics.RenderEffect);
}
public final class RenderNode {
ctor public RenderNode(@Nullable String);
method @NonNull public android.graphics.RecordingCanvas beginRecording(int, int);
@@ -15669,6 +15682,7 @@ package android.graphics {
method public boolean setPosition(@NonNull android.graphics.Rect);
method public boolean setProjectBackwards(boolean);
method public boolean setProjectionReceiver(boolean);
method public void setRenderEffect(@Nullable android.graphics.RenderEffect);
method public boolean setRotationX(float);
method public boolean setRotationY(float);
method public boolean setRotationZ(float);

View File

@@ -15592,6 +15592,19 @@ package android.graphics {
method public final boolean next(android.graphics.Rect);
}
public final class RenderEffect {
method @NonNull public static android.graphics.RenderEffect createBitmapEffect(@NonNull android.graphics.Bitmap);
method @NonNull public static android.graphics.RenderEffect createBitmapEffect(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @NonNull android.graphics.Rect);
method @NonNull public static android.graphics.RenderEffect createBlendModeEffect(@NonNull android.graphics.RenderEffect, @NonNull android.graphics.RenderEffect, @NonNull android.graphics.BlendMode);
method @NonNull public static android.graphics.RenderEffect createBlurEffect(float, float, @NonNull android.graphics.RenderEffect, @NonNull android.graphics.Shader.TileMode);
method @NonNull public static android.graphics.RenderEffect createBlurEffect(float, float, @NonNull android.graphics.Shader.TileMode);
method @NonNull public static android.graphics.RenderEffect createChainEffect(@NonNull android.graphics.RenderEffect, @NonNull android.graphics.RenderEffect);
method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter, @NonNull android.graphics.RenderEffect);
method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter);
method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float);
method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float, @NonNull android.graphics.RenderEffect);
}
public final class RenderNode {
ctor public RenderNode(@Nullable String);
method @NonNull public android.graphics.RecordingCanvas beginRecording(int, int);
@@ -15651,6 +15664,7 @@ package android.graphics {
method public boolean setPosition(@NonNull android.graphics.Rect);
method public boolean setProjectBackwards(boolean);
method public boolean setProjectionReceiver(boolean);
method public void setRenderEffect(@Nullable android.graphics.RenderEffect);
method public boolean setRotationX(float);
method public boolean setRotationY(float);
method public boolean setRotationZ(float);

View File

@@ -17,6 +17,7 @@
package android.graphics;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Shader.TileMode;
import libcore.util.NativeAllocationRegistry;
@@ -24,8 +25,6 @@ import libcore.util.NativeAllocationRegistry;
/**
* Intermediate rendering step used to render drawing commands with a corresponding
* visual effect
*
* @hide
*/
public final class RenderEffect {
@@ -99,7 +98,7 @@ public final class RenderEffect {
/**
* Create a {@link RenderEffect} that blurs the contents of the
* {@link android.graphics.RenderNode} that this RenderEffect is installed on with the
* specified radius along hte x and y axis.
* specified radius along the x and y axis.
* @param radiusX Radius of blur along the X axis
* @param radiusY Radius of blur along the Y axis
* @param edgeTreatment Policy for how to blur content near edges of the blur kernel
@@ -117,9 +116,159 @@ public final class RenderEffect {
0,
edgeTreatment.nativeInt
)
);
}
/**
* Create a {@link RenderEffect} that renders the contents of the input {@link Bitmap}.
* This is useful to create an input for other {@link RenderEffect} types such as
* {@link RenderEffect#createBlurEffect(float, float, RenderEffect, TileMode)} or
* {@link RenderEffect#createColorFilterEffect(ColorFilter, RenderEffect)}
*
* @param bitmap The source bitmap to be rendered by the created {@link RenderEffect}
*/
@NonNull
public static RenderEffect createBitmapEffect(@NonNull Bitmap bitmap) {
float right = bitmap.getWidth();
float bottom = bitmap.getHeight();
return new RenderEffect(
nativeCreateBitmapEffect(
bitmap.getNativeInstance(),
0f,
0f,
right,
bottom,
0f,
0f,
right,
bottom
)
);
}
/**
* Create a {@link RenderEffect} that renders the contents of the input {@link Bitmap}.
* This is useful to create an input for other {@link RenderEffect} types such as
* {@link RenderEffect#createBlurEffect(float, float, RenderEffect, TileMode)} or
* {@link RenderEffect#createColorFilterEffect(ColorFilter, RenderEffect)}
*
* @param bitmap The source bitmap to be rendered by the created {@link RenderEffect}
* @param src Optional subset of the bitmap to be part of the rendered output. If null
* is provided, the entire bitmap bounds are used.
* @param dst Bounds of the destination which the bitmap is translated and scaled to be
* drawn into
*/
@NonNull
public static RenderEffect createBitmapEffect(
@NonNull Bitmap bitmap,
@Nullable Rect src,
@NonNull Rect dst
) {
long bitmapHandle = bitmap.getNativeInstance();
int left = src == null ? 0 : src.left;
int top = src == null ? 0 : src.top;
int right = src == null ? bitmap.getWidth() : src.right;
int bottom = src == null ? bitmap.getHeight() : src.bottom;
return new RenderEffect(
nativeCreateBitmapEffect(
bitmapHandle,
left,
top,
right,
bottom,
dst.left,
dst.top,
dst.right,
dst.bottom
)
);
}
/**
* Create a filter that applies the color filter to the provided RenderEffect
*
* @param colorFilter ColorFilter applied to the content in the input RenderEffect
* @param renderEffect Source to be transformed by the specified {@link ColorFilter}
*/
@NonNull
public static RenderEffect createColorFilterEffect(
@NonNull ColorFilter colorFilter,
@NonNull RenderEffect renderEffect
) {
return new RenderEffect(
nativeCreateColorFilterEffect(
colorFilter.getNativeInstance(),
renderEffect.getNativeInstance()
)
);
}
/**
* Create a filter that applies the color filter to the contents of the
* {@link android.graphics.RenderNode} that this RenderEffect is installed on
* @param colorFilter ColorFilter applied to the content in the input RenderEffect
*/
@NonNull
public static RenderEffect createColorFilterEffect(@NonNull ColorFilter colorFilter) {
return new RenderEffect(
nativeCreateColorFilterEffect(
colorFilter.getNativeInstance(),
0
)
);
}
/**
* {@link RenderEffect} that is a composition of 2 other {@link RenderEffect} instances
* combined by the specified {@link BlendMode}
*
* @param dst The Dst pixels used in blending, if null the source bitmap is used.
* @param src The Src pixels used in blending, if null the source bitmap is use
* @param blendMode The {@link BlendMode} to be used to combine colors from the two
* {@link RenderEffect}s
*/
@NonNull
public static RenderEffect createBlendModeEffect(
@NonNull RenderEffect dst,
@NonNull RenderEffect src,
@NonNull BlendMode blendMode
) {
return new RenderEffect(
nativeCreateBlendModeEffect(
dst.getNativeInstance(),
src.getNativeInstance(),
blendMode.getXfermode().porterDuffMode
)
);
}
/**
* Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are
* treated as the source bitmap passed to 'outer', i.e.
*
* result = outer(inner(source)).
*
* Consumers should favor explicit chaining of {@link RenderEffect} instances at creation time
* rather than using chain effect. Chain effects are useful for situations where the input or
* output are provided from elsewhere and the input or output {@link RenderEffect} need to be
* changed.
*
* @param outer {@link RenderEffect} that consumes the output of {@param inner} as its input
* @param inner {@link RenderEffect} that is consumed as input by {@param outer}
*/
@NonNull
public static RenderEffect createChainEffect(
@NonNull RenderEffect outer,
@NonNull RenderEffect inner
) {
return new RenderEffect(
nativeCreateChainEffect(
outer.getNativeInstance(),
inner.getNativeInstance()
)
);
}
private final long mNativeRenderEffect;
/* only constructed from static factory methods */
@@ -141,5 +290,11 @@ public final class RenderEffect {
float offsetX, float offsetY, long nativeInput);
private static native long nativeCreateBlurEffect(
float radiusX, float radiusY, long nativeInput, int edgeTreatment);
private static native long nativeCreateBitmapEffect(
long bitmapHandle, float srcLeft, float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight, float dstBottom);
private static native long nativeCreateColorFilterEffect(long colorFilter, long nativeInput);
private static native long nativeCreateBlendModeEffect(long dst, long src, int blendmode);
private static native long nativeCreateChainEffect(long outer, long inner);
private static native long nativeGetFinalizer();
}

View File

@@ -858,8 +858,6 @@ public final class RenderNode {
* be blurred when this RenderNode is drawn into the destination.
* @param renderEffect to be applied to the RenderNode. Passing null clears all previously
* configured RenderEffects
*
* @hide
*/
public void setRenderEffect(@Nullable RenderEffect renderEffect) {
nSetRenderEffect(mNativeRenderNode,

View File

@@ -48,6 +48,73 @@ static jlong createBlurEffect(JNIEnv* env , jobject, jfloat radiusX,
return reinterpret_cast<jlong>(blurFilter.release());
}
static jlong createBitmapEffect(
JNIEnv* env,
jobject,
jlong bitmapHandle,
jfloat srcLeft,
jfloat srcTop,
jfloat srcRight,
jfloat srcBottom,
jfloat dstLeft,
jfloat dstTop,
jfloat dstRight,
jfloat dstBottom
) {
sk_sp<SkImage> image = android::bitmap::toBitmap(bitmapHandle).makeImage();
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
sk_sp<SkImageFilter> bitmapFilter =
SkImageFilters::Image(image, srcRect, dstRect, kLow_SkFilterQuality);
return reinterpret_cast<jlong>(bitmapFilter.release());
}
static jlong createColorFilterEffect(
JNIEnv* env,
jobject,
jlong colorFilterHandle,
jlong inputFilterHandle
) {
auto* colorFilter = reinterpret_cast<const SkColorFilter*>(colorFilterHandle);
auto* inputFilter = reinterpret_cast<const SkImageFilter*>(inputFilterHandle);
sk_sp<SkImageFilter> colorFilterImageFilter = SkImageFilters::ColorFilter(
sk_ref_sp(colorFilter), sk_ref_sp(inputFilter), nullptr);
return reinterpret_cast<jlong>(colorFilterImageFilter.release());
}
static jlong createBlendModeEffect(
JNIEnv* env,
jobject,
jlong backgroundImageFilterHandle,
jlong foregroundImageFilterHandle,
jint blendmodeHandle
) {
auto* backgroundFilter = reinterpret_cast<const SkImageFilter*>(backgroundImageFilterHandle);
auto* foregroundFilter = reinterpret_cast<const SkImageFilter*>(foregroundImageFilterHandle);
SkBlendMode blendMode = static_cast<SkBlendMode>(blendmodeHandle);
sk_sp<SkImageFilter> xfermodeFilter = SkImageFilters::Blend(
blendMode,
sk_ref_sp(backgroundFilter),
sk_ref_sp(foregroundFilter)
);
return reinterpret_cast<jlong>(xfermodeFilter.release());
}
static jlong createChainEffect(
JNIEnv* env,
jobject,
jlong outerFilterHandle,
jlong innerFilterHandle
) {
auto* outerImageFilter = reinterpret_cast<const SkImageFilter*>(outerFilterHandle);
auto* innerImageFilter = reinterpret_cast<const SkImageFilter*>(innerFilterHandle);
sk_sp<SkImageFilter> composeFilter = SkImageFilters::Compose(
sk_ref_sp(outerImageFilter),
sk_ref_sp(innerImageFilter)
);
return reinterpret_cast<jlong>(composeFilter.release());
}
static void RenderEffect_safeUnref(SkImageFilter* filter) {
SkSafeUnref(filter);
}
@@ -59,7 +126,11 @@ static jlong getRenderEffectFinalizer(JNIEnv*, jobject) {
static const JNINativeMethod gRenderEffectMethods[] = {
{"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer},
{"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect},
{"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect}
{"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect},
{"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect},
{"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect},
{"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect},
{"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect}
};
int register_android_graphics_RenderEffect(JNIEnv* env) {