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 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 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 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 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 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 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 float[] pts = { 127 0, 0, 80, 80, 80, 0, 0, 80, 40, 50, 60, 50 128 }; 129 canvas.drawLines(pts, p); 130 }) 131 .runWithComparer(mExactComparer); 132 } 133 134 @Test 135 public void testDrawWhiteScreen() { 136 createTest() 137 .addCanvasClient((canvas, width, height) -> canvas.drawColor(Color.WHITE)) 138 .runWithComparer(mExactComparer); 139 } 140 141 @Test 142 public void testBasicText() { 143 final String testString = "THIS IS A TEST"; 144 createTest() 145 .addCanvasClient((canvas, width, height) -> { 146 Paint p = new Paint(); 147 canvas.drawColor(Color.BLACK); 148 p.setColor(Color.WHITE); 149 p.setStrokeWidth(5); 150 canvas.drawText(testString, 30, 50, p); 151 }) 152 .runWithComparer(mExactComparer); 153 } 154 155 private void drawTestTextOnPath(Canvas canvas) { 156 final String testString = "THIS IS A TEST ON A CIRCLE PATH"; 157 Path path = new Path(); 158 path.addCircle(45, 45, 30, Path.Direction.CW); 159 Paint p = new Paint(); 160 p.setColor(Color.BLACK); 161 p.setAntiAlias(true); 162 canvas.drawTextOnPath(testString, path, 0f, 0f, p); 163 } 164 165 @Test 166 public void testTextOnPath() { 167 createTest() 168 .addCanvasClient((canvas, width, height) -> { 169 drawTestTextOnPath(canvas); 170 }) 171 .runWithVerifier(new GoldenImageVerifier(getActivity(), 172 // HWUI's texts are blurry, so we lower the threshold. 173 // Note that 0.7 will fail the test. 174 R.drawable.text_on_path, new MSSIMComparer(0.6))); 175 } 176 177 @Test 178 public void testTextOnPathUsingPicture() { 179 createTest() 180 .addCanvasClient((canvas, width, height) -> { 181 Picture picture = new Picture(); 182 Canvas pictureCanvas = picture.beginRecording(90, 90); 183 drawTestTextOnPath(pictureCanvas); 184 picture.endRecording(); 185 picture.draw(canvas); 186 }) 187 .runWithVerifier(new GoldenImageVerifier(getActivity(), 188 // HWUI's texts are blurry, so we lower the threshold. 189 // Note that 0.7 will fail the test. 190 R.drawable.text_on_path, new MSSIMComparer(0.6))); 191 } 192 193 @Test 194 public void testBasicColorXfermode() { 195 createTest() 196 .addCanvasClient((canvas, width, height) -> { 197 canvas.drawColor(Color.GRAY); 198 canvas.drawColor(Color.BLUE, PorterDuff.Mode.MULTIPLY); 199 }) 200 .runWithComparer(mExactComparer); 201 } 202 203 @Test 204 public void testBasicColorBlendMode() { 205 createTest().addCanvasClient((canvas, width, height) -> { 206 canvas.drawColor(Color.GRAY); 207 canvas.drawColor(Color.BLUE, BlendMode.MULTIPLY); 208 }).runWithComparer(mExactComparer); 209 } 210 211 @Test 212 public void testBluePaddedSquare() { 213 final NinePatchDrawable ninePatchDrawable = (NinePatchDrawable) 214 getActivity().getResources().getDrawable(R.drawable.blue_padded_square); 215 ninePatchDrawable.setBounds(0, 0, 90, 90); 216 217 BitmapVerifier verifier = new RectVerifier(Color.WHITE, Color.BLUE, 218 new Rect(10, 10, 80, 80)); 219 220 createTest() 221 .addCanvasClient((canvas, width, height) -> { 222 canvas.drawColor(Color.WHITE); 223 Paint p = new Paint(); 224 p.setColor(Color.BLUE); 225 canvas.drawRect(10, 10, 80, 80, p); 226 }) 227 .addCanvasClient( 228 (canvas, width, height) -> ninePatchDrawable.draw(canvas)) 229 .addLayout(R.layout.blue_padded_square, null) 230 .runWithVerifier(verifier); 231 } 232 233 @Test 234 public void testEmptyLayer() { 235 createTest() 236 .addCanvasClient((canvas, width, height) -> { 237 canvas.drawColor(Color.CYAN); 238 Paint p = new Paint(); 239 p.setColor(Color.BLACK); 240 canvas.saveLayer(10, 10, 80, 80, p); 241 canvas.restore(); 242 }) 243 .runWithComparer(mExactComparer); 244 } 245 246 @Test 247 public void testSaveLayerRounding() { 248 createTest() 249 .addCanvasClient((canvas, width, height) -> { 250 canvas.saveLayerAlpha(10.5f, 10.5f, 79.5f, 79.5f, 255); 251 canvas.drawRect(20, 20, 70, 70, new Paint()); 252 canvas.restore(); 253 }) 254 .runWithVerifier(new RectVerifier(Color.WHITE, Color.BLACK, 255 new Rect(20, 20, 70, 70))); 256 } 257 258 @Test 259 public void testUnclippedSaveLayerRounding() { 260 createTest() 261 .addCanvasClient((canvas, width, height) -> { 262 canvas.saveLayerAlpha(10.5f, 10.5f, 79.5f, 79.5f, 255); 263 canvas.drawRect(20, 20, 70, 70, new Paint()); 264 canvas.restore(); 265 }) 266 .runWithVerifier(new RectVerifier(Color.WHITE, Color.BLACK, 267 new Rect(20, 20, 70, 70))); 268 } 269 270 @Test 271 public void testBlackTriangleVertices() { 272 createTest() 273 .addCanvasClient((canvas, width, height) -> { 274 float[] vertices = new float[6]; 275 vertices[0] = width / 2.0f; 276 vertices[1] = 0; 277 vertices[2] = width; 278 vertices[3] = height; 279 vertices[4] = 0; 280 vertices[5] = height; 281 int[] colors = new int[] { Color.BLACK, Color.BLACK, Color.BLACK }; 282 canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0, 283 null, 0, colors, 0, null, 0, 0, 284 new Paint()); 285 }) 286 .runWithComparer(mExactComparer); 287 } 288 289 @Test 290 public void testBlackTriangleVertices2() { 291 BitmapVerifier verifier = new PerPixelBitmapVerifier() { 292 @Override 293 protected boolean verifyPixel(int x, int y, int observedColor) { 294 // The CanvasClient will draw the following black triangle on a white 295 // background: 296 // (40, 0) 297 // 298 // 299 // 300 // 301 // (0, 80) (80, 0) 302 if (y >= 80) { 303 // Below the triangle is white. 304 return CompareUtils.verifyPixelWithThreshold(observedColor, Color.WHITE, 0); 305 } else if (x < 40) { 306 // The line on the left is 307 // y = -2x + 80 308 // Above is white, below is black. Give some leeway for 309 // antialiasing. 310 if (y < -2 * x + 80 - 1) { 311 return CompareUtils.verifyPixelWithThreshold(observedColor, Color.WHITE, 0); 312 } else if (y > -2 * x + 80 + 1) { 313 return CompareUtils.verifyPixelWithThreshold(observedColor, Color.BLACK, 0); 314 } 315 } else { 316 // The line on the right is 317 // y = 2x - 80 318 // Above is white, below is black. Give some leeway for 319 // antialiasing. 320 if (y < 2 * x - 80 - 1) { 321 return CompareUtils.verifyPixelWithThreshold(observedColor, Color.WHITE, 0); 322 } else if (y > 2 * x - 80 + 1) { 323 return CompareUtils.verifyPixelWithThreshold(observedColor, Color.BLACK, 0); 324 } 325 } 326 // Ignore points very close to the line. 327 return true; 328 } 329 }; 330 331 createTest() 332 .addCanvasClient((canvas, width, height) -> { 333 canvas.drawColor(Color.WHITE); 334 335 float[] vertices = new float[6]; 336 vertices[0] = 40; 337 vertices[1] = 0; 338 vertices[2] = 80; 339 vertices[3] = 80; 340 vertices[4] = 0; 341 vertices[5] = 80; 342 int[] colors = new int[] { Color.BLACK, Color.BLACK, Color.BLACK }; 343 canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0, 344 null, 0, colors, 0, null, 0, 0, 345 new Paint()); 346 }) 347 .runWithVerifier(verifier); 348 } 349 350 @Test 351 public void testColorLongs() { 352 createTest() 353 .addCanvasClient((canvas, width, height) -> { 354 canvas.drawColor(Color.pack(0.5f, 0.3f, 0.1f, 1.0f, 355 ColorSpace.get(ColorSpace.Named.DISPLAY_P3))); 356 canvas.drawColor(Color.pack(0.2f, 0.2f, 0.2f, 1.0f, 357 ColorSpace.get(ColorSpace.Named.DISPLAY_P3)), BlendMode.PLUS); 358 Paint p = new Paint(); 359 p.setColor(Color.pack(0.7f, 0.9f, 0.4f, 1.0f, 360 ColorSpace.get(ColorSpace.Named.DISPLAY_P3))); 361 canvas.drawRect(20, 20, 70, 70, p); 362 }) 363 .runWithComparer(mExactComparer); 364 } 365 } 366