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