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() {
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::Make(0, 0);
114        fSizes[1] = SkSize::Make(0, 0);
115        fSizes[2] = SkSize::Make(0, 0);
116        fSizes[3] = SkSize::Make(rects[0].x() - ir.x(), rects[0].y() - ir.y());
117        for (int i = 0; i < count; i++) {
118            fSizes[i] = SkSize::Make(rects[i].width(), rects[i].height());
119        }
120        if (2 == count) {
121            fSizes[2] = SkSize::Make(rects[0].x() - rects[1].x(), rects[0].y() - rects[1].y());
122        }
123
124        this->init(&gRectsBlurKeyNamespaceLabel, 0,
125                   sizeof(fSigma) + sizeof(fStyle) + sizeof(fQuality) + sizeof(fSizes));
126    }
127
128    SkScalar    fSigma;
129    int32_t     fStyle;
130    int32_t     fQuality;
131    SkSize      fSizes[4];
132};
133
134struct RectsBlurRec : public SkResourceCache::Rec {
135    RectsBlurRec(RectsBlurKey key, const SkMask& mask, SkCachedData* data)
136        : fKey(key)
137    {
138        fValue.fMask = mask;
139        fValue.fData = data;
140        fValue.fData->attachToCacheAndRef();
141    }
142    ~RectsBlurRec() {
143        fValue.fData->detachFromCacheAndUnref();
144    }
145
146    RectsBlurKey   fKey;
147    MaskValue      fValue;
148
149    const Key& getKey() const override { return fKey; }
150    size_t bytesUsed() const override { return sizeof(*this) + fValue.fData->size(); }
151    const char* getCategory() const override { return "rects-blur"; }
152    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
153        return fValue.fData->diagnostic_only_getDiscardable();
154    }
155
156    static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
157        const RectsBlurRec& rec = static_cast<const RectsBlurRec&>(baseRec);
158        MaskValue* result = static_cast<MaskValue*>(contextData);
159
160        SkCachedData* tmpData = rec.fValue.fData;
161        tmpData->ref();
162        if (nullptr == tmpData->data()) {
163            tmpData->unref();
164            return false;
165        }
166        *result = rec.fValue;
167        return true;
168    }
169};
170} // namespace
171
172SkCachedData* SkMaskCache::FindAndRef(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
173                                      const SkRect rects[], int count, SkMask* mask,
174                                      SkResourceCache* localCache) {
175    MaskValue result;
176    RectsBlurKey key(sigma, style, quality, rects, count);
177    if (!CHECK_LOCAL(localCache, find, Find, key, RectsBlurRec::Visitor, &result)) {
178        return nullptr;
179    }
180
181    *mask = result.fMask;
182    mask->fImage = (uint8_t*)(result.fData->data());
183    return result.fData;
184}
185
186void SkMaskCache::Add(SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
187                      const SkRect rects[], int count, const SkMask& mask, SkCachedData* data,
188                      SkResourceCache* localCache) {
189    RectsBlurKey key(sigma, style, quality, rects, count);
190    return CHECK_LOCAL(localCache, add, Add, new RectsBlurRec(key, mask, data));
191}
192