xref: /aosp_15_r20/external/skia/src/effects/SkShaderMaskFilterImpl.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "src/effects/SkShaderMaskFilterImpl.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkBlendMode.h"
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkFlattenable.h"
14 #include "include/core/SkMaskFilter.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkPoint.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkScalar.h"
20 #include "include/core/SkShader.h"
21 #include "include/effects/SkShaderMaskFilter.h"
22 #include "src/core/SkMask.h"
23 #include "src/core/SkReadBuffer.h"
24 #include "src/core/SkWriteBuffer.h"
25 
26 #include <cstdint>
27 #include <cstring>
28 #include <utility>
29 
30 class SkMatrix;
31 
CreateProc(SkReadBuffer & buffer)32 sk_sp<SkFlattenable> SkShaderMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
33     return SkShaderMaskFilter::Make(buffer.readShader());
34 }
35 
flatten(SkWriteBuffer & buffer) const36 void SkShaderMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
37     buffer.writeFlattenable(fShader.get());
38 }
39 
rect_memcpy(void * dst,size_t dstRB,const void * src,size_t srcRB,size_t copyBytes,int rows)40 static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB,
41                         size_t copyBytes, int rows) {
42     for (int i = 0; i < rows; ++i) {
43         memcpy(dst, src, copyBytes);
44         dst = (char*)dst + dstRB;
45         src = (const char*)src + srcRB;
46     }
47 }
48 
filterMask(SkMaskBuilder * dst,const SkMask & src,const SkMatrix & ctm,SkIPoint * margin) const49 bool SkShaderMaskFilterImpl::filterMask(SkMaskBuilder* dst, const SkMask& src, const SkMatrix& ctm,
50                                         SkIPoint* margin) const {
51     if (src.fFormat != SkMask::kA8_Format) {
52         return false;
53     }
54 
55     if (margin) {
56         margin->set(0, 0);
57     }
58     dst->bounds()   = src.fBounds;
59     dst->rowBytes() = src.fBounds.width();   // need alignment?
60     dst->format()   = SkMask::kA8_Format;
61 
62     if (src.fImage == nullptr) {
63         dst->image() = nullptr;
64         return true;
65     }
66     size_t size = dst->computeImageSize();
67     if (0 == size) {
68         return false;   // too big to allocate, abort
69     }
70 
71     // Allocate and initialize dst image with a copy of the src image
72     dst->image() = SkMaskBuilder::AllocImage(size);
73     rect_memcpy(dst->image(), dst->fRowBytes, src.fImage, src.fRowBytes,
74                 src.fBounds.width() * sizeof(uint8_t), src.fBounds.height());
75 
76     // Now we have a dst-mask, just need to setup a canvas and draw into it
77     SkBitmap bitmap;
78     if (!bitmap.installMaskPixels(*dst)) {
79         return false;
80     }
81 
82     SkPaint paint;
83     paint.setShader(fShader);
84     // this blendmode is the trick: we only draw the shader where the mask is
85     paint.setBlendMode(SkBlendMode::kSrcIn);
86 
87     SkCanvas canvas(bitmap);
88     canvas.translate(-SkIntToScalar(dst->fBounds.fLeft), -SkIntToScalar(dst->fBounds.fTop));
89     canvas.concat(ctm);
90     canvas.drawPaint(paint);
91     return true;
92 }
93 
Make(sk_sp<SkShader> shader)94 sk_sp<SkMaskFilter> SkShaderMaskFilter::Make(sk_sp<SkShader> shader) {
95     return shader ? sk_sp<SkMaskFilter>(new SkShaderMaskFilterImpl(std::move(shader))) : nullptr;
96 }
97 
RegisterFlattenables()98 void SkShaderMaskFilter::RegisterFlattenables() {
99     SK_REGISTER_FLATTENABLE(SkShaderMaskFilterImpl);
100     // Previous name
101     SkFlattenable::Register("SkShaderMF", SkShaderMaskFilterImpl::CreateProc);
102 }
103