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/LICENSE2.0 9 * 10 * Unless required by applicable law or agreed to in riting, 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 package android.uirendering.cts.testclasses; 17 18 import android.graphics.Bitmap; 19 import android.graphics.Canvas; 20 import android.graphics.Color; 21 import android.graphics.LinearGradient; 22 import android.graphics.Paint; 23 import android.graphics.Point; 24 import android.graphics.PorterDuff; 25 import android.graphics.PorterDuffXfermode; 26 import android.graphics.Rect; 27 import android.graphics.RectF; 28 import android.graphics.Shader; 29 import android.test.suitebuilder.annotation.SmallTest; 30 import android.uirendering.cts.bitmapcomparers.BitmapComparer; 31 import android.uirendering.cts.bitmapcomparers.MSSIMComparer; 32 import android.uirendering.cts.bitmapverifiers.BitmapVerifier; 33 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier; 34 import android.uirendering.cts.testinfrastructure.ActivityTestBase; 35 import android.uirendering.cts.testinfrastructure.CanvasClient; 36 import android.uirendering.cts.testinfrastructure.DisplayModifier; 37 import android.uirendering.cts.testinfrastructure.ResourceModifier; 38 39 import java.util.LinkedHashMap; 40 import java.util.Map; 41 42 /** 43 * Test cases of all combination of resource modifications. 44 */ 45 public class SweepTests extends ActivityTestBase { 46 private static final String TAG = "SweepTests"; 47 48 public static final int BG_COLOR = 0xFFFFFFFF; 49 public static final int DST_COLOR = 0xFFFFCC44; 50 public static final int SRC_COLOR = 0xFF66AAFF; 51 public static final int MULTIPLY_COLOR = 0xFF668844; 52 public static final int SCREEN_COLOR = 0xFFFFEEFF; 53 54 // These points are in pairs, the first being the lower left corner, the second is only in the 55 // Destination bitmap, the third is the intersection of the two bitmaps, and the fourth is in 56 // the Source bitmap. 57 private final static Point[] XFERMODE_TEST_POINTS = new Point[] { 58 new Point(1, 80), new Point(25, 25), new Point(35, 35), new Point(70, 70) 59 }; 60 61 /** 62 * There are 4 locations we care about in any filter testing. 63 * 64 * 1) Both empty 65 * 2) Only src, dst empty 66 * 3) Both src + dst 67 * 4) Only dst, src empty 68 */ 69 private final Map<PorterDuff.Mode, int[]> XFERMODE_COLOR_MAP = new LinkedHashMap<PorterDuff.Mode, int[]>() { 70 { 71 put(PorterDuff.Mode.SRC, new int[] { 72 BG_COLOR, BG_COLOR, SRC_COLOR, SRC_COLOR 73 }); 74 75 put(PorterDuff.Mode.DST, new int[] { 76 BG_COLOR, DST_COLOR, DST_COLOR, BG_COLOR 77 }); 78 79 put(PorterDuff.Mode.SRC_OVER, new int[] { 80 BG_COLOR, DST_COLOR, SRC_COLOR, SRC_COLOR 81 }); 82 83 put(PorterDuff.Mode.DST_OVER, new int[] { 84 BG_COLOR, DST_COLOR, DST_COLOR, SRC_COLOR 85 }); 86 87 put(PorterDuff.Mode.SRC_IN, new int[] { 88 BG_COLOR, BG_COLOR, SRC_COLOR, BG_COLOR 89 }); 90 91 put(PorterDuff.Mode.DST_IN, new int[] { 92 BG_COLOR, BG_COLOR, DST_COLOR, BG_COLOR 93 }); 94 95 put(PorterDuff.Mode.SRC_OUT, new int[] { 96 BG_COLOR, BG_COLOR, BG_COLOR, SRC_COLOR 97 }); 98 99 put(PorterDuff.Mode.DST_OUT, new int[] { 100 BG_COLOR, DST_COLOR, BG_COLOR, BG_COLOR 101 }); 102 103 put(PorterDuff.Mode.SRC_ATOP, new int[] { 104 BG_COLOR, DST_COLOR, SRC_COLOR, BG_COLOR 105 }); 106 107 put(PorterDuff.Mode.DST_ATOP, new int[] { 108 BG_COLOR, BG_COLOR, DST_COLOR, SRC_COLOR 109 }); 110 111 put(PorterDuff.Mode.XOR, new int[] { 112 BG_COLOR, DST_COLOR, BG_COLOR, SRC_COLOR 113 }); 114 115 put(PorterDuff.Mode.MULTIPLY, new int[] { 116 BG_COLOR, BG_COLOR, MULTIPLY_COLOR, BG_COLOR 117 }); 118 119 put(PorterDuff.Mode.SCREEN, new int[] { 120 BG_COLOR, DST_COLOR, SCREEN_COLOR, SRC_COLOR 121 }); 122 } 123 }; 124 125 private final static DisplayModifier XFERMODE_MODIFIER = new DisplayModifier() { 126 private final RectF mSrcRect = new RectF(30, 30, 80, 80); 127 private final RectF mDstRect = new RectF(10, 10, 60, 60); 128 private final Bitmap mSrcBitmap = createSrc(); 129 private final Bitmap mDstBitmap = createDst(); 130 131 @Override 132 public void modifyDrawing(Paint paint, Canvas canvas) { 133 int sc = canvas.saveLayer(0, 0, TEST_WIDTH, TEST_HEIGHT, null); 134 135 canvas.drawBitmap(mDstBitmap, 0, 0, null); 136 canvas.drawBitmap(mSrcBitmap, 0, 0, paint); 137 138 canvas.restoreToCount(sc); 139 } 140 141 private Bitmap createSrc() { 142 Bitmap srcB = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888); 143 Canvas srcCanvas = new Canvas(srcB); 144 Paint srcPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 145 srcPaint.setColor(SRC_COLOR); 146 srcCanvas.drawRect(mSrcRect, srcPaint); 147 return srcB; 148 } 149 150 private Bitmap createDst() { 151 Bitmap dstB = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888); 152 Canvas dstCanvas = new Canvas(dstB); 153 Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 154 dstPaint.setColor(DST_COLOR); 155 dstCanvas.drawOval(mDstRect, dstPaint); 156 return dstB; 157 } 158 }; 159 160 // We care about one point in each of the four rectangles of different alpha values, as well as 161 // the area outside the rectangles 162 private final static Point[] COLOR_FILTER_ALPHA_POINTS = new Point[] { 163 new Point(9, 45), 164 new Point(27, 45), 165 new Point(45, 45), 166 new Point(63, 45), 167 new Point(81, 45) 168 }; 169 170 public static final int FILTER_COLOR = 0xFFBB0000; 171 private final Map<PorterDuff.Mode, int[]> COLOR_FILTER_ALPHA_MAP 172 = new LinkedHashMap<PorterDuff.Mode, int[]>() { 173 { 174 put(PorterDuff.Mode.SRC, new int[] { 175 FILTER_COLOR, FILTER_COLOR, FILTER_COLOR, FILTER_COLOR, FILTER_COLOR 176 }); 177 178 put(PorterDuff.Mode.DST, new int[] { 179 0xFFE6E6E6, 0xFFCCCCCC, 0xFFB3B3B3, 0xFF999999, 0xFFFFFFFF 180 }); 181 182 put(PorterDuff.Mode.SRC_OVER, new int[] { 183 0xFFBB0000, 0xFFBB0000, 0xFFBB0000, 0xFFBB0000, 0xFFBB0000 184 }); 185 186 put(PorterDuff.Mode.DST_OVER, new int[] { 187 0xFFAF1A1A, 0xFFA33333, 0xFF984D4D, 0xFF8B6666, 0xFFBB0000 188 }); 189 190 put(PorterDuff.Mode.SRC_IN, new int[] { 191 0xFFF1CCCC, 0xFFE49999, 0xFFD66666, 0xFFC83333, 0xFFFFFFFF 192 }); 193 194 put(PorterDuff.Mode.DST_IN, new int[] { 195 0xFFE6E6E6, 0xFFCCCCCC, 0xFFB3B3B3, 0xFF999999, 0xFFFFFFFF 196 }); 197 198 put(PorterDuff.Mode.SRC_OUT, new int[] { 199 0xFFC83333, 0xFFD66666, 0xFFE49999, 0xFFF1CCCC, 0xFFBB0000 200 }); 201 202 put(PorterDuff.Mode.DST_OUT, new int[] { 203 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF 204 }); 205 206 put(PorterDuff.Mode.SRC_ATOP, new int[] { 207 0xFFF1CCCC, 0xFFE49999, 0xFFD66666, 0xFFC93333, 0xFFFFFFFF 208 }); 209 210 put(PorterDuff.Mode.DST_ATOP, new int[] { 211 0xFFB01A1A, 0xFFA33333, 0xFF984D4D, 0xFF8B6666, 0xFFBB0000 212 }); 213 214 put(PorterDuff.Mode.XOR, new int[] { 215 0xFFC93333, 0xFFD66666, 0xFFE49999, 0xFFF1CCCC, 0xFFBB0000 216 }); 217 218 put(PorterDuff.Mode.MULTIPLY, new int[] { 219 0xFFDFCCCC, 0xFFBE9999, 0xFF9E6666, 0xFF7E3333, 0xFFFFFFFF 220 }); 221 222 put(PorterDuff.Mode.SCREEN, new int[] { 223 0xFFC21A1A, 0xFFC93333, 0xFFD04D4D, 0xFFD66666, 0xFFBB0000 224 }); 225 } 226 }; 227 228 /** 229 * Draws 5 blocks of different color/opacity to be blended against 230 */ 231 private final static DisplayModifier COLOR_FILTER_ALPHA_MODIFIER = new DisplayModifier() { 232 private final int[] BLOCK_COLORS = new int[] { 233 0x33808080, 234 0x66808080, 235 0x99808080, 236 0xCC808080, 237 0x00000000 238 }; 239 240 private final Bitmap mBitmap = createQuadRectBitmap(); 241 242 public void modifyDrawing(Paint paint, Canvas canvas) { 243 canvas.drawBitmap(mBitmap, 0, 0, paint); 244 } 245 246 private Bitmap createQuadRectBitmap() { 247 Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888); 248 Canvas canvas = new Canvas(bitmap); 249 Paint paint = new Paint(); 250 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); 251 final int blockCount = BLOCK_COLORS.length; 252 final int blockWidth = TEST_WIDTH / blockCount; 253 for (int i = 0 ; i < blockCount; i++) { 254 paint.setColor(BLOCK_COLORS[i]); 255 canvas.drawRect(i * blockWidth, 0, (i + 1) * blockWidth, TEST_HEIGHT, paint); 256 } 257 return bitmap; 258 } 259 }; 260 261 private final static DisplayModifier COLOR_FILTER_GRADIENT_MODIFIER = new DisplayModifier() { 262 private final Rect mBounds = new Rect(30, 30, 150, 150); 263 private final int[] mColors = new int[] { 264 Color.RED, Color.GREEN, Color.BLUE 265 }; 266 267 private final Bitmap mBitmap = createGradient(); 268 269 @Override 270 public void modifyDrawing(Paint paint, Canvas canvas) { 271 canvas.drawBitmap(mBitmap, 0, 0, paint); 272 } 273 274 private Bitmap createGradient() { 275 LinearGradient gradient = new LinearGradient(15, 45, 75, 45, mColors, null, 276 Shader.TileMode.REPEAT); 277 Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888); 278 Paint p = new Paint(); 279 p.setShader(gradient); 280 Canvas c = new Canvas(bitmap); 281 c.drawRect(mBounds, p); 282 return bitmap; 283 } 284 }; 285 286 public static final DisplayModifier mCircleDrawModifier = new DisplayModifier() { 287 @Override 288 public void modifyDrawing(Paint paint, Canvas canvas) { 289 canvas.drawCircle(TEST_WIDTH / 2, TEST_HEIGHT / 2, TEST_HEIGHT / 2, paint); 290 } 291 }; 292 293 /** 294 * 0.5 defines minimum similarity as 50% 295 */ 296 private static final float HIGH_THRESHOLD = 0.5f; 297 298 private static final BitmapComparer[] DEFAULT_MSSIM_COMPARER = new BitmapComparer[] { 299 new MSSIMComparer(HIGH_THRESHOLD) 300 }; 301 302 @SmallTest 303 public void testBasicDraws() { 304 sweepModifiersForMask(DisplayModifier.Accessor.SHAPES_MASK, null, DEFAULT_MSSIM_COMPARER, 305 null); 306 } 307 308 @SmallTest 309 public void testBasicShaders() { 310 sweepModifiersForMask(DisplayModifier.Accessor.SHADER_MASK, mCircleDrawModifier, 311 DEFAULT_MSSIM_COMPARER, null); 312 } 313 314 @SmallTest 315 public void testColorFilterUsingGradient() { 316 sweepModifiersForMask(DisplayModifier.Accessor.COLOR_FILTER_MASK, 317 COLOR_FILTER_GRADIENT_MODIFIER, DEFAULT_MSSIM_COMPARER, null); 318 } 319 320 @SmallTest 321 public void testColorFiltersAlphas() { 322 BitmapVerifier[] bitmapVerifiers = 323 new BitmapVerifier[DisplayModifier.PORTERDUFF_MODES.length]; 324 int index = 0; 325 for (PorterDuff.Mode mode : DisplayModifier.PORTERDUFF_MODES) { 326 bitmapVerifiers[index] = new SamplePointVerifier(COLOR_FILTER_ALPHA_POINTS, 327 COLOR_FILTER_ALPHA_MAP.get(mode)); 328 index++; 329 } 330 sweepModifiersForMask(DisplayModifier.Accessor.COLOR_FILTER_MASK, 331 COLOR_FILTER_ALPHA_MODIFIER, null, bitmapVerifiers); 332 } 333 334 @SmallTest 335 public void testXfermodes() { 336 BitmapVerifier[] bitmapVerifiers = 337 new BitmapVerifier[DisplayModifier.PORTERDUFF_MODES.length]; 338 int index = 0; 339 for (PorterDuff.Mode mode : DisplayModifier.PORTERDUFF_MODES) { 340 bitmapVerifiers[index] = new SamplePointVerifier(XFERMODE_TEST_POINTS, 341 XFERMODE_COLOR_MAP.get(mode)); 342 index++; 343 } 344 sweepModifiersForMask(DisplayModifier.Accessor.XFERMODE_MASK, XFERMODE_MODIFIER, 345 null, bitmapVerifiers); 346 } 347 348 /* 349 @SmallTest 350 public void testShaderSweeps() { 351 int mask = DisplayModifier.Accessor.AA_MASK 352 | DisplayModifier.Accessor.SHADER_MASK 353 | DisplayModifier.Accessor.XFERMODE_MASK 354 | DisplayModifier.Accessor.SHAPES_MASK; 355 sweepModifiersForMask(mask, null, DEFAULT_MSSIM_COMPARER, null); 356 } 357 */ 358 359 protected void sweepModifiersForMask(int mask, final DisplayModifier drawOp, 360 BitmapComparer[] bitmapComparers, BitmapVerifier[] bitmapVerifiers) { 361 if ((mask & DisplayModifier.Accessor.ALL_OPTIONS_MASK) == 0) { 362 throw new IllegalArgumentException("Attempt to test with a mask that is invalid"); 363 } 364 // Get the accessor of all the different modifications possible 365 final DisplayModifier.Accessor modifierAccessor = new DisplayModifier.Accessor(mask); 366 // Initialize the resources that we will need to access 367 ResourceModifier.init(getActivity().getResources()); 368 // For each modification combination, we will get the CanvasClient associated with it and 369 // from there execute a normal canvas test with that. 370 CanvasClient canvasClient = new CanvasClient() { 371 @Override 372 public void draw(Canvas canvas, int width, int height) { 373 Paint paint = new Paint(); 374 modifierAccessor.modifyDrawing(canvas, paint); 375 if (drawOp != null) { 376 drawOp.modifyDrawing(paint, canvas); 377 } 378 } 379 }; 380 381 int index = 0; 382 // Create the test cases with each combination 383 do { 384 canvasClient.setDebugString(modifierAccessor.getDebugString()); 385 if (bitmapComparers != null) { 386 int arrIndex = Math.min(index, bitmapComparers.length - 1); 387 createTest().addCanvasClient(canvasClient).runWithComparer(bitmapComparers[arrIndex]); 388 } else { 389 int arrIndex = Math.min(index, bitmapVerifiers.length - 1); 390 createTest().addCanvasClient(canvasClient).runWithVerifier(bitmapVerifiers[arrIndex]); 391 } 392 index++; 393 } while (modifierAccessor.step()); 394 } 395 } 396