| /* | |
| * 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.NonNull; | |
| import android.annotation.Nullable; | |
| import android.graphics.Shader.TileMode; | |
| import libcore.util.NativeAllocationRegistry; | |
| /** | |
| * Intermediate rendering step used to render drawing commands with a corresponding | |
| * visual effect. A {@link RenderEffect} can be configured on a {@link RenderNode} through | |
| * {@link RenderNode#setRenderEffect(RenderEffect)} and will be applied when drawn through | |
| * {@link Canvas#drawRenderNode(RenderNode)}. | |
| * Additionally a {@link RenderEffect} can be applied to a View's backing RenderNode through | |
| * {@link android.view.View#setRenderEffect(RenderEffect)} | |
| */ | |
| @android.ravenwood.annotation.RavenwoodKeepWholeClass | |
| public final class RenderEffect { | |
| private static class RenderEffectHolder { | |
| public static final NativeAllocationRegistry RENDER_EFFECT_REGISTRY = | |
| NativeAllocationRegistry.createMalloced( | |
| RenderEffect.class.getClassLoader(), nativeGetFinalizer()); | |
| } | |
| /** | |
| * Create a {@link RenderEffect} instance that will offset the drawing content | |
| * by the provided x and y offset. | |
| * @param offsetX offset along the x axis in pixels | |
| * @param offsetY offset along the y axis in pixels | |
| */ | |
| @NonNull | |
| public static RenderEffect createOffsetEffect(float offsetX, float offsetY) { | |
| return new RenderEffect(nativeCreateOffsetEffect(offsetX, offsetY, 0)); | |
| } | |
| /** | |
| * Create a {@link RenderEffect} instance with the provided x and y offset | |
| * @param offsetX offset along the x axis in pixels | |
| * @param offsetY offset along the y axis in pixels | |
| * @param input target RenderEffect used to render in the offset coordinates. | |
| */ | |
| @NonNull | |
| public static RenderEffect createOffsetEffect( | |
| float offsetX, | |
| float offsetY, | |
| @NonNull RenderEffect input | |
| ) { | |
| return new RenderEffect(nativeCreateOffsetEffect( | |
| offsetX, | |
| offsetY, | |
| input.getNativeInstance() | |
| ) | |
| ); | |
| } | |
| /** | |
| * Create a {@link RenderEffect} that blurs the contents of the optional input RenderEffect | |
| * with the specified radius along the x and y axis. If no input RenderEffect is provided | |
| * then all drawing commands issued with a {@link android.graphics.RenderNode} that this | |
| * RenderEffect 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 inputEffect Input RenderEffect that provides the content to be blurred, can be null | |
| * to indicate that the drawing commands on the RenderNode are to be | |
| * blurred instead of the input RenderEffect | |
| * @param edgeTreatment Policy for how to blur content near edges of the blur kernel | |
| */ | |
| @NonNull | |
| public static RenderEffect createBlurEffect( | |
| float radiusX, | |
| float radiusY, | |
| @NonNull RenderEffect inputEffect, | |
| @NonNull TileMode edgeTreatment | |
| ) { | |
| long nativeInputEffect = inputEffect != null ? inputEffect.mNativeRenderEffect : 0; | |
| return new RenderEffect( | |
| nativeCreateBlurEffect( | |
| radiusX, | |
| radiusY, | |
| nativeInputEffect, | |
| edgeTreatment.nativeInt | |
| ) | |
| ); | |
| } | |
| /** | |
| * 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 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 | |
| */ | |
| @NonNull | |
| public static RenderEffect createBlurEffect( | |
| float radiusX, | |
| float radiusY, | |
| @NonNull TileMode edgeTreatment | |
| ) { | |
| return new RenderEffect( | |
| nativeCreateBlurEffect( | |
| radiusX, | |
| radiusY, | |
| 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 within the bounds of the {@link RenderNode} this RenderEffect is | |
| * installed on | |
| */ | |
| @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 {@link RenderEffect} 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 {@link RenderEffect} 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 | |
| ) | |
| ); | |
| } | |
| /** | |
| * Create a {@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 | |
| * @param src The Src pixels used in blending | |
| * @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 {@link RenderEffect} that composes 'inner' with 'outer', such that the results of | |
| * 'inner' are treated as the source bitmap passed to 'outer', i.e. | |
| * | |
| * <pre> | |
| * {@code | |
| * result = outer(inner(source)) | |
| * } | |
| * </pre> | |
| * | |
| * 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() | |
| ) | |
| ); | |
| } | |
| /** | |
| * Create a {@link RenderEffect} that renders the contents of the input {@link Shader}. | |
| * This is useful to create an input for other {@link RenderEffect} types such as | |
| * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, TileMode)} | |
| * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, TileMode)} or | |
| * {@link RenderEffect#createColorFilterEffect(ColorFilter, RenderEffect)}. | |
| */ | |
| @NonNull | |
| public static RenderEffect createShaderEffect(@NonNull Shader shader) { | |
| return new RenderEffect(nativeCreateShaderEffect(shader.getNativeInstance())); | |
| } | |
| /** | |
| * Create a {@link RenderEffect} that executes the provided {@link RuntimeShader} and passes | |
| * the contents of the {@link android.graphics.RenderNode} that this RenderEffect is installed | |
| * on as an input to the shader. | |
| * @param shader the runtime shader that will bind the inputShaderName to the RenderEffect input | |
| * @param uniformShaderName the uniform name defined in the RuntimeShader's program to which | |
| * the contents of the RenderNode will be bound | |
| */ | |
| @NonNull | |
| public static RenderEffect createRuntimeShaderEffect( | |
| @NonNull RuntimeShader shader, @NonNull String uniformShaderName) { | |
| return new RenderEffect( | |
| nativeCreateRuntimeShaderEffect(shader.getNativeShaderBuilder(), | |
| uniformShaderName)); | |
| } | |
| private final long mNativeRenderEffect; | |
| /* only constructed from static factory methods */ | |
| private RenderEffect(long nativeRenderEffect) { | |
| mNativeRenderEffect = nativeRenderEffect; | |
| RenderEffectHolder.RENDER_EFFECT_REGISTRY.registerNativeAllocation( | |
| this, mNativeRenderEffect); | |
| } | |
| /** | |
| * Obtain the pointer to the underlying RenderEffect to be configured | |
| * on a RenderNode object via {@link RenderNode#setRenderEffect(RenderEffect)} | |
| */ | |
| /* package */ long getNativeInstance() { | |
| return mNativeRenderEffect; | |
| } | |
| private static native long nativeCreateOffsetEffect( | |
| 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 nativeCreateShaderEffect(long shader); | |
| private static native long nativeCreateRuntimeShaderEffect( | |
| long shaderBuilder, String inputShaderName); | |
| private static native long nativeGetFinalizer(); | |
| } |