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