1021693b967a2c5556dddd183eb0247df4079e1adStan Iliev/*
2021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * Copyright (C) 2016 The Android Open Source Project
3021693b967a2c5556dddd183eb0247df4079e1adStan Iliev *
4021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * Licensed under the Apache License, Version 2.0 (the "License");
5021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * you may not use this file except in compliance with the License.
6021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * You may obtain a copy of the License at
7021693b967a2c5556dddd183eb0247df4079e1adStan Iliev *
8021693b967a2c5556dddd183eb0247df4079e1adStan Iliev *      http://www.apache.org/licenses/LICENSE-2.0
9021693b967a2c5556dddd183eb0247df4079e1adStan Iliev *
10021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * Unless required by applicable law or agreed to in writing, software
11021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * distributed under the License is distributed on an "AS IS" BASIS,
12021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * See the License for the specific language governing permissions and
14021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * limitations under the License.
15021693b967a2c5556dddd183eb0247df4079e1adStan Iliev */
16021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
17021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "ReorderBarrierDrawables.h"
18021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "RenderNode.h"
19021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "SkiaDisplayList.h"
20500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "SkiaPipeline.h"
21021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
22021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include <SkBlurMask.h>
23021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include <SkBlurMaskFilter.h>
24021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include <SkGaussianEdgeShader.h>
25021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include <SkPathOps.h>
26f87da67df90968adcddb2404ff20a41fe49a0315Derek Sollenberger#include <SkRRectsGaussianEdgeMaskFilter.h>
2730a75debb1c2623308f04d4e01f0ef3162ad7ac1Stan Iliev#include <SkShadowUtils.h>
28021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
29021693b967a2c5556dddd183eb0247df4079e1adStan Ilievnamespace android {
30021693b967a2c5556dddd183eb0247df4079e1adStan Ilievnamespace uirenderer {
31021693b967a2c5556dddd183eb0247df4079e1adStan Ilievnamespace skiapipeline {
32021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
33021693b967a2c5556dddd183eb0247df4079e1adStan IlievStartReorderBarrierDrawable::StartReorderBarrierDrawable(SkiaDisplayList* data)
34021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        : mEndChildIndex(0)
35021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        , mBeginChildIndex(data->mChildNodes.size())
36021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        , mDisplayList(data) {
37021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
38021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
39021693b967a2c5556dddd183eb0247df4079e1adStan Ilievvoid StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
40021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    if (mChildren.empty()) {
41021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        //mChildren is allocated and initialized only the first time onDraw is called and cached for
42021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        //subsequent calls
43021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        mChildren.reserve(mEndChildIndex - mBeginChildIndex + 1);
44347691f8d87157be0eaeca26f4003d8a06a275e3Stan Iliev        for (int i = mBeginChildIndex; i <= mEndChildIndex; i++) {
45021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            mChildren.push_back(const_cast<RenderNodeDrawable*>(&mDisplayList->mChildNodes[i]));
46021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        }
47021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
48021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    std::stable_sort(mChildren.begin(), mChildren.end(),
49021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        [](RenderNodeDrawable* a, RenderNodeDrawable* b) {
50021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            const float aZValue = a->getNodeProperties().getZ();
51021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            const float bZValue = b->getNodeProperties().getZ();
52021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            return aZValue < bZValue;
53021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        });
54021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
55021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    SkASSERT(!mChildren.empty());
56021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
57021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    size_t drawIndex = 0;
58021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const size_t endIndex = mChildren.size();
59021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    while (drawIndex < endIndex) {
60021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        RenderNodeDrawable* childNode = mChildren[drawIndex];
61021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        SkASSERT(childNode);
62021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        const float casterZ = childNode->getNodeProperties().getZ();
63021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        if (casterZ >= -NON_ZERO_EPSILON) { //draw only children with negative Z
64021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            return;
65021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        }
66021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        childNode->forceDraw(canvas);
67021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        drawIndex++;
68021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
69021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
70021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
71021693b967a2c5556dddd183eb0247df4079e1adStan IlievEndReorderBarrierDrawable::EndReorderBarrierDrawable(StartReorderBarrierDrawable* startBarrier)
72021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        : mStartBarrier(startBarrier) {
73021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    mStartBarrier->mEndChildIndex = mStartBarrier->mDisplayList->mChildNodes.size() - 1;
74021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
75021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
76021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#define SHADOW_DELTA 0.1f
77021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
78021693b967a2c5556dddd183eb0247df4079e1adStan Ilievvoid EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
79021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    auto& zChildren = mStartBarrier->mChildren;
80021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    SkASSERT(!zChildren.empty());
81021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
82021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    /**
83021693b967a2c5556dddd183eb0247df4079e1adStan Iliev     * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
84021693b967a2c5556dddd183eb0247df4079e1adStan Iliev     * with very similar Z heights to draw together.
85021693b967a2c5556dddd183eb0247df4079e1adStan Iliev     *
86021693b967a2c5556dddd183eb0247df4079e1adStan Iliev     * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
87021693b967a2c5556dddd183eb0247df4079e1adStan Iliev     * underneath both, and neither's shadow is drawn on top of the other.
88021693b967a2c5556dddd183eb0247df4079e1adStan Iliev     */
89021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    size_t drawIndex = 0;
90021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
91021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const size_t endIndex = zChildren.size();
92021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    while (drawIndex < endIndex     //draw only children with positive Z
93021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            && zChildren[drawIndex]->getNodeProperties().getZ() <= NON_ZERO_EPSILON) drawIndex++;
94021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    size_t shadowIndex = drawIndex;
95021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
96021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    float lastCasterZ = 0.0f;
97021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    while (shadowIndex < endIndex || drawIndex < endIndex) {
98021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        if (shadowIndex < endIndex) {
99021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            const float casterZ = zChildren[shadowIndex]->getNodeProperties().getZ();
100021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
101021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            // attempt to render the shadow if the caster about to be drawn is its caster,
102021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            // OR if its caster's Z value is similar to the previous potential caster
103021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
104021693b967a2c5556dddd183eb0247df4079e1adStan Iliev                this->drawShadow(canvas, zChildren[shadowIndex]);
105021693b967a2c5556dddd183eb0247df4079e1adStan Iliev                lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
106021693b967a2c5556dddd183eb0247df4079e1adStan Iliev                shadowIndex++;
107021693b967a2c5556dddd183eb0247df4079e1adStan Iliev                continue;
108021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            }
109021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        }
110021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
111021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        RenderNodeDrawable* childNode = zChildren[drawIndex];
112021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        SkASSERT(childNode);
113021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        childNode->forceDraw(canvas);
114021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
115021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        drawIndex++;
116021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
117021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
118021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
119021693b967a2c5556dddd183eb0247df4079e1adStan Iliev// copied from FrameBuilder::deferShadow
120021693b967a2c5556dddd183eb0247df4079e1adStan Ilievvoid EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) {
121021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const RenderProperties& casterProperties = caster->getNodeProperties();
122021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
123021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    if (casterProperties.getAlpha() <= 0.0f
124021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            || casterProperties.getOutline().getAlpha() <= 0.0f
125021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            || !casterProperties.getOutline().getPath()
126021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            || casterProperties.getScaleX() == 0
127021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            || casterProperties.getScaleY() == 0) {
128021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        // no shadow to draw
129021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        return;
130021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
131021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
132021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const SkScalar casterAlpha = casterProperties.getAlpha()
133021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            * casterProperties.getOutline().getAlpha();
134021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    if (casterAlpha <= 0.0f) {
135021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        return;
136021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
137021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
13830a75debb1c2623308f04d4e01f0ef3162ad7ac1Stan Iliev    float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha;
13930a75debb1c2623308f04d4e01f0ef3162ad7ac1Stan Iliev    float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha;
140021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const float casterZValue = casterProperties.getZ();
141021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
142021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const RevealClip& revealClip = casterProperties.getRevealClip();
143021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const SkPath* revealClipPath = revealClip.getPath();
144021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    if (revealClipPath && revealClipPath->isEmpty()) {
145021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        // An empty reveal clip means nothing is drawn
146021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        return;
147021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
148021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
149021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    bool clippedToBounds = casterProperties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS;
150021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
151f87da67df90968adcddb2404ff20a41fe49a0315Derek Sollenberger    SkRect casterClipRect = SkRect::MakeEmpty();
152021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    if (clippedToBounds) {
153021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        Rect clipBounds;
154021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        casterProperties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
155021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        casterClipRect = clipBounds.toSkRect();
156f87da67df90968adcddb2404ff20a41fe49a0315Derek Sollenberger        if (casterClipRect.isEmpty()) {
157f87da67df90968adcddb2404ff20a41fe49a0315Derek Sollenberger            // An empty clip rect means nothing is drawn
158f87da67df90968adcddb2404ff20a41fe49a0315Derek Sollenberger            return;
159f87da67df90968adcddb2404ff20a41fe49a0315Derek Sollenberger        }
160021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
161021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
162021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    SkAutoCanvasRestore acr(canvas, true);
163021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
164021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    SkMatrix shadowMatrix;
165d7410f7829ff591ca81ad93c9c9b1632ea80d1bcStan Iliev    mat4 hwuiMatrix;
166021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    // TODO we don't pass the optional boolean to treat it as a 4x4 matrix
167021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    caster->getRenderNode()->applyViewPropertyTransforms(hwuiMatrix);
168021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    hwuiMatrix.copyTo(shadowMatrix);
169021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    canvas->concat(shadowMatrix);
170021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
171021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const SkPath* casterOutlinePath = casterProperties.getOutline().getPath();
172021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    // holds temporary SkPath to store the result of intersections
173021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    SkPath tmpPath;
174021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    const SkPath* casterPath = casterOutlinePath;
175021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
176021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    // TODO: In to following course of code that calculates the final shape, is there an optimal
177021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    //       of doing the Op calculations?
178021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    // intersect the shadow-casting path with the reveal, if present
179021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    if (revealClipPath) {
180021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath);
181021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        casterPath = &tmpPath;
182021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
183021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
184021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    // intersect the shadow-casting path with the clipBounds, if present
185021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    if (clippedToBounds) {
186021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        SkPath clipBoundsPath;
187021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        clipBoundsPath.addRect(casterClipRect);
188021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath);
189021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        casterPath = &tmpPath;
190021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    }
19130a75debb1c2623308f04d4e01f0ef3162ad7ac1Stan Iliev    const Vector3 lightPos = SkiaPipeline::getLightCenter();
19230a75debb1c2623308f04d4e01f0ef3162ad7ac1Stan Iliev    SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z);
1935745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth    if (shadowMatrix.hasPerspective() || revealClipPath || clippedToBounds) {
1945745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth        std::function<SkScalar(SkScalar, SkScalar)> casterHeightFunc;
1955745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth        if (shadowMatrix.hasPerspective()) {
1965745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            // get the matrix with the full 3D transform
1975745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            mat4 zMatrix;
1985745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            caster->getRenderNode()->applyViewPropertyTransforms(zMatrix, true);
1995745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            SkScalar A = zMatrix[2];
2005745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            SkScalar B = zMatrix[6];
2015745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            SkScalar C = zMatrix[mat4::kTranslateZ];
2025745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            casterHeightFunc = [A, B, C](SkScalar x, SkScalar y) {
2035745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth                return A*x + B*y + C;  // casterZValue already baked into C
2045745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            };
2055745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth        } else {
2065745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            casterHeightFunc = [casterZValue] (SkScalar, SkScalar) {
2075745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth                return casterZValue;
2085745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            };
2095745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth        }
2105745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth
2115745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth        SkShadowUtils::DrawUncachedShadow(canvas, *casterPath, casterHeightFunc, skiaLightPos,
21230a75debb1c2623308f04d4e01f0ef3162ad7ac1Stan Iliev            SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
21330a75debb1c2623308f04d4e01f0ef3162ad7ac1Stan Iliev            casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
2145745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth    } else {
2155745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth        SkShadowUtils::DrawShadow(canvas, *casterPath, casterZValue, skiaLightPos,
2165745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
2175745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth            casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
2185745a0a37fa8b09e6ce538ab8ef58684cc00604eJim Van Verth    }
219021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
220021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
221021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}; // namespace skiapipeline
222021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}; // namespace uirenderer
223021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}; // namespace android
224