1/*
2 * Copyright (C) 2015 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
17package android.uirendering.cts.testclasses;
18
19import static org.junit.Assert.assertNotNull;
20
21import android.content.pm.PackageManager;
22import android.graphics.Color;
23import android.graphics.Paint;
24import android.graphics.Path;
25import android.graphics.Point;
26import android.graphics.Typeface;
27import android.support.test.filters.LargeTest;
28import android.support.test.filters.MediumTest;
29import android.support.test.runner.AndroidJUnit4;
30import android.uirendering.cts.R;
31import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
32import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
33import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
34import android.uirendering.cts.testinfrastructure.ActivityTestBase;
35import android.uirendering.cts.testinfrastructure.CanvasClient;
36import android.uirendering.cts.testinfrastructure.CanvasClientDrawable;
37import android.uirendering.cts.testinfrastructure.ViewInitializer;
38import android.uirendering.cts.util.WebViewReadyHelper;
39import android.view.View;
40import android.view.ViewGroup;
41import android.webkit.WebView;
42
43import org.junit.Test;
44import org.junit.runner.RunWith;
45
46import java.util.concurrent.CountDownLatch;
47
48@MediumTest
49@RunWith(AndroidJUnit4.class)
50public class PathClippingTests extends ActivityTestBase {
51    // draw circle with hole in it, with stroked circle
52    static final CanvasClient sTorusDrawCanvasClient = (canvas, width, height) -> {
53        Paint paint = new Paint();
54        paint.setAntiAlias(false);
55        paint.setColor(Color.BLUE);
56        paint.setStyle(Paint.Style.STROKE);
57        paint.setStrokeWidth(20);
58        canvas.drawCircle(30, 30, 40, paint);
59    };
60
61    // draw circle with hole in it, by path operations + path clipping
62    static final CanvasClient sTorusClipCanvasClient = (canvas, width, height) -> {
63        canvas.save();
64
65        Path path = new Path();
66        path.addCircle(30, 30, 50, Path.Direction.CW);
67        path.addCircle(30, 30, 30, Path.Direction.CCW);
68
69        canvas.clipPath(path);
70        canvas.drawColor(Color.BLUE);
71
72        canvas.restore();
73    };
74
75    // draw circle with hole in it, by path operations + path clipping
76    static final CanvasClient sTorusClipOutCanvasClient = (canvas, width, height) -> {
77        canvas.save();
78
79        Path path1 = new Path();
80        path1.addCircle(30, 30, 50, Path.Direction.CW);
81
82        Path path2 = new Path();
83        path2.addCircle(30, 30, 30, Path.Direction.CW);
84
85        canvas.clipPath(path1);
86        canvas.clipOutPath(path2);
87        canvas.drawColor(Color.BLUE);
88
89        canvas.restore();
90    };
91
92    @Test
93    public void testCircleWithCircle() {
94        createTest()
95                .addCanvasClient("TorusDraw", sTorusDrawCanvasClient, false)
96                .addCanvasClient("TorusClip", sTorusClipCanvasClient)
97                .addCanvasClient("TorusClipOut", sTorusClipOutCanvasClient)
98                .runWithVerifier(new GoldenImageVerifier(getActivity(),
99                        R.drawable.pathclippingtest_torus, new MSSIMComparer(0.95)));
100    }
101
102    @Test
103    public void testCircleWithPoints() {
104        createTest()
105                .addCanvasClient("TorusClip", sTorusClipCanvasClient)
106                .addCanvasClient("TorusClipOut", sTorusClipOutCanvasClient)
107                .runWithVerifier(new SamplePointVerifier(
108                        new Point[] {
109                                // inside of circle
110                                new Point(30, 50),
111                                // on circle
112                                new Point(30 + 32, 30 + 32),
113                                // outside of circle
114                                new Point(30 + 38, 30 + 38),
115                                new Point(80, 80)
116                        },
117                        new int[] {
118                                Color.WHITE,
119                                Color.BLUE,
120                                Color.WHITE,
121                                Color.WHITE,
122                        }));
123    }
124
125    @Test
126    public void testViewRotate() {
127        createTest()
128                .addLayout(R.layout.blue_padded_layout, view -> {
129                    ViewGroup rootView = (ViewGroup) view;
130                    rootView.setClipChildren(true);
131                    View childView = rootView.getChildAt(0);
132                    childView.setPivotX(40);
133                    childView.setPivotY(40);
134                    childView.setRotation(45f);
135                })
136                .runWithVerifier(new SamplePointVerifier(
137                        new Point[] {
138                                // inside of rotated rect
139                                new Point(40, 40),
140                                new Point(40 + 25, 40 + 25),
141                                // outside of rotated rect
142                                new Point(40 + 31, 40 + 31),
143                                new Point(80, 80)
144                        },
145                        new int[] {
146                                Color.BLUE,
147                                Color.BLUE,
148                                Color.WHITE,
149                                Color.WHITE,
150                        }));
151    }
152
153    @Test
154    public void testPathScale() {
155        createTest()
156                .addLayout(R.layout.frame_layout, view -> {
157                    Path path = new Path();
158                    path.addCircle(TEST_WIDTH / 2, TEST_HEIGHT / 2,
159                            TEST_WIDTH / 4, Path.Direction.CW);
160                    view.setBackground(new CanvasClientDrawable((canvas, width, height) -> {
161                        canvas.clipPath(path);
162                        canvas.drawColor(Color.BLUE);
163                    }));
164                    view.setScaleX(2);
165                    view.setScaleY(2);
166                })
167                .runWithComparer(new MSSIMComparer(0.90));
168    }
169
170    @Test
171    public void testTextClip() {
172        createTest()
173                .addCanvasClient((canvas, width, height) -> {
174                    canvas.save();
175
176                    Path path = new Path();
177                    path.addCircle(0, 45, 45, Path.Direction.CW);
178                    path.addCircle(90, 45, 45, Path.Direction.CW);
179                    canvas.clipPath(path);
180
181                    Paint paint = new Paint();
182                    paint.setAntiAlias(true);
183                    paint.setTextSize(90);
184                    paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
185                    canvas.drawText("STRING", 0, 90, paint);
186
187                    canvas.restore();
188                })
189                .runWithComparer(new MSSIMComparer(0.90));
190    }
191
192    private ViewInitializer initBlueWebView(final CountDownLatch fence) {
193        return view -> {
194            WebView webview = (WebView)view.findViewById(R.id.webview);
195            assertNotNull(webview);
196            WebViewReadyHelper helper = new WebViewReadyHelper(webview, fence);
197            helper.loadData("<body style=\"background-color:blue\">");
198        };
199    }
200
201    @LargeTest
202    @Test
203    public void testWebViewClipWithCircle() {
204        if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
205            return; // no WebView to run test on
206        }
207        CountDownLatch hwFence = new CountDownLatch(1);
208        CountDownLatch swFence = new CountDownLatch(1);
209        createTest()
210                // golden client - draw a simple non-AA circle
211                .addCanvasClient((canvas, width, height) -> {
212                    Paint paint = new Paint();
213                    paint.setAntiAlias(false);
214                    paint.setColor(Color.BLUE);
215                    canvas.drawOval(0, 0, width, height, paint);
216                }, false)
217                // verify against solid color webview, clipped to its parent oval
218                .addLayout(R.layout.circle_clipped_webview,
219                        initBlueWebView(hwFence), true, hwFence)
220                .addLayout(R.layout.circle_clipped_webview,
221                        initBlueWebView(swFence), false, swFence)
222                .runWithComparer(new MSSIMComparer(0.95));
223    }
224}
225