13c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth/*
22103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth * Copyright 2017 Google Inc.
33c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth *
43c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth * Use of this source code is governed by a BSD-style license that can be
53c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth * found in the LICENSE file.
63c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth */
73c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
82103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth#include "SkSpotShadowMaskFilter.h"
93c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "SkReadBuffer.h"
103c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "SkStringUtils.h"
113c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "SkWriteBuffer.h"
123c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
133c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#if SK_SUPPORT_GPU
143c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "GrContext.h"
153c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "GrRenderTargetContext.h"
163c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "GrFragmentProcessor.h"
173c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "GrStyle.h"
183c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "GrTexture.h"
194a24da5ceccbbd5eb91c75ce680c42191a5342d0Robert Phillips#include "GrTextureProxy.h"
203c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#include "SkStrokeRec.h"
213c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#endif
223c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
232103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthclass SkSpotShadowMaskFilterImpl : public SkMaskFilter {
243c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verthpublic:
252103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth    SkSpotShadowMaskFilterImpl(SkScalar occluderHeight, const SkPoint3& lightPos,
262103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                               SkScalar lightRadius, SkScalar spotAlpha, uint32_t flags);
273c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
283c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // overrides from SkMaskFilter
293c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkMask::Format getFormat() const override;
303c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
313c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                    SkIPoint* margin) const override;
323c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
333c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#if SK_SUPPORT_GPU
343c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    bool canFilterMaskGPU(const SkRRect& devRRect,
353c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                          const SkIRect& clipBounds,
363c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                          const SkMatrix& ctm,
373c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                          SkRect* maskRect) const override;
38d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips    bool directFilterMaskGPU(GrContext*,
393c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                             GrRenderTargetContext* drawContext,
4082f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon                             GrPaint&&,
413c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                             const GrClip&,
423c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                             const SkMatrix& viewMatrix,
433c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                             const SkStrokeRec& strokeRec,
443c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                             const SkPath& path) const override;
453c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    bool directFilterRRectMaskGPU(GrContext*,
463c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                  GrRenderTargetContext* drawContext,
4782f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon                                  GrPaint&&,
483c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                  const GrClip&,
493c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                  const SkMatrix& viewMatrix,
503c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                  const SkStrokeRec& strokeRec,
513c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                  const SkRRect& rrect,
523c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                  const SkRRect& devRRect) const override;
534a24da5ceccbbd5eb91c75ce680c42191a5342d0Robert Phillips    sk_sp<GrTextureProxy> filterMaskGPU(GrContext*,
544a24da5ceccbbd5eb91c75ce680c42191a5342d0Robert Phillips                                        sk_sp<GrTextureProxy> srcProxy,
554a24da5ceccbbd5eb91c75ce680c42191a5342d0Robert Phillips                                        const SkMatrix& ctm,
564a24da5ceccbbd5eb91c75ce680c42191a5342d0Robert Phillips                                        const SkIRect& maskRect) const override;
573c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#endif
583c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
593c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    void computeFastBounds(const SkRect&, SkRect*) const override;
603c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
613c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SK_TO_STRING_OVERRIDE()
622103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotShadowMaskFilterImpl)
633c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
643c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verthprivate:
653c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkScalar fOccluderHeight;
663c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkPoint3 fLightPos;
673c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkScalar fLightRadius;
683c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkScalar fSpotAlpha;
693c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    uint32_t fFlags;
703c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
712103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth    SkSpotShadowMaskFilterImpl(SkReadBuffer&);
723c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    void flatten(SkWriteBuffer&) const override;
733c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
742103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth    friend class SkSpotShadowMaskFilter;
753c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
763c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    typedef SkMaskFilter INHERITED;
773c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth};
783c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
792103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthsk_sp<SkMaskFilter> SkSpotShadowMaskFilter::Make(SkScalar occluderHeight, const SkPoint3& lightPos,
802103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                 SkScalar lightRadius, SkScalar spotAlpha,
812103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                 uint32_t flags) {
823c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // add some param checks here for early exit
833c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
842103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth    return sk_sp<SkMaskFilter>(new SkSpotShadowMaskFilterImpl(occluderHeight, lightPos,
852103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                              lightRadius, spotAlpha, flags));
863c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
873c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
883c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth///////////////////////////////////////////////////////////////////////////////////////////////////
893c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
902103cf0ff09763aeaa35508734f765aec9b75665Jim Van VerthSkSpotShadowMaskFilterImpl::SkSpotShadowMaskFilterImpl(SkScalar occluderHeight,
912103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                       const SkPoint3& lightPos,
922103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                       SkScalar lightRadius,
932103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                       SkScalar spotAlpha,
942103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                       uint32_t flags)
953c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    : fOccluderHeight(occluderHeight)
963c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    , fLightPos(lightPos)
973c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    , fLightRadius(lightRadius)
983c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    , fSpotAlpha(spotAlpha)
993c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    , fFlags(flags) {
1003c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkASSERT(fOccluderHeight > 0);
1013c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkASSERT(fLightPos.z() > 0 && fLightPos.z() > fOccluderHeight);
1023c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkASSERT(fLightRadius > 0);
1033c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkASSERT(fSpotAlpha >= 0);
1043c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
1053c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1062103cf0ff09763aeaa35508734f765aec9b75665Jim Van VerthSkMask::Format SkSpotShadowMaskFilterImpl::getFormat() const {
1073c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    return SkMask::kA8_Format;
1083c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
1093c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1102103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthbool SkSpotShadowMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
1112103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                            const SkMatrix& matrix,
1122103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                            SkIPoint* margin) const {
1133c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // TODO something
1143c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    return false;
1153c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
1163c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1172103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthvoid SkSpotShadowMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) const {
1183c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // TODO compute based on ambient + spot data
1193c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    dst->set(src.fLeft, src.fTop, src.fRight, src.fBottom);
1203c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
1213c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1222103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthsk_sp<SkFlattenable> SkSpotShadowMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
1233c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const SkScalar occluderHeight = buffer.readScalar();
1243c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const SkScalar lightX = buffer.readScalar();
1253c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const SkScalar lightY = buffer.readScalar();
1263c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const SkScalar lightZ = buffer.readScalar();
1273c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const SkPoint3 lightPos = SkPoint3::Make(lightX, lightY, lightZ);
1283c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const SkScalar lightRadius = buffer.readScalar();
1293c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const SkScalar spotAlpha = buffer.readScalar();
1303c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const uint32_t flags = buffer.readUInt();
1313c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1322103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth    return SkSpotShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius,
1332103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                        spotAlpha, flags);
1343c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
1353c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1362103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthvoid SkSpotShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
1373c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    buffer.writeScalar(fOccluderHeight);
1383c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    buffer.writeScalar(fLightPos.fX);
1393c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    buffer.writeScalar(fLightPos.fY);
1403c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    buffer.writeScalar(fLightPos.fZ);
1413c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    buffer.writeScalar(fLightRadius);
1423c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    buffer.writeScalar(fSpotAlpha);
1433c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    buffer.writeUInt(fFlags);
1443c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
1453c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1463c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#if SK_SUPPORT_GPU
1473c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1483c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth///////////////////////////////////////////////////////////////////////////////////////////////////
1493c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1502103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthbool SkSpotShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
1512103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                  const SkIRect& clipBounds,
1522103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                  const SkMatrix& ctm,
1532103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                  SkRect* maskRect) const {
1543c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // TODO
1553c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    *maskRect = devRRect.rect();
1563c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    return true;
1573c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
1583c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
159d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillipsbool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrContext* context,
16091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth                                                     GrRenderTargetContext* rtContext,
1612103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                     GrPaint&& paint,
1622103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                     const GrClip& clip,
1632103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                     const SkMatrix& viewMatrix,
1642103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                     const SkStrokeRec& strokeRec,
1652103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                     const SkPath& path) const {
16691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    SkASSERT(rtContext);
1673c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // TODO: this will not handle local coordinates properly
1683c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
16991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (fSpotAlpha <= 0.0f) {
17091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        return true;
17191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
17291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
17391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    // only convex paths for now
17491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (!path.isConvex()) {
17591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        return false;
17691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
17791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
17891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    if (strokeRec.getStyle() != SkStrokeRec::kFill_Style) {
17991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth        return false;
18091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth    }
18191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
1823c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // if circle
1833c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we
1843c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // have our own GeometryProc.
1853c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) {
1863c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkRRect rrect = SkRRect::MakeOval(path.getBounds());
187d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips        return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip,
18882f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon                                              SkMatrix::I(), strokeRec, rrect, rrect);
1893c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    } else if (path.isRect(nullptr)) {
1903c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkRRect rrect = SkRRect::MakeRect(path.getBounds());
191d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips        return this->directFilterRRectMaskGPU(context, rtContext, std::move(paint), clip,
19282f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon                                              SkMatrix::I(), strokeRec, rrect, rrect);
1933c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    }
19491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth
195efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth    return false;
1963c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
1973c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
1982103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthbool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
1992103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                          GrRenderTargetContext* rtContext,
2002103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                          GrPaint&& paint,
2012103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                          const GrClip& clip,
2022103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                          const SkMatrix& viewMatrix,
2032103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                          const SkStrokeRec& strokeRec,
2042103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                          const SkRRect& rrect,
2052103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                          const SkRRect& devRRect) const {
2063c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // It's likely the caller has already done these checks, but we have to be sure.
2073c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // TODO: support analytic blurring of general rrect
2083c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2093c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // Fast path only supports filled rrects for now.
2103c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // TODO: fill and stroke as well.
2113c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    if (SkStrokeRec::kFill_Style != strokeRec.getStyle()) {
2123c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        return false;
2133c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    }
2143c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // Fast path only supports simple rrects with circular corners.
2153c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkASSERT(devRRect.allCornersCircular());
2163c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    if (!rrect.isRect() && !rrect.isOval() && !rrect.isSimple()) {
2173c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        return false;
2183c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    }
2193c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // Fast path only supports uniform scale.
2203c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkScalar scaleFactors[2];
2213c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    if (!viewMatrix.getMinMaxScales(scaleFactors)) {
2223c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // matrix is degenerate
2233c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        return false;
2243c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    }
2253c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    if (scaleFactors[0] != scaleFactors[1]) {
2263c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        return false;
2273c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    }
2283c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    SkScalar scaleFactor = scaleFactors[0];
2293c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2303c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
2313c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    const SkScalar minRadius = 0.5f / scaleFactor;
2323c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    bool isRect = rrect.getSimpleRadii().fX <= minRadius;
2333c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2343c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    // TODO: take flags into account when generating shadow data
2353c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2363c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    if (fSpotAlpha > 0.0f) {
2373c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        float zRatio = SkTPin(fOccluderHeight / (fLightPos.fZ - fOccluderHeight), 0.0f, 0.95f);
2383c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2393c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkScalar srcSpaceSpotRadius = 2.0f * fLightRadius * zRatio;
2403c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2413c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkRRect spotRRect;
2423c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        if (isRect) {
2433c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            spotRRect = SkRRect::MakeRectXY(rrect.rect(), minRadius, minRadius);
2443c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        } else {
2453c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            spotRRect = rrect;
2463c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        }
2473c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2483c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkRRect spotShadowRRect;
2493c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // Compute the scale and translation for the spot shadow.
2503c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        const SkScalar scale = fLightPos.fZ / (fLightPos.fZ - fOccluderHeight);
2513c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect);
2523c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2533c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(),
2543c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                       spotShadowRRect.rect().centerY());
2553c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkMatrix ctmInverse;
2563c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        if (!viewMatrix.invert(&ctmInverse)) {
2573c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            SkDebugf("Matrix is degenerate. Will not render spot shadow!\n");
2583c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            //**** TODO: this is not good
2593c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            return true;
2603c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        }
2613c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkPoint lightPos2D = SkPoint::Make(fLightPos.fX, fLightPos.fY);
2623c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        ctmInverse.mapPoints(&lightPos2D, 1);
2633c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
2643c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                                 zRatio*(center.fY - lightPos2D.fY));
2653c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2663c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // We want to extend the stroked area in so that it meets up with the caster
2673c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // geometry. The stroked geometry will, by definition already be inset half the
2683c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // stroke width but we also have to account for the scaling.
2693c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(rrect.rect().fLeft),
2703c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                                              SkTAbs(rrect.rect().fRight)),
2713c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                                       SkTMax(SkTAbs(rrect.rect().fTop),
2723c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                                              SkTAbs(rrect.rect().fBottom)));
273c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) + scaleOffset;
2743c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
2753c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // Compute area
2763c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount;
2773c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkScalar strokedArea = 2.0f*strokeWidth *
2783c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                               (spotShadowRRect.width() + spotShadowRRect.height());
2793c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius) *
2803c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                              (spotShadowRRect.width() + srcSpaceSpotRadius);
2813c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
28282f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon        GrColor4f color = paint.getColor4f();
283c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        color.fRGBA[3] *= fSpotAlpha;
28482f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon        paint.setColor4f(color);
28582f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon
2863c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkStrokeRec spotStrokeRec(SkStrokeRec::kFill_InitStyle);
2873c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // If the area of the stroked geometry is larger than the fill geometry,
2883c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // or if the caster is transparent, just fill it.
2893c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        if (strokedArea > filledArea ||
2902103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth            fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag) {
2913c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            spotStrokeRec.setStrokeStyle(srcSpaceSpotRadius, true);
2923c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        } else {
2933c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            // Since we can't have unequal strokes, inset the shadow rect so the inner
2943c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            // and outer edges of the stroke will land where we want.
2953c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            SkRect insetRect = spotShadowRRect.rect().makeInset(insetAmount / 2.0f,
2963c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                                                insetAmount / 2.0f);
2973c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            SkScalar insetRad = SkTMax(spotShadowRRect.getSimpleRadii().fX - insetAmount / 2.0f,
2983c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                                       minRadius);
2993c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            spotShadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
3003c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth            spotStrokeRec.setStrokeStyle(strokeWidth, false);
3013c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        }
3023c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3033c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        // handle scale of radius and pad due to CTM
3043c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor;
3053c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
306c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        spotShadowRRect.offset(spotOffset.fX, spotOffset.fY);
3073c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3082103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth        rtContext->drawShadowRRect(clip, std::move(paint), viewMatrix, spotShadowRRect,
3092103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                   devSpaceSpotRadius, GrStyle(spotStrokeRec, nullptr));
3103c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    }
3113c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3123c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    return true;
3133c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
3143c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3152103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthsk_sp<GrTextureProxy> SkSpotShadowMaskFilterImpl::filterMaskGPU(GrContext*,
3162103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                                sk_sp<GrTextureProxy> srcProxy,
3172103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                                const SkMatrix& ctm,
3182103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                                                                const SkIRect& maskRect) const {
319e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips    // This filter is generative and doesn't operate on pre-existing masks
3204a24da5ceccbbd5eb91c75ce680c42191a5342d0Robert Phillips    return nullptr;
3213c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
3223c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3233c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#endif
3243c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3253c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#ifndef SK_IGNORE_TO_STRING
3262103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verthvoid SkSpotShadowMaskFilterImpl::toString(SkString* str) const {
3272103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth    str->append("SkSpotShadowMaskFilterImpl: (");
3283c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3293c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append("occluderHeight: ");
3303c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->appendScalar(fOccluderHeight);
3313c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append(" ");
3323c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3333c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append("lightPos: (");
3343c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->appendScalar(fLightPos.fX);
3353c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append(", ");
3363c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->appendScalar(fLightPos.fY);
3373c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append(", ");
3383c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->appendScalar(fLightPos.fZ);
3393c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append(") ");
3403c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3413c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append("lightRadius: ");
3423c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->appendScalar(fLightRadius);
3433c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append(" ");
3443c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3453c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append("spotAlpha: ");
3463c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->appendScalar(fSpotAlpha);
3473c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append(" ");
3483c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3493c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append("flags: (");
3503c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    if (fFlags) {
3513c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        bool needSeparator = false;
3523c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkAddFlagToString(str,
3532103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                          SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag),
3543c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                          "TransparentOccluder", &needSeparator);
3553c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkAddFlagToString(str,
3562103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                          SkToBool(fFlags & SkShadowFlags::kGaussianEdge_ShadowFlag),
3573c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                          "GaussianEdge", &needSeparator);
3583c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        SkAddFlagToString(str,
3592103cf0ff09763aeaa35508734f765aec9b75665Jim Van Verth                          SkToBool(fFlags & SkShadowFlags::kLargerUmbra_ShadowFlag),
3603c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth                          "LargerUmbra", &needSeparator);
3613c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    } else {
3623c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth        str->append("None");
3633c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    }
3643c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth    str->append("))");
3653c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth}
3663c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth#endif
3673c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van Verth
3682103cf0ff09763aeaa35508734f765aec9b75665Jim Van VerthSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkSpotShadowMaskFilter)
3692103cf0ff09763aeaa35508734f765aec9b75665Jim Van VerthSK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotShadowMaskFilterImpl)
3703c1b7db2432d136df0fc50c2e3ee0b3792b01dd6Jim Van VerthSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
371