1 /*
2  * Copyright (C) 2008 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 android.graphics.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21 
22 import android.graphics.Bitmap;
23 import android.graphics.Bitmap.Config;
24 import android.graphics.Canvas;
25 import android.graphics.Color;
26 import android.graphics.Paint;
27 import android.graphics.Paint.Align;
28 import android.graphics.PaintFlagsDrawFilter;
29 import android.graphics.Rect;
30 
31 import androidx.test.filters.SmallTest;
32 import androidx.test.runner.AndroidJUnit4;
33 
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 
37 @SmallTest
38 @RunWith(AndroidJUnit4.class)
39 public class PaintFlagsDrawFilterTest {
40     private static final float TEXT_SIZE = 20;
41     private static final float TEXT_X = 50;
42     private static final float TEXT_Y = 50;
43     private static final String TEXT = "Test";
44     private static final int BITMAP_WIDTH = 100;
45     private static final int BITMAP_HEIGHT = 100;
46 
47     private float mTextWidth;
48 
49     @Test
testPaintFlagsDrawFilter()50     public void testPaintFlagsDrawFilter() {
51         Bitmap bitmapWithoutFilter = drawText(null);
52 
53         PaintFlagsDrawFilter filter = new PaintFlagsDrawFilter(Paint.UNDERLINE_TEXT_FLAG, 0);
54         Bitmap bitmapWithFilter = drawText(filter);
55 
56         Bitmap combined = delta(bitmapWithoutFilter, bitmapWithFilter);
57         verifyUnderline(combined);
58     }
59 
drawText(PaintFlagsDrawFilter filter)60     private Bitmap drawText(PaintFlagsDrawFilter filter) {
61         Paint p = new Paint(Paint.UNDERLINE_TEXT_FLAG);
62         p.setColor(Color.RED);
63         p.setTextSize(TEXT_SIZE);
64         p.setTextAlign(Align.CENTER);
65         mTextWidth = p.measureText(TEXT);
66         Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
67         Canvas c = new Canvas(b);
68         c.setDrawFilter(filter);
69         c.drawColor(Color.BLACK);
70         c.drawText(TEXT, TEXT_X, TEXT_Y, p);
71         return b;
72     }
73 
delta(Bitmap bitmapWithoutFilter, Bitmap bitmapWithFilter)74     private Bitmap delta(Bitmap bitmapWithoutFilter, Bitmap bitmapWithFilter) {
75         Bitmap combinedBitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
76         combinedBitmap.eraseColor(Color.BLACK);
77         int pixelWithoutFilter;
78         int pixelWithFilter;
79         for (int i = 0; i < BITMAP_WIDTH; i++) {
80             for (int j = 0; j < BITMAP_HEIGHT; j++) {
81                 pixelWithoutFilter = bitmapWithoutFilter.getPixel(i, j);
82                 pixelWithFilter = bitmapWithFilter.getPixel(i, j);
83                 if (pixelWithoutFilter != pixelWithFilter) {
84                     assertEquals(Color.RED, pixelWithoutFilter);
85                     assertEquals(Color.BLACK, pixelWithFilter);
86                     combinedBitmap.setPixel(i, j, Color.RED);
87                 }
88             }
89         }
90         return combinedBitmap;
91     }
92 
verifyUnderline(Bitmap bitmap)93     private void verifyUnderline(Bitmap bitmap) {
94         // Find smallest rectangle containing all RED pixels
95         Rect rect = new Rect(BITMAP_WIDTH, BITMAP_HEIGHT, 0, 0);
96         for (int y = 0; y < BITMAP_HEIGHT; y++) {
97             for (int x = 0; x < BITMAP_WIDTH; x++) {
98                 int pixel = bitmap.getPixel(x, y);
99                 if (pixel == Color.RED) {
100                     rect.left = Math.min(rect.left, x);
101                     rect.right = Math.max(rect.right, x);
102                     rect.top = Math.min(rect.top, y);
103                     rect.bottom = Math.max(rect.bottom, y);
104                 }
105             }
106         }
107         // underline is at least one pixel high
108         assertTrue(rect.top <= rect.bottom);
109         // underline is roughly the same length at the text (5% tolerance)
110         assertEquals(mTextWidth, rect.right - rect.left, mTextWidth * 0.053);
111         // underline is under the text or at least at the bottom of it
112         assertTrue(rect.top >= TEXT_Y);
113     }
114 
115     // Tests that FILTER_BITMAP_FLAG is handled properly.
116     @Test
testPaintFlagsDrawFilter2()117     public void testPaintFlagsDrawFilter2() {
118         // Create a bitmap with alternating black and white pixels.
119         int kWidth = 5;
120         int kHeight = 5;
121         int colors[] = new int [] { Color.WHITE, Color.BLACK };
122         int k = 0;
123         Bitmap grid = Bitmap.createBitmap(kWidth, kHeight, Config.ARGB_8888);
124         for (int i = 0; i < kWidth; ++i) {
125             for (int j = 0; j < kHeight; ++j) {
126                 grid.setPixel(i, j, colors[k]);
127                 k = (k + 1) % 2;
128             }
129         }
130 
131         // Setup a scaled canvas for drawing the bitmap, with and without FILTER_BITMAP_FLAG set.
132         // When the flag is set, there will be gray pixels. When the flag is not set, all pixels
133         // will be either black or white.
134         int kScale = 5;
135         Bitmap dst = Bitmap.createBitmap(kWidth * kScale, kHeight * kScale, Config.ARGB_8888);
136         Canvas canvas = new Canvas(dst);
137         canvas.scale(kScale, kScale);
138 
139         // Drawn without FILTER_BITMAP_FLAG, all pixels will be black or white.
140         Paint simplePaint = new Paint();
141         simplePaint.setFilterBitmap(false);
142         canvas.drawBitmap(grid, 0, 0, simplePaint);
143 
144         verifyContainsOnlyBlackAndWhite(dst);
145 
146         // Drawn with FILTER_BITMAP_FLAG, some pixels will be somewhere in between.
147         Paint filterBitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
148         canvas.drawBitmap(grid, 0, 0, filterBitmapPaint);
149 
150         verifyContainsNonBW(dst);
151 
152         // Drawing with a paint that FILTER_BITMAP_FLAG set and a DrawFilter that removes
153         // FILTER_BITMAP_FLAG should remove the effect of the flag, resulting in all pixels being
154         // either black or white.
155         canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
156         canvas.drawBitmap(grid, 0, 0, filterBitmapPaint);
157 
158         verifyContainsOnlyBlackAndWhite(dst);
159 
160         // Likewise, drawing with a DrawFilter that sets FILTER_BITMAP_FLAG should filter,
161         // resulting in gray pixels.
162         canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG));
163         canvas.drawBitmap(grid, 0, 0, simplePaint);
164 
165         verifyContainsNonBW(dst);
166     }
167 
168     // Assert that at least one pixel is neither black nor white. This is used to verify that
169     // filtering was done, since the original bitmap only contained black and white pixels.
verifyContainsNonBW(Bitmap bitmap)170     private void verifyContainsNonBW(Bitmap bitmap) {
171         for (int i = 0; i < bitmap.getWidth(); ++i) {
172             for (int j = 0; j < bitmap.getHeight(); ++j) {
173                 int color = bitmap.getPixel(i, j);
174                 if (color != Color.BLACK && color != Color.WHITE) {
175                     // Filtering must have been done.
176                     return;
177                 }
178             }
179         }
180         // Filtering did not happen.
181         assertTrue(false);
182     }
183 
184     // Assert that every pixel is either black or white. Used to verify that no filtering was
185     // done, since the original bitmap contained only black and white pixels.
verifyContainsOnlyBlackAndWhite(Bitmap bitmap)186     private void verifyContainsOnlyBlackAndWhite(Bitmap bitmap) {
187         for (int i = 0; i < bitmap.getWidth(); ++i) {
188             for (int j = 0; j < bitmap.getHeight(); ++j) {
189                 int color = bitmap.getPixel(i, j);
190                 assertTrue(color == Color.BLACK || color == Color.WHITE);
191             }
192         }
193     }
194 }
195