1 /*
2  * Copyright (C) 2014 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.uirendering.cts.testclasses;
18 
19 import android.graphics.BlendMode;
20 import android.graphics.Canvas;
21 import android.graphics.Color;
22 import android.graphics.ColorSpace;
23 import android.graphics.Paint;
24 import android.graphics.Path;
25 import android.graphics.Picture;
26 import android.graphics.PorterDuff;
27 import android.graphics.Rect;
28 import android.graphics.drawable.NinePatchDrawable;
29 import android.uirendering.cts.R;
30 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
31 import android.uirendering.cts.bitmapcomparers.ExactComparer;
32 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
33 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
34 import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
35 import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
36 import android.uirendering.cts.bitmapverifiers.RectVerifier;
37 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
38 import android.uirendering.cts.util.CompareUtils;
39 
40 import androidx.test.filters.MediumTest;
41 import androidx.test.runner.AndroidJUnit4;
42 
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 
46 @MediumTest
47 @RunWith(AndroidJUnit4.class)
48 public class ExactCanvasTests extends ActivityTestBase {
49     private final BitmapComparer mExactComparer = new ExactComparer();
50 
51     @Test
testBlueRect()52     public void testBlueRect() {
53         final Rect rect = new Rect(10, 10, 80, 80);
54         createTest()
55                 .addCanvasClient((canvas, width, height) -> {
56                     Paint p = new Paint();
57                     p.setAntiAlias(false);
58                     p.setColor(Color.BLUE);
59                     canvas.drawRect(rect, p);
60                 })
61                 .runWithVerifier(new RectVerifier(Color.WHITE, Color.BLUE, rect));
62     }
63 
64     @Test
testPoints()65     public void testPoints() {
66         createTest()
67                 .addCanvasClient((canvas, width, height) -> {
68                     Paint p = new Paint();
69                     p.setAntiAlias(false);
70                     p.setStrokeWidth(1f);
71                     p.setColor(Color.BLACK);
72                     for (int i = 0; i < 10; i++) {
73                         canvas.drawPoint(i * 10, i * 10, p);
74                     }
75                 })
76                 .runWithComparer(mExactComparer);
77     }
78 
79     @Test
testBlackRectWithStroke()80     public void testBlackRectWithStroke() {
81         createTest()
82                 .addCanvasClient((canvas, width, height) -> {
83                     Paint p = new Paint();
84                     p.setColor(Color.RED);
85                     canvas.drawRect(0, 0, ActivityTestBase.TEST_WIDTH,
86                             ActivityTestBase.TEST_HEIGHT, p);
87                     p.setColor(Color.BLACK);
88                     p.setStrokeWidth(5);
89                     canvas.drawRect(10, 10, 80, 80, p);
90                 })
91                 .runWithComparer(mExactComparer);
92     }
93 
94     @Test
testBlackLineOnGreenBack()95     public void testBlackLineOnGreenBack() {
96         createTest()
97                 .addCanvasClient((canvas, width, height) -> {
98                     canvas.drawColor(Color.GREEN);
99                     Paint p = new Paint();
100                     p.setColor(Color.BLACK);
101                     p.setStrokeWidth(10);
102                     canvas.drawLine(0, 0, 50, 0, p);
103                 })
104                 .runWithComparer(mExactComparer);
105     }
106 
107     @Test
testDrawRedRectOnBlueBack()108     public void testDrawRedRectOnBlueBack() {
109         createTest()
110                 .addCanvasClient((canvas, width, height) -> {
111                     canvas.drawColor(Color.BLUE);
112                     Paint p = new Paint();
113                     p.setColor(Color.RED);
114                     canvas.drawRect(10, 10, 40, 40, p);
115                 })
116                 .runWithComparer(mExactComparer);
117     }
118 
119     @Test
testDrawLine()120     public void testDrawLine() {
121         createTest()
122                 .addCanvasClient((canvas, width, height) -> {
123                     Paint p = new Paint();
124                     canvas.drawColor(Color.WHITE);
125                     p.setColor(Color.BLACK);
126                     p.setAntiAlias(false);
127                     float[] pts = {
128                             0, 0, 80, 80, 80, 0, 0, 80, 40, 50, 60, 50
129                     };
130                     canvas.drawLines(pts, p);
131                 })
132                 .runWithComparer(mExactComparer);
133     }
134 
135     @Test
testDrawWhiteScreen()136     public void testDrawWhiteScreen() {
137         createTest()
138                 .addCanvasClient((canvas, width, height) -> canvas.drawColor(Color.WHITE))
139                 .runWithComparer(mExactComparer);
140     }
141 
142     @Test
testBasicText()143     public void testBasicText() {
144         final String testString = "THIS IS A TEST";
145         createTest()
146                 .addCanvasClient((canvas, width, height) -> {
147                     Paint p = new Paint();
148                     canvas.drawColor(Color.BLACK);
149                     p.setColor(Color.WHITE);
150                     p.setStrokeWidth(5);
151                     canvas.drawText(testString, 30, 50, p);
152                 })
153                 .runWithComparer(mExactComparer);
154     }
155 
drawTestTextOnPath(Canvas canvas)156     private void drawTestTextOnPath(Canvas canvas) {
157         final String testString = "THIS IS A TEST ON A CIRCLE PATH";
158         Path path = new Path();
159         path.addCircle(45, 45, 30, Path.Direction.CW);
160         Paint p = new Paint();
161         p.setColor(Color.BLACK);
162         p.setAntiAlias(true);
163         canvas.drawTextOnPath(testString, path, 0f, 0f, p);
164     }
165 
166     @Test
testTextOnPath()167     public void testTextOnPath() {
168         createTest()
169                 .addCanvasClient((canvas, width, height) -> {
170                     drawTestTextOnPath(canvas);
171                 })
172                 .runWithVerifier(new GoldenImageVerifier(getActivity(),
173                     // HWUI's texts are blurry, so we lower the threshold.
174                     // Note that 0.7 will fail the test.
175                     R.drawable.text_on_path, new MSSIMComparer(0.6)));
176     }
177 
178     @Test
testTextOnPathUsingPicture()179     public void testTextOnPathUsingPicture() {
180         createTest()
181                 .addCanvasClient((canvas, width, height) -> {
182                     Picture picture = new Picture();
183                     Canvas pictureCanvas = picture.beginRecording(90, 90);
184                     drawTestTextOnPath(pictureCanvas);
185                     picture.endRecording();
186                     picture.draw(canvas);
187                 })
188                 .runWithVerifier(new GoldenImageVerifier(getActivity(),
189                     // HWUI's texts are blurry, so we lower the threshold.
190                     // Note that 0.7 will fail the test.
191                     R.drawable.text_on_path, new MSSIMComparer(0.6)));
192     }
193 
194     @Test
testBasicColorXfermode()195     public void testBasicColorXfermode() {
196         createTest()
197                 .addCanvasClient((canvas, width, height) -> {
198                     canvas.drawColor(Color.GRAY);
199                     canvas.drawColor(Color.BLUE, PorterDuff.Mode.MULTIPLY);
200                 })
201                 .runWithComparer(mExactComparer);
202     }
203 
204     @Test
testBasicColorBlendMode()205     public void testBasicColorBlendMode() {
206         createTest().addCanvasClient((canvas, width, height) -> {
207             canvas.drawColor(Color.GRAY);
208             canvas.drawColor(Color.BLUE, BlendMode.MULTIPLY);
209         }).runWithComparer(mExactComparer);
210     }
211 
212     @Test
testBluePaddedSquare()213     public void testBluePaddedSquare() {
214         final NinePatchDrawable ninePatchDrawable = (NinePatchDrawable)
215             getActivity().getResources().getDrawable(R.drawable.blue_padded_square);
216         ninePatchDrawable.setBounds(0, 0, 90, 90);
217 
218         BitmapVerifier verifier = new RectVerifier(Color.WHITE, Color.BLUE,
219                 new Rect(10, 10, 80, 80));
220 
221         createTest()
222                 .addCanvasClient((canvas, width, height) -> {
223                     canvas.drawColor(Color.WHITE);
224                     Paint p = new Paint();
225                     p.setColor(Color.BLUE);
226                     canvas.drawRect(10, 10, 80, 80, p);
227                 })
228                 .addCanvasClient(
229                         (canvas, width, height) -> ninePatchDrawable.draw(canvas))
230                 .addLayout(R.layout.blue_padded_square, null)
231                 .runWithVerifier(verifier);
232     }
233 
234     @Test
testEmptyLayer()235     public void testEmptyLayer() {
236         createTest()
237                 .addCanvasClient((canvas, width, height) -> {
238                     canvas.drawColor(Color.CYAN);
239                     Paint p = new Paint();
240                     p.setColor(Color.BLACK);
241                     canvas.saveLayer(10, 10, 80, 80, p);
242                     canvas.restore();
243                 })
244                 .runWithComparer(mExactComparer);
245     }
246 
247     @Test
testSaveLayerRounding()248     public void testSaveLayerRounding() {
249         createTest()
250                 .addCanvasClient((canvas, width, height) -> {
251                     canvas.saveLayerAlpha(10.5f, 10.5f, 79.5f, 79.5f, 255);
252                     canvas.drawRect(20, 20, 70, 70, new Paint());
253                     canvas.restore();
254                 })
255                 .runWithVerifier(new RectVerifier(Color.WHITE, Color.BLACK,
256                         new Rect(20, 20, 70, 70)));
257     }
258 
259     @Test
testUnclippedSaveLayerRounding()260     public void testUnclippedSaveLayerRounding() {
261         createTest()
262                 .addCanvasClient((canvas, width, height) -> {
263                     canvas.saveLayerAlpha(10.5f, 10.5f, 79.5f, 79.5f, 255);
264                     canvas.drawRect(20, 20, 70, 70, new Paint());
265                     canvas.restore();
266                 })
267                 .runWithVerifier(new RectVerifier(Color.WHITE, Color.BLACK,
268                         new Rect(20, 20, 70, 70)));
269     }
270 
271     @Test
testBlackTriangleVertices()272     public void testBlackTriangleVertices() {
273         createTest()
274                 .addCanvasClient((canvas, width, height) -> {
275                     float[] vertices = new float[6];
276                     vertices[0] = width / 2.0f;
277                     vertices[1] = 0;
278                     vertices[2] = width;
279                     vertices[3] = height;
280                     vertices[4] = 0;
281                     vertices[5] = height;
282                     int[] colors = new int[] { Color.BLACK, Color.BLACK, Color.BLACK };
283                     canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0,
284                             null, 0, colors, 0, null, 0, 0,
285                             new Paint());
286                 })
287                 .runWithComparer(mExactComparer);
288     }
289 
290     @Test
testBlackTriangleVertices2()291     public void testBlackTriangleVertices2() {
292         BitmapVerifier verifier = new PerPixelBitmapVerifier() {
293             @Override
294             protected boolean verifyPixel(int x, int y, int observedColor) {
295                 // The CanvasClient will draw the following black triangle on a white
296                 // background:
297                 //               (40, 0)
298                 //
299                 //
300                 //
301                 //
302                 // (0, 80)                      (80, 0)
303                 if (y >= 80) {
304                     // Below the triangle is white.
305                     return CompareUtils.verifyPixelWithThreshold(observedColor, Color.WHITE, 0);
306                 } else if (x < 40) {
307                     // The line on the left is
308                     //    y = -2x + 80
309                     // Above is white, below is black. Give some leeway for
310                     // antialiasing.
311                     if (y < -2 * x + 80 - 1) {
312                         return CompareUtils.verifyPixelWithThreshold(observedColor, Color.WHITE, 0);
313                     } else if (y > -2 * x + 80 + 1) {
314                         return CompareUtils.verifyPixelWithThreshold(observedColor, Color.BLACK, 0);
315                     }
316                 } else {
317                     // The line on the right is
318                     //    y = 2x - 80
319                     // Above is white, below is black. Give some leeway for
320                     // antialiasing.
321                     if (y < 2 * x - 80 - 1) {
322                         return CompareUtils.verifyPixelWithThreshold(observedColor, Color.WHITE, 0);
323                     } else if (y > 2 * x - 80 + 1) {
324                         return CompareUtils.verifyPixelWithThreshold(observedColor, Color.BLACK, 0);
325                     }
326                 }
327                 // Ignore points very close to the line.
328                 return true;
329             }
330         };
331 
332         createTest()
333                 .addCanvasClient((canvas, width, height) -> {
334                     canvas.drawColor(Color.WHITE);
335 
336                     float[] vertices = new float[6];
337                     vertices[0] = 40;
338                     vertices[1] = 0;
339                     vertices[2] = 80;
340                     vertices[3] = 80;
341                     vertices[4] = 0;
342                     vertices[5] = 80;
343                     int[] colors = new int[] { Color.BLACK, Color.BLACK, Color.BLACK };
344                     canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0,
345                             null, 0, colors, 0, null, 0, 0,
346                             new Paint());
347                 })
348                 .runWithVerifier(verifier);
349     }
350 
351     @Test
testColorLongs()352     public void testColorLongs() {
353         createTest()
354                 .addCanvasClient((canvas, width, height) -> {
355                     canvas.drawColor(Color.pack(0.5f, 0.3f, 0.1f, 1.0f,
356                                 ColorSpace.get(ColorSpace.Named.DISPLAY_P3)));
357                     canvas.drawColor(Color.pack(0.2f, 0.2f, 0.2f, 1.0f,
358                                 ColorSpace.get(ColorSpace.Named.DISPLAY_P3)), BlendMode.PLUS);
359                     Paint p = new Paint();
360                     p.setColor(Color.pack(0.7f, 0.9f, 0.4f, 1.0f,
361                                 ColorSpace.get(ColorSpace.Named.DISPLAY_P3)));
362                     canvas.drawRect(20, 20, 70, 70, p);
363                 })
364                 .runWithComparer(mExactComparer);
365     }
366 }
367