SkShadowTessellator.cpp revision 060d9820364b0cf09c7eb3bda449f24c3dcba2e2
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:
25b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    SkBaseShadowTessellator(SkShadowTessellator::HeightFunc, bool transparent);
26aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    virtual ~SkBaseShadowTessellator() {}
270dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
28aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    sk_sp<SkVertices> releaseVertices() {
29aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        if (!fSucceeded) {
30aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon            return nullptr;
31aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        }
32887cdf112809727c51890ba8b98b3ddce22249f0Mike Reed        return SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, this->vertexCount(),
3397eb4feb112967ba7fcb00d6995adda1002873c2Mike Reed                                    fPositions.begin(), nullptr, fColors.begin(),
3497eb4feb112967ba7fcb00d6995adda1002873c2Mike Reed                                    this->indexCount(), fIndices.begin());
351a8b79a79e8aa6d4723588fd1125cb3b08886af8Brian Salomon    }
36958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
37a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthprotected:
38da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    static constexpr auto kMinHeight = 0.1f;
39da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
40aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    int vertexCount() const { return fPositions.count(); }
41aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    int indexCount() const { return fIndices.count(); }
42aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon
43da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    bool setZOffset(const SkRect& bounds, bool perspective);
44da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
45a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    virtual void handleLine(const SkPoint& p) = 0;
46a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkMatrix& m, SkPoint* p);
47958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
48958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void handleQuad(const SkPoint pts[3]);
49a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleQuad(const SkMatrix& m, SkPoint pts[3]);
50958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
51a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleCubic(const SkMatrix& m, SkPoint pts[4]);
52958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
53a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w);
54958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
55da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    bool setTransformedHeightFunc(const SkMatrix& ctm);
56da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
57e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth    bool addArc(const SkVector& nextNormal, bool finishArc);
58958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
59da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkShadowTessellator::HeightFunc         fHeightFunc;
60da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    std::function<SkScalar(const SkPoint&)> fTransformedHeightFunc;
61da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar                                fZOffset;
62da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    // members for perspective height function
63da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar                                fZParams[3];
64da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar                                fPartialDeterminants[3];
65b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth
66da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    // first two points
67a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkTDArray<SkPoint>  fInitPoints;
68a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // temporary buffer
69a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkTDArray<SkPoint>  fPointBuffer;
70958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
71958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkPoint>  fPositions;
72958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkColor>  fColors;
73958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<uint16_t> fIndices;
74958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
75958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    int                 fFirstVertex;
76958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkVector            fFirstNormal;
77a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fFirstPoint;
780dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
790dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    bool                fSucceeded;
80a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    bool                fTransparent;
81a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
82a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkColor             fUmbraColor;
83a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkColor             fPenumbraColor;
84a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
85a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar            fRadius;
86a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar            fDirection;
87a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int                 fPrevUmbraIndex;
88a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkVector            fPrevNormal;
89a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fPrevPoint;
90958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon};
91958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
92da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verthstatic bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar dir,
93bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                           SkVector* newNormal) {
94bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
95bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // compute perpendicular
96bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    normal.fX = p0.fY - p1.fY;
97bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    normal.fY = p1.fX - p0.fX;
98da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    normal *= dir;
99bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (!normal.normalize()) {
100bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        return false;
101bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
102bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *newNormal = normal;
103bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    return true;
104bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
105bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
106bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verthstatic void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScalar r,
107bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                                 SkScalar* rotSin, SkScalar* rotCos, int* n) {
108e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth    const SkScalar kRecipPixelsPerArcSegment = 0.125f;
109bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
110bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar rCos = v1.dot(v2);
111bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar rSin = v1.cross(v2);
112bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar theta = SkScalarATan2(rSin, rCos);
113bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
114e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth    int steps = SkScalarFloorToInt(r*theta*kRecipPixelsPerArcSegment);
115bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
116bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar dTheta = theta / steps;
117bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *rotSin = SkScalarSinCos(dTheta, rotCos);
118e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth    *n = steps;
119bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
120bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
121b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van VerthSkBaseShadowTessellator::SkBaseShadowTessellator(SkShadowTessellator::HeightFunc heightFunc,
122b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth                                                 bool transparent)
123b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth        : fHeightFunc(heightFunc)
124da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        , fZOffset(0)
125b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth        , fFirstVertex(-1)
126aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fSucceeded(false)
127aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fTransparent(transparent)
128aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fDirection(1)
129aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fPrevUmbraIndex(-1) {
130a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fInitPoints.setReserve(3);
131a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
132a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // child classes will set reserve for positions, colors and indices
133a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
134a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
135da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verthbool SkBaseShadowTessellator::setZOffset(const SkRect& bounds, bool perspective) {
136da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar minZ = fHeightFunc(bounds.fLeft, bounds.fTop);
137da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (perspective) {
138da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar z = fHeightFunc(bounds.fLeft, bounds.fBottom);
139da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (z < minZ) {
140da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            minZ = z;
141da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        }
142da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        z = fHeightFunc(bounds.fRight, bounds.fTop);
143da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (z < minZ) {
144da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            minZ = z;
145da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        }
146da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        z = fHeightFunc(bounds.fRight, bounds.fBottom);
147da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (z < minZ) {
148da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            minZ = z;
149da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        }
150da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
151da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
152da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (minZ < kMinHeight) {
153da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fZOffset = -minZ + kMinHeight;
154da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        return true;
155da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
156da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
157da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    return false;
158da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth}
159da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
160a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth// tesselation tolerance values, in device space pixels
161b8b51e6b2f431c89907139bec52ed64b7ed303edMike Klein#if SK_SUPPORT_GPU
162a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kQuadTolerance = 0.2f;
163a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kCubicTolerance = 0.2f;
164b8b51e6b2f431c89907139bec52ed64b7ed303edMike Klein#endif
165a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kConicTolerance = 0.5f;
166a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
167aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
168a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(p, 1);
169a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(*p);
170a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
171a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
172aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) {
173a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#if SK_SUPPORT_GPU
174a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // TODO: Pull PathUtils out of Ganesh?
175a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
176a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setReserve(maxCount);
177a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint* target = fPointBuffer.begin();
178a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
179a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                     kQuadTolerance, &target, maxCount);
180a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setCount(count);
181a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; i++) {
182a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleLine(fPointBuffer[i]);
183a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
184a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#else
185a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // for now, just to draw something
186a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[1]);
187a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[2]);
188a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#endif
189a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
190a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
191aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
192a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 3);
193a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleQuad(pts);
194a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
195a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
196aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
197a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 4);
198a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#if SK_SUPPORT_GPU
199a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // TODO: Pull PathUtils out of Ganesh?
200a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
201a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setReserve(maxCount);
202a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint* target = fPointBuffer.begin();
203a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
204a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                 kCubicTolerance, &target, maxCount);
205a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setCount(count);
206a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; i++) {
207a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleLine(fPointBuffer[i]);
208a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
209a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#else
210a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // for now, just to draw something
211a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[1]);
212a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[2]);
213a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[3]);
214a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#endif
215a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
216a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
217aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
218da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (m.hasPerspective()) {
219da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        w = SkConic::TransformW(pts, w, m);
220da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
221a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 3);
222a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkAutoConicToQuads quadder;
223a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
224a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint lastPoint = *(quads++);
225a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = quadder.countQuads();
226a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; ++i) {
227a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        SkPoint quadPts[3];
228a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[0] = lastPoint;
229a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[1] = quads[0];
230a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[2] = i == count - 1 ? pts[2] : quads[1];
231a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleQuad(quadPts);
232a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        lastPoint = quadPts[2];
233a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quads += 2;
234a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
235a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
236a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
237e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verthbool SkBaseShadowTessellator::addArc(const SkVector& nextNormal, bool finishArc) {
238a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // fill in fan from previous quad
239a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar rotSin, rotCos;
240a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int numSteps;
241a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    compute_radial_steps(fPrevNormal, nextNormal, fRadius, &rotSin, &rotCos, &numSteps);
242a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkVector prevNormal = fPrevNormal;
243e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth    for (int i = 0; i < numSteps-1; ++i) {
244da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkVector currNormal;
245da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        currNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
246da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        currNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
247da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fPositions.push() = fPrevPoint + currNormal;
248a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fColors.push() = fPenumbraColor;
249a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fIndices.push() = fPrevUmbraIndex;
250a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fIndices.push() = fPositions.count() - 1;
251e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
252a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
253da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        prevNormal = currNormal;
254a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
255e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth    if (finishArc && numSteps) {
256da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fPositions.push() = fPrevPoint + nextNormal;
257da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fColors.push() = fPenumbraColor;
258da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPrevUmbraIndex;
259da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
260e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
261da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
262da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    fPrevNormal = nextNormal;
263e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth
264e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth    return (numSteps > 0);
265a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
266a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
267da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verthbool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) {
268da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (!ctm.hasPerspective()) {
269da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fTransformedHeightFunc = [this](const SkPoint& p) {
270da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            return this->fHeightFunc(0, 0);
271da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        };
272da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    } else {
273da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkMatrix ctmInverse;
274da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (!ctm.invert(&ctmInverse)) {
275da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            return false;
276da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        }
277da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar C = fHeightFunc(0, 0);
278da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar A = fHeightFunc(1, 0) - C;
279da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar B = fHeightFunc(0, 1) - C;
280da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
281da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // multiply by transpose
282da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fZParams[0] = ctmInverse[SkMatrix::kMScaleX] * A +
283da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                      ctmInverse[SkMatrix::kMSkewY] * B +
284da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                      ctmInverse[SkMatrix::kMPersp0] * C;
285da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fZParams[1] = ctmInverse[SkMatrix::kMSkewX] * A +
286da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                      ctmInverse[SkMatrix::kMScaleY] * B +
287da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                      ctmInverse[SkMatrix::kMPersp1] * C;
288da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fZParams[2] = ctmInverse[SkMatrix::kMTransX] * A +
289da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                      ctmInverse[SkMatrix::kMTransY] * B +
290da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                      ctmInverse[SkMatrix::kMPersp2] * C;
291da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
292da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // We use Cramer's rule to solve for the W value for a given post-divide X and Y,
293da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // so pre-compute those values that are independent of X and Y.
294da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // W is det(ctmInverse)/(PD[0]*X + PD[1]*Y + PD[2])
295da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fPartialDeterminants[0] = ctm[SkMatrix::kMSkewY] * ctm[SkMatrix::kMPersp1] -
296da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                                  ctm[SkMatrix::kMScaleY] * ctm[SkMatrix::kMPersp0];
297da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fPartialDeterminants[1] = ctm[SkMatrix::kMPersp0] * ctm[SkMatrix::kMSkewX] -
298da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                                  ctm[SkMatrix::kMPersp1] * ctm[SkMatrix::kMScaleX];
299da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fPartialDeterminants[2] = ctm[SkMatrix::kMScaleX] * ctm[SkMatrix::kMScaleY] -
300da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                                  ctm[SkMatrix::kMSkewX] * ctm[SkMatrix::kMSkewY];
301da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar ctmDeterminant = ctm[SkMatrix::kMTransX] * fPartialDeterminants[0] +
302da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                                  ctm[SkMatrix::kMTransY] * fPartialDeterminants[1] +
303da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                                  ctm[SkMatrix::kMPersp2] * fPartialDeterminants[2];
304da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
305da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // Pre-bake the numerator of Cramer's rule into the zParams to avoid another multiply.
306da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // TODO: this may introduce numerical instability, but I haven't seen any issues yet.
307da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fZParams[0] *= ctmDeterminant;
308da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fZParams[1] *= ctmDeterminant;
309da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fZParams[2] *= ctmDeterminant;
310da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
311da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fTransformedHeightFunc = [this](const SkPoint& p) {
312da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            SkScalar denom = p.fX * this->fPartialDeterminants[0] +
313da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                             p.fY * this->fPartialDeterminants[1] +
314da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                             this->fPartialDeterminants[2];
315da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            SkScalar w = SkScalarFastInvert(denom);
316da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            return (this->fZParams[0] * p.fX + this->fZParams[1] * p.fY + this->fZParams[2])*w +
317da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                   this->fZOffset;
318da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        };
319da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
320a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
321da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    return true;
322a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
323a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
324a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
325a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth//////////////////////////////////////////////////////////////////////////////////////////////////
326a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
327aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkAmbientShadowTessellator : public SkBaseShadowTessellator {
328a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthpublic:
329a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
330060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth                               SkShadowTessellator::HeightFunc heightFunc, bool transparent);
331a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
332a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthprivate:
333a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkPoint& p) override;
334da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
335da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
336da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    static constexpr auto kHeightFactor = 1.0f / 128.0f;
337da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    static constexpr auto kGeomFactor = 64.0f;
338da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    static constexpr auto kMaxEdgeLenSqr = 20 * 20;
339a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
340da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar offset(SkScalar z) {
341da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        return z * kHeightFactor * kGeomFactor;
342da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
343da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkColor umbraColor(SkScalar z) {
344da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(z*kHeightFactor, 0.0f)));
345060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth        return SkColorSetARGB(umbraAlpha * 255.9999f, 0, 0, 0);
346da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
347da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
348a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int                 fCentroidCount;
349a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
350aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    typedef SkBaseShadowTessellator INHERITED;
351a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth};
352a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
353efe3dedbb3493b738abdb56041b093245e4e8711Jim Van VerthSkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
354a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                       const SkMatrix& ctm,
355b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth                                                       SkShadowTessellator::HeightFunc heightFunc,
356bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                                                       bool transparent)
357060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth        : INHERITED(heightFunc, transparent) {
358da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    // Set base colors
359b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    SkScalar occluderHeight = heightFunc(0, 0);
360b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f)));
361b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    // umbraColor is the interior value, penumbraColor the exterior value.
362b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    // umbraAlpha is the factor that is linearly interpolated from outside to inside, and
363b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    // then "blurred" by the GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get
364b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    // the final alpha.
365060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth    fUmbraColor = SkColorSetARGB(umbraAlpha * 255.9999f, 0, 0, 0);
366060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth    fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
367b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth
368da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    // make sure we're not below the canvas plane
369da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    this->setZOffset(path.getBounds(), ctm.hasPerspective());
370da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
371da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    this->setTransformedHeightFunc(ctm);
372da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
373bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Outer ring: 3*numPts
374bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Middle ring: numPts
375bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fPositions.setReserve(4 * path.countPoints());
376bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fColors.setReserve(4 * path.countPoints());
377bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Outer ring: 12*numPts
378bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Middle ring: 0
379bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fIndices.setReserve(12 * path.countPoints());
380bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
381bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // walk around the path, tessellate and generate outer ring
382bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // if original path is transparent, will accumulate sum of points for centroid
383bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPath::Iter iter(path, true);
384bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPoint pts[4];
385bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPath::Verb verb;
386bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
387bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fPositions.push() = SkPoint::Make(0, 0);
388b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth        *fColors.push() = fUmbraColor;
389bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fCentroidCount = 0;
390bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
391bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
392bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        switch (verb) {
393bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kLine_Verb:
394a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->INHERITED::handleLine(ctm, &pts[1]);
395bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
396bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kQuad_Verb:
397a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleQuad(ctm, pts);
398bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
399bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kCubic_Verb:
400a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleCubic(ctm, pts);
401bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
402bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kConic_Verb:
403a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleConic(ctm, pts, iter.conicWeight());
404bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
405bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kMove_Verb:
406bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kClose_Verb:
407bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kDone_Verb:
408bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
409bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
410bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
411bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
4120dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    if (!this->indexCount()) {
4130dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        return;
4140dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    }
4150dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
416bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
417da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (compute_normal(fPrevPoint, fFirstPoint, fDirection, &normal)) {
418da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar z = fTransformedHeightFunc(fPrevPoint);
419da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fRadius = this->offset(z);
420da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkVector scaledNormal(normal);
421da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        scaledNormal *= fRadius;
422da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        this->addArc(scaledNormal, true);
423da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
424da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // set up for final edge
425da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        z = fTransformedHeightFunc(fFirstPoint);
426da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        normal *= this->offset(z);
427da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
428da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // make sure we don't end up with a sharp alpha edge along the quad diagonal
429da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (fColors[fPrevUmbraIndex] != fColors[fFirstVertex] &&
430da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            fFirstPoint.distanceToSqd(fPositions[fPrevUmbraIndex]) > kMaxEdgeLenSqr) {
431da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            SkPoint centerPoint = fPositions[fPrevUmbraIndex] + fFirstPoint;
432da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            centerPoint *= 0.5f;
433da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fPositions.push() = centerPoint;
434da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fColors.push() = SkPMLerp(fColors[fFirstVertex], fColors[fPrevUmbraIndex], 128);
435da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            SkVector midNormal = fPrevNormal + normal;
436da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            midNormal *= 0.5f;
437da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fPositions.push() = centerPoint + midNormal;
438da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fColors.push() = fPenumbraColor;
439bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
440da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPrevUmbraIndex;
441da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 3;
442da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 2;
443bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
444da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 3;
445da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
446da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 2;
447da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
448da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            fPrevUmbraIndex = fPositions.count() - 2;
449da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        }
450da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
451da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // final edge
452a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fPositions.push() = fFirstPoint + normal;
453bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fPenumbraColor;
454bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
455da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (fColors[fPrevUmbraIndex] > fColors[fFirstVertex]) {
456da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPrevUmbraIndex;
457da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 2;
458da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fFirstVertex;
459bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
460da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 2;
461da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
462da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fFirstVertex;
463da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        } else {
464da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPrevUmbraIndex;
465da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 2;
466da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
467da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
468da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPrevUmbraIndex;
469da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
470da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fFirstVertex;
471da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        }
472da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fPrevNormal = normal;
473bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
474bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
475bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // finalize centroid
476bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
477bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPositions[0] *= SkScalarFastInvert(fCentroidCount);
478bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
479bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = 0;
48066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
481bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
482bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
483bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
484bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // final fan
485bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fPositions.count() >= 3) {
48666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
487a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fPrevPoint = fFirstPoint;
488da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fRadius = this->offset(fTransformedHeightFunc(fPrevPoint));
489e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth        if (this->addArc(fFirstNormal, false)) {
490e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            *fIndices.push() = fFirstVertex;
491e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
492e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            *fIndices.push() = fFirstVertex + 1;
493e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth        } else {
494e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            // arc is too small, set the first penumbra point to be the same position
495e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            // as the last one
496e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            fPositions[fFirstVertex + 1] = fPositions[fPositions.count() - 1];
497e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth        }
498bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
4990dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    fSucceeded = true;
500bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
501bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
502efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkAmbientShadowTessellator::handleLine(const SkPoint& p)  {
503bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fInitPoints.count() < 2) {
504bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fInitPoints.push() = p;
505bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        return;
506bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
507bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
508bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fInitPoints.count() == 2) {
509bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // determine if cw or ccw
510bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkVector v0 = fInitPoints[1] - fInitPoints[0];
511bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkVector v1 = p - fInitPoints[0];
512bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkScalar perpDot = v0.fX*v1.fY - v0.fY*v1.fX;
513bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        if (SkScalarNearlyZero(perpDot)) {
514bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            // nearly parallel, just treat as straight line and continue
515bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fInitPoints[1] = p;
516bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            return;
517bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
518bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
519bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // if perpDot > 0, winding is ccw
520bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fDirection = (perpDot > 0) ? -1 : 1;
521bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
522bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // add first quad
523da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkVector normal;
524da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (!compute_normal(fInitPoints[0], fInitPoints[1], fDirection, &normal)) {
525bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            // first two points are incident, make the third point the second and continue
526bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fInitPoints[1] = p;
527bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            return;
528bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
529bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
530a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fFirstPoint = fInitPoints[0];
531bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fFirstVertex = fPositions.count();
532da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar z = fTransformedHeightFunc(fFirstPoint);
533da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fFirstNormal = normal;
534da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fFirstNormal *= this->offset(z);
535da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
536bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPrevNormal = fFirstNormal;
537a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fPrevPoint = fFirstPoint;
53866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
539bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
540da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fPositions.push() = fFirstPoint;
541da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fColors.push() = this->umbraColor(z);
542da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fPositions.push() = fFirstPoint + fFirstNormal;
543bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fPenumbraColor;
544bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        if (fTransparent) {
545da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            fPositions[0] += fFirstPoint;
546bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fCentroidCount = 1;
547bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
548da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
549da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // add the first quad
550da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        z = fTransformedHeightFunc(fInitPoints[1]);
551da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fRadius = this->offset(z);
552da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fUmbraColor = this->umbraColor(z);
553da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        normal *= fRadius;
554da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        this->addEdge(fInitPoints[1], normal);
555bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
556bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // to ensure we skip this block next time
557bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fInitPoints.push() = p;
558bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
559bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
560bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
561da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (compute_normal(fPositions[fPrevUmbraIndex], p, fDirection, &normal)) {
562da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkVector scaledNormal = normal;
563da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        scaledNormal *= fRadius;
564da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        this->addArc(scaledNormal, true);
565da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar z = fTransformedHeightFunc(p);
566da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fRadius = this->offset(z);
567da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fUmbraColor = this->umbraColor(z);
568da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        normal *= fRadius;
569da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        this->addEdge(p, normal);
570bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
571bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
572bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
573efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
574da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    // make sure we don't end up with a sharp alpha edge along the quad diagonal
575da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (fColors[fPrevUmbraIndex] != fUmbraColor &&
576da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        nextPoint.distanceToSqd(fPositions[fPrevUmbraIndex]) > kMaxEdgeLenSqr) {
577da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkPoint centerPoint = fPositions[fPrevUmbraIndex] + nextPoint;
578da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        centerPoint *= 0.5f;
579da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fPositions.push() = centerPoint;
580da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fColors.push() = SkPMLerp(fUmbraColor, fColors[fPrevUmbraIndex], 128);
581da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkVector midNormal = fPrevNormal + nextNormal;
582da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        midNormal *= 0.5f;
583da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fPositions.push() = centerPoint + midNormal;
584da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fColors.push() = fPenumbraColor;
585da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
586da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // set triangularization to get best interpolation of color
587da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (fColors[fPrevUmbraIndex] > fColors[fPositions.count() - 2]) {
588da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPrevUmbraIndex;
589da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 3;
590da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 2;
591da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
592da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 3;
593da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
594da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 2;
595da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        } else {
596da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPrevUmbraIndex;
597da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 2;
598da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
599da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
600da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPrevUmbraIndex;
601da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
602da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            *fIndices.push() = fPositions.count() - 3;
603da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        }
604da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
605da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fPrevUmbraIndex = fPositions.count() - 2;
606da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
607da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
608bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // add next quad
609bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fPositions.push() = nextPoint;
610bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fColors.push() = fUmbraColor;
611bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fPositions.push() = nextPoint + nextNormal;
612bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fColors.push() = fPenumbraColor;
613bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
614da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    // set triangularization to get best interpolation of color
615da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (fColors[fPrevUmbraIndex] > fColors[fPositions.count() - 2]) {
616da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPrevUmbraIndex;
617da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 3;
618da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
619bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
620da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 3;
621da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
622da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
623da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    } else {
624da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPrevUmbraIndex;
625da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
626da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
627da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
628da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPrevUmbraIndex;
629da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
630da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        *fIndices.push() = fPositions.count() - 3;
631da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
632bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
633bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // if transparent, add point to first one in array and add to center fan
634bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
635bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPositions[0] += nextPoint;
636bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        ++fCentroidCount;
637bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
638bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = 0;
63966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
640bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
641bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
642bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
64366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPrevUmbraIndex = fPositions.count() - 2;
644bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fPrevNormal = nextNormal;
645a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPrevPoint = nextPoint;
646bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
64791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
64891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth///////////////////////////////////////////////////////////////////////////////////////////////////
64991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
650aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkSpotShadowTessellator : public SkBaseShadowTessellator {
651958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonpublic:
652a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
653060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth                            SkShadowTessellator::HeightFunc heightFunc, const SkPoint3& lightPos,
654060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth                            SkScalar lightRadius, bool transparent);
655958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
656958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonprivate:
657ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    void computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
658da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                                    const SkMatrix& shadowTransform);
659ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    void computeClipVectorsAndTestCentroid();
66066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint);
661ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int getClosestUmbraPoint(const SkPoint& point);
662958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
663a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkPoint& p) override;
664ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    void handlePolyPoint(const SkPoint& p);
665958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
666958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count);
667ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    bool addInnerPoint(const SkPoint& pathPoint);
668da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
669da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
670da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar offset(SkScalar z) {
671da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        float zRatio = SkTPin(z / (fLightZ - z), 0.0f, 0.95f);
672da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        return fLightRadius*zRatio;
673da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
674da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
675da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar            fLightZ;
676da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar            fLightRadius;
677da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar            fOffsetAdjust;
678958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
679958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkPoint>  fClipPolygon;
68066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkTDArray<SkVector> fClipVectors;
681a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fCentroid;
682ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar            fArea;
683a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
684ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkTDArray<SkPoint>  fPathPolygon;
685ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkTDArray<SkPoint>  fUmbraPolygon;
686ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int                 fCurrClipPoint;
687ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int                 fCurrUmbraPoint;
68866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool                fPrevUmbraOutside;
68966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool                fFirstUmbraOutside;
690a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    bool                fValidUmbra;
691958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
692aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    typedef SkBaseShadowTessellator INHERITED;
693958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon};
694958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
695a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van VerthSkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
696b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth                                                 SkShadowTessellator::HeightFunc heightFunc,
697b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth                                                 const SkPoint3& lightPos, SkScalar lightRadius,
698060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth                                                 bool transparent)
699da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    : INHERITED(heightFunc, transparent)
700da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    , fLightZ(lightPos.fZ)
701da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    , fLightRadius(lightRadius)
702da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    , fOffsetAdjust(0)
703da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    , fCurrClipPoint(0)
704da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    , fPrevUmbraOutside(false)
705da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    , fFirstUmbraOutside(false)
706da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    , fValidUmbra(true) {
707da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
708da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    // make sure we're not below the canvas plane
709da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (this->setZOffset(path.getBounds(), ctm.hasPerspective())) {
710da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // Adjust light height and radius
711da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fLightRadius *= (fLightZ + fZOffset) / fLightZ;
712da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fLightZ += fZOffset;
713da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
714b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth
715b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    // Set radius and colors
716b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
717da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkScalar occluderHeight = heightFunc(center.fX, center.fY) + fZOffset;
718da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    float zRatio = SkTPin(occluderHeight / (fLightZ - occluderHeight), 0.0f, 0.95f);
719b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    SkScalar radius = lightRadius * zRatio;
720b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    fRadius = radius;
721060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth    fUmbraColor = SkColorSetARGB(255, 0, 0, 0);
722060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth    fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
723b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth
724b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth    // Compute the scale and translation for the spot shadow.
725da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkMatrix shadowTransform;
726da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (!ctm.hasPerspective()) {
727da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar scale = fLightZ / (fLightZ - occluderHeight);
728da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkVector translate = SkVector::Make(-zRatio * lightPos.fX, -zRatio * lightPos.fY);
729da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        shadowTransform.setScaleTranslate(scale, scale, translate.fX, translate.fY);
730da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    } else {
731da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // For perspective, we have a scale, a z-shear, and another projective divide --
732da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // this varies at each point so we can't use an affine transform.
733da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // We'll just apply this to each generated point in turn.
734da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        shadowTransform.reset();
735da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        // Also can't cull the center (for now).
736da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fTransparent = true;
737da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
738da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkMatrix fullTransform = SkMatrix::Concat(shadowTransform, ctm);
739da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
740da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    // Set up our reverse mapping
741da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    this->setTransformedHeightFunc(fullTransform);
742b436655ad5c40a04b65c1642d0a0e781ce296c96Jim Van Verth
743ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // TODO: calculate these reserves better
74466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Penumbra ring: 3*numPts
74566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Umbra ring: numPts
74691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // Inner ring: numPts
74766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPositions.setReserve(5 * path.countPoints());
74866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fColors.setReserve(5 * path.countPoints());
74966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Penumbra ring: 12*numPts
75066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Umbra ring: 3*numPts
75166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fIndices.setReserve(15 * path.countPoints());
752e7c85c45c4c0a97adc6711bb12ecacc36af4ba11Brian Salomon    fClipPolygon.setReserve(path.countPoints());
753ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
754ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // compute rough clip bounds for umbra, plus offset polygon, plus centroid
755da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    this->computeClipAndPathPolygons(path, ctm, shadowTransform);
756ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fClipPolygon.count() < 3 || fPathPolygon.count() < 3) {
75766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        return;
75866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
75966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
760ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // check to see if umbra collapses
761ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar minDistSq = fCentroid.distanceToLineSegmentBetweenSqd(fPathPolygon[0],
762ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                                   fPathPolygon[1]);
763da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    SkRect bounds;
764da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    bounds.setBounds(&fPathPolygon[0], fPathPolygon.count());
765ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    for (int i = 1; i < fPathPolygon.count(); ++i) {
766ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        int j = i + 1;
767ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        if (i == fPathPolygon.count() - 1) {
768ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            j = 0;
769ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        }
770ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkPoint currPoint = fPathPolygon[i];
771ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkPoint nextPoint = fPathPolygon[j];
772ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar distSq = fCentroid.distanceToLineSegmentBetweenSqd(currPoint, nextPoint);
773ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        if (distSq < minDistSq) {
774ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            minDistSq = distSq;
775ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        }
776ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
777ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr auto kTolerance = 1.0e-2f;
778ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (minDistSq < (radius + kTolerance)*(radius + kTolerance)) {
779ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
780ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar newRadius = SkScalarSqrt(minDistSq) - kTolerance;
781da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fOffsetAdjust = newRadius - radius;
782b6069dfba7b7ab563a3fccb2f38307e47035300cJim Van Verth        SkScalar ratio = 128 * (newRadius + radius) / radius;
783ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // they aren't PMColors, but the interpolation algorithm is the same
784ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fUmbraColor = SkPMLerp(fUmbraColor, fPenumbraColor, (unsigned)ratio);
785ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        radius = newRadius;
786ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
787e5f5bf5175e426ebb6aa234f4387831c898f20adJim Van Verth
788ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // compute vectors for clip tests
789ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    this->computeClipVectorsAndTestCentroid();
790ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
791ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // generate inner ring
792da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), radius,
793da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                              &fUmbraPolygon)) {
794ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // this shouldn't happen, but just in case we'll inset using the centroid
795ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fValidUmbra = false;
796ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
797ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
798ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // walk around the path polygon, generate outer ring and connect to inner ring
79966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (fTransparent) {
80066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fPositions.push() = fCentroid;
80166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fColors.push() = fUmbraColor;
80266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
803ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fCurrUmbraPoint = 0;
804ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    for (int i = 0; i < fPathPolygon.count(); ++i) {
805ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        this->handlePolyPoint(fPathPolygon[i]);
80691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
80791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
8080dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    if (!this->indexCount()) {
8090dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        return;
8100dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    }
8110dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
812ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // finish up the final verts
81391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkVector normal;
814da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (compute_normal(fPrevPoint, fFirstPoint, fDirection, &normal)) {
815da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        normal *= fRadius;
816da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        this->addArc(normal, true);
81791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
81866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // add to center fan
81966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (fTransparent) {
82066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = 0;
82166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fPrevUmbraIndex;
82266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fFirstVertex;
82366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // or to clip ring
82466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else {
82566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (fFirstUmbraOutside) {
82666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
82766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex;
82866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex + 1;
82966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                if (fPrevUmbraOutside) {
83066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    // fill out quad
83166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex;
83266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fFirstVertex + 1;
83366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex + 1;
83466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                }
83566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            } else if (fPrevUmbraOutside) {
83666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // add tri
83766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
83866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex;
83966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex + 1;
84066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
84166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
84266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
84391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // add final edge
84491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fPositions.push() = fFirstPoint + normal;
84591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fColors.push() = fPenumbraColor;
84691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
84766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
84891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
84991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fFirstVertex;
85091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
85191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
85291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
85391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fFirstVertex;
854da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
855da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fPrevNormal = normal;
85691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
85791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
85891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // final fan
85991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fPositions.count() >= 3) {
86066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
86191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevPoint = fFirstPoint;
862e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth        if (this->addArc(fFirstNormal, false)) {
863e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            *fIndices.push() = fFirstVertex;
864e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            *fIndices.push() = fPositions.count() - 1;
865e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            if (fFirstUmbraOutside) {
866e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth                *fIndices.push() = fFirstVertex + 2;
867e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            } else {
868e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth                *fIndices.push() = fFirstVertex + 1;
869e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            }
87066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else {
871e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            // no arc added, fix up by setting first penumbra point position to last one
872e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            if (fFirstUmbraOutside) {
873e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth                fPositions[fFirstVertex + 2] = fPositions[fPositions.count() - 1];
874e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            } else {
875e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth                fPositions[fFirstVertex + 1] = fPositions[fPositions.count() - 1];
876e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth            }
87766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
87891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
879da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
880da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (ctm.hasPerspective()) {
881da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        for (int i = 0; i < fPositions.count(); ++i) {
882da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            SkScalar pathZ = fTransformedHeightFunc(fPositions[i]);
883da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            SkScalar factor = SkScalarInvert(fLightZ - pathZ);
884da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            fPositions[i].fX = (fPositions[i].fX*fLightZ - lightPos.fX*pathZ)*factor;
885da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            fPositions[i].fY = (fPositions[i].fY*fLightZ - lightPos.fY*pathZ)*factor;
886da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        }
887da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth#ifdef DRAW_CENTROID
888da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar pathZ = fTransformedHeightFunc(fCentroid);
889da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        SkScalar factor = SkScalarInvert(fLightZ - pathZ);
890da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fCentroid.fX = (fCentroid.fX*fLightZ - lightPos.fX*pathZ)*factor;
891da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fCentroid.fY = (fCentroid.fY*fLightZ - lightPos.fY*pathZ)*factor;
892da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth#endif
893da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    }
894da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth#ifdef DRAW_CENTROID
895da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fPositions.push() = fCentroid + SkVector::Make(-2, -2);
896da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fColors.push() = SkColorSetARGB(255, 0, 255, 255);
897da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fPositions.push() = fCentroid + SkVector::Make(2, -2);
898da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fColors.push() = SkColorSetARGB(255, 0, 255, 255);
899da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fPositions.push() = fCentroid + SkVector::Make(-2, 2);
900da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fColors.push() = SkColorSetARGB(255, 0, 255, 255);
901da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fPositions.push() = fCentroid + SkVector::Make(2, 2);
902da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fColors.push() = SkColorSetARGB(255, 0, 255, 255);
903da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
904da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fIndices.push() = fPositions.count() - 4;
905da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fIndices.push() = fPositions.count() - 2;
906da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fIndices.push() = fPositions.count() - 1;
907da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
908da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fIndices.push() = fPositions.count() - 4;
909da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fIndices.push() = fPositions.count() - 1;
910da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    *fIndices.push() = fPositions.count() - 3;
911da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth#endif
912da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth
9130dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    fSucceeded = true;
91491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
91591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
916ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
917da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth                                                         const SkMatrix& shadowTransform) {
918ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
919ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fPathPolygon.setReserve(path.countPoints());
920ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
921ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // Walk around the path and compute clip polygon and path polygon.
922ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // Will also accumulate sum of areas for centroid.
923ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // For Bezier curves, we compute additional interior points on curve.
92491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPath::Iter iter(path, true);
92591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPoint pts[4];
92691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPath::Verb verb;
92791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
928e7c85c45c4c0a97adc6711bb12ecacc36af4ba11Brian Salomon    fClipPolygon.reset();
929e5f5bf5175e426ebb6aa234f4387831c898f20adJim Van Verth
930ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // init centroid
931ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fCentroid = SkPoint::Make(0, 0);
932ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fArea = 0;
933ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
93466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // coefficients to compute cubic Bezier at t = 5/16
935ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kA = 0.32495117187f;
936ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kB = 0.44311523437f;
937ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kC = 0.20141601562f;
938ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kD = 0.03051757812f;
93966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
94066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkPoint curvePoint;
94166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar w;
94291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
94391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        switch (verb) {
94491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kLine_Verb:
945a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(&pts[1], 1);
94691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                *fClipPolygon.push() = pts[1];
947ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                this->INHERITED::handleLine(shadowTransform, &pts[1]);
94891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
94991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kQuad_Verb:
950a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 3);
95166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 1/2
95266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = 0.25f*pts[0].fX + 0.5f*pts[1].fX + 0.25f*pts[2].fX;
95366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = 0.25f*pts[0].fY + 0.5f*pts[1].fY + 0.25f*pts[2].fY;
95466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
95566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[2];
956ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                this->handleQuad(shadowTransform, pts);
95791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
95891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kConic_Verb:
959a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 3);
96066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                w = iter.conicWeight();
961a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                // point at t = 1/2
96266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = 0.25f*pts[0].fX + w*0.5f*pts[1].fX + 0.25f*pts[2].fX;
96366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = 0.25f*pts[0].fY + w*0.5f*pts[1].fY + 0.25f*pts[2].fY;
96466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint *= SkScalarInvert(0.5f + 0.5f*w);
96566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
96666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[2];
967ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                this->handleConic(shadowTransform, pts, w);
96891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
96991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kCubic_Verb:
970a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 4);
97166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 5/16
97266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = kA*pts[0].fX + kB*pts[1].fX + kC*pts[2].fX + kD*pts[3].fX;
97366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = kA*pts[0].fY + kB*pts[1].fY + kC*pts[2].fY + kD*pts[3].fY;
97466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
97566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 11/16
97666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = kD*pts[0].fX + kC*pts[1].fX + kB*pts[2].fX + kA*pts[3].fX;
97766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = kD*pts[0].fY + kC*pts[1].fY + kB*pts[2].fY + kA*pts[3].fY;
97866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
97966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[3];
980ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                this->handleCubic(shadowTransform, pts);
98191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
982ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            case SkPath::kMove_Verb:
98391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kClose_Verb:
984ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            case SkPath::kDone_Verb:
98591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
98691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            default:
98791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                SkDEBUGFAIL("unknown verb");
98891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
98991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
99091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
991ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // finish centroid
992ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fPathPolygon.count() > 0) {
993ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkPoint currPoint = fPathPolygon[fPathPolygon.count() - 1];
994ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkPoint nextPoint = fPathPolygon[0];
995ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar quadArea = currPoint.cross(nextPoint);
996ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid.fX += (currPoint.fX + nextPoint.fX) * quadArea;
997ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid.fY += (currPoint.fY + nextPoint.fY) * quadArea;
998ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fArea += quadArea;
999ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid *= SK_Scalar1 / (3 * fArea);
1000ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
1001ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1002ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fCurrClipPoint = fClipPolygon.count() - 1;
100366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon}
100466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
1005ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::computeClipVectorsAndTestCentroid() {
100666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkASSERT(fClipPolygon.count() >= 3);
100766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
1008ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // init clip vectors
100966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkVector v0 = fClipPolygon[1] - fClipPolygon[0];
101066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fClipVectors.push() = v0;
101166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
101266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // init centroid check
101366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool hiddenCentroid = true;
1014ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkVector v1 = fCentroid - fClipPolygon[0];
101566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar initCross = v0.cross(v1);
101666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
101766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    for (int p = 1; p < fClipPolygon.count(); ++p) {
1018ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // add to clip vectors
101966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        v0 = fClipPolygon[(p + 1) % fClipPolygon.count()] - fClipPolygon[p];
102066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fClipVectors.push() = v0;
102166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // Determine if transformed centroid is inside clipPolygon.
1022ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        v1 = fCentroid - fClipPolygon[p];
102366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (initCross*v0.cross(v1) <= 0) {
102466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            hiddenCentroid = false;
102566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
102666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
102766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkASSERT(fClipVectors.count() == fClipPolygon.count());
102866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
1029ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fTransparent = fTransparent || !hiddenCentroid;
103066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon}
103166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
103266085ed41779211f9e7e17aa493d4585d73445feBrian Salomonbool SkSpotShadowTessellator::clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid,
103366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                                             SkPoint* clipPoint) {
103466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkVector segmentVector = centroid - umbraPoint;
103566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
1036ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int startClipPoint = fCurrClipPoint;
103766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    do {
1038ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkVector dp = umbraPoint - fClipPolygon[fCurrClipPoint];
1039ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar denom = fClipVectors[fCurrClipPoint].cross(segmentVector);
104066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkScalar t_num = dp.cross(segmentVector);
104166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // if line segments are nearly parallel
104266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (SkScalarNearlyZero(denom)) {
104366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // and collinear
104466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (SkScalarNearlyZero(t_num)) {
104566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                return false;
104666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
104766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // otherwise are separate, will try the next poly segment
104866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // else if crossing lies within poly segment
104966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else if (t_num >= 0 && t_num <= denom) {
1050ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            SkScalar s_num = dp.cross(fClipVectors[fCurrClipPoint]);
105166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // if umbra point is inside the clip polygon
1052da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth            if (s_num >= 0 && s_num <= denom) {
105366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                segmentVector *= s_num/denom;
105466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *clipPoint = umbraPoint + segmentVector;
105566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                return true;
105666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
105766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
1058ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCurrClipPoint = (fCurrClipPoint + 1) % fClipPolygon.count();
1059ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    } while (fCurrClipPoint != startClipPoint);
106066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
106166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    return false;
106291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
106391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
1064ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonint SkSpotShadowTessellator::getClosestUmbraPoint(const SkPoint& p) {
1065ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar minDistance = p.distanceToSqd(fUmbraPolygon[fCurrUmbraPoint]);
1066ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int index = fCurrUmbraPoint;
1067ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int dir = 1;
1068ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int next = (index + dir) % fUmbraPolygon.count();
1069ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1070ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // init travel direction
1071ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar distance = p.distanceToSqd(fUmbraPolygon[next]);
1072ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (distance < minDistance) {
1073ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        index = next;
1074ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        minDistance = distance;
1075ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    } else {
1076ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        dir = fUmbraPolygon.count()-1;
1077ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
1078ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1079ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // iterate until we find a point that increases the distance
1080ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    next = (index + dir) % fUmbraPolygon.count();
1081ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    distance = p.distanceToSqd(fUmbraPolygon[next]);
1082ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    while (distance < minDistance) {
1083ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        index = next;
1084ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        minDistance = distance;
1085ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        next = (index + dir) % fUmbraPolygon.count();
1086ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        distance = p.distanceToSqd(fUmbraPolygon[next]);
1087ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
1088ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1089ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    fCurrUmbraPoint = index;
1090ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    return index;
1091ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon}
1092ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1093efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate,
109491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                                        SkPoint* pts, int count) {
109591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // TODO: vectorize
109691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    for (int i = 0; i < count; ++i) {
109791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        pts[i] *= scale;
109891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        pts[i] += xlate;
109991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
110091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
110191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
1102ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonstatic bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) {
1103ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kClose = (SK_Scalar1 / 16);
1104ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    static constexpr SkScalar kCloseSqd = kClose*kClose;
1105ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1106ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkScalar distSq = p0.distanceToSqd(p1);
1107ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    return distSq < kCloseSqd;
1108ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon}
1109ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1110ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonstatic bool is_collinear(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
1111ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkVector v0 = p1 - p0;
1112ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkVector v1 = p2 - p0;
1113ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    return (SkScalarNearlyZero(v0.cross(v1)));
1114ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon}
1115ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1116efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::handleLine(const SkPoint& p) {
1117ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // remove coincident points and add to centroid
1118ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fPathPolygon.count() > 0) {
1119ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        const SkPoint& lastPoint = fPathPolygon[fPathPolygon.count() - 1];
1120ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        if (duplicate_pt(p, lastPoint)) {
1121ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            return;
1122ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        }
1123ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar quadArea = lastPoint.cross(p);
1124ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid.fX += (p.fX + lastPoint.fX) * quadArea;
1125ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fCentroid.fY += (p.fY + lastPoint.fY) * quadArea;
1126ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fArea += quadArea;
1127ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
1128ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1129ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // try to remove collinear points
1130ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (fPathPolygon.count() > 1 && is_collinear(fPathPolygon[fPathPolygon.count()-2],
1131ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                 fPathPolygon[fPathPolygon.count()-1],
1132ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                 p)) {
1133ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        fPathPolygon[fPathPolygon.count() - 1] = p;
1134ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    } else {
1135ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fPathPolygon.push() = p;
1136ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
1137ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon}
1138ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1139ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::handlePolyPoint(const SkPoint& p) {
114091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fInitPoints.count() < 2) {
114191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fInitPoints.push() = p;
114291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        return;
114391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
114491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
114591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fInitPoints.count() == 2) {
114691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // determine if cw or ccw
114791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkVector v0 = fInitPoints[1] - fInitPoints[0];
114891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkVector v1 = p - fInitPoints[0];
1149ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkScalar perpDot = v0.cross(v1);
115091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        if (SkScalarNearlyZero(perpDot)) {
115191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            // nearly parallel, just treat as straight line and continue
115291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            fInitPoints[1] = p;
115391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            return;
115491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
115591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
115691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // if perpDot > 0, winding is ccw
115791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fDirection = (perpDot > 0) ? -1 : 1;
115891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
115991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // add first quad
1160da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        if (!compute_normal(fInitPoints[0], fInitPoints[1], fDirection, &fFirstNormal)) {
116191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            // first two points are incident, make the third point the second and continue
116291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            fInitPoints[1] = p;
116391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            return;
116491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
116591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
1166da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        fFirstNormal *= fRadius;
116791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fFirstPoint = fInitPoints[0];
116891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fFirstVertex = fPositions.count();
116991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevNormal = fFirstNormal;
117091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevPoint = fFirstPoint;
1171e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth        fPrevUmbraIndex = -1;
117266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
117366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        this->addInnerPoint(fFirstPoint);
1174e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth        fPrevUmbraIndex = fFirstVertex;
117566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
117666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (!fTransparent) {
117766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkPoint clipPoint;
117866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            bool isOutside = this->clipUmbraPoint(fPositions[fFirstVertex], fCentroid, &clipPoint);
117966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (isOutside) {
118066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fPositions.push() = clipPoint;
118166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fColors.push() = fUmbraColor;
118266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
118366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fPrevUmbraOutside = isOutside;
118466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fFirstUmbraOutside = isOutside;
118566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
118691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
118791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkPoint newPoint = fFirstPoint + fFirstNormal;
118891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fPositions.push() = newPoint;
118991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fColors.push() = fPenumbraColor;
119091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addEdge(fInitPoints[1], fFirstNormal);
119191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
119291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // to ensure we skip this block next time
119391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fInitPoints.push() = p;
119491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
119591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
119691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkVector normal;
1197da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth    if (compute_normal(fPrevPoint, p, fDirection, &normal)) {
1198da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        normal *= fRadius;
1199da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        this->addArc(normal, true);
1200da96550d3941cb794a799c73506a1c5b695c70a1Jim Van Verth        this->addEdge(p, normal);
120191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
120291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
120391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
1204ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonbool SkSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint) {
1205ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    SkPoint umbraPoint;
1206ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (!fValidUmbra) {
1207ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        SkVector v = fCentroid - pathPoint;
1208ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        v *= 0.95f;
1209ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        umbraPoint = pathPoint + v;
121091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    } else {
1211ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        umbraPoint = fUmbraPolygon[this->getClosestUmbraPoint(pathPoint)];
121291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
121366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
121491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fPrevPoint = pathPoint;
1215ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1216ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    // merge "close" points
1217e7e1d9d039b12a86b9a595871a2bd13fe1c28f72Jim Van Verth    if (fPrevUmbraIndex == -1 ||
1218ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        !duplicate_pt(umbraPoint, fPositions[fPrevUmbraIndex])) {
1219ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fPositions.push() = umbraPoint;
1220ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fColors.push() = fUmbraColor;
1221ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon
1222ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        return false;
1223ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    } else {
1224ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        return true;
1225ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
122691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
122791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
1228efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
122966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // add next umbra point
1230ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    bool duplicate = this->addInnerPoint(nextPoint);
1231ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int prevPenumbraIndex = duplicate ? fPositions.count()-1 : fPositions.count()-2;
1232ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    int currUmbraIndex = duplicate ? fPrevUmbraIndex : fPositions.count()-1;
123366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
1234ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (!duplicate) {
1235ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // add to center fan if transparent or centroid showing
1236ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        if (fTransparent) {
1237ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            *fIndices.push() = 0;
1238ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            *fIndices.push() = fPrevUmbraIndex;
1239ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            *fIndices.push() = currUmbraIndex;
1240ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        // otherwise add to clip ring
1241ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        } else {
124266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkPoint clipPoint;
1243ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon            bool isOutside = this->clipUmbraPoint(fPositions[currUmbraIndex], fCentroid,
1244ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon                                                  &clipPoint);
124566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (isOutside) {
124666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fPositions.push() = clipPoint;
124766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fColors.push() = fUmbraColor;
124866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
124966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
125066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex;
125166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex + 1;
125266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                if (fPrevUmbraOutside) {
125366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    // fill out quad
125466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex;
125566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = currUmbraIndex + 1;
125666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex + 1;
125766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                }
125866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            } else if (fPrevUmbraOutside) {
125966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // add tri
126066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
126166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex;
126266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex + 1;
126366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
126466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fPrevUmbraOutside = isOutside;
126566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
126666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
126766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
126866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // add next penumbra point and quad
126991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPoint newPoint = nextPoint + nextNormal;
127091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fPositions.push() = newPoint;
127191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fColors.push() = fPenumbraColor;
127291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
1273ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    if (!duplicate) {
1274ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
1275ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fIndices.push() = prevPenumbraIndex;
1276ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon        *fIndices.push() = currUmbraIndex;
1277ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon    }
127891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
127966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = prevPenumbraIndex;
128091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fIndices.push() = fPositions.count() - 1;
128166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = currUmbraIndex;
128291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
128366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPrevUmbraIndex = currUmbraIndex;
128491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fPrevNormal = nextNormal;
128591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
1286958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
1287958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon///////////////////////////////////////////////////////////////////////////////////////////////////
1288958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
1289aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonsk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
1290060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth                                                   HeightFunc heightFunc, bool transparent) {
1291060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth    SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, transparent);
1292aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    return ambientTess.releaseVertices();
1293958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon}
1294958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
1295aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonsk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
1296060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth                                                HeightFunc heightFunc, const SkPoint3& lightPos,
1297060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth                                                SkScalar lightRadius,  bool transparent) {
1298060d9820364b0cf09c7eb3bda449f24c3dcba2e2Jim Van Verth    SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius, transparent);
1299aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    return spotTess.releaseVertices();
1300958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon}
1301