diff --git a/core/api/current.txt b/core/api/current.txt index ab2624c83998e..abd3d5f1bb75c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -14912,7 +14912,9 @@ package android.graphics { public class BitmapShader extends android.graphics.Shader { ctor public BitmapShader(@NonNull android.graphics.Bitmap, @NonNull android.graphics.Shader.TileMode, @NonNull android.graphics.Shader.TileMode); method public int getFilterMode(); + method public int getMaxAnisotropy(); method public void setFilterMode(int); + method public void setMaxAnisotropy(@IntRange(from=1) int); field public static final int FILTER_MODE_DEFAULT = 0; // 0x0 field public static final int FILTER_MODE_LINEAR = 2; // 0x2 field public static final int FILTER_MODE_NEAREST = 1; // 0x1 diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 43cb5ee8b5c0c..2f6dd468511b6 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -17,6 +17,7 @@ package android.graphics; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import java.lang.annotation.Retention; @@ -102,6 +103,8 @@ public class BitmapShader extends Shader { private boolean mRequestDirectSampling; + private int mMaxAniso = 0; + /** * Call this to create a new shader that will draw with a bitmap. * @@ -135,15 +138,47 @@ public class BitmapShader extends Shader { } /** - * Set the filter mode to be used when sampling from this shader + * Set the filter mode to be used when sampling from this shader. If this is configured + * then the anisotropic filtering value specified in any previous call to + * {@link #setMaxAnisotropy(int)} is ignored. */ public void setFilterMode(@FilterMode int mode) { if (mode != mFilterMode) { mFilterMode = mode; + mMaxAniso = 0; discardNativeInstance(); } } + /** + * Enables and configures the max anisotropy sampling value. If this value is configured, + * {@link #setFilterMode(int)} is ignored. + * + * Anisotropic filtering can enhance visual quality by removing aliasing effects of images + * that are at oblique viewing angles. This value is typically consumed as a power of 2 and + * anisotropic values of the next power of 2 typically provide twice the quality improvement + * as the previous value. For example, a sampling value of 4 would provide twice the improvement + * of a sampling value of 2. It is important to note that higher sampling values reach + * diminishing returns as the improvements between 8 and 16 can be slight. + * + * @param maxAnisotropy The Anisotropy value to use for filtering. Must be greater than 0. + */ + public void setMaxAnisotropy(@IntRange(from = 1) int maxAnisotropy) { + if (mMaxAniso != maxAnisotropy && maxAnisotropy > 0) { + mMaxAniso = maxAnisotropy; + mFilterMode = FILTER_MODE_DEFAULT; + discardNativeInstance(); + } + } + + /** + * Returns the current max anisotropic filtering value configured by + * {@link #setFilterMode(int)}. If {@link #setFilterMode(int)} is invoked this returns zero. + */ + public int getMaxAnisotropy() { + return mMaxAniso; + } + /** @hide */ /* package */ synchronized long getNativeInstanceWithDirectSampling() { mRequestDirectSampling = true; @@ -162,8 +197,13 @@ public class BitmapShader extends Shader { mIsDirectSampled = mRequestDirectSampling; mRequestDirectSampling = false; - return nativeCreate(nativeMatrix, mBitmap.getNativeInstance(), mTileX, mTileY, - enableLinearFilter, mIsDirectSampled); + if (mMaxAniso > 0) { + return nativeCreateWithMaxAniso(nativeMatrix, mBitmap.getNativeInstance(), mTileX, + mTileY, mMaxAniso, mIsDirectSampled); + } else { + return nativeCreate(nativeMatrix, mBitmap.getNativeInstance(), mTileX, mTileY, + enableLinearFilter, mIsDirectSampled); + } } /** @hide */ @@ -175,5 +215,8 @@ public class BitmapShader extends Shader { private static native long nativeCreate(long nativeMatrix, long bitmapHandle, int shaderTileModeX, int shaderTileModeY, boolean filter, boolean isDirectSampled); + + private static native long nativeCreateWithMaxAniso(long nativeMatrix, long bitmapHandle, + int shaderTileModeX, int shaderTileModeY, int maxAniso, boolean isDirectSampled); } diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp index fa8e2e79c831a..8a0db1c91d464 100644 --- a/libs/hwui/jni/Shader.cpp +++ b/libs/hwui/jni/Shader.cpp @@ -71,11 +71,9 @@ static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) { return static_cast(reinterpret_cast(&Shader_safeUnref)); } -/////////////////////////////////////////////////////////////////////////////////////////////// - -static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle, - jint tileModeX, jint tileModeY, bool filter, - bool isDirectSampled) { +static jlong createBitmapShaderHelper(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle, + jint tileModeX, jint tileModeY, bool isDirectSampled, + const SkSamplingOptions& sampling) { const SkMatrix* matrix = reinterpret_cast(matrixPtr); sk_sp image; if (bitmapHandle) { @@ -88,8 +86,7 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j SkBitmap bitmap; image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); } - SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest, - SkMipmapMode::kNone); + sk_sp shader; if (isDirectSampled) { shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling); @@ -107,6 +104,26 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j /////////////////////////////////////////////////////////////////////////////////////////////// +static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle, + jint tileModeX, jint tileModeY, bool filter, + bool isDirectSampled) { + SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest, + SkMipmapMode::kNone); + return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY, + isDirectSampled, sampling); +} + +static jlong BitmapShader_constructorWithMaxAniso(JNIEnv* env, jobject o, jlong matrixPtr, + jlong bitmapHandle, jint tileModeX, + jint tileModeY, jint maxAniso, + bool isDirectSampled) { + auto sampling = SkSamplingOptions::Aniso(static_cast(maxAniso)); + return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY, + isDirectSampled, sampling); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + static std::vector convertColorLongs(JNIEnv* env, jlongArray colorArray) { const size_t count = env->GetArrayLength(colorArray); const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr); @@ -408,6 +425,8 @@ static const JNINativeMethod gShaderMethods[] = { static const JNINativeMethod gBitmapShaderMethods[] = { {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor}, + {"nativeCreateWithMaxAniso", "(JJIIIZ)J", (void*)BitmapShader_constructorWithMaxAniso}, + }; static const JNINativeMethod gLinearGradientMethods[] = {