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