1/*
2 * Copyright 2014 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 "SkMaskCache.h"
9
10#define CHECK_LOCAL(localCache, localName, globalName, ...) \
11    ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
12
13struct MaskValue {
14    SkMask          fMask;
15    SkCachedData*   fData;
16};
17
18namespace {
19static unsigned gRRectBlurKeyNamespaceLabel;
20
21struct RRectBlurKey : public SkResourceCache::Key {
22public:
23    RRectBlurKey(SkScalar sigma, const SkRRect& rrect, SkBlurStyle style, SkBlurQuality quality)
24        : fSigma(sigma)
25        , fStyle(style)
26        , fQuality(quality)
27        , fRRect(rrect)
28    {
29        this->init(&gRRectBlurKeyNamespaceLabel, 0,
30                   sizeof(fSigma) + sizeof(fStyle) + sizeof(fQuality) + sizeof(fRRect));
31    }
32
33    SkScalar   fSigma;
34    int32_t    fStyle;
35    int32_t    fQuality;
36    SkRRect    fRRect;
37};
38
39struct RRectBlurRec : public SkResourceCache::Rec {
40    RRectBlurRec(RRectBlurKey key, const SkMask& mask, SkCachedData* data)
41        : fKey(key)
42    {
43        fValue.fMask = mask;
44        fValue.fData = data;
45        fValue.fData->attachToCacheAndRef();
46    }
47    ~RRectBlurRec() override {
48        fValue.fData->detachFromCacheAndUnref();
49    }
50
51    RRectBlurKey   fKey;
52    MaskValue      fValue;
53
54    const Key& getKey() const override { return fKey; }
55    size_t bytesUsed() const override { return sizeof(*this) + fValue.fData->size(); }
56    const char* getCategory() const override { return "rrect-blur"; }
57    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
58        return fValue.fData->diagnostic_only_getDiscardable();
59    }
60
61    static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
62        const RRectBlurRec& rec = static_cast<const RRectBlurRec&>(baseRec);
63        MaskValue* result = (MaskValue*)contextData;
64
65        SkCachedData* tmpData = rec.fValue.fData;
66        tmpData->ref();
67        if (nullptr == tmpData->data()) {
68            tmpData->unref();
69            return false;
70        }
71        *result = rec.fValue;
72        return true;
73    }
74};
75} // namespace
76
77SkCachedData* SkMaskCache::FindAndRef(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
78                                  const SkRRect& rrect, SkMask* mask, SkResourceCache* localCache) {
79    MaskValue result;
80    RRectBlurKey key(sigma, rrect, style, quality);
81    if (!CHECK_LOCAL(localCache, find, Find, key, RRectBlurRec::Visitor, &result)) {
82        return nullptr;
83    }
84
85    *mask = result.fMask;
86    mask->fImage = (uint8_t*)(result.fData->data());
87    return result.fData;
88}
89
90void SkMaskCache::Add(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
91                      const SkRRect& rrect, const SkMask& mask, SkCachedData* data,
92                      SkResourceCache* localCache) {
93    RRectBlurKey key(sigma, rrect, style, quality);
94    return CHECK_LOCAL(localCache, add, Add, new RRectBlurRec(key, mask, data));
95}
96
97//////////////////////////////////////////////////////////////////////////////////////////
98
99namespace {
100static unsigned gRectsBlurKeyNamespaceLabel;
101
102struct RectsBlurKey : public SkResourceCache::Key {
103public:
104    RectsBlurKey(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
105                 const SkRect rects[], int count)
106        : fSigma(sigma)
107        , fStyle(style)
108        , fQuality(quality)
109    {
110        SkASSERT(1 == count || 2 == count);
111        SkIRect ir;
112        rects[0].roundOut(&ir);
113        fSizes[0] = SkSize{rects[0].width(), rects[0].height()};
114        if (2 == count) {
115            fSizes[1] = SkSize{rects[1].width(), rects[1].height()};
116            fSizes[2] = SkSize{rects[0].x() - rects[1].x(), rects[0].y() - rects[1].y()};
117        } else {
118            fSizes[1] = SkSize{0, 0};
119            fSizes[2] = SkSize{0, 0};
120        }
121        fSizes[3] = SkSize{rects[0].x() - ir.x(), rects[0].y() - ir.y()};
122
123        this->init(&gRectsBlurKeyNamespaceLabel, 0,
124                   sizeof(fSigma) + sizeof(fStyle) + sizeof(fQuality) + sizeof(fSizes));
125    }
126
127    SkScalar    fSigma;
128    int32_t     fStyle;
129    int32_t     fQuality;
130    SkSize      fSizes[4];
131};
132
133struct RectsBlurRec : public SkResourceCache::Rec {
134    RectsBlurRec(RectsBlurKey key, const SkMask& mask, SkCachedData* data)
135        : fKey(key)
136    {
137        fValue.fMask = mask;
138        fValue.fData = data;
139        fValue.fData->attachToCacheAndRef();
140    }
141    ~RectsBlurRec() override {
142        fValue.fData->detachFromCacheAndUnref();
143    }
144
145    RectsBlurKey   fKey;
146    MaskValue      fValue;
147
148    const Key& getKey() const override { return fKey; }
149    size_t bytesUsed() const override { return sizeof(*this) + fValue.fData->size(); }
150    const char* getCategory() const override { return "rects-blur"; }
151    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
152        return fValue.fData->diagnostic_only_getDiscardable();
153    }
154
155    static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
156        const RectsBlurRec& rec = static_cast<const RectsBlurRec&>(baseRec);
157        MaskValue* result = static_cast<MaskValue*>(contextData);
158
159        SkCachedData* tmpData = rec.fValue.fData;
160        tmpData->ref();
161        if (nullptr == tmpData->data()) {
162            tmpData->unref();
163            return false;
164        }
165        *result = rec.fValue;
166        return true;
167    }
168};
169} // namespace
170
171SkCachedData* SkMaskCache::FindAndRef(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
172                                      const SkRect rects[], int count, SkMask* mask,
173                                      SkResourceCache* localCache) {
174    MaskValue result;
175    RectsBlurKey key(sigma, style, quality, rects, count);
176    if (!CHECK_LOCAL(localCache, find, Find, key, RectsBlurRec::Visitor, &result)) {
177        return nullptr;
178    }
179
180    *mask = result.fMask;
181    mask->fImage = (uint8_t*)(result.fData->data());
182    return result.fData;
183}
184
185void SkMaskCache::Add(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
186                      const SkRect rects[], int count, const SkMask& mask, SkCachedData* data,
187                      SkResourceCache* localCache) {
188    RectsBlurKey key(sigma, style, quality, rects, count);
189    return CHECK_LOCAL(localCache, add, Add, new RectsBlurRec(key, mask, data));
190}
191