Home | History | Annotate | Download | only in core
      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