ReorderBarrierDrawables.cpp revision e547dd0b80b819bbd377bd7de228737b10570aa0
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 28namespace android { 29namespace uirenderer { 30namespace skiapipeline { 31 32StartReorderBarrierDrawable::StartReorderBarrierDrawable(SkiaDisplayList* data) 33 : mEndChildIndex(0) 34 , mBeginChildIndex(data->mChildNodes.size()) 35 , mDisplayList(data) { 36} 37 38void StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) { 39 if (mChildren.empty()) { 40 //mChildren is allocated and initialized only the first time onDraw is called and cached for 41 //subsequent calls 42 mChildren.reserve(mEndChildIndex - mBeginChildIndex + 1); 43 for (unsigned int i = mBeginChildIndex; i <= mEndChildIndex; i++) { 44 mChildren.push_back(const_cast<RenderNodeDrawable*>(&mDisplayList->mChildNodes[i])); 45 } 46 } 47 std::stable_sort(mChildren.begin(), mChildren.end(), 48 [](RenderNodeDrawable* a, RenderNodeDrawable* b) { 49 const float aZValue = a->getNodeProperties().getZ(); 50 const float bZValue = b->getNodeProperties().getZ(); 51 return aZValue < bZValue; 52 }); 53 54 SkASSERT(!mChildren.empty()); 55 56 size_t drawIndex = 0; 57 const size_t endIndex = mChildren.size(); 58 while (drawIndex < endIndex) { 59 RenderNodeDrawable* childNode = mChildren[drawIndex]; 60 SkASSERT(childNode); 61 const float casterZ = childNode->getNodeProperties().getZ(); 62 if (casterZ >= -NON_ZERO_EPSILON) { //draw only children with negative Z 63 return; 64 } 65 childNode->forceDraw(canvas); 66 drawIndex++; 67 } 68} 69 70EndReorderBarrierDrawable::EndReorderBarrierDrawable(StartReorderBarrierDrawable* startBarrier) 71 : mStartBarrier(startBarrier) { 72 mStartBarrier->mEndChildIndex = mStartBarrier->mDisplayList->mChildNodes.size() - 1; 73} 74 75#define SHADOW_DELTA 0.1f 76 77void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) { 78 auto& zChildren = mStartBarrier->mChildren; 79 SkASSERT(!zChildren.empty()); 80 81 /** 82 * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters 83 * with very similar Z heights to draw together. 84 * 85 * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are 86 * underneath both, and neither's shadow is drawn on top of the other. 87 */ 88 size_t drawIndex = 0; 89 90 const size_t endIndex = zChildren.size(); 91 while (drawIndex < endIndex //draw only children with positive Z 92 && zChildren[drawIndex]->getNodeProperties().getZ() <= NON_ZERO_EPSILON) drawIndex++; 93 size_t shadowIndex = drawIndex; 94 95 float lastCasterZ = 0.0f; 96 while (shadowIndex < endIndex || drawIndex < endIndex) { 97 if (shadowIndex < endIndex) { 98 const float casterZ = zChildren[shadowIndex]->getNodeProperties().getZ(); 99 100 // attempt to render the shadow if the caster about to be drawn is its caster, 101 // OR if its caster's Z value is similar to the previous potential caster 102 if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) { 103 this->drawShadow(canvas, zChildren[shadowIndex]); 104 lastCasterZ = casterZ; // must do this even if current caster not casting a shadow 105 shadowIndex++; 106 continue; 107 } 108 } 109 110 RenderNodeDrawable* childNode = zChildren[drawIndex]; 111 SkASSERT(childNode); 112 childNode->forceDraw(canvas); 113 114 drawIndex++; 115 } 116} 117 118/** 119 * @param canvas the destination for the shadow draws 120 * @param shape the shape casting the shadow 121 * @param casterZValue the Z value of the caster RRect 122 * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow 123 * @param draw the function used to draw 'shape' 124 */ 125template <typename Shape, typename F> 126static void DrawAmbientShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue, 127 float ambientAlpha, F&& draw) { 128 if (ambientAlpha <= 0) { 129 return; 130 } 131 132 const float kHeightFactor = 1.f/128.f; 133 const float kGeomFactor = 64; 134 135 float umbraAlpha = 1 / (1 + SkMaxScalar(casterZValue*kHeightFactor, 0)); 136 float radius = casterZValue*kHeightFactor*kGeomFactor; 137 138 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 139 SkBlurMask::ConvertRadiusToSigma(radius), SkBlurMaskFilter::kNone_BlurFlag); 140 SkPaint paint; 141 paint.setAntiAlias(true); 142 paint.setMaskFilter(std::move(mf)); 143 paint.setARGB(ambientAlpha*umbraAlpha, 0, 0, 0); 144 145 draw(shape, paint); 146} 147 148/** 149 * @param canvas the destination for the shadow draws 150 * @param shape the shape casting the shadow 151 * @param casterZValue the Z value of the caster RRect 152 * @param lightPos the position of the light casting the shadow 153 * @param lightWidth 154 * @param spotAlpha the maximum alpha value to use when drawing the spot shadow 155 * @param draw the function used to draw 'shape' 156 */ 157template <typename Shape, typename F> 158static void DrawSpotShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue, 159 float spotAlpha, F&& draw) { 160 if (spotAlpha <= 0) { 161 return; 162 } 163 164 const Vector3 lightPos = SkiaPipeline::getLightCenter(); 165 float zRatio = casterZValue / (lightPos.z - casterZValue); 166 // clamp 167 if (zRatio < 0.0f) { 168 zRatio = 0.0f; 169 } else if (zRatio > 0.95f) { 170 zRatio = 0.95f; 171 } 172 173 float blurRadius = SkiaPipeline::getLightRadius()*zRatio; 174 175 SkAutoCanvasRestore acr(canvas, true); 176 177 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 178 SkBlurMask::ConvertRadiusToSigma(blurRadius), SkBlurMaskFilter::kNone_BlurFlag); 179 180 SkPaint paint; 181 paint.setAntiAlias(true); 182 paint.setMaskFilter(std::move(mf)); 183 paint.setARGB(spotAlpha, 0, 0, 0); 184 185 // approximate projection by translating and scaling projected offset of bounds center 186 // TODO: compute the actual 2D projection 187 SkScalar scale = lightPos.z / (lightPos.z - casterZValue); 188 canvas->scale(scale, scale); 189 SkPoint center = SkPoint::Make(shape.getBounds().centerX(), shape.getBounds().centerY()); 190 SkMatrix ctmInverse; 191 if (!canvas->getTotalMatrix().invert(&ctmInverse)) { 192 ALOGW("Matrix is degenerate. Will not render shadow!"); 193 return; 194 } 195 SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); 196 ctmInverse.mapPoints(&lightPos2D, 1); 197 canvas->translate(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY)); 198 199 draw(shape, paint); 200} 201 202#define MAX_BLUR_RADIUS 16383.75f 203#define MAX_PAD 64 204 205/** 206 * @param casterRect the rectangle bounds of the RRect casting the shadow 207 * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow 208 * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow 209 * @param spotAlpha the maximum alpha value to use when drawing the spot shadow 210 * @param casterAlpha the alpha value of the RRect casting the shadow (0.0-1.0 range) 211 * @param casterZValue the Z value of the caster RRect 212 * @param scaleFactor the scale needed to map from src-space to device-space 213 * @param canvas the destination for the shadow draws 214 */ 215static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadius, 216 SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, 217 SkScalar scaleFactor, SkCanvas* canvas) { 218 SkASSERT(casterCornerRadius >= 0.0f); 219 220 // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space 221 const SkScalar minRadius = 0.5f / scaleFactor; 222 223 const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()), 224 SkScalarHalf(casterRect.height())); 225 const bool isRect = casterCornerRadius <= minRadius; 226 227 sk_sp<SkShader> edgeShader(SkGaussianEdgeShader::Make()); 228 229 if (ambientAlpha > 0.0f) { 230 static const float kHeightFactor = 1.0f / 128.0f; 231 static const float kGeomFactor = 64.0f; 232 233 SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor; 234 // the device-space radius sent to the blur shader must fit in 14.2 fixed point 235 if (srcSpaceAmbientRadius*scaleFactor > MAX_BLUR_RADIUS) { 236 srcSpaceAmbientRadius = MAX_BLUR_RADIUS/scaleFactor; 237 } 238 const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f)); 239 const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha; 240 241 // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius 242 // to get our stroke shape. 243 SkScalar ambientPathOutset = std::max(ambientOffset - srcSpaceAmbientRadius * 0.5f, 244 minRadius); 245 246 SkRRect ambientRRect; 247 const SkRect temp = casterRect.makeOutset(ambientPathOutset, ambientPathOutset); 248 if (isOval) { 249 ambientRRect = SkRRect::MakeOval(temp); 250 } else if (isRect) { 251 ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset); 252 } else { 253 ambientRRect = SkRRect::MakeRectXY(temp, casterCornerRadius + ambientPathOutset, 254 casterCornerRadius + ambientPathOutset); 255 } 256 257 SkPaint paint; 258 paint.setAntiAlias(true); 259 paint.setStyle(SkPaint::kStroke_Style); 260 // we outset the stroke a little to cover up AA on the interior edge 261 float pad = 0.5f; 262 paint.setStrokeWidth(srcSpaceAmbientRadius + 2.0f * pad); 263 // handle scale of radius and pad due to CTM 264 pad *= scaleFactor; 265 const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor; 266 SkASSERT(devSpaceAmbientRadius <= MAX_BLUR_RADIUS); 267 SkASSERT(pad < MAX_PAD); 268 // convert devSpaceAmbientRadius to 14.2 fixed point and place in the R & G components 269 // convert pad to 6.2 fixed point and place in the B component 270 uint16_t iDevSpaceAmbientRadius = (uint16_t)(4.0f * devSpaceAmbientRadius); 271 paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, iDevSpaceAmbientRadius >> 8, 272 iDevSpaceAmbientRadius & 0xff, (unsigned char)(4.0f * pad))); 273 274 paint.setShader(edgeShader); 275 canvas->drawRRect(ambientRRect, paint); 276 } 277 278 if (spotAlpha > 0.0f) { 279 const Vector3 lightPos = SkiaPipeline::getLightCenter(); 280 float zRatio = casterZValue / (lightPos.z - casterZValue); 281 // clamp 282 if (zRatio < 0.0f) { 283 zRatio = 0.0f; 284 } else if (zRatio > 0.95f) { 285 zRatio = 0.95f; 286 } 287 288 const SkScalar lightWidth = SkiaPipeline::getLightRadius(); 289 SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio; 290 // the device-space radius sent to the blur shader must fit in 14.2 fixed point 291 if (srcSpaceSpotRadius*scaleFactor > MAX_BLUR_RADIUS) { 292 srcSpaceSpotRadius = MAX_BLUR_RADIUS/scaleFactor; 293 } 294 295 SkRRect spotRRect; 296 if (isOval) { 297 spotRRect = SkRRect::MakeOval(casterRect); 298 } else if (isRect) { 299 spotRRect = SkRRect::MakeRectXY(casterRect, minRadius, minRadius); 300 } else { 301 spotRRect = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius); 302 } 303 304 SkRRect spotShadowRRect; 305 // Compute the scale and translation for the spot shadow. 306 const SkScalar scale = lightPos.z / (lightPos.z - casterZValue); 307 spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect); 308 309 SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(), 310 spotShadowRRect.rect().centerY()); 311 SkMatrix ctmInverse; 312 if (!canvas->getTotalMatrix().invert(&ctmInverse)) { 313 ALOGW("Matrix is degenerate. Will not render spot shadow!"); 314 return; 315 } 316 SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); 317 ctmInverse.mapPoints(&lightPos2D, 1); 318 const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX), 319 zRatio*(center.fY - lightPos2D.fY)); 320 321 SkAutoCanvasRestore acr(canvas, true); 322 323 // We want to extend the stroked area in so that it meets up with the caster 324 // geometry. The stroked geometry will, by definition already be inset half the 325 // stroke width but we also have to account for the scaling. 326 // We also add 1/2 to cover up AA on the interior edge. 327 SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(casterRect.fLeft), 328 SkTAbs(casterRect.fRight)), SkTMax(SkTAbs(casterRect.fTop), 329 SkTAbs(casterRect.fBottom))); 330 SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) + 331 scaleOffset + 0.5f; 332 333 // Compute area 334 SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount; 335 SkScalar strokedArea = 2.0f*strokeWidth * (spotShadowRRect.width() 336 + spotShadowRRect.height()); 337 SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius) 338 * (spotShadowRRect.width() + srcSpaceSpotRadius); 339 340 SkPaint paint; 341 paint.setAntiAlias(true); 342 343 // If the area of the stroked geometry is larger than the fill geometry, just fill it. 344 if (strokedArea > filledArea || casterAlpha < 1.0f || insetAmount < 0.0f) { 345 paint.setStyle(SkPaint::kStrokeAndFill_Style); 346 paint.setStrokeWidth(srcSpaceSpotRadius); 347 } else { 348 // Since we can't have unequal strokes, inset the shadow rect so the inner 349 // and outer edges of the stroke will land where we want. 350 SkRect insetRect = spotShadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f); 351 SkScalar insetRad = SkTMax(spotShadowRRect.getSimpleRadii().fX - insetAmount/2.0f, 352 minRadius); 353 spotShadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad); 354 paint.setStyle(SkPaint::kStroke_Style); 355 paint.setStrokeWidth(strokeWidth); 356 } 357 358 // handle scale of radius and pad due to CTM 359 const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor; 360 SkASSERT(devSpaceSpotRadius <= MAX_BLUR_RADIUS); 361 362 const SkScalar devSpaceSpotPad = 0; 363 SkASSERT(devSpaceSpotPad < MAX_PAD); 364 365 // convert devSpaceSpotRadius to 14.2 fixed point and place in the R & G 366 // components convert devSpaceSpotPad to 6.2 fixed point and place in the B component 367 uint16_t iDevSpaceSpotRadius = (uint16_t)(4.0f * devSpaceSpotRadius); 368 paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, iDevSpaceSpotRadius >> 8, 369 iDevSpaceSpotRadius & 0xff, (unsigned char)(4.0f * devSpaceSpotPad))); 370 paint.setShader(edgeShader); 371 372 canvas->translate(spotOffset.fX, spotOffset.fY); 373 canvas->drawRRect(spotShadowRRect, paint); 374 } 375} 376 377/** 378 * @param casterRect the rectangle bounds of the RRect casting the shadow 379 * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow 380 * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow 381 * @param spotAlpha the maximum alpha value to use when drawing the spot shadow 382 * @param casterZValue the Z value of the caster RRect 383 * @param scaleFactor the scale needed to map from src-space to device-space 384 * @param clipRR the oval or rect with which the drawn roundrect must be intersected 385 * @param canvas the destination for the shadow draws 386 */ 387static void DrawRRectShadowsWithClip(const SkRect& casterRect, SkScalar casterCornerRadius, 388 SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterZValue, SkScalar scaleFactor, 389 const SkRRect& clipRR, SkCanvas* canvas) { 390 SkASSERT(casterCornerRadius >= 0.0f); 391 392 const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()), 393 SkScalarHalf(casterRect.height())); 394 395 if (ambientAlpha > 0.0f) { 396 static const float kHeightFactor = 1.0f / 128.0f; 397 static const float kGeomFactor = 64.0f; 398 399 const SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor; 400 const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor; 401 402 const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f)); 403 const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha; 404 405 const SkRect srcSpaceAmbientRect = casterRect.makeOutset(ambientOffset, ambientOffset); 406 SkRect devSpaceAmbientRect; 407 canvas->getTotalMatrix().mapRect(&devSpaceAmbientRect, srcSpaceAmbientRect); 408 409 SkRRect devSpaceAmbientRRect; 410 if (isOval) { 411 devSpaceAmbientRRect = SkRRect::MakeOval(devSpaceAmbientRect); 412 } else { 413 const SkScalar devSpaceCornerRadius = scaleFactor * (casterCornerRadius + ambientOffset); 414 devSpaceAmbientRRect = SkRRect::MakeRectXY(devSpaceAmbientRect, devSpaceCornerRadius, 415 devSpaceCornerRadius); 416 } 417 418 const SkRect srcSpaceAmbClipRect = clipRR.rect().makeOutset(ambientOffset, ambientOffset); 419 SkRect devSpaceAmbClipRect; 420 canvas->getTotalMatrix().mapRect(&devSpaceAmbClipRect, srcSpaceAmbClipRect); 421 SkRRect devSpaceAmbientClipRR; 422 if (clipRR.isOval()) { 423 devSpaceAmbientClipRR = SkRRect::MakeOval(devSpaceAmbClipRect); 424 } else { 425 SkASSERT(clipRR.isRect()); 426 devSpaceAmbientClipRR = SkRRect::MakeRect(devSpaceAmbClipRect); 427 } 428 429 SkRect cover = srcSpaceAmbClipRect; 430 if (!cover.intersect(srcSpaceAmbientRect)) { 431 return; 432 } 433 434 SkPaint paint; 435 paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, 0, 0, 0)); 436 paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceAmbientRRect, 437 devSpaceAmbientClipRR, devSpaceAmbientRadius)); 438 canvas->drawRect(cover, paint); 439 } 440 441 if (spotAlpha > 0.0f) { 442 const Vector3 lightPos = SkiaPipeline::getLightCenter(); 443 float zRatio = casterZValue / (lightPos.z - casterZValue); 444 // clamp 445 if (zRatio < 0.0f) { 446 zRatio = 0.0f; 447 } else if (zRatio > 0.95f) { 448 zRatio = 0.95f; 449 } 450 451 const SkScalar lightWidth = SkiaPipeline::getLightRadius(); 452 const SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio; 453 const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor; 454 455 // Compute the scale and translation for the spot shadow. 456 const SkScalar scale = lightPos.z / (lightPos.z - casterZValue); 457 const SkMatrix spotMatrix = SkMatrix::MakeScale(scale, scale); 458 459 SkRect srcSpaceScaledRect = casterRect; 460 spotMatrix.mapRect(&srcSpaceScaledRect); 461 srcSpaceScaledRect.outset(SkScalarHalf(srcSpaceSpotRadius), 462 SkScalarHalf(srcSpaceSpotRadius)); 463 464 SkRRect srcSpaceSpotRRect; 465 if (isOval) { 466 srcSpaceSpotRRect = SkRRect::MakeOval(srcSpaceScaledRect); 467 } else { 468 srcSpaceSpotRRect = SkRRect::MakeRectXY(srcSpaceScaledRect, casterCornerRadius * scale, 469 casterCornerRadius * scale); 470 } 471 472 SkPoint center = SkPoint::Make(srcSpaceSpotRRect.rect().centerX(), 473 srcSpaceSpotRRect.rect().centerY()); 474 SkMatrix ctmInverse; 475 if (!canvas->getTotalMatrix().invert(&ctmInverse)) { 476 ALOGW("Matrix is degenerate. Will not render spot shadow!"); 477 return; 478 } 479 SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y); 480 ctmInverse.mapPoints(&lightPos2D, 1); 481 const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX), 482 zRatio*(center.fY - lightPos2D.fY)); 483 484 SkAutoCanvasRestore acr(canvas, true); 485 canvas->translate(spotOffset.fX, spotOffset.fY); 486 487 SkRect devSpaceScaledRect; 488 canvas->getTotalMatrix().mapRect(&devSpaceScaledRect, srcSpaceScaledRect); 489 490 SkRRect devSpaceSpotRRect; 491 if (isOval) { 492 devSpaceSpotRRect = SkRRect::MakeOval(devSpaceScaledRect); 493 } else { 494 const SkScalar devSpaceScaledCornerRadius = casterCornerRadius * scale * scaleFactor; 495 devSpaceSpotRRect = SkRRect::MakeRectXY(devSpaceScaledRect, devSpaceScaledCornerRadius, 496 devSpaceScaledCornerRadius); 497 } 498 499 SkPaint paint; 500 paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, 0, 0, 0)); 501 502 SkRect srcSpaceScaledClipRect = clipRR.rect(); 503 spotMatrix.mapRect(&srcSpaceScaledClipRect); 504 srcSpaceScaledClipRect.outset(SkScalarHalf(srcSpaceSpotRadius), 505 SkScalarHalf(srcSpaceSpotRadius)); 506 507 SkRect devSpaceScaledClipRect; 508 canvas->getTotalMatrix().mapRect(&devSpaceScaledClipRect, srcSpaceScaledClipRect); 509 SkRRect devSpaceSpotClipRR; 510 if (clipRR.isOval()) { 511 devSpaceSpotClipRR = SkRRect::MakeOval(devSpaceScaledClipRect); 512 } else { 513 SkASSERT(clipRR.isRect()); 514 devSpaceSpotClipRR = SkRRect::MakeRect(devSpaceScaledClipRect); 515 } 516 517 paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceSpotRRect, 518 devSpaceSpotClipRR, devSpaceSpotRadius)); 519 520 SkRect cover = srcSpaceScaledClipRect; 521 if (!cover.intersect(srcSpaceSpotRRect.rect())) { 522 return; 523 } 524 525 canvas->drawRect(cover, paint); 526 } 527} 528 529/** 530 * @param casterRect the rectangle bounds of the RRect casting the shadow 531 * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow 532 * @param casterClipRect a rectangular clip that must be intersected with the 533 * shadow-casting RRect prior to casting the shadow 534 * @param revealClip a circular clip that must be interested with the castClipRect 535 * and the shadow-casting rect prior to casting the shadow 536 * @param ambientAlpha the maximum alpha value to use when drawing the ambient shadow 537 * @param spotAlpha the maximum alpha value to use when drawing the spot shadow 538 * @param casterAlpha the alpha value of the RRect casting the shadow (0.0-1.0 range) 539 * @param casterZValue the Z value of the caster RRect 540 * @param canvas the destination for the shadow draws 541 * 542 * We have special cases for 4 round rect shadow draws: 543 * 1) a RRect clipped by a reveal animation 544 * 2) a RRect clipped by a rectangle 545 * 3) an unclipped RRect with non-uniform scale 546 * 4) an unclipped RRect with uniform scale 547 * 1,2 and 4 require that the scale is uniform. 548 * 1 and 2 require that rects stay rects. 549 */ 550static bool DrawShadowsAsRRects(const SkRect& casterRect, SkScalar casterCornerRadius, 551 const SkRect& casterClipRect, const RevealClip& revealClip, SkScalar ambientAlpha, 552 SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, SkCanvas* canvas) { 553 SkScalar scaleFactors[2]; 554 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) { 555 ALOGW("Matrix is degenerate. Will not render shadow!"); 556 return false; 557 } 558 559 // The casterClipRect will be empty when bounds clipping is disabled 560 bool casterIsClippedByRect = !casterClipRect.isEmpty(); 561 bool uniformScale = scaleFactors[0] == scaleFactors[1]; 562 563 if (revealClip.willClip()) { 564 if (casterIsClippedByRect || !uniformScale || !canvas->getTotalMatrix().rectStaysRect()) { 565 return false; // Fall back to the slow path since PathOps are required 566 } 567 568 const float revealRadius = revealClip.getRadius(); 569 SkRect revealClipRect = SkRect::MakeLTRB(revealClip.getX()-revealRadius, 570 revealClip.getY()-revealRadius, revealClip.getX()+revealRadius, 571 revealClip.getY()+revealRadius); 572 SkRRect revealClipRR = SkRRect::MakeOval(revealClipRect); 573 574 DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, 575 casterZValue, scaleFactors[0], revealClipRR, canvas); 576 return true; 577 } 578 579 if (casterIsClippedByRect) { 580 if (!uniformScale || !canvas->getTotalMatrix().rectStaysRect()) { 581 return false; // Fall back to the slow path since PathOps are required 582 } 583 584 SkRRect casterClipRR = SkRRect::MakeRect(casterClipRect); 585 586 DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, 587 casterZValue, scaleFactors[0], casterClipRR, canvas); 588 return true; 589 } 590 591 // The fast path needs uniform scale 592 if (!uniformScale) { 593 SkRRect casterRR = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius); 594 DrawAmbientShadowGeneral(canvas, casterRR, casterZValue, ambientAlpha, 595 [&](const SkRRect& rrect, const SkPaint& paint) { 596 canvas->drawRRect(rrect, paint); 597 }); 598 DrawSpotShadowGeneral(canvas, casterRR, casterZValue, spotAlpha, 599 [&](const SkRRect& rrect, const SkPaint& paint) { 600 canvas->drawRRect(rrect, paint); 601 }); 602 return true; 603 } 604 605 DrawRRectShadows(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterAlpha, 606 casterZValue, scaleFactors[0], canvas); 607 return true; 608} 609 610// copied from FrameBuilder::deferShadow 611void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) { 612 const RenderProperties& casterProperties = caster->getNodeProperties(); 613 614 if (casterProperties.getAlpha() <= 0.0f 615 || casterProperties.getOutline().getAlpha() <= 0.0f 616 || !casterProperties.getOutline().getPath() 617 || casterProperties.getScaleX() == 0 618 || casterProperties.getScaleY() == 0) { 619 // no shadow to draw 620 return; 621 } 622 623 const SkScalar casterAlpha = casterProperties.getAlpha() 624 * casterProperties.getOutline().getAlpha(); 625 if (casterAlpha <= 0.0f) { 626 return; 627 } 628 629 float ambientAlpha = SkiaPipeline::getAmbientShadowAlpha()*casterAlpha; 630 float spotAlpha = SkiaPipeline::getSpotShadowAlpha()*casterAlpha; 631 const float casterZValue = casterProperties.getZ(); 632 633 const RevealClip& revealClip = casterProperties.getRevealClip(); 634 const SkPath* revealClipPath = revealClip.getPath(); 635 if (revealClipPath && revealClipPath->isEmpty()) { 636 // An empty reveal clip means nothing is drawn 637 return; 638 } 639 640 bool clippedToBounds = casterProperties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS; 641 642 SkRect casterClipRect = SkRect::MakeEmpty(); 643 if (clippedToBounds) { 644 Rect clipBounds; 645 casterProperties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds); 646 casterClipRect = clipBounds.toSkRect(); 647 if (casterClipRect.isEmpty()) { 648 // An empty clip rect means nothing is drawn 649 return; 650 } 651 } 652 653 SkAutoCanvasRestore acr(canvas, true); 654 655 SkMatrix shadowMatrix; 656 mat4 hwuiMatrix(caster->getRecordedMatrix()); 657 // TODO we don't pass the optional boolean to treat it as a 4x4 matrix 658 caster->getRenderNode()->applyViewPropertyTransforms(hwuiMatrix); 659 hwuiMatrix.copyTo(shadowMatrix); 660 canvas->concat(shadowMatrix); 661 662 const Outline& casterOutline = casterProperties.getOutline(); 663 Rect possibleRect; 664 float radius; 665 if (casterOutline.getAsRoundRect(&possibleRect, &radius)) { 666 if (DrawShadowsAsRRects(possibleRect.toSkRect(), radius, casterClipRect, revealClip, 667 ambientAlpha, spotAlpha, casterAlpha, casterZValue, canvas)) { 668 return; 669 } 670 } 671 672 // Hard cases and calls to general shadow code 673 const SkPath* casterOutlinePath = casterProperties.getOutline().getPath(); 674 675 // holds temporary SkPath to store the result of intersections 676 SkPath tmpPath; 677 const SkPath* casterPath = casterOutlinePath; 678 679 // TODO: In to following course of code that calculates the final shape, is there an optimal 680 // of doing the Op calculations? 681 // intersect the shadow-casting path with the reveal, if present 682 if (revealClipPath) { 683 Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath); 684 casterPath = &tmpPath; 685 } 686 687 // intersect the shadow-casting path with the clipBounds, if present 688 if (clippedToBounds) { 689 SkPath clipBoundsPath; 690 clipBoundsPath.addRect(casterClipRect); 691 Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath); 692 casterPath = &tmpPath; 693 } 694 695 DrawAmbientShadowGeneral(canvas, *casterPath, casterZValue, ambientAlpha, 696 [&](const SkPath& path, const SkPaint& paint) { 697 canvas->drawPath(path, paint); 698 }); 699 700 DrawSpotShadowGeneral(canvas, *casterPath, casterZValue, spotAlpha, 701 [&](const SkPath& path, const SkPaint& paint) { 702 canvas->drawPath(path, paint); 703 }); 704} 705 706}; // namespace skiapipeline 707}; // namespace uirenderer 708}; // namespace android 709