1/*
2 * Copyright (C) 2017 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.uirendering.cts.testclasses;
18
19import static android.graphics.Bitmap.Config.ARGB_8888;
20import static android.graphics.Bitmap.Config.HARDWARE;
21import static android.graphics.Bitmap.Config.RGB_565;
22
23import android.content.res.AssetManager;
24import android.graphics.Bitmap;
25import android.graphics.BitmapFactory;
26import android.graphics.BitmapShader;
27import android.graphics.Canvas;
28import android.graphics.Paint;
29import android.graphics.Point;
30import android.graphics.Shader;
31import android.support.annotation.NonNull;
32import android.support.annotation.Nullable;
33import android.support.test.filters.MediumTest;
34import android.support.test.runner.AndroidJUnit4;
35import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
36import android.uirendering.cts.testinfrastructure.ActivityTestBase;
37
38import org.junit.Before;
39import org.junit.Test;
40import org.junit.runner.RunWith;
41
42import java.io.IOException;
43import java.io.InputStream;
44
45@MediumTest
46@RunWith(AndroidJUnit4.class)
47public class ColorSpaceTests extends ActivityTestBase {
48    private Bitmap mMask;
49
50    @Before
51    public void loadMask() {
52        Bitmap res = BitmapFactory.decodeResource(getActivity().getResources(),
53                android.uirendering.cts.R.drawable.alpha_mask);
54        mMask = Bitmap.createBitmap(res.getWidth(), res.getHeight(), Bitmap.Config.ALPHA_8);
55        Canvas c = new Canvas(mMask);
56        c.drawBitmap(res, 0, 0, null);
57    }
58
59    @Test
60    public void testDrawDisplayP3() {
61        // Uses hardware transfer function
62        Bitmap bitmap8888 = loadAsset("green-p3.png", ARGB_8888);
63        Bitmap bitmapHardware = loadAsset("green-p3.png", HARDWARE);
64        createTest()
65                .addCanvasClient("Draw_DisplayP3_8888",
66                        (c, w, h) -> drawAsset(c, bitmap8888), true)
67                .addCanvasClientWithoutUsingPicture(
68                        (c, w, h) -> drawAsset(c, bitmapHardware), true)
69                .runWithVerifier(new SamplePointVerifier(
70                        new Point[] {
71                                point(0, 0), point(48, 0), point(32, 40), point(0, 40), point(0, 56)
72                        },
73                        new int[] { 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xffffffff, 0xff7f7f00 }
74                ));
75    }
76
77    @Test
78    public void testDrawDisplayP3Config565() {
79        // Uses hardware transfer function
80        Bitmap bitmap = loadAsset("green-p3.png", RGB_565);
81        createTest()
82                .addCanvasClient("Draw_DisplayP3_565", (c, w, h) -> drawAsset(c, bitmap), true)
83                .runWithVerifier(new SamplePointVerifier(
84                        new Point[] {
85                                point(0, 0), point(48, 0), point(32, 40), point(0, 40), point(0, 56)
86                        },
87                        new int[] { 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xffffffff, 0xff7f7f00 }
88                ));
89    }
90
91    @Test
92    public void testDrawProPhotoRGB() {
93        // Uses hardware limited shader transfer function
94        Bitmap bitmap8888 = loadAsset("orange-prophotorgb.png", ARGB_8888);
95        Bitmap bitmapHardware = loadAsset("orange-prophotorgb.png", HARDWARE);
96        createTest()
97                .addCanvasClient("Draw_ProPhotoRGB_8888",
98                        (c, w, h) -> drawAsset(c, bitmap8888), true)
99                .addCanvasClientWithoutUsingPicture(
100                        (c, w, h) -> drawAsset(c, bitmapHardware), true)
101                .runWithVerifier(new SamplePointVerifier(
102                        new Point[] {
103                                point(0, 0), point(48, 0), point(32, 40), point(0, 40), point(0, 56)
104                        },
105                        new int[] { 0xffff7f00, 0xffff7f00, 0xffff7f00, 0xffffffff, 0xffff3f00 }
106                ));
107    }
108
109    @Test
110    public void testDrawProPhotoRGBConfig565() {
111        // Uses hardware limited shader transfer function
112        Bitmap bitmap = loadAsset("orange-prophotorgb.png", RGB_565);
113        createTest()
114                .addCanvasClient("Draw_ProPhotoRGB_565",
115                        (c, w, h) -> drawAsset(c, bitmap), true)
116                .runWithVerifier(new SamplePointVerifier(
117                        new Point[] {
118                                point(0, 0), point(48, 0), point(32, 40), point(0, 40), point(0, 56)
119                        },
120                        new int[] { 0xffff7f00, 0xffff7f00, 0xffff7f00, 0xffffffff, 0xffff3f00 }
121                ));
122    }
123
124    @Test
125    public void testDrawTranslucentAdobeRGB() {
126        // Uses hardware simplified gamma transfer function
127        Bitmap bitmap8888 = loadAsset("red-adobergb.png", ARGB_8888);
128        Bitmap bitmapHardware = loadAsset("red-adobergb.png", HARDWARE);
129        createTest()
130                .addCanvasClient("Draw_AdobeRGB_Translucent_8888",
131                        (c, w, h) -> drawTranslucentAsset(c, bitmap8888), true)
132                .addCanvasClientWithoutUsingPicture(
133                        (c, w, h) -> drawTranslucentAsset(c, bitmapHardware), true)
134                .runWithVerifier(new SamplePointVerifier(
135                        new Point[] { point(0, 0) },
136                        new int[] { 0xffed8080 }
137                ));
138    }
139
140    private void drawAsset(@NonNull Canvas canvas, Bitmap bitmap) {
141        // Render bitmap directly
142        canvas.save();
143        canvas.clipRect(0, 0, 32, 32);
144        canvas.drawBitmap(bitmap, 0, 0, null);
145        canvas.restore();
146
147        // Render bitmap via shader
148        Paint p = new Paint();
149        p.setShader(new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
150        canvas.drawRect(32.0f, 0.0f, 64.0f, 32.0f, p);
151
152        // Render bitmap via shader using another bitmap as a mask
153        canvas.save();
154        canvas.clipRect(0, 32, 64, 48);
155        canvas.drawBitmap(mMask, 0, 0, p);
156        canvas.restore();
157
158        // Render bitmap with alpha to test modulation
159        p.setShader(null);
160        p.setAlpha(127);
161        canvas.save();
162        canvas.clipRect(0, 48, 64, 64);
163        canvas.drawColor(0xffff0000);
164        canvas.drawBitmap(bitmap, 0, 0, p);
165        canvas.restore();
166    }
167
168    @Nullable
169    private Bitmap loadAsset(@NonNull String assetName, @NonNull Bitmap.Config config) {
170        Bitmap bitmap;
171        AssetManager assets = getActivity().getResources().getAssets();
172        try (InputStream in = assets.open(assetName)) {
173            BitmapFactory.Options opts = new BitmapFactory.Options();
174            opts.inPreferredConfig = config;
175
176            bitmap = BitmapFactory.decodeStream(in, null, opts);
177        } catch (IOException e) {
178            throw new RuntimeException("Test failed: ", e);
179        }
180        return bitmap;
181    }
182
183    private void drawTranslucentAsset(@NonNull Canvas canvas, Bitmap bitmap) {
184        canvas.drawBitmap(bitmap, 0, 0, null);
185    }
186
187    @NonNull
188    private static Point point(int x, int y) {
189        return new Point(x, y);
190    }
191}
192