xref: /aosp_15_r20/external/skia/src/effects/SkTableMaskFilter.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2011 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 "include/effects/SkTableMaskFilter.h"
9 
10 #include "include/core/SkFlattenable.h"
11 #include "include/core/SkMaskFilter.h"
12 #include "include/core/SkPoint.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkTypes.h"
17 #include "include/private/base/SkAlign.h"
18 #include "include/private/base/SkFixed.h"
19 #include "include/private/base/SkFloatingPoint.h"
20 #include "include/private/base/SkTPin.h"
21 #include "src/core/SkMask.h"
22 #include "src/core/SkMaskFilterBase.h"
23 #include "src/core/SkReadBuffer.h"
24 #include "src/core/SkWriteBuffer.h"
25 
26 #include <cmath>
27 #include <cstdint>
28 #include <cstring>
29 
30 class SkMatrix;
31 
32 class SkTableMaskFilterImpl : public SkMaskFilterBase {
33 public:
34     explicit SkTableMaskFilterImpl(const uint8_t table[256]);
35 
36     SkMask::Format getFormat() const override;
37     bool filterMask(SkMaskBuilder*, const SkMask&, const SkMatrix&, SkIPoint*) const override;
type() const38     SkMaskFilterBase::Type type() const override { return SkMaskFilterBase::Type::kTable; }
39 
40 protected:
41     ~SkTableMaskFilterImpl() override;
42 
43     void flatten(SkWriteBuffer&) const override;
44 
45 private:
46     SK_FLATTENABLE_HOOKS(SkTableMaskFilterImpl)
47 
48     SkTableMaskFilterImpl();
49 
50     uint8_t fTable[256];
51 
52     using INHERITED = SkMaskFilter;
53 };
54 
SkTableMaskFilterImpl()55 SkTableMaskFilterImpl::SkTableMaskFilterImpl() {
56     for (int i = 0; i < 256; i++) {
57         fTable[i] = i;
58     }
59 }
60 
SkTableMaskFilterImpl(const uint8_t table[256])61 SkTableMaskFilterImpl::SkTableMaskFilterImpl(const uint8_t table[256]) {
62     memcpy(fTable, table, sizeof(fTable));
63 }
64 
~SkTableMaskFilterImpl()65 SkTableMaskFilterImpl::~SkTableMaskFilterImpl() {}
66 
filterMask(SkMaskBuilder * dst,const SkMask & src,const SkMatrix &,SkIPoint * margin) const67 bool SkTableMaskFilterImpl::filterMask(SkMaskBuilder* dst, const SkMask& src,
68                                        const SkMatrix&, SkIPoint* margin) const {
69     if (src.fFormat != SkMask::kA8_Format) {
70         return false;
71     }
72 
73     dst->bounds() = src.fBounds;
74     dst->rowBytes() = SkAlign4(dst->fBounds.width());
75     dst->format() = SkMask::kA8_Format;
76     dst->image() = nullptr;
77 
78     if (src.fImage) {
79         dst->image() = SkMaskBuilder::AllocImage(dst->computeImageSize());
80 
81         const uint8_t* srcP = src.fImage;
82         uint8_t* dstP = dst->image();
83         const uint8_t* table = fTable;
84         int dstWidth = dst->fBounds.width();
85         int extraZeros = dst->fRowBytes - dstWidth;
86 
87         for (int y = dst->fBounds.height() - 1; y >= 0; --y) {
88             for (int x = dstWidth - 1; x >= 0; --x) {
89                 dstP[x] = table[srcP[x]];
90             }
91             srcP += src.fRowBytes;
92             // we can't just inc dstP by rowbytes, because if it has any
93             // padding between its width and its rowbytes, we need to zero those
94             // so that the bitters can read those safely if that is faster for
95             // them
96             dstP += dstWidth;
97             for (int i = extraZeros - 1; i >= 0; --i) {
98                 *dstP++ = 0;
99             }
100         }
101     }
102 
103     if (margin) {
104         margin->set(0, 0);
105     }
106     return true;
107 }
108 
getFormat() const109 SkMask::Format SkTableMaskFilterImpl::getFormat() const {
110     return SkMask::kA8_Format;
111 }
112 
flatten(SkWriteBuffer & wb) const113 void SkTableMaskFilterImpl::flatten(SkWriteBuffer& wb) const {
114     wb.writeByteArray(fTable, 256);
115 }
116 
CreateProc(SkReadBuffer & buffer)117 sk_sp<SkFlattenable> SkTableMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
118     uint8_t table[256];
119     if (!buffer.readByteArray(table, 256)) {
120         return nullptr;
121     }
122     return sk_sp<SkFlattenable>(SkTableMaskFilter::Create(table));
123 }
124 
125 ///////////////////////////////////////////////////////////////////////////////
126 
Create(const uint8_t table[256])127 SkMaskFilter* SkTableMaskFilter::Create(const uint8_t table[256]) {
128     return new SkTableMaskFilterImpl(table);
129 }
130 
CreateGamma(SkScalar gamma)131 SkMaskFilter* SkTableMaskFilter::CreateGamma(SkScalar gamma) {
132     uint8_t table[256];
133     MakeGammaTable(table, gamma);
134     return new SkTableMaskFilterImpl(table);
135 }
136 
CreateClip(uint8_t min,uint8_t max)137 SkMaskFilter* SkTableMaskFilter::CreateClip(uint8_t min, uint8_t max) {
138     uint8_t table[256];
139     MakeClipTable(table, min, max);
140     return new SkTableMaskFilterImpl(table);
141 }
142 
MakeGammaTable(uint8_t table[256],SkScalar gamma)143 void SkTableMaskFilter::MakeGammaTable(uint8_t table[256], SkScalar gamma) {
144     const float dx = 1 / 255.0f;
145     const float g = gamma;
146 
147     float x = 0;
148     for (int i = 0; i < 256; i++) {
149      // float ee = powf(x, g) * 255;
150         table[i] = SkTPin(sk_float_round2int(powf(x, g) * 255), 0, 255);
151         x += dx;
152     }
153 }
154 
MakeClipTable(uint8_t table[256],uint8_t min,uint8_t max)155 void SkTableMaskFilter::MakeClipTable(uint8_t table[256], uint8_t min,
156                                       uint8_t max) {
157     if (0 == max) {
158         max = 1;
159     }
160     if (min >= max) {
161         min = max - 1;
162     }
163     SkASSERT(min < max);
164 
165     SkFixed scale = (1 << 16) * 255 / (max - min);
166     memset(table, 0, min + 1);
167     for (int i = min + 1; i < max; i++) {
168         int value = SkFixedRoundToInt(scale * (i - min));
169         SkASSERT(value <= 255);
170         table[i] = value;
171     }
172     memset(table + max, 255, 256 - max);
173 
174 #if 0
175     int j;
176     for (j = 0; j < 256; j++) {
177         if (table[j]) {
178             break;
179         }
180     }
181     SkDebugf("%d %d start [%d]", min, max, j);
182     for (; j < 256; j++) {
183         SkDebugf(" %d", table[j]);
184     }
185     SkDebugf("\n\n");
186 #endif
187 }
188