1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics; 18 19 import android.annotation.IntDef; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 23 import java.lang.annotation.Retention; 24 import java.lang.annotation.RetentionPolicy; 25 26 /** 27 * Shader used to draw a bitmap as a texture. The bitmap can be repeated or 28 * mirrored by setting the tiling mode. 29 */ 30 public class BitmapShader extends Shader { 31 /** 32 * Prevent garbage collection. 33 */ 34 /*package*/ Bitmap mBitmap; 35 36 private int mTileX; 37 private int mTileY; 38 39 /** @hide */ 40 @IntDef(prefix = {"FILTER_MODE"}, value = { 41 FILTER_MODE_DEFAULT, 42 FILTER_MODE_NEAREST, 43 FILTER_MODE_LINEAR 44 }) 45 @Retention(RetentionPolicy.SOURCE) 46 public @interface FilterMode {} 47 48 /** 49 * This FilterMode value will respect the value of the Paint#isFilterBitmap flag while the 50 * shader is attached to the Paint. 51 * 52 * <p>The exception to this rule is when a Shader is attached as input to a RuntimeShader. In 53 * that case this mode will default to FILTER_MODE_NEAREST.</p> 54 * 55 * @see #setFilterMode(int) 56 */ 57 public static final int FILTER_MODE_DEFAULT = 0; 58 /** 59 * This FilterMode value will cause the shader to sample from the nearest pixel to the requested 60 * sample point. 61 * 62 * <p>This value will override the effect of Paint#isFilterBitmap.</p> 63 * 64 * @see #setFilterMode(int) 65 */ 66 public static final int FILTER_MODE_NEAREST = 1; 67 /** 68 * This FilterMode value will cause the shader to interpolate the output of the shader from a 69 * 2x2 grid of pixels nearest to the sample point (i.e. bilinear interpolation). 70 * 71 * <p>This value will override the effect of Paint#isFilterBitmap.</p> 72 * 73 * @see #setFilterMode(int) 74 */ 75 public static final int FILTER_MODE_LINEAR = 2; 76 77 @FilterMode 78 private int mFilterMode; 79 80 /* 81 * This is cache of the last value from the Paint of bitmap-filtering. 82 * In the future, BitmapShaders will carry their own (expanded) data for this 83 * (e.g. including mipmap options, or bicubic weights) 84 * 85 * When that happens, this bool will become those extended values, and we will 86 * need to track whether this Shader was created with those new constructors, 87 * or from the current "legacy" constructor, which (for compatibility) will 88 * still need to know the Paint's setting. 89 * 90 * When the filter Paint setting is finally gone, we will be able to remove 91 * the filterFromPaint parameter currently being passed to createNativeInstance() 92 * and shouldDiscardNativeInstance(), as shaders will always know their filter 93 * settings. 94 */ 95 private boolean mFilterFromPaint; 96 97 /** 98 * Stores whether or not the contents of this shader's bitmap will be sampled 99 * without modification or if the bitmap's properties, like colorspace and 100 * premultiplied alpha, will be respected when sampling from the bitmap's buffer. 101 */ 102 private boolean mIsDirectSampled; 103 104 private boolean mRequestDirectSampling; 105 106 private int mMaxAniso = 0; 107 108 /** 109 * Call this to create a new shader that will draw with a bitmap. 110 * 111 * @param bitmap The bitmap to use inside the shader 112 * @param tileX The tiling mode for x to draw the bitmap in. 113 * @param tileY The tiling mode for y to draw the bitmap in. 114 */ BitmapShader(@onNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)115 public BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY) { 116 this(bitmap, tileX.nativeInt, tileY.nativeInt); 117 } 118 BitmapShader(Bitmap bitmap, int tileX, int tileY)119 private BitmapShader(Bitmap bitmap, int tileX, int tileY) { 120 if (bitmap == null) { 121 throw new IllegalArgumentException("Bitmap must be non-null"); 122 } 123 bitmap.checkRecycled("Cannot create BitmapShader for recycled bitmap"); 124 mBitmap = bitmap; 125 mTileX = tileX; 126 mTileY = tileY; 127 mFilterMode = FILTER_MODE_DEFAULT; 128 mFilterFromPaint = false; 129 mIsDirectSampled = false; 130 mRequestDirectSampling = false; 131 } 132 133 /** 134 * Returns the filter mode used when sampling from this shader 135 */ 136 @FilterMode getFilterMode()137 public int getFilterMode() { 138 return mFilterMode; 139 } 140 141 /** 142 * Set the filter mode to be used when sampling from this shader. If this is configured 143 * then the anisotropic filtering value specified in any previous call to 144 * {@link #setMaxAnisotropy(int)} is ignored. 145 */ setFilterMode(@ilterMode int mode)146 public void setFilterMode(@FilterMode int mode) { 147 if (mode != mFilterMode) { 148 mFilterMode = mode; 149 mMaxAniso = 0; 150 discardNativeInstance(); 151 } 152 } 153 154 /** 155 * Enables and configures the max anisotropy sampling value. If this value is configured, 156 * {@link #setFilterMode(int)} is ignored. 157 * 158 * Anisotropic filtering can enhance visual quality by removing aliasing effects of images 159 * that are at oblique viewing angles. This value is typically consumed as a power of 2 and 160 * anisotropic values of the next power of 2 typically provide twice the quality improvement 161 * as the previous value. For example, a sampling value of 4 would provide twice the improvement 162 * of a sampling value of 2. It is important to note that higher sampling values reach 163 * diminishing returns as the improvements between 8 and 16 can be slight. 164 * 165 * @param maxAnisotropy The Anisotropy value to use for filtering. Must be greater than 0. 166 */ setMaxAnisotropy(@ntRangefrom = 1) int maxAnisotropy)167 public void setMaxAnisotropy(@IntRange(from = 1) int maxAnisotropy) { 168 if (mMaxAniso != maxAnisotropy && maxAnisotropy > 0) { 169 mMaxAniso = maxAnisotropy; 170 mFilterMode = FILTER_MODE_DEFAULT; 171 discardNativeInstance(); 172 } 173 } 174 175 /** 176 * Returns the current max anisotropic filtering value configured by 177 * {@link #setFilterMode(int)}. If {@link #setFilterMode(int)} is invoked this returns zero. 178 */ getMaxAnisotropy()179 public int getMaxAnisotropy() { 180 return mMaxAniso; 181 } 182 183 /** @hide */ getNativeInstanceWithDirectSampling()184 /* package */ synchronized long getNativeInstanceWithDirectSampling() { 185 mRequestDirectSampling = true; 186 return getNativeInstance(); 187 } 188 189 /** @hide */ 190 @Override createNativeInstance(long nativeMatrix, boolean filterFromPaint)191 protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) { 192 mBitmap.checkRecycled("BitmapShader's bitmap has been recycled"); 193 194 boolean enableLinearFilter = mFilterMode == FILTER_MODE_LINEAR; 195 if (mFilterMode == FILTER_MODE_DEFAULT) { 196 mFilterFromPaint = filterFromPaint; 197 enableLinearFilter = mFilterFromPaint; 198 } 199 200 mIsDirectSampled = mRequestDirectSampling; 201 mRequestDirectSampling = false; 202 203 if (mMaxAniso > 0) { 204 return nativeCreateWithMaxAniso(nativeMatrix, mBitmap.getNativeInstance(), mTileX, 205 mTileY, mMaxAniso, mIsDirectSampled); 206 } else { 207 return nativeCreate(nativeMatrix, mBitmap.getNativeInstance(), mTileX, mTileY, 208 enableLinearFilter, mIsDirectSampled); 209 } 210 } 211 212 /** @hide */ 213 @Override shouldDiscardNativeInstance(boolean filterFromPaint)214 protected boolean shouldDiscardNativeInstance(boolean filterFromPaint) { 215 return mIsDirectSampled != mRequestDirectSampling 216 || (mFilterMode == FILTER_MODE_DEFAULT && mFilterFromPaint != filterFromPaint); 217 } 218 nativeCreate(long nativeMatrix, long bitmapHandle, int shaderTileModeX, int shaderTileModeY, boolean filter, boolean isDirectSampled)219 private static native long nativeCreate(long nativeMatrix, long bitmapHandle, 220 int shaderTileModeX, int shaderTileModeY, boolean filter, boolean isDirectSampled); 221 nativeCreateWithMaxAniso(long nativeMatrix, long bitmapHandle, int shaderTileModeX, int shaderTileModeY, int maxAniso, boolean isDirectSampled)222 private static native long nativeCreateWithMaxAniso(long nativeMatrix, long bitmapHandle, 223 int shaderTileModeX, int shaderTileModeY, int maxAniso, boolean isDirectSampled); 224 } 225 226