blob: 0f4e122d147ac6435892097a6fd46144e7a58c84 [file] [log] [blame]
/*
* 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;
}
}