• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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.ColorInt;
20 import android.annotation.ColorLong;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 
24 import libcore.util.NativeAllocationRegistry;
25 
26 /**
27  * Shader is the base class for objects that return horizontal spans of colors
28  * during drawing. A subclass of Shader is installed in a Paint calling
29  * paint.setShader(shader). After that any object (other than a bitmap) that is
30  * drawn with that paint will get its color(s) from the shader.
31  */
32 @android.ravenwood.annotation.RavenwoodKeepWholeClass
33 public class Shader {
34 
35     private static class NoImagePreloadHolder {
36         public static final NativeAllocationRegistry sRegistry =
37                 NativeAllocationRegistry.createMalloced(
38                 Shader.class.getClassLoader(), nativeGetFinalizer());
39     }
40 
41     /**
42      * @deprecated Use subclass constructors directly instead.
43      */
44     @Deprecated
Shader()45     public Shader() {
46         mColorSpace = null;
47     }
48 
49     /**
50      * @hide Only to be used by subclasses in android.graphics.
51      */
Shader(ColorSpace colorSpace)52     protected Shader(ColorSpace colorSpace) {
53         mColorSpace = colorSpace;
54         if (colorSpace == null) {
55             throw new IllegalArgumentException(
56                     "Use Shader() to create a Shader with no ColorSpace");
57         }
58 
59         // This just ensures that if the ColorSpace is invalid, the Exception will be thrown now.
60         mColorSpace.getNativeInstance();
61     }
62 
63     private final ColorSpace mColorSpace;
64 
65     /**
66      * @hide Only to be used by subclasses in android.graphics.
67      */
colorSpace()68     protected ColorSpace colorSpace() {
69         return mColorSpace;
70     }
71 
72     /**
73      * Current native shader instance. Created and updated lazily when {@link #getNativeInstance()}
74      * is called - otherwise may be out of date with java setters/properties.
75      */
76     private long mNativeInstance;
77     // Runnable to do immediate destruction
78     private Runnable mCleaner;
79 
80     /**
81      * Current matrix - always set to null if local matrix is identity.
82      */
83     private Matrix mLocalMatrix;
84 
85     public enum TileMode {
86         /**
87          * Replicate the edge color if the shader draws outside of its
88          * original bounds.
89          */
90         CLAMP   (0),
91         /**
92          * Repeat the shader's image horizontally and vertically.
93          */
94         REPEAT  (1),
95         /**
96          * Repeat the shader's image horizontally and vertically, alternating
97          * mirror images so that adjacent images always seam.
98          */
99         MIRROR(2),
100         /**
101          * Render the shader's image pixels only within its original bounds. If the shader
102          * draws outside of its original bounds, transparent black is drawn instead.
103          */
104         DECAL(3);
105 
TileMode(int nativeInt)106         TileMode(int nativeInt) {
107             this.nativeInt = nativeInt;
108         }
109         final int nativeInt;
110     }
111 
112     /**
113      * Return true if the shader has a non-identity local matrix.
114      * @param localM Set to the local matrix of the shader, if the shader's matrix is non-null.
115      * @return true if the shader has a non-identity local matrix
116      */
getLocalMatrix(@onNull Matrix localM)117     public boolean getLocalMatrix(@NonNull Matrix localM) {
118         if (mLocalMatrix != null) {
119             localM.set(mLocalMatrix);
120             return true; // presence of mLocalMatrix means it's not identity
121         }
122         return false;
123     }
124 
125     /**
126      * Set the shader's local matrix. Passing null will reset the shader's
127      * matrix to identity. If the matrix has scale value as 0, the drawing
128      * result is undefined.
129      *
130      * @param localM The shader's new local matrix, or null to specify identity
131      */
setLocalMatrix(@ullable Matrix localM)132     public void setLocalMatrix(@Nullable Matrix localM) {
133         if (localM == null || localM.isIdentity()) {
134             if (mLocalMatrix != null) {
135                 mLocalMatrix = null;
136                 discardNativeInstance();
137             }
138         } else {
139             if (mLocalMatrix == null) {
140                 mLocalMatrix = new Matrix(localM);
141                 discardNativeInstance();
142             } else if (!mLocalMatrix.equals(localM)) {
143                 mLocalMatrix.set(localM);
144                 discardNativeInstance();
145             }
146         }
147     }
148 
149     /**
150      *  @hide Only to be used by subclasses in the graphics package.
151      */
createNativeInstance(long nativeMatrix, boolean filterFromPaint)152     protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
153         return 0;
154     }
155 
156     /**
157      *  @hide Only to be used by subclasses in the graphics package.
158      */
discardNativeInstance()159     protected synchronized final void discardNativeInstance() {
160         discardNativeInstanceLocked();
161     }
162 
163     // For calling inside a synchronized method.
discardNativeInstanceLocked()164     private void discardNativeInstanceLocked() {
165         if (mNativeInstance != 0) {
166             mCleaner.run();
167             mCleaner = null;
168             mNativeInstance = 0;
169         }
170     }
171 
172     /**
173      * Callback for subclasses to specify whether the most recently
174      * constructed native instance is still valid.
175      *  @hide Only to be used by subclasses in the graphics package.
176      */
shouldDiscardNativeInstance(boolean filterBitmap)177     protected boolean shouldDiscardNativeInstance(boolean filterBitmap) {
178         return false;
179     }
180 
181 
182     /**
183      * @hide so it can be called by android.graphics.drawable but must not be called from outside
184      * the module.
185      */
getNativeInstance(boolean filterFromPaint)186     public final synchronized long getNativeInstance(boolean filterFromPaint) {
187         if (shouldDiscardNativeInstance(filterFromPaint)) {
188             discardNativeInstanceLocked();
189         }
190 
191         if (mNativeInstance == 0) {
192             mNativeInstance = createNativeInstance(mLocalMatrix == null
193                     ? 0 : mLocalMatrix.ni(), filterFromPaint);
194             if (mNativeInstance != 0) {
195                 mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
196                         this, mNativeInstance);
197             }
198         }
199         return mNativeInstance;
200     }
201 
202     /**
203      * @hide so it can be called by android.graphics.drawable but must not be called from outside
204      * the module.
205      */
getNativeInstance()206     public final long getNativeInstance() {
207         // If the caller has no paint flag for filtering bitmaps, we just pass false
208         return getNativeInstance(false);
209     }
210 
211     /**
212      * @hide Only to be called by subclasses in the android.graphics package.
213      */
convertColors(@onNull @olorInt int[] colors)214     protected static @ColorLong long[] convertColors(@NonNull @ColorInt int[] colors) {
215         if (colors.length < 2) {
216             throw new IllegalArgumentException("needs >= 2 number of colors");
217         }
218 
219         long[] colorLongs = new long[colors.length];
220         for (int i = 0; i < colors.length; ++i) {
221             colorLongs[i] = Color.pack(colors[i]);
222         }
223 
224         return colorLongs;
225     }
226 
227     /**
228      * Detect the ColorSpace that the {@code colors} share.
229      *
230      * @throws IllegalArgumentException if the colors do not all share the same,
231      *      valid ColorSpace, or if there are less than 2 colors.
232      *
233      * @hide Only to be called by subclasses in the android.graphics package.
234      */
detectColorSpace(@onNull @olorLong long[] colors)235     protected static ColorSpace detectColorSpace(@NonNull @ColorLong long[] colors) {
236         if (colors.length < 2) {
237             throw new IllegalArgumentException("needs >= 2 number of colors");
238         }
239         final ColorSpace colorSpace = Color.colorSpace(colors[0]);
240         for (int i = 1; i < colors.length; ++i) {
241             if (Color.colorSpace(colors[i]) != colorSpace) {
242                 throw new IllegalArgumentException("All colors must be in the same ColorSpace!");
243             }
244         }
245         return colorSpace;
246     }
247 
nativeGetFinalizer()248     private static native long nativeGetFinalizer();
249 
250 }
251 
252