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