| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.test.hwuicompare; |
| |
| import java.util.LinkedHashMap; |
| import java.util.Map.Entry; |
| |
| import android.graphics.Canvas; |
| import android.graphics.Paint; |
| import android.graphics.RectF; |
| import android.util.Log; |
| |
| public abstract class DisplayModifier { |
| |
| // automated tests ignore any combination of operations that don't together return TOTAL_MASK |
| protected final static int TOTAL_MASK = 0x1F; |
| |
| // if we're filling, ensure we're not also sweeping over stroke parameters |
| protected final static int SWEEP_STROKE_WIDTH_BIT = 0x1 << 0; |
| protected final static int SWEEP_STROKE_CAP_BIT = 0x1 << 1; |
| protected final static int SWEEP_STROKE_JOIN_BIT = 0x1 << 2; |
| |
| protected final static int SWEEP_SHADER_BIT = 0x1 << 3; // only allow non-simple shaders to use rectangle drawing |
| protected final static int SWEEP_TRANSFORM_BIT = 0x1 << 4; // only sweep over specified transforms |
| |
| abstract public void modifyDrawing(Paint paint, Canvas canvas); |
| protected int mask() { return 0x0; }; |
| |
| private static final RectF gRect = new RectF(0, 0, 200, 175); |
| private static final float[] gPts = new float[] { |
| 0, 100, 100, 0, 100, 200, 200, 100 |
| }; |
| |
| private static final int NUM_PARALLEL_LINES = 24; |
| private static final float[] gTriPts = new float[] { |
| 75, 0, 130, 130, 130, 130, 0, 130, 0, 130, 75, 0 |
| }; |
| private static final float[] gLinePts = new float[NUM_PARALLEL_LINES * 8 + gTriPts.length]; |
| static { |
| int index; |
| for (index = 0; index < gTriPts.length; index++) { |
| gLinePts[index] = gTriPts[index]; |
| } |
| float val = 0; |
| for (int i = 0; i < NUM_PARALLEL_LINES; i++) { |
| gLinePts[index + 0] = 150; |
| gLinePts[index + 1] = val; |
| gLinePts[index + 2] = 300; |
| gLinePts[index + 3] = val; |
| index += 4; |
| val += 8 + (2.0f/NUM_PARALLEL_LINES); |
| } |
| val = 0; |
| for (int i = 0; i < NUM_PARALLEL_LINES; i++) { |
| gLinePts[index + 0] = val; |
| gLinePts[index + 1] = 150; |
| gLinePts[index + 2] = val; |
| gLinePts[index + 3] = 300; |
| index += 4; |
| val += 8 + (2.0f/NUM_PARALLEL_LINES); |
| } |
| }; |
| |
| @SuppressWarnings("serial") |
| private static final LinkedHashMap<String, LinkedHashMap<String, DisplayModifier>> gMaps = new LinkedHashMap<String, LinkedHashMap<String, DisplayModifier>>() { |
| { |
| put("aa", new LinkedHashMap<String, DisplayModifier>() { |
| { |
| put("true", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setAntiAlias(true); |
| } |
| }); |
| put("false", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setAntiAlias(false); |
| } |
| }); |
| } |
| }); |
| put("style", new LinkedHashMap<String, DisplayModifier>() { |
| { |
| put("fill", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStyle(Paint.Style.FILL); |
| } |
| }); |
| put("stroke", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStyle(Paint.Style.STROKE); |
| } |
| @Override |
| protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } |
| }); |
| put("fillAndStroke", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStyle(Paint.Style.FILL_AND_STROKE); |
| } |
| |
| @Override |
| protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } |
| }); |
| } |
| }); |
| put("strokeWidth", new LinkedHashMap<String, DisplayModifier>() { |
| { |
| put("hair", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeWidth(0); |
| } |
| @Override |
| protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } |
| }); |
| put("0.3", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeWidth(0.3f); |
| } |
| }); |
| put("1", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeWidth(1); |
| } |
| }); |
| put("5", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeWidth(5); |
| } |
| }); |
| put("30", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeWidth(30); |
| } |
| }); |
| } |
| }); |
| put("strokeCap", new LinkedHashMap<String, DisplayModifier>() { |
| { |
| put("butt", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeCap(Paint.Cap.BUTT); |
| } |
| @Override |
| protected int mask() { return SWEEP_STROKE_CAP_BIT; } |
| }); |
| put("round", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeCap(Paint.Cap.ROUND); |
| } |
| }); |
| put("square", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeCap(Paint.Cap.SQUARE); |
| } |
| }); |
| } |
| }); |
| put("strokeJoin", new LinkedHashMap<String, DisplayModifier>() { |
| { |
| put("bevel", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeJoin(Paint.Join.BEVEL); |
| } |
| @Override |
| protected int mask() { return SWEEP_STROKE_JOIN_BIT; } |
| }); |
| put("round", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeJoin(Paint.Join.ROUND); |
| } |
| }); |
| put("miter", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setStrokeJoin(Paint.Join.MITER); |
| } |
| }); |
| // TODO: add miter0, miter1 etc to test miter distances |
| } |
| }); |
| |
| put("transform", new LinkedHashMap<String, DisplayModifier>() { |
| { |
| put("noTransform", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) {} |
| @Override |
| protected int mask() { return SWEEP_TRANSFORM_BIT; }; |
| }); |
| put("rotate5", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.rotate(5); |
| } |
| }); |
| put("rotate45", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.rotate(45); |
| } |
| }); |
| put("rotate90", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.rotate(90); |
| canvas.translate(0, -200); |
| } |
| }); |
| put("scale2x2", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.scale(2, 2); |
| } |
| @Override |
| protected int mask() { return SWEEP_TRANSFORM_BIT; }; |
| }); |
| put("rot20scl1x4", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.rotate(20); |
| canvas.scale(1, 4); |
| } |
| @Override |
| protected int mask() { return SWEEP_TRANSFORM_BIT; }; |
| }); |
| } |
| }); |
| |
| put("shader", new LinkedHashMap<String, DisplayModifier>() { |
| { |
| put("noShader", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) {} |
| @Override |
| protected int mask() { return SWEEP_SHADER_BIT; }; |
| }); |
| put("repeatShader", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mRepeatShader); |
| } |
| @Override |
| protected int mask() { return SWEEP_SHADER_BIT; }; |
| }); |
| put("translatedShader", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mTranslatedShader); |
| } |
| }); |
| put("scaledShader", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mScaledShader); |
| } |
| }); |
| put("horGradient", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mHorGradient); |
| } |
| }); |
| put("diagGradient", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mDiagGradient); |
| } |
| @Override |
| protected int mask() { return SWEEP_SHADER_BIT; }; |
| }); |
| put("vertGradient", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mVertGradient); |
| } |
| }); |
| put("radGradient", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mRadGradient); |
| } |
| }); |
| put("sweepGradient", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mSweepGradient); |
| } |
| }); |
| put("composeShader", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mComposeShader); |
| } |
| }); |
| put("bad composeShader", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mBadComposeShader); |
| } |
| }); |
| put("bad composeShader 2", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader); |
| } |
| }); |
| } |
| }); |
| |
| // FINAL MAP: DOES ACTUAL DRAWING |
| put("drawing", new LinkedHashMap<String, DisplayModifier>() { |
| { |
| put("roundRect", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawRoundRect(gRect, 20, 20, paint); |
| } |
| }); |
| put("rect", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawRect(gRect, paint); |
| } |
| @Override |
| protected int mask() { return SWEEP_SHADER_BIT | SWEEP_STROKE_CAP_BIT; }; |
| }); |
| put("circle", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawCircle(100, 100, 75, paint); |
| } |
| }); |
| put("oval", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawOval(gRect, paint); |
| } |
| }); |
| put("lines", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawLines(gLinePts, paint); |
| } |
| @Override |
| protected int mask() { return SWEEP_STROKE_CAP_BIT; }; |
| }); |
| put("plusPoints", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawPoints(gPts, paint); |
| } |
| }); |
| put("text", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setTextSize(36); |
| canvas.drawText("TEXTTEST", 0, 50, paint); |
| } |
| }); |
| put("shadowtext", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| paint.setTextSize(36); |
| paint.setShadowLayer(3.0f, 0.0f, 3.0f, 0xffff00ff); |
| canvas.drawText("TEXTTEST", 0, 50, paint); |
| } |
| }); |
| put("bitmapMesh", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawBitmapMesh(ResourceModifiers.instance().mBitmap, 3, 3, |
| ResourceModifiers.instance().mBitmapVertices, 0, null, 0, null); |
| } |
| }); |
| put("arc", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawArc(gRect, 260, 285, false, paint); |
| } |
| @Override |
| protected int mask() { return SWEEP_STROKE_CAP_BIT; }; |
| }); |
| put("arcFromCenter", new DisplayModifier() { |
| @Override |
| public void modifyDrawing(Paint paint, Canvas canvas) { |
| canvas.drawArc(gRect, 260, 285, true, paint); |
| } |
| @Override |
| protected int mask() { return SWEEP_STROKE_JOIN_BIT; }; |
| }); |
| } |
| }); |
| // WARNING: DON'T PUT MORE MAPS BELOW THIS |
| } |
| }; |
| |
| private static LinkedHashMap<String, DisplayModifier> getMapAtIndex(int index) { |
| for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { |
| if (index == 0) { |
| return map; |
| } |
| index--; |
| } |
| return null; |
| } |
| |
| // indices instead of iterators for easier bidirectional traversal |
| private static final int mIndices[] = new int[gMaps.size()]; |
| private static final String[] mLastAppliedModifications = new String[gMaps.size()]; |
| |
| private static boolean stepInternal(boolean forward) { |
| int modifierMapIndex = gMaps.size() - 1; |
| while (modifierMapIndex >= 0) { |
| LinkedHashMap<String, DisplayModifier> map = getMapAtIndex(modifierMapIndex); |
| mIndices[modifierMapIndex] += (forward ? 1 : -1); |
| |
| if (mIndices[modifierMapIndex] >= 0 && mIndices[modifierMapIndex] < map.size()) { |
| break; |
| } |
| |
| mIndices[modifierMapIndex] = (forward ? 0 : map.size() - 1); |
| modifierMapIndex--; |
| } |
| return modifierMapIndex < 0; // true if resetting |
| } |
| |
| public static boolean step() { |
| boolean ret = false; |
| do { |
| ret |= stepInternal(true); |
| } while (!checkModificationStateMask()); |
| return ret; |
| } |
| |
| public static boolean stepBack() { |
| boolean ret = false; |
| do { |
| ret |= stepInternal(false); |
| } while (!checkModificationStateMask()); |
| return ret; |
| } |
| |
| private static boolean checkModificationStateMask() { |
| int operatorMask = 0x0; |
| int mapIndex = 0; |
| for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { |
| int displayModifierIndex = mIndices[mapIndex]; |
| for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) { |
| if (displayModifierIndex == 0) { |
| mLastAppliedModifications[mapIndex] = modifierEntry.getKey(); |
| operatorMask |= modifierEntry.getValue().mask(); |
| break; |
| } |
| displayModifierIndex--; |
| } |
| mapIndex++; |
| } |
| return operatorMask == TOTAL_MASK; |
| } |
| |
| public static void apply(Paint paint, Canvas canvas) { |
| int mapIndex = 0; |
| for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { |
| int displayModifierIndex = mIndices[mapIndex]; |
| for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) { |
| if (displayModifierIndex == 0) { |
| mLastAppliedModifications[mapIndex] = modifierEntry.getKey(); |
| modifierEntry.getValue().modifyDrawing(paint, canvas); |
| break; |
| } |
| displayModifierIndex--; |
| } |
| mapIndex++; |
| } |
| } |
| |
| public static String[] getLastAppliedModifications() { |
| return mLastAppliedModifications.clone(); |
| } |
| |
| public static String[][] getStrings() { |
| String[][] keys = new String[gMaps.size()][]; |
| |
| int i = 0; |
| for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { |
| keys[i] = new String[map.size()]; |
| int j = 0; |
| for (String key : map.keySet()) { |
| keys[i][j++] = key; |
| } |
| i++; |
| } |
| |
| return keys; |
| } |
| |
| public static void setIndex(int mapIndex, int newIndexValue) { |
| mIndices[mapIndex] = newIndexValue; |
| } |
| |
| public static int[] getIndices() { |
| return mIndices; |
| } |
| } |