1 /* 2 * Copyright (C) 2012 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 com.android.test.hwuicompare; 18 19 import java.util.LinkedHashMap; 20 import java.util.Map.Entry; 21 22 import android.graphics.Canvas; 23 import android.graphics.Paint; 24 import android.graphics.RectF; 25 import android.util.Log; 26 27 public abstract class DisplayModifier { 28 29 // automated tests ignore any combination of operations that don't together return TOTAL_MASK 30 protected final static int TOTAL_MASK = 0x1F; 31 32 // if we're filling, ensure we're not also sweeping over stroke parameters 33 protected final static int SWEEP_STROKE_WIDTH_BIT = 0x1 << 0; 34 protected final static int SWEEP_STROKE_CAP_BIT = 0x1 << 1; 35 protected final static int SWEEP_STROKE_JOIN_BIT = 0x1 << 2; 36 37 protected final static int SWEEP_SHADER_BIT = 0x1 << 3; // only allow non-simple shaders to use rectangle drawing 38 protected final static int SWEEP_TRANSFORM_BIT = 0x1 << 4; // only sweep over specified transforms 39 40 abstract public void modifyDrawing(Paint paint, Canvas canvas); 41 protected int mask() { return 0x0; }; 42 43 private static final RectF gRect = new RectF(0, 0, 200, 175); 44 private static final float[] gPts = new float[] { 45 0, 100, 100, 0, 100, 200, 200, 100 46 }; 47 48 private static final int NUM_PARALLEL_LINES = 24; 49 private static final float[] gTriPts = new float[] { 50 75, 0, 130, 130, 130, 130, 0, 130, 0, 130, 75, 0 51 }; 52 private static final float[] gLinePts = new float[NUM_PARALLEL_LINES * 8 + gTriPts.length]; 53 static { 54 int index; 55 for (index = 0; index < gTriPts.length; index++) { 56 gLinePts[index] = gTriPts[index]; 57 } 58 float val = 0; 59 for (int i = 0; i < NUM_PARALLEL_LINES; i++) { 60 gLinePts[index + 0] = 150; 61 gLinePts[index + 1] = val; 62 gLinePts[index + 2] = 300; 63 gLinePts[index + 3] = val; 64 index += 4; 65 val += 8 + (2.0f/NUM_PARALLEL_LINES); 66 } 67 val = 0; 68 for (int i = 0; i < NUM_PARALLEL_LINES; i++) { 69 gLinePts[index + 0] = val; 70 gLinePts[index + 1] = 150; 71 gLinePts[index + 2] = val; 72 gLinePts[index + 3] = 300; 73 index += 4; 74 val += 8 + (2.0f/NUM_PARALLEL_LINES); 75 } 76 }; 77 78 @SuppressWarnings("serial") 79 private static final LinkedHashMap<String, LinkedHashMap<String, DisplayModifier>> gMaps = new LinkedHashMap<String, LinkedHashMap<String, DisplayModifier>>() { 80 { 81 put("aa", new LinkedHashMap<String, DisplayModifier>() { 82 { 83 put("true", new DisplayModifier() { 84 @Override 85 public void modifyDrawing(Paint paint, Canvas canvas) { 86 paint.setAntiAlias(true); 87 } 88 }); 89 put("false", new DisplayModifier() { 90 @Override 91 public void modifyDrawing(Paint paint, Canvas canvas) { 92 paint.setAntiAlias(false); 93 } 94 }); 95 } 96 }); 97 put("style", new LinkedHashMap<String, DisplayModifier>() { 98 { 99 put("fill", new DisplayModifier() { 100 @Override 101 public void modifyDrawing(Paint paint, Canvas canvas) { 102 paint.setStyle(Paint.Style.FILL); 103 } 104 }); 105 put("stroke", new DisplayModifier() { 106 @Override 107 public void modifyDrawing(Paint paint, Canvas canvas) { 108 paint.setStyle(Paint.Style.STROKE); 109 } 110 @Override 111 protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } 112 }); 113 put("fillAndStroke", new DisplayModifier() { 114 @Override 115 public void modifyDrawing(Paint paint, Canvas canvas) { 116 paint.setStyle(Paint.Style.FILL_AND_STROKE); 117 } 118 119 @Override 120 protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } 121 }); 122 } 123 }); 124 put("strokeWidth", new LinkedHashMap<String, DisplayModifier>() { 125 { 126 put("hair", new DisplayModifier() { 127 @Override 128 public void modifyDrawing(Paint paint, Canvas canvas) { 129 paint.setStrokeWidth(0); 130 } 131 @Override 132 protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } 133 }); 134 put("0.3", new DisplayModifier() { 135 @Override 136 public void modifyDrawing(Paint paint, Canvas canvas) { 137 paint.setStrokeWidth(0.3f); 138 } 139 }); 140 put("1", new DisplayModifier() { 141 @Override 142 public void modifyDrawing(Paint paint, Canvas canvas) { 143 paint.setStrokeWidth(1); 144 } 145 }); 146 put("5", new DisplayModifier() { 147 @Override 148 public void modifyDrawing(Paint paint, Canvas canvas) { 149 paint.setStrokeWidth(5); 150 } 151 }); 152 put("30", new DisplayModifier() { 153 @Override 154 public void modifyDrawing(Paint paint, Canvas canvas) { 155 paint.setStrokeWidth(30); 156 } 157 }); 158 } 159 }); 160 put("strokeCap", new LinkedHashMap<String, DisplayModifier>() { 161 { 162 put("butt", new DisplayModifier() { 163 @Override 164 public void modifyDrawing(Paint paint, Canvas canvas) { 165 paint.setStrokeCap(Paint.Cap.BUTT); 166 } 167 @Override 168 protected int mask() { return SWEEP_STROKE_CAP_BIT; } 169 }); 170 put("round", new DisplayModifier() { 171 @Override 172 public void modifyDrawing(Paint paint, Canvas canvas) { 173 paint.setStrokeCap(Paint.Cap.ROUND); 174 } 175 }); 176 put("square", new DisplayModifier() { 177 @Override 178 public void modifyDrawing(Paint paint, Canvas canvas) { 179 paint.setStrokeCap(Paint.Cap.SQUARE); 180 } 181 }); 182 } 183 }); 184 put("strokeJoin", new LinkedHashMap<String, DisplayModifier>() { 185 { 186 put("bevel", new DisplayModifier() { 187 @Override 188 public void modifyDrawing(Paint paint, Canvas canvas) { 189 paint.setStrokeJoin(Paint.Join.BEVEL); 190 } 191 @Override 192 protected int mask() { return SWEEP_STROKE_JOIN_BIT; } 193 }); 194 put("round", new DisplayModifier() { 195 @Override 196 public void modifyDrawing(Paint paint, Canvas canvas) { 197 paint.setStrokeJoin(Paint.Join.ROUND); 198 } 199 }); 200 put("miter", new DisplayModifier() { 201 @Override 202 public void modifyDrawing(Paint paint, Canvas canvas) { 203 paint.setStrokeJoin(Paint.Join.MITER); 204 } 205 }); 206 // TODO: add miter0, miter1 etc to test miter distances 207 } 208 }); 209 210 put("transform", new LinkedHashMap<String, DisplayModifier>() { 211 { 212 put("noTransform", new DisplayModifier() { 213 @Override 214 public void modifyDrawing(Paint paint, Canvas canvas) {} 215 @Override 216 protected int mask() { return SWEEP_TRANSFORM_BIT; }; 217 }); 218 put("rotate5", new DisplayModifier() { 219 @Override 220 public void modifyDrawing(Paint paint, Canvas canvas) { 221 canvas.rotate(5); 222 } 223 }); 224 put("rotate45", new DisplayModifier() { 225 @Override 226 public void modifyDrawing(Paint paint, Canvas canvas) { 227 canvas.rotate(45); 228 } 229 }); 230 put("rotate90", new DisplayModifier() { 231 @Override 232 public void modifyDrawing(Paint paint, Canvas canvas) { 233 canvas.rotate(90); 234 canvas.translate(0, -200); 235 } 236 }); 237 put("scale2x2", new DisplayModifier() { 238 @Override 239 public void modifyDrawing(Paint paint, Canvas canvas) { 240 canvas.scale(2, 2); 241 } 242 @Override 243 protected int mask() { return SWEEP_TRANSFORM_BIT; }; 244 }); 245 put("rot20scl1x4", new DisplayModifier() { 246 @Override 247 public void modifyDrawing(Paint paint, Canvas canvas) { 248 canvas.rotate(20); 249 canvas.scale(1, 4); 250 } 251 @Override 252 protected int mask() { return SWEEP_TRANSFORM_BIT; }; 253 }); 254 } 255 }); 256 257 put("shader", new LinkedHashMap<String, DisplayModifier>() { 258 { 259 put("noShader", new DisplayModifier() { 260 @Override 261 public void modifyDrawing(Paint paint, Canvas canvas) {} 262 @Override 263 protected int mask() { return SWEEP_SHADER_BIT; }; 264 }); 265 put("repeatShader", new DisplayModifier() { 266 @Override 267 public void modifyDrawing(Paint paint, Canvas canvas) { 268 paint.setShader(ResourceModifiers.instance().mRepeatShader); 269 } 270 @Override 271 protected int mask() { return SWEEP_SHADER_BIT; }; 272 }); 273 put("translatedShader", new DisplayModifier() { 274 @Override 275 public void modifyDrawing(Paint paint, Canvas canvas) { 276 paint.setShader(ResourceModifiers.instance().mTranslatedShader); 277 } 278 }); 279 put("scaledShader", new DisplayModifier() { 280 @Override 281 public void modifyDrawing(Paint paint, Canvas canvas) { 282 paint.setShader(ResourceModifiers.instance().mScaledShader); 283 } 284 }); 285 put("horGradient", new DisplayModifier() { 286 @Override 287 public void modifyDrawing(Paint paint, Canvas canvas) { 288 paint.setShader(ResourceModifiers.instance().mHorGradient); 289 } 290 }); 291 put("diagGradient", new DisplayModifier() { 292 @Override 293 public void modifyDrawing(Paint paint, Canvas canvas) { 294 paint.setShader(ResourceModifiers.instance().mDiagGradient); 295 } 296 @Override 297 protected int mask() { return SWEEP_SHADER_BIT; }; 298 }); 299 put("vertGradient", new DisplayModifier() { 300 @Override 301 public void modifyDrawing(Paint paint, Canvas canvas) { 302 paint.setShader(ResourceModifiers.instance().mVertGradient); 303 } 304 }); 305 put("radGradient", new DisplayModifier() { 306 @Override 307 public void modifyDrawing(Paint paint, Canvas canvas) { 308 paint.setShader(ResourceModifiers.instance().mRadGradient); 309 } 310 }); 311 put("sweepGradient", new DisplayModifier() { 312 @Override 313 public void modifyDrawing(Paint paint, Canvas canvas) { 314 paint.setShader(ResourceModifiers.instance().mSweepGradient); 315 } 316 }); 317 put("composeShader", new DisplayModifier() { 318 @Override 319 public void modifyDrawing(Paint paint, Canvas canvas) { 320 paint.setShader(ResourceModifiers.instance().mComposeShader); 321 } 322 }); 323 put("bad composeShader", new DisplayModifier() { 324 @Override 325 public void modifyDrawing(Paint paint, Canvas canvas) { 326 paint.setShader(ResourceModifiers.instance().mBadComposeShader); 327 } 328 }); 329 put("bad composeShader 2", new DisplayModifier() { 330 @Override 331 public void modifyDrawing(Paint paint, Canvas canvas) { 332 paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader); 333 } 334 }); 335 } 336 }); 337 338 // FINAL MAP: DOES ACTUAL DRAWING 339 put("drawing", new LinkedHashMap<String, DisplayModifier>() { 340 { 341 put("roundRect", new DisplayModifier() { 342 @Override 343 public void modifyDrawing(Paint paint, Canvas canvas) { 344 canvas.drawRoundRect(gRect, 20, 20, paint); 345 } 346 }); 347 put("rect", new DisplayModifier() { 348 @Override 349 public void modifyDrawing(Paint paint, Canvas canvas) { 350 canvas.drawRect(gRect, paint); 351 } 352 @Override 353 protected int mask() { return SWEEP_SHADER_BIT | SWEEP_STROKE_CAP_BIT; }; 354 }); 355 put("circle", new DisplayModifier() { 356 @Override 357 public void modifyDrawing(Paint paint, Canvas canvas) { 358 canvas.drawCircle(100, 100, 75, paint); 359 } 360 }); 361 put("oval", new DisplayModifier() { 362 @Override 363 public void modifyDrawing(Paint paint, Canvas canvas) { 364 canvas.drawOval(gRect, paint); 365 } 366 }); 367 put("lines", new DisplayModifier() { 368 @Override 369 public void modifyDrawing(Paint paint, Canvas canvas) { 370 canvas.drawLines(gLinePts, paint); 371 } 372 @Override 373 protected int mask() { return SWEEP_STROKE_CAP_BIT; }; 374 }); 375 put("plusPoints", new DisplayModifier() { 376 @Override 377 public void modifyDrawing(Paint paint, Canvas canvas) { 378 canvas.drawPoints(gPts, paint); 379 } 380 }); 381 put("text", new DisplayModifier() { 382 @Override 383 public void modifyDrawing(Paint paint, Canvas canvas) { 384 paint.setTextSize(36); 385 canvas.drawText("TEXTTEST", 0, 50, paint); 386 } 387 }); 388 put("shadowtext", new DisplayModifier() { 389 @Override 390 public void modifyDrawing(Paint paint, Canvas canvas) { 391 paint.setTextSize(36); 392 paint.setShadowLayer(3.0f, 0.0f, 3.0f, 0xffff00ff); 393 canvas.drawText("TEXTTEST", 0, 50, paint); 394 } 395 }); 396 put("bitmapMesh", new DisplayModifier() { 397 @Override 398 public void modifyDrawing(Paint paint, Canvas canvas) { 399 canvas.drawBitmapMesh(ResourceModifiers.instance().mBitmap, 3, 3, 400 ResourceModifiers.instance().mBitmapVertices, 0, null, 0, null); 401 } 402 }); 403 put("arc", new DisplayModifier() { 404 @Override 405 public void modifyDrawing(Paint paint, Canvas canvas) { 406 canvas.drawArc(gRect, 260, 285, false, paint); 407 } 408 @Override 409 protected int mask() { return SWEEP_STROKE_CAP_BIT; }; 410 }); 411 put("arcFromCenter", new DisplayModifier() { 412 @Override 413 public void modifyDrawing(Paint paint, Canvas canvas) { 414 canvas.drawArc(gRect, 260, 285, true, paint); 415 } 416 @Override 417 protected int mask() { return SWEEP_STROKE_JOIN_BIT; }; 418 }); 419 } 420 }); 421 // WARNING: DON'T PUT MORE MAPS BELOW THIS 422 } 423 }; 424 425 private static LinkedHashMap<String, DisplayModifier> getMapAtIndex(int index) { 426 for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { 427 if (index == 0) { 428 return map; 429 } 430 index--; 431 } 432 return null; 433 } 434 435 // indices instead of iterators for easier bidirectional traversal 436 private static final int mIndices[] = new int[gMaps.size()]; 437 private static final String[] mLastAppliedModifications = new String[gMaps.size()]; 438 439 private static boolean stepInternal(boolean forward) { 440 int modifierMapIndex = gMaps.size() - 1; 441 while (modifierMapIndex >= 0) { 442 LinkedHashMap<String, DisplayModifier> map = getMapAtIndex(modifierMapIndex); 443 mIndices[modifierMapIndex] += (forward ? 1 : -1); 444 445 if (mIndices[modifierMapIndex] >= 0 && mIndices[modifierMapIndex] < map.size()) { 446 break; 447 } 448 449 mIndices[modifierMapIndex] = (forward ? 0 : map.size() - 1); 450 modifierMapIndex--; 451 } 452 return modifierMapIndex < 0; // true if resetting 453 } 454 455 public static boolean step() { 456 boolean ret = false; 457 do { 458 ret |= stepInternal(true); 459 } while (!checkModificationStateMask()); 460 return ret; 461 } 462 463 public static boolean stepBack() { 464 boolean ret = false; 465 do { 466 ret |= stepInternal(false); 467 } while (!checkModificationStateMask()); 468 return ret; 469 } 470 471 private static boolean checkModificationStateMask() { 472 int operatorMask = 0x0; 473 int mapIndex = 0; 474 for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { 475 int displayModifierIndex = mIndices[mapIndex]; 476 for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) { 477 if (displayModifierIndex == 0) { 478 mLastAppliedModifications[mapIndex] = modifierEntry.getKey(); 479 operatorMask |= modifierEntry.getValue().mask(); 480 break; 481 } 482 displayModifierIndex--; 483 } 484 mapIndex++; 485 } 486 return operatorMask == TOTAL_MASK; 487 } 488 489 public static void apply(Paint paint, Canvas canvas) { 490 int mapIndex = 0; 491 for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { 492 int displayModifierIndex = mIndices[mapIndex]; 493 for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) { 494 if (displayModifierIndex == 0) { 495 mLastAppliedModifications[mapIndex] = modifierEntry.getKey(); 496 modifierEntry.getValue().modifyDrawing(paint, canvas); 497 break; 498 } 499 displayModifierIndex--; 500 } 501 mapIndex++; 502 } 503 } 504 505 public static String[] getLastAppliedModifications() { 506 return mLastAppliedModifications.clone(); 507 } 508 509 public static String[][] getStrings() { 510 String[][] keys = new String[gMaps.size()][]; 511 512 int i = 0; 513 for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { 514 keys[i] = new String[map.size()]; 515 int j = 0; 516 for (String key : map.keySet()) { 517 keys[i][j++] = key; 518 } 519 i++; 520 } 521 522 return keys; 523 } 524 525 public static void setIndex(int mapIndex, int newIndexValue) { 526 mIndices[mapIndex] = newIndexValue; 527 } 528 529 public static int[] getIndices() { 530 return mIndices; 531 } 532 } 533