1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "ReorderBarrierDrawables.h" 18 #include "RenderNode.h" 19 #include "SkiaDisplayList.h" 20 #include "SkiaPipeline.h" 21 22 #include <SkBlurMask.h> 23 #include <SkBlurMaskFilter.h> 24 #include <SkGaussianEdgeShader.h> 25 #include <SkPathOps.h> 26 #include <SkRRectsGaussianEdgeMaskFilter.h> 27 #include <SkShadowUtils.h> 28 29 namespace android { 30 namespace uirenderer { 31 namespace skiapipeline { 32 33 StartReorderBarrierDrawable::StartReorderBarrierDrawable(SkiaDisplayList* data) 34 : mEndChildIndex(0) 35 , mBeginChildIndex(data->mChildNodes.size()) 36 , mDisplayList(data) { 37 } 38 39 void StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) { 40 if (mChildren.empty()) { 41 //mChildren is allocated and initialized only the first time onDraw is called and cached for 42 //subsequent calls 43 mChildren.reserve(mEndChildIndex - mBeginChildIndex + 1); 44 for (int i = mBeginChildIndex; i <= mEndChildIndex; i++) { 45 mChildren.push_back(const_cast<RenderNodeDrawable*>(&mDisplayList->mChildNodes[i])); 46 } 47 } 48 std::stable_sort(mChildren.begin(), mChildren.end(), 49 [](RenderNodeDrawable* a, RenderNodeDrawable* b) { 50 const float aZValue = a->getNodeProperties().getZ(); 51 const float bZValue = b->getNodeProperties().getZ(); 52 return aZValue < bZValue; 53 }); 54 55 SkASSERT(!mChildren.empty()); 56 57 size_t drawIndex = 0; 58 const size_t endIndex = mChildren.size(); 59 while (drawIndex < endIndex) { 60 RenderNodeDrawable* childNode = mChildren[drawIndex]; 61 SkASSERT(childNode); 62 const float casterZ = childNode->getNodeProperties().getZ(); 63 if (casterZ >= -NON_ZERO_EPSILON) { //draw only children with negative Z 64 return; 65 } 66 childNode->forceDraw(canvas); 67 drawIndex++; 68 } 69 } 70 71 EndReorderBarrierDrawable::EndReorderBarrierDrawable(StartReorderBarrierDrawable* startBarrier) 72 : mStartBarrier(startBarrier) { 73 mStartBarrier->mEndChildIndex = mStartBarrier->mDisplayList->mChildNodes.size() - 1; 74 } 75 76 #define SHADOW_DELTA 0.1f 77 78 void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) { 79 auto& zChildren = mStartBarrier->mChildren; 80 SkASSERT(!zChildren.empty()); 81 82 /** 83 * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters 84 * with very similar Z heights to draw together. 85 * 86 * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are 87 * underneath both, and neither's shadow is drawn on top of the other. 88 */ 89 size_t drawIndex = 0; 90 91 const size_t endIndex = zChildren.size(); 92 while (drawIndex < endIndex //draw only children with positive Z 93 && zChildren[drawIndex]->getNodeProperties().getZ() <= NON_ZERO_EPSILON) drawIndex++; 94 size_t shadowIndex = drawIndex; 95 96 float lastCasterZ = 0.0f; 97 while (shadowIndex < endIndex || drawIndex < endIndex) { 98 if (shadowIndex < endIndex) { 99 const float casterZ = zChildren[shadowIndex]->getNodeProperties().getZ(); 100 101 // attempt to render the shadow if the caster about to be drawn is its caster, 102 // OR if its caster's Z value is similar to the previous potential caster 103 if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) { 104 this->drawShadow(canvas, zChildren[shadowIndex]); 105 lastCasterZ = casterZ; // must do this even if current caster not casting a shadow 106 shadowIndex++; 107 continue; 108 } 109 } 110 111 RenderNodeDrawable* childNode = zChildren[drawIndex]; 112 SkASSERT(childNode); 113 childNode->forceDraw(canvas); 114 115 drawIndex++; 116 } 117 } 118 119 // copied from FrameBuilder::deferShadow 120 void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) { 121 const RenderProperties& casterProperties = caster->getNodeProperties(); 122 123 if (casterProperties.getAlpha() <= 0.0f 124 || casterProperties.getOutline().getAlpha() <= 0.0f 125 || !casterProperties.getOutline().getPath() 126 || casterProperties.getScaleX() == 0 127 || casterProperties.getScaleY() == 0) { 128 // no shadow to draw 129 return; 130 } 131 132 const SkScalar casterAlpha = casterProperties.getAlpha() 133 * casterProperties.getOutline().getAlpha(); 134 if (casterAlpha <= 0.0f) { 135 return; 136 } 137 138 float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha; 139 float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha; 140 const float casterZValue = casterProperties.getZ(); 141 142 const RevealClip& revealClip = casterProperties.getRevealClip(); 143 const SkPath* revealClipPath = revealClip.getPath(); 144 if (revealClipPath && revealClipPath->isEmpty()) { 145 // An empty reveal clip means nothing is drawn 146 return; 147 } 148 149 bool clippedToBounds = casterProperties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS; 150 151 SkRect casterClipRect = SkRect::MakeEmpty(); 152 if (clippedToBounds) { 153 Rect clipBounds; 154 casterProperties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds); 155 casterClipRect = clipBounds.toSkRect(); 156 if (casterClipRect.isEmpty()) { 157 // An empty clip rect means nothing is drawn 158 return; 159 } 160 } 161 162 SkAutoCanvasRestore acr(canvas, true); 163 164 SkMatrix shadowMatrix; 165 mat4 hwuiMatrix; 166 // TODO we don't pass the optional boolean to treat it as a 4x4 matrix 167 caster->getRenderNode()->applyViewPropertyTransforms(hwuiMatrix); 168 hwuiMatrix.copyTo(shadowMatrix); 169 canvas->concat(shadowMatrix); 170 171 const SkPath* casterOutlinePath = casterProperties.getOutline().getPath(); 172 // holds temporary SkPath to store the result of intersections 173 SkPath tmpPath; 174 const SkPath* casterPath = casterOutlinePath; 175 176 // TODO: In to following course of code that calculates the final shape, is there an optimal 177 // of doing the Op calculations? 178 // intersect the shadow-casting path with the reveal, if present 179 if (revealClipPath) { 180 Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath); 181 casterPath = &tmpPath; 182 } 183 184 // intersect the shadow-casting path with the clipBounds, if present 185 if (clippedToBounds) { 186 SkPath clipBoundsPath; 187 clipBoundsPath.addRect(casterClipRect); 188 Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath); 189 casterPath = &tmpPath; 190 } 191 const Vector3 lightPos = SkiaPipeline::getLightCenter(); 192 SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z); 193 if (shadowMatrix.hasPerspective() || revealClipPath || clippedToBounds) { 194 std::function<SkScalar(SkScalar, SkScalar)> casterHeightFunc; 195 if (shadowMatrix.hasPerspective()) { 196 // get the matrix with the full 3D transform 197 mat4 zMatrix; 198 caster->getRenderNode()->applyViewPropertyTransforms(zMatrix, true); 199 SkScalar A = zMatrix[2]; 200 SkScalar B = zMatrix[6]; 201 SkScalar C = zMatrix[mat4::kTranslateZ]; 202 casterHeightFunc = [A, B, C](SkScalar x, SkScalar y) { 203 return A*x + B*y + C; // casterZValue already baked into C 204 }; 205 } else { 206 casterHeightFunc = [casterZValue] (SkScalar, SkScalar) { 207 return casterZValue; 208 }; 209 } 210 211 SkShadowUtils::DrawUncachedShadow(canvas, *casterPath, casterHeightFunc, skiaLightPos, 212 SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK, 213 casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0); 214 } else { 215 SkShadowUtils::DrawShadow(canvas, *casterPath, casterZValue, skiaLightPos, 216 SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK, 217 casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0); 218 } 219 } 220 221 }; // namespace skiapipeline 222 }; // namespace uirenderer 223 }; // namespace android 224