blob: 90c1d8ffcc66150b846f2acd3d7329f6e9a26bb6 [file] [log] [blame]
Jim Van Verth1af03d42017-07-31 09:34:58 -04001/*
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 "SkCanvas.h"
9#include "SkDrawShadowInfo.h"
10#include "SkPath.h"
11#include "SkShadowTessellator.h"
12#include "SkShadowUtils.h"
13#include "SkVertices.h"
14#include "Test.h"
15
16void tessellate_shadow(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm,
17 bool expectSuccess) {
18
19 auto heightParams = SkPoint3::Make(0, 0, 4);
20
21 auto verts = SkShadowTessellator::MakeAmbient(path, ctm, heightParams, true);
22 if (expectSuccess != SkToBool(verts)) {
23 ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
24 expectSuccess ? "succeed" : "fail");
25 }
26 verts = SkShadowTessellator::MakeAmbient(path, ctm, heightParams, false);
27 if (expectSuccess != SkToBool(verts)) {
28 ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
29 expectSuccess ? "succeed" : "fail");
30 }
31 verts = SkShadowTessellator::MakeSpot(path, ctm, heightParams, {0, 0, 128}, 128.f, false);
32 if (expectSuccess != SkToBool(verts)) {
33 ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
34 expectSuccess ? "succeed" : "fail");
35 }
36 verts = SkShadowTessellator::MakeSpot(path, ctm, heightParams, {0, 0, 128}, 128.f, false);
37 if (expectSuccess != SkToBool(verts)) {
38 ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
39 expectSuccess ? "succeed" : "fail");
40 }
41}
42
43DEF_TEST(ShadowUtils, reporter) {
44 SkCanvas canvas(100, 100);
45
46 SkPath path;
47 path.cubicTo(100, 50, 20, 100, 0, 0);
48 tessellate_shadow(reporter, path, canvas.getTotalMatrix(), true);
49
50 // This line segment has no area and no shadow.
51 path.reset();
52 path.lineTo(10.f, 10.f);
53 tessellate_shadow(reporter, path, canvas.getTotalMatrix(), false);
54
55 // A series of colinear line segments
56 path.reset();
57 for (int i = 0; i < 10; ++i) {
58 path.lineTo((SkScalar)i, (SkScalar)i);
59 }
60 tessellate_shadow(reporter, path, canvas.getTotalMatrix(), false);
61}
62
63void check_xformed_bounds(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm) {
64 const SkDrawShadowRec rec = {
65 SkPoint3::Make(0, 0, 4),
66 SkPoint3::Make(100, 0, 600),
67 800.f,
Jim Van Verthb1b80f72018-01-18 15:19:13 -050068 0x08000000,
69 0x40000000,
Jim Van Verth1af03d42017-07-31 09:34:58 -040070 0
71 };
72 SkRect bounds;
73 SkDrawShadowMetrics::GetLocalBounds(path, rec, ctm, &bounds);
74 ctm.mapRect(&bounds);
75
76 auto verts = SkShadowTessellator::MakeAmbient(path, ctm, rec.fZPlaneParams, true);
77 if (verts) {
78 REPORTER_ASSERT(reporter, bounds.contains(verts->bounds()));
79 }
80
81 SkPoint mapXY = ctm.mapXY(rec.fLightPos.fX, rec.fLightPos.fY);
82 SkPoint3 devLightPos = SkPoint3::Make(mapXY.fX, mapXY.fY, rec.fLightPos.fZ);
83 verts = SkShadowTessellator::MakeSpot(path, ctm, rec.fZPlaneParams, devLightPos,
84 rec.fLightRadius, false);
85 if (verts) {
86 REPORTER_ASSERT(reporter, bounds.contains(verts->bounds()));
87 }
88}
89
90void check_bounds(skiatest::Reporter* reporter, const SkPath& path) {
91 SkMatrix ctm;
92 ctm.setTranslate(100, 100);
93 check_xformed_bounds(reporter, path, ctm);
94 ctm.postScale(2, 2);
95 check_xformed_bounds(reporter, path, ctm);
96 ctm.preRotate(45);
97 check_xformed_bounds(reporter, path, ctm);
98 ctm.preSkew(40, -20);
99 check_xformed_bounds(reporter, path, ctm);
100 ctm[SkMatrix::kMPersp0] = 0.0001f;
101 ctm[SkMatrix::kMPersp1] = 12.f;
102 check_xformed_bounds(reporter, path, ctm);
103}
104
105DEF_TEST(ShadowBounds, reporter) {
106 SkPath path;
107 path.addRRect(SkRRect::MakeRectXY(SkRect::MakeLTRB(-50, -20, 40, 30), 4, 4));
108 check_bounds(reporter, path);
109
110 path.reset();
111 path.addOval(SkRect::MakeLTRB(300, 300, 900, 900));
112 check_bounds(reporter, path);
113
114 path.reset();
115 path.cubicTo(100, 50, 20, 100, 0, 0);
116 check_bounds(reporter, path);
117}