blob: 74352acb65e4183a998b48d30f8bc779907caff5 [file] [log] [blame]
Mike Reed6e87eee2018-01-18 16:06:54 -05001/*
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"
Mike Reed80747ef2018-01-23 15:29:32 -05009#include "SkMaskFilterBase.h"
Mike Reed6e87eee2018-01-18 16:06:54 -050010#include "SkReadBuffer.h"
11#include "SkShaderMaskFilter.h"
Mike Reed28eaed22018-02-01 11:24:53 -050012#include "SkShaderBase.h"
Mike Reed6e87eee2018-01-18 16:06:54 -050013#include "SkString.h"
14
Mike Reed80747ef2018-01-23 15:29:32 -050015class SkShaderMF : public SkMaskFilterBase {
Mike Reed6e87eee2018-01-18 16:06:54 -050016public:
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
Mike Reed28eaed22018-02-01 11:24:53 -050033protected:
34#if SK_SUPPORT_GPU
35 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs&) const override;
36 bool onHasFragmentProcessor() const override;
37#endif
38
Mike Reed6e87eee2018-01-18 16:06:54 -050039private:
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
51void SkShaderMF::toString(SkString* str) const {
52 str->set("SkShaderMF:");
53}
54#endif
55
56sk_sp<SkFlattenable> SkShaderMF::CreateProc(SkReadBuffer& buffer) {
57 return SkShaderMaskFilter::Make(buffer.readShader());
58}
59
60void SkShaderMF::flatten(SkWriteBuffer& buffer) const {
61 buffer.writeFlattenable(fShader.get());
62}
63
64static 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
73bool 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///////////////////////////////////////////////////////////////////////////////////////////////////
Mike Reed28eaed22018-02-01 11:24:53 -0500117#if SK_SUPPORT_GPU
118#include "GrFragmentProcessor.h"
119
120std::unique_ptr<GrFragmentProcessor> SkShaderMF::onAsFragmentProcessor(const GrFPArgs& args) const {
121 return GrFragmentProcessor::MulInputByChildAlpha(as_SB(fShader)->asFragmentProcessor(args));
122}
123
124bool SkShaderMF::onHasFragmentProcessor() const {
125 return true;
126}
127
128#endif
129///////////////////////////////////////////////////////////////////////////////////////////////////
Mike Reed6e87eee2018-01-18 16:06:54 -0500130
131sk_sp<SkMaskFilter> SkShaderMaskFilter::Make(sk_sp<SkShader> shader) {
132 return shader ? sk_sp<SkMaskFilter>(new SkShaderMF(std::move(shader))) : nullptr;
133}
134
135SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderMaskFilter)
136 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkShaderMF)
137SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END