Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / tests / ShadowTest.cpp
1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkPath.h"
10 #include "include/core/SkRRect.h"
11 #include "include/core/SkVertices.h"
12 #include "include/utils/SkShadowUtils.h"
13 #include "src/core/SkDrawShadowInfo.h"
14 #include "src/core/SkVerticesPriv.h"
15 #include "src/utils/SkShadowTessellator.h"
16 #include "tests/Test.h"
17
18 enum ExpectVerts {
19     kDont_ExpectVerts,
20     kDo_ExpectVerts
21 };
22
23 void check_result(skiatest::Reporter* reporter, sk_sp<SkVertices> verts,
24                   ExpectVerts expectVerts, bool expectSuccess) {
25     if (expectSuccess != SkToBool(verts)) {
26         ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
27                expectSuccess ? "succeed" : "fail");
28     }
29     if (SkToBool(verts)) {
30         if (kDont_ExpectVerts == expectVerts && verts->priv().vertexCount()) {
31             ERRORF(reporter, "Expected shadow tessellation to generate no vertices but it did.");
32         } else if (kDo_ExpectVerts == expectVerts && !verts->priv().vertexCount()) {
33             ERRORF(reporter, "Expected shadow tessellation to generate vertices but it didn't.");
34         }
35     }
36 }
37
38 void tessellate_shadow(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm,
39                        const SkPoint3& heightParams, ExpectVerts expectVerts, bool expectSuccess) {
40
41     auto verts = SkShadowTessellator::MakeAmbient(path, ctm, heightParams, true);
42     check_result(reporter, verts, expectVerts, expectSuccess);
43
44     verts = SkShadowTessellator::MakeAmbient(path, ctm, heightParams, false);
45     check_result(reporter, verts, expectVerts, expectSuccess);
46
47     verts = SkShadowTessellator::MakeSpot(path, ctm, heightParams, {0, 0, 128}, 128.f, true, false);
48     check_result(reporter, verts, expectVerts, expectSuccess);
49
50     verts = SkShadowTessellator::MakeSpot(path, ctm, heightParams, {0, 0, 128}, 128.f, false,
51                                           false);
52     check_result(reporter, verts, expectVerts, expectSuccess);
53
54     verts = SkShadowTessellator::MakeSpot(path, ctm, heightParams, {0, 0, 128}, 128.f, true, true);
55     check_result(reporter, verts, expectVerts, expectSuccess);
56
57     verts = SkShadowTessellator::MakeSpot(path, ctm, heightParams, {0, 0, 128}, 128.f, false, true);
58     check_result(reporter, verts, expectVerts, expectSuccess);
59 }
60
61 DEF_TEST(ShadowUtils, reporter) {
62     SkCanvas canvas(100, 100);
63
64     SkPath path;
65     path.cubicTo(100, 50, 20, 100, 0, 0);
66     tessellate_shadow(reporter, path, canvas.getTotalMatrix(), {0, 0, 4}, kDo_ExpectVerts, true);
67     // super high path
68     tessellate_shadow(reporter, path, canvas.getTotalMatrix(), {0, 0, 4.0e+37f},
69                       kDo_ExpectVerts, true);
70
71     // This line segment has no area and no shadow.
72     path.reset();
73     path.lineTo(10.f, 10.f);
74     tessellate_shadow(reporter, path, canvas.getTotalMatrix(), {0, 0, 4}, kDont_ExpectVerts, true);
75
76     // A series of collinear line segments
77     path.reset();
78     for (int i = 0; i < 10; ++i) {
79         path.lineTo((SkScalar)i, (SkScalar)i);
80     }
81     tessellate_shadow(reporter, path, canvas.getTotalMatrix(), {0, 0, 4}, kDont_ExpectVerts, true);
82
83     // ugly degenerate path
84     path.reset();
85     path.moveTo(-134217728, 2.22265153e+21f);
86     path.cubicTo(-2.33326106e+21f, 7.36298265e-41f, 3.72237738e-22f, 5.99502692e-36f,
87                  1.13631943e+22f, 2.0890786e+33f);
88     path.cubicTo(1.03397626e-25f, 5.99502692e-36f, 9.18354962e-41f, 0, 4.6142745e-37f, -213558848);
89     path.lineTo(-134217728, 2.2226515e+21f);
90     tessellate_shadow(reporter, path, canvas.getTotalMatrix(), {0, 0, 9}, kDont_ExpectVerts, true);
91
92     // simple concave path (star of David)
93     path.reset();
94     path.moveTo(0.0f, -50.0f);
95     path.lineTo(14.43f, -25.0f);
96     path.lineTo(43.30f, -25.0f);
97     path.lineTo(28.86f, 0.0f);
98     path.lineTo(43.30f, 25.0f);
99     path.lineTo(14.43f, 25.0f);
100     path.lineTo(0.0f, 50.0f);
101     path.lineTo(-14.43f, 25.0f);
102     path.lineTo(-43.30f, 25.0f);
103     path.lineTo(-28.86f, 0.0f);
104     path.lineTo(-43.30f, -25.0f);
105     path.lineTo(-14.43f, -25.0f);
106 // uncomment when transparent concave shadows are working
107 //    tessellate_shadow(reporter, path, canvas.getTotalMatrix(), {0, 0, 9}, kDo_ExpectVerts, true);
108
109     // complex concave path (bowtie)
110     path.reset();
111     path.moveTo(-50, -50);
112     path.lineTo(-50, 50);
113     path.lineTo(50, -50);
114     path.lineTo(50, 50);
115     path.lineTo(-50, -50);
116     tessellate_shadow(reporter, path, canvas.getTotalMatrix(), {0, 0, 9}, kDont_ExpectVerts, false);
117
118     // multiple contour path
119     path.close();
120     path.moveTo(0, 0);
121     path.lineTo(1, 0);
122     path.lineTo(0, 1);
123     tessellate_shadow(reporter, path, canvas.getTotalMatrix(), {0, 0, 9}, kDont_ExpectVerts, false);
124 }
125
126 void check_xformed_bounds(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm) {
127     SkDrawShadowRec rec = {
128         SkPoint3::Make(0, 0, 4),
129         SkPoint3::Make(100, 0, 600),
130         800.f,
131         0x08000000,
132         0x40000000,
133         0
134     };
135     // point light
136     SkRect bounds;
137     SkDrawShadowMetrics::GetLocalBounds(path, rec, ctm, &bounds);
138     ctm.mapRect(&bounds);
139
140     auto verts = SkShadowTessellator::MakeAmbient(path, ctm, rec.fZPlaneParams, true);
141     if (verts) {
142         REPORTER_ASSERT(reporter, bounds.contains(verts->bounds()));
143     }
144
145     SkPoint mapXY = ctm.mapXY(rec.fLightPos.fX, rec.fLightPos.fY);
146     SkPoint3 devLightPos = SkPoint3::Make(mapXY.fX, mapXY.fY, rec.fLightPos.fZ);
147     verts = SkShadowTessellator::MakeSpot(path, ctm, rec.fZPlaneParams, devLightPos,
148                                           rec.fLightRadius, false, false);
149     if (verts) {
150         REPORTER_ASSERT(reporter, bounds.contains(verts->bounds()));
151     }
152
153     // directional light
154     rec.fFlags |= SkShadowFlags::kDirectionalLight_ShadowFlag;
155     rec.fLightRadius = 2.0f;
156     SkDrawShadowMetrics::GetLocalBounds(path, rec, ctm, &bounds);
157     ctm.mapRect(&bounds);
158
159     verts = SkShadowTessellator::MakeAmbient(path, ctm, rec.fZPlaneParams, true);
160     if (verts) {
161         REPORTER_ASSERT(reporter, bounds.contains(verts->bounds()));
162     }
163
164     devLightPos = rec.fLightPos;
165     devLightPos.normalize();
166     verts = SkShadowTessellator::MakeSpot(path, ctm, rec.fZPlaneParams, devLightPos,
167                                           rec.fLightRadius, false, true);
168     if (verts) {
169         REPORTER_ASSERT(reporter, bounds.contains(verts->bounds()));
170     }
171 }
172
173 void check_bounds(skiatest::Reporter* reporter, const SkPath& path) {
174     const bool fixed_shadows_in_perspective = false;    // skbug.com/9698
175
176     SkMatrix ctm;
177     ctm.setTranslate(100, 100);
178     check_xformed_bounds(reporter, path, ctm);
179     ctm.postScale(2, 2);
180     check_xformed_bounds(reporter, path, ctm);
181     ctm.preRotate(45);
182     check_xformed_bounds(reporter, path, ctm);
183     ctm.preSkew(40, -20);
184     check_xformed_bounds(reporter, path, ctm);
185     if (fixed_shadows_in_perspective) {
186         ctm[SkMatrix::kMPersp0] = 0.0001f;
187         ctm[SkMatrix::kMPersp1] = 12.f;
188         check_xformed_bounds(reporter, path, ctm);
189         ctm[SkMatrix::kMPersp0] = 0.0001f;
190         ctm[SkMatrix::kMPersp1] = -12.f;
191         check_xformed_bounds(reporter, path, ctm);
192         ctm[SkMatrix::kMPersp0] = 12.f;
193         ctm[SkMatrix::kMPersp1] = 0.0001f;
194         check_xformed_bounds(reporter, path, ctm);
195     }
196 }
197
198 DEF_TEST(ShadowBounds, reporter) {
199     SkPath path;
200     path.addRRect(SkRRect::MakeRectXY(SkRect::MakeLTRB(-50, -20, 40, 30), 4, 4));
201     check_bounds(reporter, path);
202
203     path.reset();
204     path.addOval(SkRect::MakeLTRB(300, 300, 900, 900));
205     check_bounds(reporter, path);
206
207     path.reset();
208     path.cubicTo(100, 50, 20, 100, 0, 0);
209     check_bounds(reporter, path);
210 }