1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkDrawShadowInfo.h" 9 #include "SkMatrix.h" 10 #include "SkPath.h" 11 #include "SkRect.h" 12 13 namespace SkDrawShadowMetrics { 14 15 static SkScalar compute_z(SkScalar x, SkScalar y, const SkPoint3& params) { 16 return x*params.fX + y*params.fY + params.fZ; 17 } 18 19 void GetLocalBounds(const SkPath& path, const SkDrawShadowRec& rec, const SkMatrix& ctm, 20 SkRect* bounds) { 21 SkRect ambientBounds = path.getBounds(); 22 SkScalar occluderZ; 23 if (SkScalarNearlyZero(rec.fZPlaneParams.fX) && SkScalarNearlyZero(rec.fZPlaneParams.fY)) { 24 occluderZ = rec.fZPlaneParams.fZ; 25 } else { 26 occluderZ = compute_z(ambientBounds.fLeft, ambientBounds.fTop, rec.fZPlaneParams); 27 occluderZ = SkTMax(occluderZ, compute_z(ambientBounds.fRight, ambientBounds.fTop, 28 rec.fZPlaneParams)); 29 occluderZ = SkTMax(occluderZ, compute_z(ambientBounds.fLeft, ambientBounds.fBottom, 30 rec.fZPlaneParams)); 31 occluderZ = SkTMax(occluderZ, compute_z(ambientBounds.fRight, ambientBounds.fBottom, 32 rec.fZPlaneParams)); 33 } 34 SkScalar ambientBlur; 35 SkScalar spotBlur; 36 SkScalar spotScale; 37 SkPoint spotOffset; 38 if (ctm.hasPerspective()) { 39 // transform ambient and spot bounds into device space 40 ctm.mapRect(&ambientBounds); 41 42 // get ambient blur (in device space) 43 ambientBlur = SkDrawShadowMetrics::AmbientBlurRadius(occluderZ); 44 45 // get spot params (in device space) 46 SkPoint devLightPos = SkPoint::Make(rec.fLightPos.fX, rec.fLightPos.fY); 47 ctm.mapPoints(&devLightPos, 1); 48 SkDrawShadowMetrics::GetSpotParams(occluderZ, devLightPos.fX, devLightPos.fY, 49 rec.fLightPos.fZ, rec.fLightRadius, 50 &spotBlur, &spotScale, &spotOffset); 51 } else { 52 SkScalar devToSrcScale = SkScalarInvert(ctm.getMinScale()); 53 54 // get ambient blur (in local space) 55 SkScalar devSpaceAmbientBlur = SkDrawShadowMetrics::AmbientBlurRadius(occluderZ); 56 ambientBlur = devSpaceAmbientBlur*devToSrcScale; 57 58 // get spot params (in local space) 59 SkDrawShadowMetrics::GetSpotParams(occluderZ, rec.fLightPos.fX, rec.fLightPos.fY, 60 rec.fLightPos.fZ, rec.fLightRadius, 61 &spotBlur, &spotScale, &spotOffset); 62 63 // convert spot blur to local space 64 spotBlur *= devToSrcScale; 65 } 66 67 // in both cases, adjust ambient and spot bounds 68 SkRect spotBounds = ambientBounds; 69 ambientBounds.outset(ambientBlur, ambientBlur); 70 spotBounds.fLeft *= spotScale; 71 spotBounds.fTop *= spotScale; 72 spotBounds.fRight *= spotScale; 73 spotBounds.fBottom *= spotScale; 74 spotBounds.offset(spotOffset.fX, spotOffset.fY); 75 spotBounds.outset(spotBlur, spotBlur); 76 77 // merge bounds 78 *bounds = ambientBounds; 79 bounds->join(spotBounds); 80 // outset a bit to account for floating point error 81 bounds->outset(1, 1); 82 83 // if perspective, transform back to src space 84 if (ctm.hasPerspective()) { 85 // TODO: create tighter mapping from dev rect back to src rect 86 SkMatrix inverse; 87 if (ctm.invert(&inverse)) { 88 inverse.mapRect(bounds); 89 } 90 } 91 } 92 93 94 } 95 96