19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik
20b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craikimport android.annotation.NonNull;
21b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik
22e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio/** A subclass of shader that returns the composition of two other shaders, combined by
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    an {@link android.graphics.Xfermode} subclass.
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ComposeShader extends Shader {
26e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio
27b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    Shader mShaderA;
28b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    private long mNativeInstanceShaderA;
29b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    Shader mShaderB;
30b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    private long mNativeInstanceShaderB;
315d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck    private int mPorterDuffMode;
32b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik
33b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    /**
34b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * Create a new compose shader, given shaders A, B, and a combining mode.
35b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * When the mode is applied, it will be given the result from shader A as its
36b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * "dst", and the result from shader B as its "src".
37b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     *
38b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * @param shaderA  The colors from this shader are seen as the "dst" by the mode
39b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * @param shaderB  The colors from this shader are seen as the "src" by the mode
40b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * @param mode     The mode that combines the colors from the two shaders. If mode
41b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     *                 is null, then SRC_OVER is assumed.
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
43b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull Xfermode mode) {
445d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck        this(shaderA, shaderB, mode.porterDuffMode);
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
47b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    /**
48b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
49b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * When the mode is applied, it will be given the result from shader A as its
50b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * "dst", and the result from shader B as its "src".
51b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     *
52b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * @param shaderA  The colors from this shader are seen as the "dst" by the mode
53b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * @param shaderB  The colors from this shader are seen as the "src" by the mode
54b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik     * @param mode     The PorterDuff mode that combines the colors from the two shaders.
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
56b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB,
57b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik            @NonNull PorterDuff.Mode mode) {
585d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck        this(shaderA, shaderB, mode.nativeInt);
595d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck    }
605d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck
615d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck    private ComposeShader(Shader shaderA, Shader shaderB, int nativeMode) {
62b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik        if (shaderA == null || shaderB == null) {
63b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik            throw new IllegalArgumentException("Shader parameters must not be null");
64b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik        }
65b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik
66de0547c07a65b59d5330588cdd8b1e410a613e9cRomain Guy        mShaderA = shaderA;
67de0547c07a65b59d5330588cdd8b1e410a613e9cRomain Guy        mShaderB = shaderB;
685d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck        mPorterDuffMode = nativeMode;
69b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    }
70b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik
71b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    @Override
72b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    long createNativeInstance(long nativeMatrix) {
73b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik        mNativeInstanceShaderA = mShaderA.getNativeInstance();
74b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik        mNativeInstanceShaderB = mShaderB.getNativeInstance();
75b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik        return nativeCreate(nativeMatrix,
76b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik                mShaderA.getNativeInstance(), mShaderB.getNativeInstance(), mPorterDuffMode);
77b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    }
78b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik
793915e25d41ce40f24fd41d8bcd6a058403d0bbc5John Reck    /** @hide */
80f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik    @Override
813915e25d41ce40f24fd41d8bcd6a058403d0bbc5John Reck    protected void verifyNativeInstance() {
82f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik        if (mShaderA.getNativeInstance() != mNativeInstanceShaderA
83f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik                || mShaderB.getNativeInstance() != mNativeInstanceShaderB) {
84f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik            // Child shader native instance has been updated,
85f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik            // so our cached native instance is no longer valid - discard it
86f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik            discardNativeInstance();
87f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik        }
88f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik    }
89f6b0e60bd07436edb033ffe975030b7c1ee91626Chris Craik
90e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio    /**
91e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio     * @hide
92e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio     */
93e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio    @Override
94e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio    protected Shader copy() {
955d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck        final ComposeShader copy = new ComposeShader(
965d31a293ad0a832c7b8b445c1a67fb1800e5da32John Reck                mShaderA.copy(), mShaderB.copy(), mPorterDuffMode);
97e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio        copyLocalMatrix(copy);
98e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio        return copy;
99e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio    }
100e3c526f4f603e83c5fa8b9e399506b085f5648b7Fabrice Di Meglio
101b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik    private static native long nativeCreate(long nativeMatrix,
102b581e6704fc1478bc1dda517502abd3eab2558d6Chris Craik            long nativeShaderA, long nativeShaderB, int porterDuffMode);
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
104