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