Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2018 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 "SkCanvas.h"
      9 #include "SkMaskFilterBase.h"
     10 #include "SkReadBuffer.h"
     11 #include "SkShaderMaskFilter.h"
     12 #include "SkShaderBase.h"
     13 #include "SkString.h"
     14 
     15 class SkShaderMF : public SkMaskFilterBase {
     16 public:
     17     SkShaderMF(sk_sp<SkShader> shader) : fShader(std::move(shader)) {}
     18 
     19     SkMask::Format getFormat() const override { return SkMask::kA8_Format; }
     20 
     21     bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
     22                     SkIPoint* margin) const override;
     23 
     24     void computeFastBounds(const SkRect& src, SkRect* dst) const override {
     25         *dst = src;
     26     }
     27 
     28     bool asABlur(BlurRec*) const override { return false; }
     29 
     30     SK_TO_STRING_OVERRIDE()
     31     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkShaderMF)
     32 
     33 protected:
     34 #if SK_SUPPORT_GPU
     35     std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs&) const override;
     36     bool onHasFragmentProcessor() const override;
     37 #endif
     38 
     39 private:
     40     sk_sp<SkShader> fShader;
     41 
     42     SkShaderMF(SkReadBuffer&);
     43     void flatten(SkWriteBuffer&) const override;
     44 
     45     friend class SkShaderMaskFilter;
     46 
     47     typedef SkMaskFilter INHERITED;
     48 };
     49 
     50 #ifndef SK_IGNORE_TO_STRING
     51 void SkShaderMF::toString(SkString* str) const {
     52     str->set("SkShaderMF:");
     53 }
     54 #endif
     55 
     56 sk_sp<SkFlattenable> SkShaderMF::CreateProc(SkReadBuffer& buffer) {
     57     return SkShaderMaskFilter::Make(buffer.readShader());
     58 }
     59 
     60 void SkShaderMF::flatten(SkWriteBuffer& buffer) const {
     61     buffer.writeFlattenable(fShader.get());
     62 }
     63 
     64 static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB,
     65                         size_t copyBytes, int rows) {
     66     for (int i = 0; i < rows; ++i) {
     67         memcpy(dst, src, copyBytes);
     68         dst = (char*)dst + dstRB;
     69         src = (const char*)src + srcRB;
     70     }
     71 }
     72 
     73 bool SkShaderMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
     74                             SkIPoint* margin) const {
     75     SkASSERT(src.fFormat == SkMask::kA8_Format);
     76 
     77     if (margin) {
     78         margin->set(0, 0);
     79     }
     80     dst->fBounds   = src.fBounds;
     81     dst->fRowBytes = src.fBounds.width();   // need alignment?
     82     dst->fFormat   = SkMask::kA8_Format;
     83 
     84     if (src.fImage == nullptr) {
     85         dst->fImage = nullptr;
     86         return true;
     87     }
     88     size_t size = dst->computeImageSize();
     89     if (0 == size) {
     90         return false;   // too big to allocate, abort
     91     }
     92 
     93     // Allocate and initialize dst image with a copy of the src image
     94     dst->fImage = SkMask::AllocImage(size);
     95     rect_memcpy(dst->fImage, dst->fRowBytes, src.fImage, src.fRowBytes,
     96                 src.fBounds.width() * sizeof(uint8_t), src.fBounds.height());
     97 
     98     // Now we have a dst-mask, just need to setup a canvas and draw into it
     99     SkBitmap bitmap;
    100     if (!bitmap.installMaskPixels(*dst)) {
    101         return false;
    102     }
    103 
    104     SkPaint paint;
    105     paint.setShader(fShader);
    106     // this blendmode is the trick: we only draw the shader where the mask is
    107     paint.setBlendMode(SkBlendMode::kSrcIn);
    108 
    109     SkCanvas canvas(bitmap);
    110     canvas.translate(-SkIntToScalar(dst->fBounds.fLeft), -SkIntToScalar(dst->fBounds.fTop));
    111     canvas.concat(ctm);
    112     canvas.drawPaint(paint);
    113     return true;
    114 }
    115 
    116 ///////////////////////////////////////////////////////////////////////////////////////////////////
    117 #if SK_SUPPORT_GPU
    118 #include "GrFragmentProcessor.h"
    119 
    120 std::unique_ptr<GrFragmentProcessor> SkShaderMF::onAsFragmentProcessor(const GrFPArgs& args) const {
    121     return GrFragmentProcessor::MulInputByChildAlpha(as_SB(fShader)->asFragmentProcessor(args));
    122 }
    123 
    124 bool SkShaderMF::onHasFragmentProcessor() const {
    125     return true;
    126 }
    127 
    128 #endif
    129 ///////////////////////////////////////////////////////////////////////////////////////////////////
    130 
    131 sk_sp<SkMaskFilter> SkShaderMaskFilter::Make(sk_sp<SkShader> shader) {
    132     return shader ? sk_sp<SkMaskFilter>(new SkShaderMF(std::move(shader))) : nullptr;
    133 }
    134 
    135 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderMaskFilter)
    136     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkShaderMF)
    137 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
    138