Shader.java revision b581e6704fc1478bc1dda517502abd3eab2558d6
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
17package android.graphics;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21
22/**
23 * Shader is the based class for objects that return horizontal spans of colors
24 * during drawing. A subclass of Shader is installed in a Paint calling
25 * paint.setShader(shader). After that any object (other than a bitmap) that is
26 * drawn with that paint will get its color(s) from the shader.
27 */
28public class Shader {
29    /**
30     * @deprecated Use subclass constructors directly instead.
31     */
32    @Deprecated
33    public Shader() {}
34
35    /**
36     * Current native shader instance. Created and updated lazily when {@link #getNativeInstance()}
37     * is called - otherwise may be out of date with java setters/properties.
38     */
39    private long mNativeInstance;
40
41    private Matrix mLocalMatrix;
42
43    public enum TileMode {
44        /**
45         * replicate the edge color if the shader draws outside of its
46         * original bounds
47         */
48        CLAMP   (0),
49        /**
50         * repeat the shader's image horizontally and vertically
51         */
52        REPEAT  (1),
53        /**
54         * repeat the shader's image horizontally and vertically, alternating
55         * mirror images so that adjacent images always seam
56         */
57        MIRROR  (2);
58
59        TileMode(int nativeInt) {
60            this.nativeInt = nativeInt;
61        }
62        final int nativeInt;
63    }
64
65    /**
66     * Return true if the shader has a non-identity local matrix.
67     * @param localM Set to the local matrix of the shader, if the shader's matrix is non-null.
68     * @return true if the shader has a non-identity local matrix
69     */
70    public boolean getLocalMatrix(@NonNull Matrix localM) {
71        if (mLocalMatrix != null) {
72            localM.set(mLocalMatrix);
73            return true;
74        }
75        return false;
76    }
77
78    /**
79     * Set the shader's local matrix. Passing null will reset the shader's
80     * matrix to identity.
81     *
82     * @param localM The shader's new local matrix, or null to specify identity
83     */
84    public void setLocalMatrix(@Nullable Matrix localM) {
85        if (localM == null || localM.isIdentity()) {
86            if (mLocalMatrix != null) {
87                mLocalMatrix = null;
88                discardNativeInstance();
89            }
90        } else {
91            if (mLocalMatrix == null) {
92                mLocalMatrix = new Matrix(localM);
93                discardNativeInstance();
94            } else if (!mLocalMatrix.equals(localM)) {
95                mLocalMatrix.set(localM);
96                discardNativeInstance();
97            }
98        }
99    }
100
101    long createNativeInstance(long nativeMatrix) {
102        return 0;
103    }
104
105    void discardNativeInstance() {
106        nativeSafeUnref(mNativeInstance);
107        mNativeInstance = 0;
108    }
109
110    /**
111     * Callback for subclasses to call {@link #discardNativeInstance()} if the most recently
112     * constructed native instance is no longer valid.
113     */
114    void verifyNativeInstance() {
115    }
116
117    @Override
118    protected void finalize() throws Throwable {
119        try {
120            nativeSafeUnref(mNativeInstance);
121            mNativeInstance = -1;
122        } finally {
123            super.finalize();
124        }
125    }
126
127    /**
128     * @hide
129     */
130    protected Shader copy() {
131        final Shader copy = new Shader();
132        copyLocalMatrix(copy);
133        return copy;
134    }
135
136    /**
137     * @hide
138     */
139    protected void copyLocalMatrix(Shader dest) {
140        dest.mLocalMatrix.set(mLocalMatrix);
141    }
142
143    /**
144     * @hide
145     */
146    public long getNativeInstance() {
147        if (mNativeInstance == -1) {
148            throw new IllegalStateException("attempting to use a finalized Shader");
149        }
150
151        // verify mNativeInstance is valid
152        verifyNativeInstance();
153
154        if (mNativeInstance == 0) {
155            mNativeInstance = createNativeInstance(mLocalMatrix == null
156                    ? 0 : mLocalMatrix.native_instance);
157        }
158        return mNativeInstance;
159    }
160
161    private static native void nativeSafeUnref(long nativeInstance);
162}
163