blob: 8a921d8bc892bccf0732f0196990142ef3367d9e [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,
68 0.035f,
69 0.25f,
70 SK_ColorBLACK,
71 0
72 };
73 SkRect bounds;
74 SkDrawShadowMetrics::GetLocalBounds(path, rec, ctm, &bounds);
75 ctm.mapRect(&bounds);
76
77 auto verts = SkShadowTessellator::MakeAmbient(path, ctm, rec.fZPlaneParams, true);
78 if (verts) {
79 REPORTER_ASSERT(reporter, bounds.contains(verts->bounds()));
80 }
81
82 SkPoint mapXY = ctm.mapXY(rec.fLightPos.fX, rec.fLightPos.fY);
83 SkPoint3 devLightPos = SkPoint3::Make(mapXY.fX, mapXY.fY, rec.fLightPos.fZ);
84 verts = SkShadowTessellator::MakeSpot(path, ctm, rec.fZPlaneParams, devLightPos,
85 rec.fLightRadius, false);
86 if (verts) {
87 REPORTER_ASSERT(reporter, bounds.contains(verts->bounds()));
88 }
89}
90
91void check_bounds(skiatest::Reporter* reporter, const SkPath& path) {
92 SkMatrix ctm;
93 ctm.setTranslate(100, 100);
94 check_xformed_bounds(reporter, path, ctm);
95 ctm.postScale(2, 2);
96 check_xformed_bounds(reporter, path, ctm);
97 ctm.preRotate(45);
98 check_xformed_bounds(reporter, path, ctm);
99 ctm.preSkew(40, -20);
100 check_xformed_bounds(reporter, path, ctm);
101 ctm[SkMatrix::kMPersp0] = 0.0001f;
102 ctm[SkMatrix::kMPersp1] = 12.f;
103 check_xformed_bounds(reporter, path, ctm);
104}
105
106DEF_TEST(ShadowBounds, reporter) {
107 SkPath path;
108 path.addRRect(SkRRect::MakeRectXY(SkRect::MakeLTRB(-50, -20, 40, 30), 4, 4));
109 check_bounds(reporter, path);
110
111 path.reset();
112 path.addOval(SkRect::MakeLTRB(300, 300, 900, 900));
113 check_bounds(reporter, path);
114
115 path.reset();
116 path.cubicTo(100, 50, 20, 100, 0, 0);
117 check_bounds(reporter, path);
118}