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 } 306 }); 307 308 // FINAL MAP: DOES ACTUAL DRAWING 309 put("drawing", new LinkedHashMap<String, DisplayModifier>() { 310 { 311 put("roundRect", new DisplayModifier() { 312 @Override 313 public void modifyDrawing(Paint paint, Canvas canvas) { 314 canvas.drawRoundRect(gRect, 20, 20, paint); 315 } 316 }); 317 put("rect", new DisplayModifier() { 318 @Override 319 public void modifyDrawing(Paint paint, Canvas canvas) { 320 canvas.drawRect(gRect, paint); 321 } 322 @Override 323 protected int mask() { return SWEEP_SHADER_BIT | SWEEP_STROKE_CAP_BIT; }; 324 }); 325 put("circle", new DisplayModifier() { 326 @Override 327 public void modifyDrawing(Paint paint, Canvas canvas) { 328 canvas.drawCircle(100, 100, 75, paint); 329 } 330 }); 331 put("oval", new DisplayModifier() { 332 @Override 333 public void modifyDrawing(Paint paint, Canvas canvas) { 334 canvas.drawOval(gRect, paint); 335 } 336 }); 337 put("lines", new DisplayModifier() { 338 @Override 339 public void modifyDrawing(Paint paint, Canvas canvas) { 340 canvas.drawLines(gLinePts, paint); 341 } 342 @Override 343 protected int mask() { return SWEEP_STROKE_CAP_BIT; }; 344 }); 345 put("plusPoints", new DisplayModifier() { 346 @Override 347 public void modifyDrawing(Paint paint, Canvas canvas) { 348 canvas.drawPoints(gPts, paint); 349 } 350 }); 351 put("text", new DisplayModifier() { 352 @Override 353 public void modifyDrawing(Paint paint, Canvas canvas) { 354 paint.setTextSize(36); 355 canvas.drawText("TEXTTEST", 0, 50, paint); 356 } 357 }); 358 put("shadowtext", new DisplayModifier() { 359 @Override 360 public void modifyDrawing(Paint paint, Canvas canvas) { 361 paint.setTextSize(36); 362 paint.setShadowLayer(3.0f, 0.0f, 3.0f, 0xffff00ff); 363 canvas.drawText("TEXTTEST", 0, 50, paint); 364 } 365 }); 366 put("bitmapMesh", new DisplayModifier() { 367 @Override 368 public void modifyDrawing(Paint paint, Canvas canvas) { 369 canvas.drawBitmapMesh(ResourceModifiers.instance().mBitmap, 3, 3, 370 ResourceModifiers.instance().mBitmapVertices, 0, null, 0, null); 371 } 372 }); 373 put("arc", new DisplayModifier() { 374 @Override 375 public void modifyDrawing(Paint paint, Canvas canvas) { 376 canvas.drawArc(gRect, 260, 285, false, paint); 377 } 378 @Override 379 protected int mask() { return SWEEP_STROKE_CAP_BIT; }; 380 }); 381 put("arcFromCenter", new DisplayModifier() { 382 @Override 383 public void modifyDrawing(Paint paint, Canvas canvas) { 384 canvas.drawArc(gRect, 260, 285, true, paint); 385 } 386 @Override 387 protected int mask() { return SWEEP_STROKE_JOIN_BIT; }; 388 }); 389 } 390 }); 391 // WARNING: DON'T PUT MORE MAPS BELOW THIS 392 } 393 }; 394 395 private static LinkedHashMap<String, DisplayModifier> getMapAtIndex(int index) { 396 for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { 397 if (index == 0) { 398 return map; 399 } 400 index--; 401 } 402 return null; 403 } 404 405 // indices instead of iterators for easier bidirectional traversal 406 private static final int mIndices[] = new int[gMaps.size()]; 407 private static final String[] mLastAppliedModifications = new String[gMaps.size()]; 408 409 private static boolean stepInternal(boolean forward) { 410 int modifierMapIndex = gMaps.size() - 1; 411 while (modifierMapIndex >= 0) { 412 LinkedHashMap<String, DisplayModifier> map = getMapAtIndex(modifierMapIndex); 413 mIndices[modifierMapIndex] += (forward ? 1 : -1); 414 415 if (mIndices[modifierMapIndex] >= 0 && mIndices[modifierMapIndex] < map.size()) { 416 break; 417 } 418 419 mIndices[modifierMapIndex] = (forward ? 0 : map.size() - 1); 420 modifierMapIndex--; 421 } 422 return modifierMapIndex < 0; // true if resetting 423 } 424 425 public static boolean step() { 426 boolean ret = false; 427 do { 428 ret |= stepInternal(true); 429 } while (!checkModificationStateMask()); 430 return ret; 431 } 432 433 public static boolean stepBack() { 434 boolean ret = false; 435 do { 436 ret |= stepInternal(false); 437 } while (!checkModificationStateMask()); 438 return ret; 439 } 440 441 private static boolean checkModificationStateMask() { 442 int operatorMask = 0x0; 443 int mapIndex = 0; 444 for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { 445 int displayModifierIndex = mIndices[mapIndex]; 446 for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) { 447 if (displayModifierIndex == 0) { 448 mLastAppliedModifications[mapIndex] = modifierEntry.getKey(); 449 operatorMask |= modifierEntry.getValue().mask(); 450 break; 451 } 452 displayModifierIndex--; 453 } 454 mapIndex++; 455 } 456 return operatorMask == TOTAL_MASK; 457 } 458 459 public static void apply(Paint paint, Canvas canvas) { 460 int mapIndex = 0; 461 for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { 462 int displayModifierIndex = mIndices[mapIndex]; 463 for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) { 464 if (displayModifierIndex == 0) { 465 mLastAppliedModifications[mapIndex] = modifierEntry.getKey(); 466 modifierEntry.getValue().modifyDrawing(paint, canvas); 467 break; 468 } 469 displayModifierIndex--; 470 } 471 mapIndex++; 472 } 473 } 474 475 public static String[] getLastAppliedModifications() { 476 return mLastAppliedModifications.clone(); 477 } 478 479 public static String[][] getStrings() { 480 String[][] keys = new String[gMaps.size()][]; 481 482 int i = 0; 483 for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { 484 keys[i] = new String[map.size()]; 485 int j = 0; 486 for (String key : map.keySet()) { 487 keys[i][j++] = key; 488 } 489 i++; 490 } 491 492 return keys; 493 } 494 495 public static void setIndex(int mapIndex, int newIndexValue) { 496 mIndices[mapIndex] = newIndexValue; 497 } 498 499 public static int[] getIndices() { 500 return mIndices; 501 } 502 } 503