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