1/*
2 * Copyright (C) 2016 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 */
16package android.uirendering.cts.testclasses;
17
18import android.graphics.Bitmap;
19import android.graphics.Canvas;
20import android.graphics.Color;
21import android.graphics.Paint;
22import android.graphics.Point;
23import android.graphics.PorterDuff;
24import android.graphics.PorterDuffXfermode;
25import android.graphics.RectF;
26import android.graphics.drawable.ColorDrawable;
27import android.support.test.filters.LargeTest;
28import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
29import android.uirendering.cts.testinfrastructure.ActivityTestBase;
30import android.uirendering.cts.testinfrastructure.CanvasClient;
31
32import org.junit.Test;
33import org.junit.runner.RunWith;
34import org.junit.runners.Parameterized;
35
36import java.util.ArrayList;
37import java.util.List;
38
39@LargeTest // Temporarily hidden from presubmit
40@RunWith(Parameterized.class)
41public class XfermodeTest extends ActivityTestBase {
42    /**
43     * There are 4 locations we care about in testing each filter:
44     *
45     * 1) Both empty
46     * 2) Only src, dst empty
47     * 3) Both src + dst
48     * 4) Only dst, src empty
49     */
50    private final static Point[] TEST_POINTS = new Point[] {
51            new Point(1, 80),
52            new Point(25, 25),
53            new Point(35, 35),
54            new Point(70, 70)
55    };
56
57    public static class Config {
58        final boolean hardwareAccelerated;
59        final PorterDuff.Mode mode;
60        final int[] expectedColors;
61
62        Config(boolean hardwareAccelerated, Object[] modeAndExpectedColors) {
63            this.hardwareAccelerated = hardwareAccelerated;
64            mode = (PorterDuff.Mode) modeAndExpectedColors[0];
65            expectedColors = (int[]) modeAndExpectedColors[1];
66        }
67
68        @Override
69        public String toString() {
70            return mode.name() + ", hardwareAccelerated=" + hardwareAccelerated;
71        }
72    };
73
74    public static List<XfermodeTest.Config> configs(Object[][] modesAndExpectedColors) {
75        List<XfermodeTest.Config> configs = new ArrayList<>();
76        for (boolean hardwareAccelerated : new boolean[] {false, true}) {
77            for (Object[] modeAndExpectedColors : modesAndExpectedColors) {
78                configs.add(new XfermodeTest.Config(hardwareAccelerated, modeAndExpectedColors));
79            }
80        }
81        return configs;
82    }
83
84    private static final int BG_COLOR = 0xFFFFFFFF;
85    private static final int DST_COLOR = 0xFFFFCC44;
86    private static final int SRC_COLOR = 0xFF66AAFF;
87    private static final int MULTIPLY_COLOR = 0xFF668844;
88    private static final int SCREEN_COLOR = 0xFFFFEEFF;
89
90    private static Object[][] MODES_AND_EXPECTED_COLORS = new Object[][] {
91        { PorterDuff.Mode.SRC, new int[] {
92                BG_COLOR, BG_COLOR, SRC_COLOR, SRC_COLOR } },
93
94        { PorterDuff.Mode.DST, new int[] {
95                BG_COLOR, DST_COLOR, DST_COLOR, BG_COLOR } },
96
97        { PorterDuff.Mode.SRC_OVER, new int[] {
98                BG_COLOR, DST_COLOR, SRC_COLOR, SRC_COLOR } },
99
100        { PorterDuff.Mode.DST_OVER, new int[] {
101                BG_COLOR, DST_COLOR, DST_COLOR, SRC_COLOR } },
102
103        { PorterDuff.Mode.SRC_IN, new int[] {
104                BG_COLOR, BG_COLOR, SRC_COLOR, BG_COLOR } },
105
106        { PorterDuff.Mode.DST_IN, new int[] {
107                BG_COLOR, BG_COLOR, DST_COLOR, BG_COLOR } },
108
109        { PorterDuff.Mode.SRC_OUT, new int[] {
110                BG_COLOR, BG_COLOR, BG_COLOR, SRC_COLOR } },
111
112        { PorterDuff.Mode.DST_OUT, new int[] {
113                BG_COLOR, DST_COLOR, BG_COLOR, BG_COLOR } },
114
115        { PorterDuff.Mode.SRC_ATOP, new int[] {
116                BG_COLOR, DST_COLOR, SRC_COLOR, BG_COLOR } },
117
118        { PorterDuff.Mode.DST_ATOP, new int[] {
119                BG_COLOR, BG_COLOR, DST_COLOR, SRC_COLOR } },
120
121        { PorterDuff.Mode.XOR, new int[] {
122                BG_COLOR, DST_COLOR, BG_COLOR, SRC_COLOR } },
123
124        { PorterDuff.Mode.MULTIPLY, new int[] {
125                BG_COLOR, BG_COLOR, MULTIPLY_COLOR, BG_COLOR } },
126
127        { PorterDuff.Mode.SCREEN, new int[] {
128                BG_COLOR, DST_COLOR, SCREEN_COLOR, SRC_COLOR } },
129    };
130
131    @Parameterized.Parameters(name = "{0}")
132    public static List<Config> configs() {
133        return configs(MODES_AND_EXPECTED_COLORS);
134    }
135
136    private final Config mConfig;
137
138    public XfermodeTest(Config config) {
139        mConfig = config;
140    }
141
142
143    @Override
144    public void setUp() {
145        super.setUp();
146
147        // temporary - ensure test isn't capturing window bg only
148        getInstrumentation().runOnMainSync(() -> getActivity().getWindow().setBackgroundDrawable(
149                        new ColorDrawable(Color.GREEN)));
150
151    }
152
153    private CanvasClient mCanvasClient = new CanvasClient() {
154        final Paint mPaint = new Paint();
155        private final RectF mSrcRect = new RectF(30, 30, 80, 80);
156        private final RectF mDstRect = new RectF(10, 10, 60, 60);
157        private final Bitmap mSrcBitmap = createSrc();
158        private final Bitmap mDstBitmap = createDst();
159
160        @Override
161        public void draw(Canvas canvas, int width, int height) {
162            canvas.drawColor(Color.WHITE); // temporary - ensure test isn't capturing window bg only
163
164            int sc = canvas.saveLayer(0, 0, TEST_WIDTH, TEST_HEIGHT, null);
165
166            canvas.drawBitmap(mDstBitmap, 0, 0, null);
167            mPaint.setXfermode(new PorterDuffXfermode(mConfig.mode));
168            canvas.drawBitmap(mSrcBitmap, 0, 0, mPaint);
169
170            canvas.restoreToCount(sc);
171        }
172
173        private Bitmap createSrc() {
174            Bitmap srcB = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
175            Canvas srcCanvas = new Canvas(srcB);
176            Paint srcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
177            srcPaint.setColor(SRC_COLOR);
178            srcCanvas.drawRect(mSrcRect, srcPaint);
179            return srcB;
180        }
181
182        private Bitmap createDst() {
183            Bitmap dstB = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
184            Canvas dstCanvas = new Canvas(dstB);
185            Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
186            dstPaint.setColor(DST_COLOR);
187            dstCanvas.drawOval(mDstRect, dstPaint);
188            return dstB;
189        }
190    };
191
192    @Test
193    public void test() {
194        createTest()
195                .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
196                .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
197    }
198}
199