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