SkShadowTessellator.cpp revision ab664fa5b5fb96dd1079c090534330ca7e8a10ef
1bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth/*
2bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth * Copyright 2017 Google Inc.
3bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *
4bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth * Use of this source code is governed by a BSD-style license that can be
5bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth * found in the LICENSE file.
6bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth */
7bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
8efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth#include "SkShadowTessellator.h"
966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon#include "SkColorPriv.h"
1058abc9e2c56464336472493745e91133819deb96Jim Van Verth#include "SkGeometry.h"
11ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon#include "SkInsetConvexPolygon.h"
1285dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#include "SkPath.h"
13aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon#include "SkVertices.h"
1485dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth
1585dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#if SK_SUPPORT_GPU
1685dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#include "GrPathUtils.h"
1785dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#endif
1858abc9e2c56464336472493745e91133819deb96Jim Van Verth
19958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
20a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth/**
21a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth * Base class
22a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth */
23aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkBaseShadowTessellator {
24958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonpublic:
25aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor, SkColor penumbraColor,
26aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                            bool transparent);
27aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    virtual ~SkBaseShadowTessellator() {}
280dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
29aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    sk_sp<SkVertices> releaseVertices() {
30aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        if (!fSucceeded) {
31aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon            return nullptr;
32aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        }
3397eb4feb112967ba7fcb00d6995adda1002873c2Mike Reed        return SkVertices::MakeCopy(SkCanvas::kTriangles_VertexMode, this->vertexCount(),
3497eb4feb112967ba7fcb00d6995adda1002873c2Mike Reed                                    fPositions.begin(), nullptr, fColors.begin(),
3597eb4feb112967ba7fcb00d6995adda1002873c2Mike Reed                                    this->indexCount(), fIndices.begin());
361a8b79a79e8aa6d4723588fd1125cb3b08886af8Brian Salomon    }
37958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
38a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthprotected:
39aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    int vertexCount() const { return fPositions.count(); }
40aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    int indexCount() const { return fIndices.count(); }
41aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon
42a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    virtual void handleLine(const SkPoint& p) = 0;
43a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkMatrix& m, SkPoint* p);
44958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
45958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void handleQuad(const SkPoint pts[3]);
46a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleQuad(const SkMatrix& m, SkPoint pts[3]);
47958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
48a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleCubic(const SkMatrix& m, SkPoint pts[4]);
49958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
50a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w);
51958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
52958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void addArc(const SkVector& nextNormal);
53958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
54a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    virtual void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) = 0;
55958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
56a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // first three points
57a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkTDArray<SkPoint>  fInitPoints;
58a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // temporary buffer
59a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkTDArray<SkPoint>  fPointBuffer;
60958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
61958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkPoint>  fPositions;
62958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkColor>  fColors;
63958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<uint16_t> fIndices;
64958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
65958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    int                 fFirstVertex;
66958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkVector            fFirstNormal;
67a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fFirstPoint;
680dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
690dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    bool                fSucceeded;
70a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    bool                fTransparent;
71a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
72a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkColor             fUmbraColor;
73a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkColor             fPenumbraColor;
74a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
75a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar            fRadius;
76a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar            fDirection;
77a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int                 fPrevUmbraIndex;
78a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkVector            fPrevNormal;
79a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fPrevPoint;
80958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon};
81958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
82bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verthstatic bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar radius, SkScalar dir,
83bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                           SkVector* newNormal) {
84bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
85bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // compute perpendicular
86bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    normal.fX = p0.fY - p1.fY;
87bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    normal.fY = p1.fX - p0.fX;
88bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (!normal.normalize()) {
89bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        return false;
90bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
91bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    normal *= radius*dir;
92bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *newNormal = normal;
93bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    return true;
94bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
95bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
96bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verthstatic void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScalar r,
97bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                                 SkScalar* rotSin, SkScalar* rotCos, int* n) {
98bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    const SkScalar kRecipPixelsPerArcSegment = 0.25f;
99bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
100bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar rCos = v1.dot(v2);
101bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar rSin = v1.cross(v2);
102bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar theta = SkScalarATan2(rSin, rCos);
103bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
104bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar steps = r*theta*kRecipPixelsPerArcSegment;
105bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
106bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar dTheta = theta / steps;
107bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *rotSin = SkScalarSinCos(dTheta, rotCos);
108bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *n = SkScalarFloorToInt(steps);
109bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
110bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
111aff27a23ad4b38851429066dbfb43cfa7199e37cBrian SalomonSkBaseShadowTessellator::SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor,
112aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                 SkColor penumbraColor, bool transparent)
113aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        : fFirstVertex(-1)
114aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fSucceeded(false)
115aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fTransparent(transparent)
116aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fUmbraColor(umbraColor)
117aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fPenumbraColor(penumbraColor)
118aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fRadius(radius)
119aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fDirection(1)
120aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fPrevUmbraIndex(-1) {
121a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fInitPoints.setReserve(3);
122a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
123a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // child classes will set reserve for positions, colors and indices
124a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
125a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
126a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth// tesselation tolerance values, in device space pixels
127b8b51e6b2f431c89907139bec52ed64b7ed303edMike Klein#if SK_SUPPORT_GPU
128a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kQuadTolerance = 0.2f;
129a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kCubicTolerance = 0.2f;
130b8b51e6b2f431c89907139bec52ed64b7ed303edMike Klein#endif
131a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kConicTolerance = 0.5f;
132a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
133aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
134a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(p, 1);
135a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(*p);
136a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
137a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
138aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) {
139a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#if SK_SUPPORT_GPU
140a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // TODO: Pull PathUtils out of Ganesh?
141a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
142a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setReserve(maxCount);
143a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint* target = fPointBuffer.begin();
144a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
145a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                     kQuadTolerance, &target, maxCount);
146a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setCount(count);
147a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; i++) {
148a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleLine(fPointBuffer[i]);
149a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
150a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#else
151a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // for now, just to draw something
152a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[1]);
153a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[2]);
154a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#endif
155a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
156a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
157aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
158a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 3);
159a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleQuad(pts);
160a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
161a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
162aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
163a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 4);
164a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#if SK_SUPPORT_GPU
165a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // TODO: Pull PathUtils out of Ganesh?
166a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
167a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setReserve(maxCount);
168a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint* target = fPointBuffer.begin();
169a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
170a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                 kCubicTolerance, &target, maxCount);
171a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setCount(count);
172a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; i++) {
173a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleLine(fPointBuffer[i]);
174a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
175a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#else
176a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // for now, just to draw something
177a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[1]);
178a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[2]);
179a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[3]);
180a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#endif
181a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
182a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
183aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
184a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 3);
185a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkAutoConicToQuads quadder;
186a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
187a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint lastPoint = *(quads++);
188a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = quadder.countQuads();
189a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; ++i) {
190a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        SkPoint quadPts[3];
191a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[0] = lastPoint;
192a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[1] = quads[0];
193a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[2] = i == count - 1 ? pts[2] : quads[1];
194a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleQuad(quadPts);
195a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        lastPoint = quadPts[2];
196a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quads += 2;
197a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
198a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
199a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
200aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::addArc(const SkVector& nextNormal) {
201a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // fill in fan from previous quad
202a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar rotSin, rotCos;
203a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int numSteps;
204a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    compute_radial_steps(fPrevNormal, nextNormal, fRadius, &rotSin, &rotCos, &numSteps);
205a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkVector prevNormal = fPrevNormal;
206a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < numSteps; ++i) {
207a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        SkVector nextNormal;
208a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        nextNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
209a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        nextNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
210a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fPositions.push() = fPrevPoint + nextNormal;
211a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fColors.push() = fPenumbraColor;
212a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fIndices.push() = fPrevUmbraIndex;
213a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fIndices.push() = fPositions.count() - 2;
214a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fIndices.push() = fPositions.count() - 1;
215a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
216a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        prevNormal = nextNormal;
217a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
218a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
219a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
220aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
221aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                  const SkVector& nextNormal) {
222a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // close out previous arc
223a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fPositions.push() = fPrevPoint + nextNormal;
224a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fColors.push() = fPenumbraColor;
225a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fIndices.push() = fPrevUmbraIndex;
226a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fIndices.push() = fPositions.count() - 2;
227a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fIndices.push() = fPositions.count() - 1;
228a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
229a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->addEdge(nextPoint, nextNormal);
230a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
231a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
232a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
233a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth//////////////////////////////////////////////////////////////////////////////////////////////////
234a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
235aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkAmbientShadowTessellator : public SkBaseShadowTessellator {
236a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthpublic:
237a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
238a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                               SkScalar radius, SkColor umbraColor,
239a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                               SkColor penumbraColor, bool transparent);
240a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
241a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthprivate:
242a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkPoint& p) override;
243a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) override;
244a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
245a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int                 fCentroidCount;
246a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
247aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    typedef SkBaseShadowTessellator INHERITED;
248a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth};
249a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
250efe3dedbb3493b738abdb56041b093245e4e8711Jim Van VerthSkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
251a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                       const SkMatrix& ctm,
252bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                                                       SkScalar radius,
253efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth                                                       SkColor umbraColor,
254efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth                                                       SkColor penumbraColor,
255bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                                                       bool transparent)
256a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        : INHERITED(radius, umbraColor, penumbraColor, transparent) {
257bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Outer ring: 3*numPts
258bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Middle ring: numPts
259bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fPositions.setReserve(4 * path.countPoints());
260bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fColors.setReserve(4 * path.countPoints());
261bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Outer ring: 12*numPts
262bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Middle ring: 0
263bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fIndices.setReserve(12 * path.countPoints());
264bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
265bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // walk around the path, tessellate and generate outer ring
266bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // if original path is transparent, will accumulate sum of points for centroid
267bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPath::Iter iter(path, true);
268bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPoint pts[4];
269bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPath::Verb verb;
270bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
271bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fPositions.push() = SkPoint::Make(0, 0);
272bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = umbraColor;
273bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fCentroidCount = 0;
274bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
275bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
276bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        switch (verb) {
277bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kLine_Verb:
278a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->INHERITED::handleLine(ctm, &pts[1]);
279bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
280bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kQuad_Verb:
281a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleQuad(ctm, pts);
282bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
283bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kCubic_Verb:
284a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleCubic(ctm, pts);
285bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
286bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kConic_Verb:
287a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleConic(ctm, pts, iter.conicWeight());
288bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
289bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kMove_Verb:
290bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kClose_Verb:
291bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kDone_Verb:
292bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
293bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
294bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
295bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
2960dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    if (!this->indexCount()) {
2970dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        return;
2980dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    }
2990dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
300bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
301a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection,
302bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                       &normal)) {
303bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        this->addArc(normal);
304bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
305bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // close out previous arc
306a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fPositions.push() = fPrevPoint + normal;
307bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fPenumbraColor;
30866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
309bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
310bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 1;
311bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
312bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // add final edge
313a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fPositions.push() = fFirstPoint + normal;
314bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fPenumbraColor;
315bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
31666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
317bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
318bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
319bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
320bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
321bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 1;
322bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
323bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
324bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
325bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // finalize centroid
326bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
327bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPositions[0] *= SkScalarFastInvert(fCentroidCount);
328bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
329bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = 0;
33066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
331bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
332bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
333bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
334bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // final fan
335bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fPositions.count() >= 3) {
33666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
337bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPrevNormal = normal;
338a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fPrevPoint = fFirstPoint;
339bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        this->addArc(fFirstNormal);
340bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
341bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
342bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 1;
343bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex + 1;
344bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
3450dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    fSucceeded = true;
346bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
347bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
348efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkAmbientShadowTessellator::handleLine(const SkPoint& p)  {
349bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fInitPoints.count() < 2) {
350bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fInitPoints.push() = p;
351bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        return;
352bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
353bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
354bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fInitPoints.count() == 2) {
355bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // determine if cw or ccw
356bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkVector v0 = fInitPoints[1] - fInitPoints[0];
357bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkVector v1 = p - fInitPoints[0];
358bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkScalar perpDot = v0.fX*v1.fY - v0.fY*v1.fX;
359bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        if (SkScalarNearlyZero(perpDot)) {
360bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            // nearly parallel, just treat as straight line and continue
361bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fInitPoints[1] = p;
362bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            return;
363bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
364bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
365bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // if perpDot > 0, winding is ccw
366bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fDirection = (perpDot > 0) ? -1 : 1;
367bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
368bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // add first quad
369bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        if (!compute_normal(fInitPoints[0], fInitPoints[1], fRadius, fDirection,
370bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                            &fFirstNormal)) {
371bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            // first two points are incident, make the third point the second and continue
372bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fInitPoints[1] = p;
373bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            return;
374bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
375bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
376a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fFirstPoint = fInitPoints[0];
377bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fFirstVertex = fPositions.count();
378bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPrevNormal = fFirstNormal;
379a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fPrevPoint = fFirstPoint;
38066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
381bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
382bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fPositions.push() = fInitPoints[0];
383bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fUmbraColor;
384bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fPositions.push() = fInitPoints[0] + fFirstNormal;
385bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fPenumbraColor;
386bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        if (fTransparent) {
387bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fPositions[0] += fInitPoints[0];
388bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fCentroidCount = 1;
389bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
390bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        this->addEdge(fInitPoints[1], fFirstNormal);
391bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
392bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // to ensure we skip this block next time
393bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fInitPoints.push() = p;
394bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
395bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
396bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
39766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (compute_normal(fPositions[fPrevUmbraIndex], p, fRadius, fDirection, &normal)) {
398bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        this->addArc(normal);
39991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->finishArcAndAddEdge(p, normal);
400bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
401bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
402bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
403efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
404bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // add next quad
405bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fPositions.push() = nextPoint;
406bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fColors.push() = fUmbraColor;
407bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fPositions.push() = nextPoint + nextNormal;
408bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fColors.push() = fPenumbraColor;
409bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
41066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = fPrevUmbraIndex;
411bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 3;
412bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 2;
413bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
414bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 3;
415bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 1;
416bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 2;
417bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
418bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // if transparent, add point to first one in array and add to center fan
419bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
420bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPositions[0] += nextPoint;
421bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        ++fCentroidCount;
422bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
423bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = 0;
42466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
425bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
426bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
427bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
42866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPrevUmbraIndex = fPositions.count() - 2;
429bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fPrevNormal = nextNormal;
430a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPrevPoint = nextPoint;
431bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
43291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
43391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth///////////////////////////////////////////////////////////////////////////////////////////////////
43491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
435aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkSpotShadowTessellator : public SkBaseShadowTessellator {
436958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonpublic:
437a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
438a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                            SkScalar scale, const SkVector& translate,
439958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon                            SkScalar radius, SkColor umbraColor, SkColor penumbraColor,
440958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon                            bool transparent);
441958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
442958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonprivate:
443ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    void computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
444ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                    SkScalar scale, const SkVector& xlate);
445ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    void computeClipVectorsAndTestCentroid();
44666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint);
447ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int getClosestUmbraPoint(const SkPoint& point);
448958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
449a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkPoint& p) override;
450ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    void handlePolyPoint(const SkPoint& p);
451958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
452958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count);
453ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    bool addInnerPoint(const SkPoint& pathPoint);
454a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) override;
455958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
456958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkPoint>  fClipPolygon;
45766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkTDArray<SkVector> fClipVectors;
458a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fCentroid;
459ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar            fArea;
460a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
461ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkTDArray<SkPoint>  fPathPolygon;
462ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkTDArray<SkPoint>  fUmbraPolygon;
463ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int                 fCurrClipPoint;
464ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int                 fCurrUmbraPoint;
46566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool                fPrevUmbraOutside;
46666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool                fFirstUmbraOutside;
467a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    bool                fValidUmbra;
468958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
469aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    typedef SkBaseShadowTessellator INHERITED;
470958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon};
471958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
472a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van VerthSkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
47391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                                                 SkScalar scale, const SkVector& translate,
474a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                 SkScalar radius, SkColor umbraColor,
475a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                 SkColor penumbraColor, bool transparent)
476a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        : INHERITED(radius, umbraColor, penumbraColor, transparent)
477ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        , fCurrClipPoint(0)
4780dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        , fPrevUmbraOutside(false)
4790dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        , fFirstUmbraOutside(false)
480a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        , fValidUmbra(true) {
481ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // TODO: calculate these reserves better
48266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Penumbra ring: 3*numPts
48366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Umbra ring: numPts
48491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // Inner ring: numPts
48566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPositions.setReserve(5 * path.countPoints());
48666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fColors.setReserve(5 * path.countPoints());
48766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Penumbra ring: 12*numPts
48866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Umbra ring: 3*numPts
48966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fIndices.setReserve(15 * path.countPoints());
490e7c85c45c4c0a97adc6711bb12ecacc36af4ba11Brian Salomon    fClipPolygon.setReserve(path.countPoints());
491ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
492ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // compute rough clip bounds for umbra, plus offset polygon, plus centroid
493ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    this->computeClipAndPathPolygons(path, ctm, scale, translate);
494ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fClipPolygon.count() < 3 || fPathPolygon.count() < 3) {
49566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        return;
49666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
49766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
498ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // check to see if umbra collapses
499ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar minDistSq = fCentroid.distanceToLineSegmentBetweenSqd(fPathPolygon[0],
500ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                                   fPathPolygon[1]);
501ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    for (int i = 1; i < fPathPolygon.count(); ++i) {
502ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        int j = i + 1;
503ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        if (i == fPathPolygon.count() - 1) {
504ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            j = 0;
505ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        }
506ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkPoint currPoint = fPathPolygon[i];
507ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkPoint nextPoint = fPathPolygon[j];
508ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar distSq = fCentroid.distanceToLineSegmentBetweenSqd(currPoint, nextPoint);
509ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        if (distSq < minDistSq) {
510ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            minDistSq = distSq;
511ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        }
512ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
513ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr auto kTolerance = 1.0e-2f;
514ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (minDistSq < (radius + kTolerance)*(radius + kTolerance)) {
515ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
516ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar newRadius = SkScalarSqrt(minDistSq) - kTolerance;
517ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar ratio = 256 * newRadius / radius;
518ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // they aren't PMColors, but the interpolation algorithm is the same
519ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fUmbraColor = SkPMLerp(fUmbraColor, fPenumbraColor, (unsigned)ratio);
520ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        radius = newRadius;
521ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
522e5f5bf5175e426ebb6aa234f4387831c898f20adJim Van Verth
523ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // compute vectors for clip tests
524ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    this->computeClipVectorsAndTestCentroid();
525ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
526ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // generate inner ring
527ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), radius, &fUmbraPolygon)) {
528ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // this shouldn't happen, but just in case we'll inset using the centroid
529ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fValidUmbra = false;
530ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
531ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
532ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // walk around the path polygon, generate outer ring and connect to inner ring
53366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (fTransparent) {
53466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fPositions.push() = fCentroid;
53566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fColors.push() = fUmbraColor;
53666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
537ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fCurrUmbraPoint = 0;
538ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    for (int i = 0; i < fPathPolygon.count(); ++i) {
539ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        this->handlePolyPoint(fPathPolygon[i]);
54091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
54191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
5420dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    if (!this->indexCount()) {
5430dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        return;
5440dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    }
5450dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
546ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // finish up the final verts
54791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkVector normal;
548ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection, &normal)) {
54991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addArc(normal);
55091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
55191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // close out previous arc
55291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fPositions.push() = fPrevPoint + normal;
55391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fColors.push() = fPenumbraColor;
55466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
55591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
55691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
55791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
55866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // add to center fan
55966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (fTransparent) {
56066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = 0;
56166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fPrevUmbraIndex;
56266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fFirstVertex;
56366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // or to clip ring
56466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else {
56566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (fFirstUmbraOutside) {
56666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
56766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex;
56866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex + 1;
56966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                if (fPrevUmbraOutside) {
57066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    // fill out quad
57166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex;
57266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fFirstVertex + 1;
57366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex + 1;
57466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                }
57566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            } else if (fPrevUmbraOutside) {
57666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // add tri
57766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
57866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex;
57966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex + 1;
58066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
58166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
58266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
58391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // add final edge
58491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fPositions.push() = fFirstPoint + normal;
58591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fColors.push() = fPenumbraColor;
58691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
58766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
58891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
58991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fFirstVertex;
59091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
59191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
59291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
59391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fFirstVertex;
59491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
59591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
59691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // final fan
59791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fPositions.count() >= 3) {
59866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
59991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevPoint = fFirstPoint;
60091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevNormal = normal;
60191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addArc(fFirstNormal);
60291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
60391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fFirstVertex;
60491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
60566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (fFirstUmbraOutside) {
60666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fFirstVertex + 2;
60766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else {
60866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fFirstVertex + 1;
60966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
61091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
6110dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    fSucceeded = true;
61291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
61391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
614ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
615ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                         SkScalar scale, const SkVector& xlate) {
616ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // For the path polygon we are going to apply 'scale' and 'xlate' (in that order) to each
617ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // computed path point. We want the effect to be to scale the points relative to the path
618ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // bounds center and then translate them by the 'xlate' param we were passed.
619ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
620ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    ctm.mapPoints(&center, 1);
621ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkVector translate = center * (1.f - scale) + xlate;
622ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkMatrix shadowTransform;
623ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    shadowTransform.setScaleTranslate(scale, scale, translate.fX, translate.fY);
624ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
625ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fPathPolygon.setReserve(path.countPoints());
626ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
627ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // Walk around the path and compute clip polygon and path polygon.
628ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // Will also accumulate sum of areas for centroid.
629ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // For Bezier curves, we compute additional interior points on curve.
63091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPath::Iter iter(path, true);
63191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPoint pts[4];
63291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPath::Verb verb;
63391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
634e7c85c45c4c0a97adc6711bb12ecacc36af4ba11Brian Salomon    fClipPolygon.reset();
635e5f5bf5175e426ebb6aa234f4387831c898f20adJim Van Verth
636ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // init centroid
637ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fCentroid = SkPoint::Make(0, 0);
638ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fArea = 0;
639ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
64066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // coefficients to compute cubic Bezier at t = 5/16
641ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kA = 0.32495117187f;
642ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kB = 0.44311523437f;
643ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kC = 0.20141601562f;
644ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kD = 0.03051757812f;
64566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
64666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkPoint curvePoint;
64766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar w;
64891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
64991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        switch (verb) {
65091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kLine_Verb:
651a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(&pts[1], 1);
65291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                *fClipPolygon.push() = pts[1];
653ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                this->INHERITED::handleLine(shadowTransform, &pts[1]);
65491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
65591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kQuad_Verb:
656a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 3);
65766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 1/2
65866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = 0.25f*pts[0].fX + 0.5f*pts[1].fX + 0.25f*pts[2].fX;
65966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = 0.25f*pts[0].fY + 0.5f*pts[1].fY + 0.25f*pts[2].fY;
66066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
66166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[2];
662ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                this->handleQuad(shadowTransform, pts);
66391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
66491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kConic_Verb:
665a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 3);
66666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                w = iter.conicWeight();
667a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                // point at t = 1/2
66866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = 0.25f*pts[0].fX + w*0.5f*pts[1].fX + 0.25f*pts[2].fX;
66966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = 0.25f*pts[0].fY + w*0.5f*pts[1].fY + 0.25f*pts[2].fY;
67066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint *= SkScalarInvert(0.5f + 0.5f*w);
67166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
67266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[2];
673ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                this->handleConic(shadowTransform, pts, w);
67491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
67591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kCubic_Verb:
676a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 4);
67766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 5/16
67866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = kA*pts[0].fX + kB*pts[1].fX + kC*pts[2].fX + kD*pts[3].fX;
67966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = kA*pts[0].fY + kB*pts[1].fY + kC*pts[2].fY + kD*pts[3].fY;
68066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
68166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 11/16
68266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = kD*pts[0].fX + kC*pts[1].fX + kB*pts[2].fX + kA*pts[3].fX;
68366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = kD*pts[0].fY + kC*pts[1].fY + kB*pts[2].fY + kA*pts[3].fY;
68466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
68566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[3];
686ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                this->handleCubic(shadowTransform, pts);
68791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
688ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            case SkPath::kMove_Verb:
68991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kClose_Verb:
690ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            case SkPath::kDone_Verb:
69191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
69291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            default:
69391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                SkDEBUGFAIL("unknown verb");
69491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
69591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
69691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
697ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // finish centroid
698ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fPathPolygon.count() > 0) {
699ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkPoint currPoint = fPathPolygon[fPathPolygon.count() - 1];
700ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkPoint nextPoint = fPathPolygon[0];
701ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar quadArea = currPoint.cross(nextPoint);
702ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid.fX += (currPoint.fX + nextPoint.fX) * quadArea;
703ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid.fY += (currPoint.fY + nextPoint.fY) * quadArea;
704ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fArea += quadArea;
705ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid *= SK_Scalar1 / (3 * fArea);
706ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
707ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
708ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fCurrClipPoint = fClipPolygon.count() - 1;
70966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon}
71066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
711ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::computeClipVectorsAndTestCentroid() {
71266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkASSERT(fClipPolygon.count() >= 3);
71366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
714ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // init clip vectors
71566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkVector v0 = fClipPolygon[1] - fClipPolygon[0];
71666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fClipVectors.push() = v0;
71766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
71866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // init centroid check
71966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool hiddenCentroid = true;
720ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkVector v1 = fCentroid - fClipPolygon[0];
72166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar initCross = v0.cross(v1);
72266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
72366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    for (int p = 1; p < fClipPolygon.count(); ++p) {
724ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // add to clip vectors
72566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        v0 = fClipPolygon[(p + 1) % fClipPolygon.count()] - fClipPolygon[p];
72666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fClipVectors.push() = v0;
72766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // Determine if transformed centroid is inside clipPolygon.
728ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        v1 = fCentroid - fClipPolygon[p];
72966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (initCross*v0.cross(v1) <= 0) {
73066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            hiddenCentroid = false;
73166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
73266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
73366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkASSERT(fClipVectors.count() == fClipPolygon.count());
73466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
735ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fTransparent = fTransparent || !hiddenCentroid;
73666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon}
73766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
73866085ed41779211f9e7e17aa493d4585d73445feBrian Salomonbool SkSpotShadowTessellator::clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid,
73966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                                             SkPoint* clipPoint) {
74066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkVector segmentVector = centroid - umbraPoint;
74166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
742ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int startClipPoint = fCurrClipPoint;
74366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    do {
744ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkVector dp = umbraPoint - fClipPolygon[fCurrClipPoint];
745ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar denom = fClipVectors[fCurrClipPoint].cross(segmentVector);
74666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkScalar t_num = dp.cross(segmentVector);
74766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // if line segments are nearly parallel
74866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (SkScalarNearlyZero(denom)) {
74966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // and collinear
75066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (SkScalarNearlyZero(t_num)) {
75166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                return false;
75266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
75366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // otherwise are separate, will try the next poly segment
75466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // else if crossing lies within poly segment
75566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else if (t_num >= 0 && t_num <= denom) {
756ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            SkScalar s_num = dp.cross(fClipVectors[fCurrClipPoint]);
75766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // if umbra point is inside the clip polygon
75866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (s_num < 0) {
75966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                return false;
76066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            } else {
76166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                segmentVector *= s_num/denom;
76266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *clipPoint = umbraPoint + segmentVector;
76366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                return true;
76466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
76566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
766ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCurrClipPoint = (fCurrClipPoint + 1) % fClipPolygon.count();
767ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    } while (fCurrClipPoint != startClipPoint);
76866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
76966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    return false;
77091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
77191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
772ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonint SkSpotShadowTessellator::getClosestUmbraPoint(const SkPoint& p) {
773ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar minDistance = p.distanceToSqd(fUmbraPolygon[fCurrUmbraPoint]);
774ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int index = fCurrUmbraPoint;
775ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int dir = 1;
776ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int next = (index + dir) % fUmbraPolygon.count();
777ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
778ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // init travel direction
779ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar distance = p.distanceToSqd(fUmbraPolygon[next]);
780ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (distance < minDistance) {
781ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        index = next;
782ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        minDistance = distance;
783ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    } else {
784ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        dir = fUmbraPolygon.count()-1;
785ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
786ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
787ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // iterate until we find a point that increases the distance
788ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    next = (index + dir) % fUmbraPolygon.count();
789ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    distance = p.distanceToSqd(fUmbraPolygon[next]);
790ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    while (distance < minDistance) {
791ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        index = next;
792ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        minDistance = distance;
793ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        next = (index + dir) % fUmbraPolygon.count();
794ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        distance = p.distanceToSqd(fUmbraPolygon[next]);
795ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
796ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
797ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fCurrUmbraPoint = index;
798ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    return index;
799ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon}
800ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
801efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate,
80291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                                        SkPoint* pts, int count) {
80391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // TODO: vectorize
80491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    for (int i = 0; i < count; ++i) {
80591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        pts[i] *= scale;
80691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        pts[i] += xlate;
80791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
80891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
80991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
810ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonstatic bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) {
811ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kClose = (SK_Scalar1 / 16);
812ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kCloseSqd = kClose*kClose;
813ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
814ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar distSq = p0.distanceToSqd(p1);
815ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    return distSq < kCloseSqd;
816ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon}
817ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
818ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonstatic bool is_collinear(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
819ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkVector v0 = p1 - p0;
820ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkVector v1 = p2 - p0;
821ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    return (SkScalarNearlyZero(v0.cross(v1)));
822ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon}
823ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
824efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::handleLine(const SkPoint& p) {
825ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // remove coincident points and add to centroid
826ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fPathPolygon.count() > 0) {
827ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        const SkPoint& lastPoint = fPathPolygon[fPathPolygon.count() - 1];
828ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        if (duplicate_pt(p, lastPoint)) {
829ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            return;
830ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        }
831ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar quadArea = lastPoint.cross(p);
832ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid.fX += (p.fX + lastPoint.fX) * quadArea;
833ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid.fY += (p.fY + lastPoint.fY) * quadArea;
834ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fArea += quadArea;
835ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
836ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
837ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // try to remove collinear points
838ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fPathPolygon.count() > 1 && is_collinear(fPathPolygon[fPathPolygon.count()-2],
839ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                 fPathPolygon[fPathPolygon.count()-1],
840ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                 p)) {
841ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fPathPolygon[fPathPolygon.count() - 1] = p;
842ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    } else {
843ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fPathPolygon.push() = p;
844ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
845ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon}
846ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
847ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::handlePolyPoint(const SkPoint& p) {
84891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fInitPoints.count() < 2) {
84991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fInitPoints.push() = p;
85091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        return;
85191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
85291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
85391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fInitPoints.count() == 2) {
85491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // determine if cw or ccw
85591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkVector v0 = fInitPoints[1] - fInitPoints[0];
85691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkVector v1 = p - fInitPoints[0];
857ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar perpDot = v0.cross(v1);
85891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        if (SkScalarNearlyZero(perpDot)) {
85991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            // nearly parallel, just treat as straight line and continue
86091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            fInitPoints[1] = p;
86191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            return;
86291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
86391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
86491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // if perpDot > 0, winding is ccw
86591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fDirection = (perpDot > 0) ? -1 : 1;
86691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
86791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // add first quad
86891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        if (!compute_normal(fInitPoints[0], fInitPoints[1], fRadius, fDirection,
86991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                            &fFirstNormal)) {
87091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            // first two points are incident, make the third point the second and continue
87191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            fInitPoints[1] = p;
87291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            return;
87391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
87491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
87591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fFirstPoint = fInitPoints[0];
87691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fFirstVertex = fPositions.count();
87791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevNormal = fFirstNormal;
87891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevPoint = fFirstPoint;
87966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
88066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
88166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        this->addInnerPoint(fFirstPoint);
88266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
88366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (!fTransparent) {
88466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkPoint clipPoint;
88566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            bool isOutside = this->clipUmbraPoint(fPositions[fFirstVertex], fCentroid, &clipPoint);
88666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (isOutside) {
88766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fPositions.push() = clipPoint;
88866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fColors.push() = fUmbraColor;
88966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
89066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fPrevUmbraOutside = isOutside;
89166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fFirstUmbraOutside = isOutside;
89266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
89391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
89491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkPoint newPoint = fFirstPoint + fFirstNormal;
89591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fPositions.push() = newPoint;
89691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fColors.push() = fPenumbraColor;
89791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addEdge(fInitPoints[1], fFirstNormal);
89891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
89991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // to ensure we skip this block next time
90091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fInitPoints.push() = p;
90191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
90291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
90391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkVector normal;
90491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (compute_normal(fPrevPoint, p, fRadius, fDirection, &normal)) {
90591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addArc(normal);
90691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->finishArcAndAddEdge(p, normal);
90791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
90891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
90991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
910ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonbool SkSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint) {
911ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkPoint umbraPoint;
912ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (!fValidUmbra) {
913ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkVector v = fCentroid - pathPoint;
914ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        v *= 0.95f;
915ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        umbraPoint = pathPoint + v;
91691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    } else {
917ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        umbraPoint = fUmbraPolygon[this->getClosestUmbraPoint(pathPoint)];
91891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
91966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
92091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fPrevPoint = pathPoint;
921ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
922ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // merge "close" points
923ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fPrevUmbraIndex == fFirstVertex ||
924ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        !duplicate_pt(umbraPoint, fPositions[fPrevUmbraIndex])) {
925ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fPositions.push() = umbraPoint;
926ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fColors.push() = fUmbraColor;
927ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
928ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        return false;
929ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    } else {
930ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        return true;
931ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
93291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
93391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
934efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
93566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // add next umbra point
936ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    bool duplicate = this->addInnerPoint(nextPoint);
937ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int prevPenumbraIndex = duplicate ? fPositions.count()-1 : fPositions.count()-2;
938ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int currUmbraIndex = duplicate ? fPrevUmbraIndex : fPositions.count()-1;
93966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
940ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (!duplicate) {
941ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // add to center fan if transparent or centroid showing
942ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        if (fTransparent) {
943ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            *fIndices.push() = 0;
944ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            *fIndices.push() = fPrevUmbraIndex;
945ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            *fIndices.push() = currUmbraIndex;
946ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // otherwise add to clip ring
947ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        } else {
94866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkPoint clipPoint;
949ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            bool isOutside = this->clipUmbraPoint(fPositions[currUmbraIndex], fCentroid,
950ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                  &clipPoint);
95166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (isOutside) {
95266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fPositions.push() = clipPoint;
95366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fColors.push() = fUmbraColor;
95466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
95566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
95666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex;
95766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex + 1;
95866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                if (fPrevUmbraOutside) {
95966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    // fill out quad
96066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex;
96166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = currUmbraIndex + 1;
96266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex + 1;
96366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                }
96466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            } else if (fPrevUmbraOutside) {
96566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // add tri
96666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
96766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex;
96866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex + 1;
96966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
97066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fPrevUmbraOutside = isOutside;
97166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
97266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
97366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
97466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // add next penumbra point and quad
97591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPoint newPoint = nextPoint + nextNormal;
97691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fPositions.push() = newPoint;
97791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fColors.push() = fPenumbraColor;
97891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
979ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (!duplicate) {
980ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
981ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fIndices.push() = prevPenumbraIndex;
982ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fIndices.push() = currUmbraIndex;
983ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
98491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
98566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = prevPenumbraIndex;
98691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fIndices.push() = fPositions.count() - 1;
98766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = currUmbraIndex;
98891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
98966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPrevUmbraIndex = currUmbraIndex;
99091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fPrevNormal = nextNormal;
99191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
992958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
993958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon///////////////////////////////////////////////////////////////////////////////////////////////////
994958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
995aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonsk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
996aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                   SkScalar radius, SkColor umbra, SkColor penumbra,
997aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                   bool transparent) {
998a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkAmbientShadowTessellator ambientTess(path, ctm, radius, umbra, penumbra, transparent);
999aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    return ambientTess.releaseVertices();
1000958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon}
1001958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
1002aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonsk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
1003aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                SkScalar scale, const SkVector& translate,
1004aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                SkScalar radius, SkColor umbraColor,
1005aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                SkColor penumbraColor, bool transparent) {
1006a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkSpotShadowTessellator spotTess(path, ctm, scale, translate, radius, umbraColor,
1007a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                     penumbraColor, transparent);
1008aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    return spotTess.releaseVertices();
1009958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon}
1010