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/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 */
16package android.uirendering.cts.testclasses;
17
18import android.graphics.Bitmap;
19import android.graphics.Color;
20import android.graphics.Paint;
21import android.graphics.PaintFlagsDrawFilter;
22import android.support.test.filters.MediumTest;
23import android.support.test.runner.AndroidJUnit4;
24import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
25import android.uirendering.cts.bitmapverifiers.ColorVerifier;
26import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
27import android.uirendering.cts.testinfrastructure.ActivityTestBase;
28import android.uirendering.cts.testinfrastructure.CanvasClient;
29
30import org.junit.Test;
31import org.junit.runner.RunWith;
32
33@MediumTest
34@RunWith(AndroidJUnit4.class)
35public class BitmapFilterTests extends ActivityTestBase {
36    private static final int WHITE_WEIGHT = 255 * 3;
37    private enum FilterEnum {
38        // Creates Paint object that will have bitmap filtering
39        PAINT_FILTER,
40        // First uses a Paint object with bitmap filtering, then uses canvas.setDrawFilter to remove
41        // the bitmap filtering
42        REMOVE_FILTER,
43        // Sets DrawFilter to use Paint.FILTER_BITMAP_FLAG
44        ADD_FILTER
45    }
46
47    private static final BitmapVerifier BLACK_WHITE_ONLY_VERIFIER
48            = new PerPixelBitmapVerifier(PerPixelBitmapVerifier.DEFAULT_THRESHOLD, 0.99f) {
49        @Override
50        protected boolean verifyPixel(int x, int y, int color) {
51            int weight = Color.red(color) + Color.blue(color) + Color.green(color);
52            return weight < DEFAULT_THRESHOLD // is approx Color.BLACK
53                    || weight > WHITE_WEIGHT - DEFAULT_THRESHOLD; // is approx Color.WHITE
54        }
55    };
56    private static final BitmapVerifier GREY_ONLY_VERIFIER
57            = new ColorVerifier(Color.argb(255, 127, 127, 127),
58            150); // content will be entirely grey, for a fairly wide range of grey
59    private static final BitmapVerifier GREY_PARTIAL_VERIFIER
60            = new ColorVerifier(Color.argb(255, 127, 127, 127),
61            300, 0.8f); // content will be mostly grey, for a wide range of grey
62
63
64    private static Bitmap createGridBitmap(int width, int height) {
65        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
66        for (int i = 0 ; i < width ; i++) {
67            for (int j = 0 ; j < height ; j++) {
68                boolean isWhite = (i + j * width) % 2 == 0;
69                bitmap.setPixel(i, j, isWhite ? Color.WHITE : Color.BLACK);
70            }
71        }
72        return bitmap;
73    }
74
75    private static final int SMALL_GRID_SIZE = 5;
76    private Bitmap mSmallGridBitmap = createGridBitmap(SMALL_GRID_SIZE, SMALL_GRID_SIZE);
77
78    // samples will occur in the middle of 4 pixels, 2 white
79    // and 2 black, and thus each be close to x7F7F7F grey
80    private static final int BIG_GRID_SIZE = TEST_WIDTH * 2;
81    private Bitmap mBigGridBitmap = createGridBitmap(BIG_GRID_SIZE, BIG_GRID_SIZE);
82
83    @Test
84    public void testPaintFilterScaleUp() {
85        runScaleTest(FilterEnum.PAINT_FILTER, true);
86    }
87
88    @Test
89    public void testPaintFilterScaleDown() {
90        runScaleTest(FilterEnum.PAINT_FILTER, false);
91    }
92
93    @Test
94    public void testDrawFilterRemoveFilterScaleUp() {
95        runScaleTest(FilterEnum.REMOVE_FILTER, true);
96    }
97
98    @Test
99    public void testDrawFilterRemoveFilterScaleDown() {
100        runScaleTest(FilterEnum.REMOVE_FILTER, false);
101    }
102
103    @Test
104    public void testDrawFilterScaleUp() {
105        runScaleTest(FilterEnum.ADD_FILTER, true);
106    }
107
108    @Test
109    public void testDrawFilterScaleDown() {
110        runScaleTest(FilterEnum.ADD_FILTER, false);
111    }
112
113    private void runScaleTest(final FilterEnum filterEnum, final boolean scaleUp) {
114        final int gridWidth = scaleUp ? SMALL_GRID_SIZE : BIG_GRID_SIZE;
115        final Paint paint = new Paint(filterEnum.equals(FilterEnum.ADD_FILTER) ?
116                0 : Paint.FILTER_BITMAP_FLAG);
117
118        CanvasClient canvasClient = (canvas, width, height) -> {
119            canvas.scale(1.0f * width / gridWidth, 1.0f * height / gridWidth);
120            if (filterEnum.equals(FilterEnum.ADD_FILTER)) {
121                canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG));
122            } else if (filterEnum.equals(FilterEnum.REMOVE_FILTER)) {
123                canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
124            }
125            canvas.drawBitmap(scaleUp ? mSmallGridBitmap : mBigGridBitmap, 0, 0, paint);
126            canvas.setDrawFilter(null);
127        };
128        createTest()
129                // Picture does not support PaintFlagsDrawFilter
130                .addCanvasClientWithoutUsingPicture(canvasClient)
131                .runWithVerifier(getVerifierForTest(filterEnum, scaleUp));
132    }
133
134    private static BitmapVerifier getVerifierForTest(FilterEnum filterEnum, boolean scaleUp) {
135        if (filterEnum.equals(FilterEnum.REMOVE_FILTER)) {
136            // filtering disabled, so only black and white pixels will come through
137            return BLACK_WHITE_ONLY_VERIFIER;
138        }
139        // if scaling up, output pixels may have single source to sample from,
140        // will only be *mostly* grey.
141        return scaleUp ? GREY_PARTIAL_VERIFIER : GREY_ONLY_VERIFIER;
142    }
143}
144