SkShadowTessellator.cpp revision aff27a23ad4b38851429066dbfb43cfa7199e37c
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"
1185dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#include "SkPath.h"
12aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon#include "SkVertices.h"
1385dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth
1485dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#if SK_SUPPORT_GPU
1585dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#include "GrPathUtils.h"
1685dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#endif
1758abc9e2c56464336472493745e91133819deb96Jim Van Verth
18958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
19a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth/**
20a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth * Base class
21a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth */
22aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkBaseShadowTessellator {
23958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonpublic:
24aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor, SkColor penumbraColor,
25aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                            bool transparent);
26aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    virtual ~SkBaseShadowTessellator() {}
270dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
28aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    sk_sp<SkVertices> releaseVertices() {
29aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        if (!fSucceeded) {
30aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon            return nullptr;
31aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        }
32aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        int vCount = this->vertexCount();
33aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        int iCount = this->indexCount();
34aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        // We copy here for two reasons: 1) To tighten up our arrays and 2) to get into memory
35aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        // allocated by new[] rather than malloc.
36aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        // TODO: If we know we're not caching then we should avoid this.
37aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        SkPoint* positions = new SkPoint[vCount];
38aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        SkColor* colors = new SkColor[vCount];
39aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        uint16_t* indices = new uint16_t[iCount];
40aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        memcpy(positions, fPositions.begin(), sizeof(SkPoint) * vCount);
41aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        memcpy(colors, fColors.begin(), sizeof(SkColor) * vCount);
42aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        memcpy(indices, fIndices.begin(), sizeof(uint16_t) * iCount);
43aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        return SkVertices::MakeIndexed(SkCanvas::kTriangles_VertexMode,
44aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                       std::unique_ptr<const SkPoint[]>(positions),
45aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                       std::unique_ptr<const SkColor[]>(colors),
46aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                       nullptr,
47aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                       vCount,
48aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                       std::unique_ptr<const uint16_t[]>(indices),
49aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                       iCount);
501a8b79a79e8aa6d4723588fd1125cb3b08886af8Brian Salomon    }
51958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
52a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthprotected:
53aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    int vertexCount() const { return fPositions.count(); }
54aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    int indexCount() const { return fIndices.count(); }
55aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon
56a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    virtual void handleLine(const SkPoint& p) = 0;
57a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkMatrix& m, SkPoint* p);
58958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
59958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void handleQuad(const SkPoint pts[3]);
60a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleQuad(const SkMatrix& m, SkPoint pts[3]);
61958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
62a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleCubic(const SkMatrix& m, SkPoint pts[4]);
63958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
64a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w);
65958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
66958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void addArc(const SkVector& nextNormal);
67958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
68a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    virtual void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) = 0;
69958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
70a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // first three points
71a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkTDArray<SkPoint>  fInitPoints;
72a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // temporary buffer
73a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkTDArray<SkPoint>  fPointBuffer;
74958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
75958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkPoint>  fPositions;
76958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkColor>  fColors;
77958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<uint16_t> fIndices;
78958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
79958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    int                 fFirstVertex;
80958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkVector            fFirstNormal;
81a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fFirstPoint;
820dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
830dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    bool                fSucceeded;
84a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    bool                fTransparent;
85a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
86a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkColor             fUmbraColor;
87a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkColor             fPenumbraColor;
88a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
89a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar            fRadius;
90a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar            fDirection;
91a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int                 fPrevUmbraIndex;
92a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkVector            fPrevNormal;
93a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fPrevPoint;
94958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon};
95958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
96bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verthstatic bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar radius, SkScalar dir,
97bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                           SkVector* newNormal) {
98bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
99bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // compute perpendicular
100bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    normal.fX = p0.fY - p1.fY;
101bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    normal.fY = p1.fX - p0.fX;
102bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (!normal.normalize()) {
103bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        return false;
104bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
105bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    normal *= radius*dir;
106bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *newNormal = normal;
107bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    return true;
108bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
109bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
110bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verthstatic void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScalar r,
111bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                                 SkScalar* rotSin, SkScalar* rotCos, int* n) {
112bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    const SkScalar kRecipPixelsPerArcSegment = 0.25f;
113bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
114bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar rCos = v1.dot(v2);
115bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar rSin = v1.cross(v2);
116bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar theta = SkScalarATan2(rSin, rCos);
117bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
118bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar steps = r*theta*kRecipPixelsPerArcSegment;
119bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
120bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkScalar dTheta = theta / steps;
121bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *rotSin = SkScalarSinCos(dTheta, rotCos);
122bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *n = SkScalarFloorToInt(steps);
123bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
124bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
125aff27a23ad4b38851429066dbfb43cfa7199e37cBrian SalomonSkBaseShadowTessellator::SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor,
126aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                 SkColor penumbraColor, bool transparent)
127aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        : fFirstVertex(-1)
128aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fSucceeded(false)
129aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fTransparent(transparent)
130aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fUmbraColor(umbraColor)
131aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fPenumbraColor(penumbraColor)
132aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fRadius(radius)
133aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fDirection(1)
134aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon        , fPrevUmbraIndex(-1) {
135a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fInitPoints.setReserve(3);
136a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
137a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // child classes will set reserve for positions, colors and indices
138a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
139a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
140a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth// tesselation tolerance values, in device space pixels
141a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kQuadTolerance = 0.2f;
142a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kCubicTolerance = 0.2f;
143a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kConicTolerance = 0.5f;
144a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
145aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
146a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(p, 1);
147a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(*p);
148a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
149a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
150aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) {
151a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#if SK_SUPPORT_GPU
152a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // TODO: Pull PathUtils out of Ganesh?
153a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
154a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setReserve(maxCount);
155a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint* target = fPointBuffer.begin();
156a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
157a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                     kQuadTolerance, &target, maxCount);
158a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setCount(count);
159a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; i++) {
160a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleLine(fPointBuffer[i]);
161a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
162a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#else
163a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // for now, just to draw something
164a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[1]);
165a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[2]);
166a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#endif
167a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
168a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
169aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
170a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 3);
171a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleQuad(pts);
172a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
173a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
174aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
175a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 4);
176a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#if SK_SUPPORT_GPU
177a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // TODO: Pull PathUtils out of Ganesh?
178a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
179a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setReserve(maxCount);
180a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint* target = fPointBuffer.begin();
181a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
182a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                 kCubicTolerance, &target, maxCount);
183a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPointBuffer.setCount(count);
184a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; i++) {
185a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleLine(fPointBuffer[i]);
186a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
187a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#else
188a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // for now, just to draw something
189a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[1]);
190a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[2]);
191a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->handleLine(pts[3]);
192a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#endif
193a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
194a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
195aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
196a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    m.mapPoints(pts, 3);
197a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkAutoConicToQuads quadder;
198a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
199a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint lastPoint = *(quads++);
200a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int count = quadder.countQuads();
201a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < count; ++i) {
202a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        SkPoint quadPts[3];
203a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[0] = lastPoint;
204a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[1] = quads[0];
205a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quadPts[2] = i == count - 1 ? pts[2] : quads[1];
206a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        this->handleQuad(quadPts);
207a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        lastPoint = quadPts[2];
208a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        quads += 2;
209a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
210a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
211a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
212aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::addArc(const SkVector& nextNormal) {
213a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // fill in fan from previous quad
214a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkScalar rotSin, rotCos;
215a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int numSteps;
216a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    compute_radial_steps(fPrevNormal, nextNormal, fRadius, &rotSin, &rotCos, &numSteps);
217a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkVector prevNormal = fPrevNormal;
218a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    for (int i = 0; i < numSteps; ++i) {
219a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        SkVector nextNormal;
220a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        nextNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
221a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        nextNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
222a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fPositions.push() = fPrevPoint + nextNormal;
223a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fColors.push() = fPenumbraColor;
224a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fIndices.push() = fPrevUmbraIndex;
225a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fIndices.push() = fPositions.count() - 2;
226a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fIndices.push() = fPositions.count() - 1;
227a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
228a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        prevNormal = nextNormal;
229a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    }
230a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
231a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
232aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
233aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                  const SkVector& nextNormal) {
234a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    // close out previous arc
235a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fPositions.push() = fPrevPoint + nextNormal;
236a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fColors.push() = fPenumbraColor;
237a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fIndices.push() = fPrevUmbraIndex;
238a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fIndices.push() = fPositions.count() - 2;
239a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    *fIndices.push() = fPositions.count() - 1;
240a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
241a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->addEdge(nextPoint, nextNormal);
242a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}
243a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
244a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
245a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth//////////////////////////////////////////////////////////////////////////////////////////////////
246a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
247aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkAmbientShadowTessellator : public SkBaseShadowTessellator {
248a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthpublic:
249a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
250a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                               SkScalar radius, SkColor umbraColor,
251a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                               SkColor penumbraColor, bool transparent);
252a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
253a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthprivate:
254a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkPoint& p) override;
255a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) override;
256a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
257a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    int                 fCentroidCount;
258a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
259aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    typedef SkBaseShadowTessellator INHERITED;
260a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth};
261a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
262efe3dedbb3493b738abdb56041b093245e4e8711Jim Van VerthSkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
263a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                       const SkMatrix& ctm,
264bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                                                       SkScalar radius,
265efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth                                                       SkColor umbraColor,
266efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth                                                       SkColor penumbraColor,
267bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                                                       bool transparent)
268a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        : INHERITED(radius, umbraColor, penumbraColor, transparent) {
269bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Outer ring: 3*numPts
270bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Middle ring: numPts
271bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fPositions.setReserve(4 * path.countPoints());
272bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fColors.setReserve(4 * path.countPoints());
273bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Outer ring: 12*numPts
274bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // Middle ring: 0
275bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fIndices.setReserve(12 * path.countPoints());
276bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
277bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // walk around the path, tessellate and generate outer ring
278bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // if original path is transparent, will accumulate sum of points for centroid
279bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPath::Iter iter(path, true);
280bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPoint pts[4];
281bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkPath::Verb verb;
282bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
283bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fPositions.push() = SkPoint::Make(0, 0);
284bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = umbraColor;
285bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fCentroidCount = 0;
286bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
287bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
288bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        switch (verb) {
289bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kLine_Verb:
290a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->INHERITED::handleLine(ctm, &pts[1]);
291bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
292bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kQuad_Verb:
293a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleQuad(ctm, pts);
294bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
295bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kCubic_Verb:
296a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleCubic(ctm, pts);
297bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
298bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kConic_Verb:
299a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleConic(ctm, pts, iter.conicWeight());
300bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
301bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kMove_Verb:
302bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kClose_Verb:
303bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            case SkPath::kDone_Verb:
304bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                break;
305bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
306bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
307bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
3080dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    if (!this->indexCount()) {
3090dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        return;
3100dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    }
3110dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
312bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
313a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection,
314bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                       &normal)) {
315bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        this->addArc(normal);
316bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
317bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // close out previous arc
318a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fPositions.push() = fPrevPoint + normal;
319bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fPenumbraColor;
32066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
321bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
322bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 1;
323bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
324bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // add final edge
325a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        *fPositions.push() = fFirstPoint + normal;
326bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fPenumbraColor;
327bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
32866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
329bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
330bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
331bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
332bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
333bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 1;
334bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
335bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
336bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
337bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // finalize centroid
338bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
339bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPositions[0] *= SkScalarFastInvert(fCentroidCount);
340bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
341bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = 0;
34266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
343bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
344bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
345bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
346bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // final fan
347bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fPositions.count() >= 3) {
34866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
349bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPrevNormal = normal;
350a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fPrevPoint = fFirstPoint;
351bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        this->addArc(fFirstNormal);
352bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
353bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex;
354bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 1;
355bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fFirstVertex + 1;
356bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
3570dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    fSucceeded = true;
358bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
359bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
360efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkAmbientShadowTessellator::handleLine(const SkPoint& p)  {
361bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fInitPoints.count() < 2) {
362bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fInitPoints.push() = p;
363bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        return;
364bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
365bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
366bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fInitPoints.count() == 2) {
367bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // determine if cw or ccw
368bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkVector v0 = fInitPoints[1] - fInitPoints[0];
369bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkVector v1 = p - fInitPoints[0];
370bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        SkScalar perpDot = v0.fX*v1.fY - v0.fY*v1.fX;
371bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        if (SkScalarNearlyZero(perpDot)) {
372bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            // nearly parallel, just treat as straight line and continue
373bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fInitPoints[1] = p;
374bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            return;
375bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
376bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
377bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // if perpDot > 0, winding is ccw
378bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fDirection = (perpDot > 0) ? -1 : 1;
379bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
380bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // add first quad
381bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        if (!compute_normal(fInitPoints[0], fInitPoints[1], fRadius, fDirection,
382bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth                            &fFirstNormal)) {
383bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            // first two points are incident, make the third point the second and continue
384bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fInitPoints[1] = p;
385bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            return;
386bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
387bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
388a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fFirstPoint = fInitPoints[0];
389bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fFirstVertex = fPositions.count();
390bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPrevNormal = fFirstNormal;
391a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        fPrevPoint = fFirstPoint;
39266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
393bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
394bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fPositions.push() = fInitPoints[0];
395bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fUmbraColor;
396bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fPositions.push() = fInitPoints[0] + fFirstNormal;
397bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fColors.push() = fPenumbraColor;
398bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        if (fTransparent) {
399bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fPositions[0] += fInitPoints[0];
400bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth            fCentroidCount = 1;
401bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        }
402bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        this->addEdge(fInitPoints[1], fFirstNormal);
403bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
404bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        // to ensure we skip this block next time
405bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fInitPoints.push() = p;
406bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
407bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
408bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    SkVector normal;
40966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (compute_normal(fPositions[fPrevUmbraIndex], p, fRadius, fDirection, &normal)) {
410bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        this->addArc(normal);
41191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->finishArcAndAddEdge(p, normal);
412bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
413bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
414bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
415efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
416bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // add next quad
417bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fPositions.push() = nextPoint;
418bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fColors.push() = fUmbraColor;
419bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fPositions.push() = nextPoint + nextNormal;
420bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fColors.push() = fPenumbraColor;
421bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
42266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = fPrevUmbraIndex;
423bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 3;
424bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 2;
425bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
426bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 3;
427bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 1;
428bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    *fIndices.push() = fPositions.count() - 2;
429bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
430bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    // if transparent, add point to first one in array and add to center fan
431bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    if (fTransparent) {
432bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        fPositions[0] += nextPoint;
433bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        ++fCentroidCount;
434bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
435bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = 0;
43666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
437bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth        *fIndices.push() = fPositions.count() - 2;
438bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    }
439bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth
44066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPrevUmbraIndex = fPositions.count() - 2;
441bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth    fPrevNormal = nextNormal;
442a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    fPrevPoint = nextPoint;
443bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth}
44491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
44591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth///////////////////////////////////////////////////////////////////////////////////////////////////
44691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
447aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkSpotShadowTessellator : public SkBaseShadowTessellator {
448958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonpublic:
449a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
450a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                            SkScalar scale, const SkVector& translate,
451958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon                            SkScalar radius, SkColor umbraColor, SkColor penumbraColor,
452958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon                            bool transparent);
453958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
454958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonprivate:
455a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void computeClipBounds(const SkPath& path, const SkMatrix& ctm, SkPath* devPath);
45666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    void checkUmbraAndTransformCentroid(SkScalar scale, const SkVector& xlate,
45766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                                        bool useDistanceToPoint);
45866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint);
459958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
460a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void handleLine(const SkPoint& p) override;
461958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
462958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count);
46366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    void addInnerPoint(const SkPoint& pathPoint);
464a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) override;
465958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
466958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon    SkTDArray<SkPoint>  fClipPolygon;
46766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkTDArray<SkVector> fClipVectors;
468a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPoint             fCentroid;
469a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth
47066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    int                 fCurrPolyPoint;
47166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool                fPrevUmbraOutside;
47266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool                fFirstUmbraOutside;
473a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    bool                fValidUmbra;
474958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
475aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    typedef SkBaseShadowTessellator INHERITED;
476958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon};
477958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
478a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van VerthSkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
47991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                                                 SkScalar scale, const SkVector& translate,
480a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                 SkScalar radius, SkColor umbraColor,
481a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                 SkColor penumbraColor, bool transparent)
482a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        : INHERITED(radius, umbraColor, penumbraColor, transparent)
4830dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        , fCurrPolyPoint(0)
4840dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        , fPrevUmbraOutside(false)
4850dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        , fFirstUmbraOutside(false)
486a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth        , fValidUmbra(true) {
48791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // TODO: calculate these better
48866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Penumbra ring: 3*numPts
48966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Umbra ring: numPts
49091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // Inner ring: numPts
49166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPositions.setReserve(5 * path.countPoints());
49266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fColors.setReserve(5 * path.countPoints());
49366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Penumbra ring: 12*numPts
49466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // Umbra ring: 3*numPts
49566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fIndices.setReserve(15 * path.countPoints());
49691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
49791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fClipPolygon.setReserve(path.countPoints());
49866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // compute rough clip bounds for umbra, plus centroid
499a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPath devPath;
500a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    this->computeClipBounds(path, ctm, &devPath);
50166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (fClipPolygon.count() < 3) {
50266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        return;
50366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
5040bd699e497819344083df4715928a54a597cd630Brian Salomon    // We are going to apply 'scale' and 'xlate' (in that order) to each computed path point. We
5050bd699e497819344083df4715928a54a597cd630Brian Salomon    // want the effect to be to scale the points relative to the path centroid and then translate
5060bd699e497819344083df4715928a54a597cd630Brian Salomon    // them by the 'translate' param we were passed.
5070bd699e497819344083df4715928a54a597cd630Brian Salomon    SkVector xlate = fCentroid * (1.f - scale) + translate;
50866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
50966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // check to see if we have a valid umbra at all
51066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool usePointCheck = path.isRRect(nullptr) || path.isRect(nullptr) || path.isOval(nullptr);
51166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    this->checkUmbraAndTransformCentroid(scale, translate, usePointCheck);
51291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
51391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // walk around the path, tessellate and generate inner and outer rings
514a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkPath::Iter iter(devPath, true);
51591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPoint pts[4];
51691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPath::Verb verb;
51766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (fTransparent) {
51866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fPositions.push() = fCentroid;
51966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fColors.push() = fUmbraColor;
52066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
521a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkMatrix shadowTransform;
522a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    shadowTransform.setScaleTranslate(scale, scale, xlate.fX, xlate.fY);
52391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
52491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        switch (verb) {
52591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kLine_Verb:
526a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->INHERITED::handleLine(shadowTransform, &pts[1]);
52791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
52891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kQuad_Verb:
529a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleQuad(shadowTransform, pts);
53091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
53191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kCubic_Verb:
532a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleCubic(shadowTransform, pts);
53391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
53491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kConic_Verb:
535a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                this->handleConic(shadowTransform, pts, iter.conicWeight());
53691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
53791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kMove_Verb:
53891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kClose_Verb:
53991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kDone_Verb:
54091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
54191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
54291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
54391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
5440dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    if (!this->indexCount()) {
5450dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon        return;
5460dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    }
5470dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon
54891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkVector normal;
54991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection,
55091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                        &normal)) {
55191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addArc(normal);
55291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
55391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // close out previous arc
55491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fPositions.push() = fPrevPoint + normal;
55591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fColors.push() = fPenumbraColor;
55666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
55791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
55891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
55991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
56066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // add to center fan
56166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (fTransparent) {
56266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = 0;
56366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fPrevUmbraIndex;
56466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fFirstVertex;
56566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // or to clip ring
56666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else {
56766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (fFirstUmbraOutside) {
56866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
56966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex;
57066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex + 1;
57166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                if (fPrevUmbraOutside) {
57266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    // fill out quad
57366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex;
57466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fFirstVertex + 1;
57566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex + 1;
57666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                }
57766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            } else if (fPrevUmbraOutside) {
57866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // add tri
57966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
58066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fFirstVertex;
58166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex + 1;
58266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
58366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
58466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
58591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // add final edge
58691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fPositions.push() = fFirstPoint + normal;
58791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fColors.push() = fPenumbraColor;
58891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
58966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
59091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
59191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fFirstVertex;
59291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
59391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 2;
59491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
59591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fFirstVertex;
59691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
59791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
59891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // final fan
59991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fPositions.count() >= 3) {
60066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
60191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevPoint = fFirstPoint;
60291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevNormal = normal;
60391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addArc(fFirstNormal);
60491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
60591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fFirstVertex;
60691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fIndices.push() = fPositions.count() - 1;
60766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (fFirstUmbraOutside) {
60866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fFirstVertex + 2;
60966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else {
61066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            *fIndices.push() = fFirstVertex + 1;
61166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
61291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
6130dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon    fSucceeded = true;
61491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
61591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
616a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthvoid SkSpotShadowTessellator::computeClipBounds(const SkPath& path, const SkMatrix& ctm,
617a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                                SkPath* devPath) {
61891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // walk around the path and compute clip polygon
61991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // if original path is transparent, will accumulate sum of points for centroid
62066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // for Bezier curves, we compute additional interior points on curve
62191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPath::Iter iter(path, true);
62291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPoint pts[4];
62391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPath::Verb verb;
62491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
62591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fCentroid = SkPoint::Make(0, 0);
62691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    int centroidCount = 0;
62791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fClipPolygon.reset();
62891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
62966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // coefficients to compute cubic Bezier at t = 5/16
63066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    const SkScalar kA = 0.32495117187f;
63166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    const SkScalar kB = 0.44311523437f;
63266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    const SkScalar kC = 0.20141601562f;
63366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    const SkScalar kD = 0.03051757812f;
63466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
63566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkPoint curvePoint;
63666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar w;
63791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
63891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        switch (verb) {
63991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kMove_Verb:
640a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(&pts[0], 1);
641a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                devPath->moveTo(pts[0]);
64291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
64391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kLine_Verb:
644a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(&pts[1], 1);
645a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                devPath->lineTo(pts[1]);
64691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                fCentroid += pts[1];
64791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                centroidCount++;
64891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                *fClipPolygon.push() = pts[1];
64991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
65091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kQuad_Verb:
651a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 3);
652a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                devPath->quadTo(pts[1], pts[2]);
65366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 1/2
65466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = 0.25f*pts[0].fX + 0.5f*pts[1].fX + 0.25f*pts[2].fX;
65566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = 0.25f*pts[0].fY + 0.5f*pts[1].fY + 0.25f*pts[2].fY;
65666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
65766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                fCentroid += curvePoint;
65866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[2];
65991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                fCentroid += pts[2];
66091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                centroidCount += 2;
66191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
66291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kConic_Verb:
663a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 3);
66466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                w = iter.conicWeight();
665a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                devPath->conicTo(pts[1], pts[2], w);
666a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                // point at t = 1/2
66766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = 0.25f*pts[0].fX + w*0.5f*pts[1].fX + 0.25f*pts[2].fX;
66866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = 0.25f*pts[0].fY + w*0.5f*pts[1].fY + 0.25f*pts[2].fY;
66966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint *= SkScalarInvert(0.5f + 0.5f*w);
67066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
67166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                fCentroid += curvePoint;
67266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[2];
67391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                fCentroid += pts[2];
67491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                centroidCount += 2;
67591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
67691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kCubic_Verb:
677a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                ctm.mapPoints(pts, 4);
678a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                devPath->cubicTo(pts[1], pts[2], pts[3]);
67966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 5/16
68066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = kA*pts[0].fX + kB*pts[1].fX + kC*pts[2].fX + kD*pts[3].fX;
68166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = kA*pts[0].fY + kB*pts[1].fY + kC*pts[2].fY + kD*pts[3].fY;
68266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
68366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                fCentroid += curvePoint;
68466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // point at t = 11/16
68566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fX = kD*pts[0].fX + kC*pts[1].fX + kB*pts[2].fX + kA*pts[3].fX;
68666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                curvePoint.fY = kD*pts[0].fY + kC*pts[1].fY + kB*pts[2].fY + kA*pts[3].fY;
68766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = curvePoint;
68866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                fCentroid += curvePoint;
68966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fClipPolygon.push() = pts[3];
69091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                fCentroid += pts[3];
69191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                centroidCount += 3;
69291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
69391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            case SkPath::kClose_Verb:
694a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                devPath->close();
69591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                break;
69691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            default:
69791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                SkDEBUGFAIL("unknown verb");
69891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
69991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
70091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
70191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fCentroid *= SkScalarInvert(centroidCount);
70266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fCurrPolyPoint = fClipPolygon.count() - 1;
70366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon}
70466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
70566085ed41779211f9e7e17aa493d4585d73445feBrian Salomonvoid SkSpotShadowTessellator::checkUmbraAndTransformCentroid(SkScalar scale,
70666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                                                             const SkVector& xlate,
70766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                                                             bool useDistanceToPoint) {
70866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkASSERT(fClipPolygon.count() >= 3);
70966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkPoint transformedCentroid = fCentroid;
71066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    transformedCentroid += xlate;
71166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
71266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar localRadius = fRadius / scale;
71366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    localRadius *= localRadius;
71466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
71566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // init umbra check
71666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkVector w = fCentroid - fClipPolygon[0];
71766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkVector v0 = fClipPolygon[1] - fClipPolygon[0];
71866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fClipVectors.push() = v0;
71966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool validUmbra;
72066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar minDistance;
72166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // check distance against line segment
72266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (useDistanceToPoint) {
72366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        minDistance = w.lengthSqd();
72466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    } else {
72566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkScalar vSq = v0.dot(v0);
72666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkScalar wDotV = w.dot(v0);
72766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        minDistance = w.dot(w) - wDotV*wDotV/vSq;
72866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
72966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    validUmbra = (minDistance >= localRadius);
73066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
73166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // init centroid check
73266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    bool hiddenCentroid = true;
73366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkVector v1 = transformedCentroid - fClipPolygon[0];
73466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar initCross = v0.cross(v1);
73566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
73666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    for (int p = 1; p < fClipPolygon.count(); ++p) {
73766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // Determine whether we have a real umbra by insetting clipPolygon by radius/scale
73866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // and see if it extends past centroid.
73966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // TODO: adjust this later for more accurate umbra calcs
74066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        w = fCentroid - fClipPolygon[p];
74166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        v0 = fClipPolygon[(p + 1) % fClipPolygon.count()] - fClipPolygon[p];
74266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fClipVectors.push() = v0;
74366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // check distance against line segment
74466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkScalar distance;
74566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (useDistanceToPoint) {
74666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            distance = w.lengthSqd();
74766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else {
74866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkScalar vSq = v0.dot(v0);
74966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkScalar wDotV = w.dot(v0);
75066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            distance = w.dot(w) - wDotV*wDotV/vSq;
75166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
75266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (distance < localRadius) {
75366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            validUmbra = false;
75466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
75566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (distance < minDistance) {
75666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            minDistance = distance;
75766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
75866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // Determine if transformed centroid is inside clipPolygon.
75966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        v1 = transformedCentroid - fClipPolygon[p];
76066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (initCross*v0.cross(v1) <= 0) {
76166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            hiddenCentroid = false;
76266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
76366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
76466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkASSERT(fClipVectors.count() == fClipPolygon.count());
76566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
76666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (!validUmbra) {
76766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkScalar ratio = 256 * SkScalarSqrt(minDistance / localRadius);
76866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // they aren't PMColors, but the interpolation algorithm is the same
76966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fUmbraColor = SkPMLerp(fUmbraColor, fPenumbraColor, (unsigned)ratio);
77066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
77166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
77266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fTransparent = fTransparent || !hiddenCentroid || !validUmbra;
77366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fValidUmbra = validUmbra;
77466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fCentroid = transformedCentroid;
77566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon}
77666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
77766085ed41779211f9e7e17aa493d4585d73445feBrian Salomonbool SkSpotShadowTessellator::clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid,
77866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                                             SkPoint* clipPoint) {
77966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkVector segmentVector = centroid - umbraPoint;
78066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
78166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    int startPolyPoint = fCurrPolyPoint;
78266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    do {
78366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkVector dp = umbraPoint - fClipPolygon[fCurrPolyPoint];
78466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkScalar denom = fClipVectors[fCurrPolyPoint].cross(segmentVector);
78566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkScalar t_num = dp.cross(segmentVector);
78666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // if line segments are nearly parallel
78766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (SkScalarNearlyZero(denom)) {
78866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // and collinear
78966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (SkScalarNearlyZero(t_num)) {
79066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                return false;
79166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
79266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // otherwise are separate, will try the next poly segment
79366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        // else if crossing lies within poly segment
79466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        } else if (t_num >= 0 && t_num <= denom) {
79566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkScalar s_num = dp.cross(fClipVectors[fCurrPolyPoint]);
79666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            // if umbra point is inside the clip polygon
79766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (s_num < 0) {
79866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                return false;
79966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            } else {
80066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                segmentVector *= s_num/denom;
80166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *clipPoint = umbraPoint + segmentVector;
80266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                return true;
80366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
80466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
80566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fCurrPolyPoint = (fCurrPolyPoint + 1) % fClipPolygon.count();
80666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    } while (fCurrPolyPoint != startPolyPoint);
80766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
80866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    return false;
80991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
81091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
811efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate,
81291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                                        SkPoint* pts, int count) {
81391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // TODO: vectorize
81491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    for (int i = 0; i < count; ++i) {
81591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        pts[i] *= scale;
81691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        pts[i] += xlate;
81791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
81891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
81991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
820efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::handleLine(const SkPoint& p) {
82191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fInitPoints.count() < 2) {
82291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fInitPoints.push() = p;
82391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        return;
82491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
82591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
82691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fInitPoints.count() == 2) {
82791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // determine if cw or ccw
82891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkVector v0 = fInitPoints[1] - fInitPoints[0];
82991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkVector v1 = p - fInitPoints[0];
83091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkScalar perpDot = v0.fX*v1.fY - v0.fY*v1.fX;
83191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        if (SkScalarNearlyZero(perpDot)) {
83291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            // nearly parallel, just treat as straight line and continue
83391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            fInitPoints[1] = p;
83491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            return;
83591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
83691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
83791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // if perpDot > 0, winding is ccw
83891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fDirection = (perpDot > 0) ? -1 : 1;
83991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
84091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // add first quad
84191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        if (!compute_normal(fInitPoints[0], fInitPoints[1], fRadius, fDirection,
84291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                            &fFirstNormal)) {
84391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            // first two points are incident, make the third point the second and continue
84491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            fInitPoints[1] = p;
84591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth            return;
84691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        }
84791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
84891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fFirstPoint = fInitPoints[0];
84991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fFirstVertex = fPositions.count();
85091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevNormal = fFirstNormal;
85191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        fPrevPoint = fFirstPoint;
85266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        fPrevUmbraIndex = fFirstVertex;
85366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
85466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        this->addInnerPoint(fFirstPoint);
85566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
85666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (!fTransparent) {
85766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkPoint clipPoint;
85866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            bool isOutside = this->clipUmbraPoint(fPositions[fFirstVertex], fCentroid, &clipPoint);
85966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (isOutside) {
86066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fPositions.push() = clipPoint;
86166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fColors.push() = fUmbraColor;
86266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
86366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fPrevUmbraOutside = isOutside;
86466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fFirstUmbraOutside = isOutside;
86566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
86691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
86791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        SkPoint newPoint = fFirstPoint + fFirstNormal;
86891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fPositions.push() = newPoint;
86991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fColors.push() = fPenumbraColor;
87091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addEdge(fInitPoints[1], fFirstNormal);
87191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
87291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        // to ensure we skip this block next time
87391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        *fInitPoints.push() = p;
87491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
87591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
87691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkVector normal;
87791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (compute_normal(fPrevPoint, p, fRadius, fDirection, &normal)) {
87891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->addArc(normal);
87991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        this->finishArcAndAddEdge(p, normal);
88091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
88191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
88291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
88366085ed41779211f9e7e17aa493d4585d73445feBrian Salomonvoid SkSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint) {
88491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkVector v = fCentroid - pathPoint;
88591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkScalar distance = v.length();
88666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkScalar t;
88766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (fValidUmbra) {
88866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        SkASSERT(distance >= fRadius);
88966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        t = fRadius / distance;
89091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    } else {
89166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        t = 0.95f;
89291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
89366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    v *= t;
89466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    SkPoint umbraPoint = pathPoint + v;
89566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fPositions.push() = umbraPoint;
89666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fColors.push() = fUmbraColor;
89766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
89891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fPrevPoint = pathPoint;
89991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
90091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
901efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
90266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // add next umbra point
90366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    this->addInnerPoint(nextPoint);
90466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    int prevPenumbraIndex = fPositions.count() - 2;
90566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    int currUmbraIndex = fPositions.count() - 1;
90666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
90766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // add to center fan if transparent or centroid showing
90866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    if (fTransparent) {
90966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = 0;
91066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = fPrevUmbraIndex;
91166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        *fIndices.push() = currUmbraIndex;
91266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // otherwise add to clip ring
91366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    } else {
91466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        if (!fTransparent) {
91566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            SkPoint clipPoint;
91666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            bool isOutside = clipUmbraPoint(fPositions[currUmbraIndex], fCentroid, &clipPoint);
91766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            if (isOutside) {
91866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fPositions.push() = clipPoint;
91966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fColors.push() = fUmbraColor;
92066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
92166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
92266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex;
92366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex + 1;
92466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                if (fPrevUmbraOutside) {
92566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    // fill out quad
92666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex;
92766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = currUmbraIndex + 1;
92866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                    *fIndices.push() = fPrevUmbraIndex + 1;
92966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                }
93066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            } else if (fPrevUmbraOutside) {
93166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                // add tri
93266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex;
93366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = currUmbraIndex;
93466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon                *fIndices.push() = fPrevUmbraIndex + 1;
93566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            }
93666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon            fPrevUmbraOutside = isOutside;
93766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon        }
93866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    }
93966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon
94066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    // add next penumbra point and quad
94191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkPoint newPoint = nextPoint + nextNormal;
94291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fPositions.push() = newPoint;
94391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fColors.push() = fPenumbraColor;
94491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
94566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = fPrevUmbraIndex;
94666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = prevPenumbraIndex;
94766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = currUmbraIndex;
94891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
94966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = prevPenumbraIndex;
95091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    *fIndices.push() = fPositions.count() - 1;
95166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    *fIndices.push() = currUmbraIndex;
95291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
95366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon    fPrevUmbraIndex = currUmbraIndex;
95491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    fPrevNormal = nextNormal;
95591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth}
956958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
957958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon///////////////////////////////////////////////////////////////////////////////////////////////////
958958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
959aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonsk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
960aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                   SkScalar radius, SkColor umbra, SkColor penumbra,
961aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                   bool transparent) {
962a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkAmbientShadowTessellator ambientTess(path, ctm, radius, umbra, penumbra, transparent);
963aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    return ambientTess.releaseVertices();
964958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon}
965958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon
966aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonsk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
967aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                SkScalar scale, const SkVector& translate,
968aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                SkScalar radius, SkColor umbraColor,
969aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon                                                SkColor penumbraColor, bool transparent) {
970a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth    SkSpotShadowTessellator spotTess(path, ctm, scale, translate, radius, umbraColor,
971a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth                                     penumbraColor, transparent);
972aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon    return spotTess.releaseVertices();
973958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon}
974