LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/effects/shadows - SkSpotShadowMaskFilter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 157 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "SkSpotShadowMaskFilter.h"
       9             : #include "SkReadBuffer.h"
      10             : #include "SkStringUtils.h"
      11             : #include "SkWriteBuffer.h"
      12             : 
      13             : #if SK_SUPPORT_GPU
      14             : #include "GrContext.h"
      15             : #include "GrRenderTargetContext.h"
      16             : #include "GrFragmentProcessor.h"
      17             : #include "GrStyle.h"
      18             : #include "GrTexture.h"
      19             : #include "GrTextureProxy.h"
      20             : #include "SkStrokeRec.h"
      21             : #endif
      22             : 
      23           0 : class SkSpotShadowMaskFilterImpl : public SkMaskFilter {
      24             : public:
      25             :     SkSpotShadowMaskFilterImpl(SkScalar occluderHeight, const SkPoint3& lightPos,
      26             :                                SkScalar lightRadius, SkScalar spotAlpha, uint32_t flags);
      27             : 
      28             :     // overrides from SkMaskFilter
      29             :     SkMask::Format getFormat() const override;
      30             :     bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
      31             :                     SkIPoint* margin) const override;
      32             : 
      33             : #if SK_SUPPORT_GPU
      34             :     bool canFilterMaskGPU(const SkRRect& devRRect,
      35             :                           const SkIRect& clipBounds,
      36             :                           const SkMatrix& ctm,
      37             :                           SkRect* maskRect) const override;
      38             :     bool directFilterMaskGPU(GrContext*,
      39             :                              GrRenderTargetContext* drawContext,
      40             :                              GrPaint&&,
      41             :                              const GrClip&,
      42             :                              const SkMatrix& viewMatrix,
      43             :                              const SkStrokeRec& strokeRec,
      44             :                              const SkPath& path) const override;
      45             :     bool directFilterRRectMaskGPU(GrContext*,
      46             :                                   GrRenderTargetContext* drawContext,
      47             :                                   GrPaint&&,
      48             :                                   const GrClip&,
      49             :                                   const SkMatrix& viewMatrix,
      50             :                                   const SkStrokeRec& strokeRec,
      51             :                                   const SkRRect& rrect,
      52             :                                   const SkRRect& devRRect) const override;
      53             :     sk_sp<GrTextureProxy> filterMaskGPU(GrContext*,
      54             :                                         sk_sp<GrTextureProxy> srcProxy,
      55             :                                         const SkMatrix& ctm,
      56             :                                         const SkIRect& maskRect) const override;
      57             : #endif
      58             : 
      59             :     void computeFastBounds(const SkRect&, SkRect*) const override;
      60             : 
      61             :     SK_TO_STRING_OVERRIDE()
      62           0 :     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotShadowMaskFilterImpl)
      63             : 
      64             : private:
      65             :     SkScalar fOccluderHeight;
      66             :     SkPoint3 fLightPos;
      67             :     SkScalar fLightRadius;
      68             :     SkScalar fSpotAlpha;
      69             :     uint32_t fFlags;
      70             : 
      71             :     SkSpotShadowMaskFilterImpl(SkReadBuffer&);
      72             :     void flatten(SkWriteBuffer&) const override;
      73             : 
      74             :     friend class SkSpotShadowMaskFilter;
      75             : 
      76             :     typedef SkMaskFilter INHERITED;
      77             : };
      78             : 
      79           0 : sk_sp<SkMaskFilter> SkSpotShadowMaskFilter::Make(SkScalar occluderHeight, const SkPoint3& lightPos,
      80             :                                                  SkScalar lightRadius, SkScalar spotAlpha,
      81             :                                                  uint32_t flags) {
      82             :     // add some param checks here for early exit
      83             : 
      84             :     return sk_sp<SkMaskFilter>(new SkSpotShadowMaskFilterImpl(occluderHeight, lightPos,
      85           0 :                                                               lightRadius, spotAlpha, flags));
      86             : }
      87             : 
      88             : ///////////////////////////////////////////////////////////////////////////////////////////////////
      89             : 
      90           0 : SkSpotShadowMaskFilterImpl::SkSpotShadowMaskFilterImpl(SkScalar occluderHeight,
      91             :                                                        const SkPoint3& lightPos,
      92             :                                                        SkScalar lightRadius,
      93             :                                                        SkScalar spotAlpha,
      94           0 :                                                        uint32_t flags)
      95             :     : fOccluderHeight(occluderHeight)
      96             :     , fLightPos(lightPos)
      97             :     , fLightRadius(lightRadius)
      98             :     , fSpotAlpha(spotAlpha)
      99           0 :     , fFlags(flags) {
     100           0 :     SkASSERT(fOccluderHeight > 0);
     101           0 :     SkASSERT(fLightPos.z() > 0 && fLightPos.z() > fOccluderHeight);
     102           0 :     SkASSERT(fLightRadius > 0);
     103           0 :     SkASSERT(fSpotAlpha >= 0);
     104           0 : }
     105             : 
     106           0 : SkMask::Format SkSpotShadowMaskFilterImpl::getFormat() const {
     107           0 :     return SkMask::kA8_Format;
     108             : }
     109             : 
     110           0 : bool SkSpotShadowMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
     111             :                                             const SkMatrix& matrix,
     112             :                                             SkIPoint* margin) const {
     113             :     // TODO something
     114           0 :     return false;
     115             : }
     116             : 
     117           0 : void SkSpotShadowMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) const {
     118             :     // TODO compute based on ambient + spot data
     119           0 :     dst->set(src.fLeft, src.fTop, src.fRight, src.fBottom);
     120           0 : }
     121             : 
     122           0 : sk_sp<SkFlattenable> SkSpotShadowMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
     123           0 :     const SkScalar occluderHeight = buffer.readScalar();
     124           0 :     const SkScalar lightX = buffer.readScalar();
     125           0 :     const SkScalar lightY = buffer.readScalar();
     126           0 :     const SkScalar lightZ = buffer.readScalar();
     127           0 :     const SkPoint3 lightPos = SkPoint3::Make(lightX, lightY, lightZ);
     128           0 :     const SkScalar lightRadius = buffer.readScalar();
     129           0 :     const SkScalar spotAlpha = buffer.readScalar();
     130           0 :     const uint32_t flags = buffer.readUInt();
     131             : 
     132           0 :     return SkSpotShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius,
     133           0 :                                         spotAlpha, flags);
     134             : }
     135             : 
     136           0 : void SkSpotShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
     137           0 :     buffer.writeScalar(fOccluderHeight);
     138           0 :     buffer.writeScalar(fLightPos.fX);
     139           0 :     buffer.writeScalar(fLightPos.fY);
     140           0 :     buffer.writeScalar(fLightPos.fZ);
     141           0 :     buffer.writeScalar(fLightRadius);
     142           0 :     buffer.writeScalar(fSpotAlpha);
     143           0 :     buffer.writeUInt(fFlags);
     144           0 : }
     145             : 
     146             : #if SK_SUPPORT_GPU
     147             : 
     148             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     149             : 
     150           0 : bool SkSpotShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
     151             :                                                   const SkIRect& clipBounds,
     152             :                                                   const SkMatrix& ctm,
     153             :                                                   SkRect* maskRect) const {
     154             :     // TODO
     155           0 :     *maskRect = devRRect.rect();
     156           0 :     return true;
     157             : }
     158             : 
     159           0 : bool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrContext* context,
     160             :                                                      GrRenderTargetContext* rtContext,
     161             :                                                      GrPaint&& paint,
     162             :                                                      const GrClip& clip,
     163             :                                                      const SkMatrix& viewMatrix,
     164             :                                                      const SkStrokeRec& strokeRec,
     165             :                                                      const SkPath& path) const {
     166           0 :     SkASSERT(rtContext);
     167             :     // TODO: this will not handle local coordinates properly
     168             : 
     169           0 :     if (fSpotAlpha <= 0.0f) {
     170           0 :         return true;
     171             :     }
     172             : 
     173             :     // only convex paths for now
     174           0 :     if (!path.isConvex()) {
     175           0 :         return false;
     176             :     }
     177             : 
     178           0 :     if (strokeRec.getStyle() != SkStrokeRec::kFill_Style) {
     179           0 :         return false;
     180             :     }
     181             : 
     182             :     // if circle
     183             :     // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we
     184             :     // have our own GeometryProc.
     185           0 :     if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) {
     186           0 :         SkRRect rrect = SkRRect::MakeOval(path.getBounds());
     187           0 :         return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip,
     188           0 :                                               SkMatrix::I(), strokeRec, rrect, rrect);
     189           0 :     } else if (path.isRect(nullptr)) {
     190           0 :         SkRRect rrect = SkRRect::MakeRect(path.getBounds());
     191           0 :         return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip,
     192           0 :                                               SkMatrix::I(), strokeRec, rrect, rrect);
     193             :     }
     194             : 
     195           0 :     return false;
     196             : }
     197             : 
     198           0 : bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
     199             :                                                           GrRenderTargetContext* rtContext,
     200             :                                                           GrPaint&& paint,
     201             :                                                           const GrClip& clip,
     202             :                                                           const SkMatrix& viewMatrix,
     203             :                                                           const SkStrokeRec& strokeRec,
     204             :                                                           const SkRRect& rrect,
     205             :                                                           const SkRRect& devRRect) const {
     206             :     // It's likely the caller has already done these checks, but we have to be sure.
     207             :     // TODO: support analytic blurring of general rrect
     208             : 
     209             :     // Fast path only supports filled rrects for now.
     210             :     // TODO: fill and stroke as well.
     211           0 :     if (SkStrokeRec::kFill_Style != strokeRec.getStyle()) {
     212           0 :         return false;
     213             :     }
     214             :     // Fast path only supports simple rrects with circular corners.
     215           0 :     SkASSERT(devRRect.allCornersCircular());
     216           0 :     if (!rrect.isRect() && !rrect.isOval() && !rrect.isSimple()) {
     217           0 :         return false;
     218             :     }
     219             :     // Fast path only supports uniform scale.
     220             :     SkScalar scaleFactors[2];
     221           0 :     if (!viewMatrix.getMinMaxScales(scaleFactors)) {
     222             :         // matrix is degenerate
     223           0 :         return false;
     224             :     }
     225           0 :     if (scaleFactors[0] != scaleFactors[1]) {
     226           0 :         return false;
     227             :     }
     228           0 :     SkScalar scaleFactor = scaleFactors[0];
     229             : 
     230             :     // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
     231           0 :     const SkScalar minRadius = 0.5f / scaleFactor;
     232           0 :     bool isRect = rrect.getSimpleRadii().fX <= minRadius;
     233             : 
     234             :     // TODO: take flags into account when generating shadow data
     235             : 
     236           0 :     if (fSpotAlpha > 0.0f) {
     237           0 :         float zRatio = SkTPin(fOccluderHeight / (fLightPos.fZ - fOccluderHeight), 0.0f, 0.95f);
     238             : 
     239           0 :         SkScalar srcSpaceSpotRadius = 2.0f * fLightRadius * zRatio;
     240             : 
     241           0 :         SkRRect spotRRect;
     242           0 :         if (isRect) {
     243           0 :             spotRRect = SkRRect::MakeRectXY(rrect.rect(), minRadius, minRadius);
     244             :         } else {
     245           0 :             spotRRect = rrect;
     246             :         }
     247             : 
     248           0 :         SkRRect spotShadowRRect;
     249             :         // Compute the scale and translation for the spot shadow.
     250           0 :         const SkScalar scale = fLightPos.fZ / (fLightPos.fZ - fOccluderHeight);
     251           0 :         spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect);
     252             : 
     253           0 :         SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(),
     254           0 :                                        spotShadowRRect.rect().centerY());
     255             :         SkMatrix ctmInverse;
     256           0 :         if (!viewMatrix.invert(&ctmInverse)) {
     257           0 :             SkDebugf("Matrix is degenerate. Will not render spot shadow!\n");
     258             :             //**** TODO: this is not good
     259           0 :             return true;
     260             :         }
     261           0 :         SkPoint lightPos2D = SkPoint::Make(fLightPos.fX, fLightPos.fY);
     262           0 :         ctmInverse.mapPoints(&lightPos2D, 1);
     263           0 :         const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
     264           0 :                                                  zRatio*(center.fY - lightPos2D.fY));
     265             : 
     266             :         // We want to extend the stroked area in so that it meets up with the caster
     267             :         // geometry. The stroked geometry will, by definition already be inset half the
     268             :         // stroke width but we also have to account for the scaling.
     269           0 :         SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(rrect.rect().fLeft),
     270           0 :                                                               SkTAbs(rrect.rect().fRight)),
     271           0 :                                                        SkTMax(SkTAbs(rrect.rect().fTop),
     272           0 :                                                               SkTAbs(rrect.rect().fBottom)));
     273           0 :         SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) + scaleOffset;
     274             : 
     275             :         // Compute area
     276           0 :         SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount;
     277           0 :         SkScalar strokedArea = 2.0f*strokeWidth *
     278           0 :                                (spotShadowRRect.width() + spotShadowRRect.height());
     279           0 :         SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius) *
     280           0 :                               (spotShadowRRect.width() + srcSpaceSpotRadius);
     281             : 
     282           0 :         GrColor4f color = paint.getColor4f();
     283           0 :         color.fRGBA[3] *= fSpotAlpha;
     284           0 :         paint.setColor4f(color);
     285             : 
     286           0 :         SkStrokeRec spotStrokeRec(SkStrokeRec::kFill_InitStyle);
     287             :         // If the area of the stroked geometry is larger than the fill geometry,
     288             :         // or if the caster is transparent, just fill it.
     289           0 :         if (strokedArea > filledArea ||
     290           0 :             fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag) {
     291           0 :             spotStrokeRec.setStrokeStyle(srcSpaceSpotRadius, true);
     292             :         } else {
     293             :             // Since we can't have unequal strokes, inset the shadow rect so the inner
     294             :             // and outer edges of the stroke will land where we want.
     295           0 :             SkRect insetRect = spotShadowRRect.rect().makeInset(insetAmount / 2.0f,
     296           0 :                                                                 insetAmount / 2.0f);
     297           0 :             SkScalar insetRad = SkTMax(spotShadowRRect.getSimpleRadii().fX - insetAmount / 2.0f,
     298           0 :                                        minRadius);
     299           0 :             spotShadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
     300           0 :             spotStrokeRec.setStrokeStyle(strokeWidth, false);
     301             :         }
     302             : 
     303             :         // handle scale of radius and pad due to CTM
     304           0 :         const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor;
     305             : 
     306           0 :         spotShadowRRect.offset(spotOffset.fX, spotOffset.fY);
     307             : 
     308           0 :         rtContext->drawShadowRRect(clip, std::move(paint), viewMatrix, spotShadowRRect,
     309           0 :                                    devSpaceSpotRadius, GrStyle(spotStrokeRec, nullptr));
     310             :     }
     311             : 
     312           0 :     return true;
     313             : }
     314             : 
     315           0 : sk_sp<GrTextureProxy> SkSpotShadowMaskFilterImpl::filterMaskGPU(GrContext*,
     316             :                                                                 sk_sp<GrTextureProxy> srcProxy,
     317             :                                                                 const SkMatrix& ctm,
     318             :                                                                 const SkIRect& maskRect) const {
     319             :     // This filter is generative and doesn't operate on pre-existing masks
     320           0 :     return nullptr;
     321             : }
     322             : 
     323             : #endif
     324             : 
     325             : #ifndef SK_IGNORE_TO_STRING
     326           0 : void SkSpotShadowMaskFilterImpl::toString(SkString* str) const {
     327           0 :     str->append("SkSpotShadowMaskFilterImpl: (");
     328             : 
     329           0 :     str->append("occluderHeight: ");
     330           0 :     str->appendScalar(fOccluderHeight);
     331           0 :     str->append(" ");
     332             : 
     333           0 :     str->append("lightPos: (");
     334           0 :     str->appendScalar(fLightPos.fX);
     335           0 :     str->append(", ");
     336           0 :     str->appendScalar(fLightPos.fY);
     337           0 :     str->append(", ");
     338           0 :     str->appendScalar(fLightPos.fZ);
     339           0 :     str->append(") ");
     340             : 
     341           0 :     str->append("lightRadius: ");
     342           0 :     str->appendScalar(fLightRadius);
     343           0 :     str->append(" ");
     344             : 
     345           0 :     str->append("spotAlpha: ");
     346           0 :     str->appendScalar(fSpotAlpha);
     347           0 :     str->append(" ");
     348             : 
     349           0 :     str->append("flags: (");
     350           0 :     if (fFlags) {
     351           0 :         bool needSeparator = false;
     352           0 :         SkAddFlagToString(str,
     353           0 :                           SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag),
     354           0 :                           "TransparentOccluder", &needSeparator);
     355           0 :         SkAddFlagToString(str,
     356           0 :                           SkToBool(fFlags & SkShadowFlags::kGaussianEdge_ShadowFlag),
     357           0 :                           "GaussianEdge", &needSeparator);
     358           0 :         SkAddFlagToString(str,
     359           0 :                           SkToBool(fFlags & SkShadowFlags::kLargerUmbra_ShadowFlag),
     360           0 :                           "LargerUmbra", &needSeparator);
     361             :     } else {
     362           0 :         str->append("None");
     363             :     }
     364           0 :     str->append("))");
     365           0 : }
     366             : #endif
     367             : 
     368           0 : SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkSpotShadowMaskFilter)
     369           0 : SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotShadowMaskFilterImpl)
     370           0 : SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END

Generated by: LCOV version 1.13