Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkImageFilter.cpp
1 /*
2  * Copyright 2012 The Android Open Source Project
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 "SkImageFilter.h"
9
10 #include "SkBitmap.h"
11 #include "SkChecksum.h"
12 #include "SkDevice.h"
13 #include "SkLazyPtr.h"
14 #include "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16 #include "SkRect.h"
17 #include "SkTDynamicHash.h"
18 #include "SkTInternalLList.h"
19 #include "SkValidationUtils.h"
20 #if SK_SUPPORT_GPU
21 #include "GrContext.h"
22 #include "SkGrPixelRef.h"
23 #include "SkGr.h"
24 #endif
25
26 enum { kDefaultCacheSize = 128 * 1024 * 1024 };
27
28 static int32_t next_image_filter_unique_id() {
29     static int32_t gImageFilterUniqueID;
30
31     // Never return 0.
32     int32_t id;
33     do {
34         id = sk_atomic_inc(&gImageFilterUniqueID) + 1;
35     } while (0 == id);
36     return id;
37 }
38
39 struct SkImageFilter::Cache::Key {
40     Key(const uint32_t uniqueID, const SkMatrix& matrix, const SkIRect& clipBounds, uint32_t srcGenID)
41       : fUniqueID(uniqueID), fMatrix(matrix), fClipBounds(clipBounds), fSrcGenID(srcGenID) {
42         // Assert that Key is tightly-packed, since it is hashed.
43         SK_COMPILE_ASSERT(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + sizeof(SkIRect) +
44                                          sizeof(uint32_t), image_filter_key_tight_packing);
45         fMatrix.getType();  // force initialization of type, so hashes match
46     }
47     uint32_t fUniqueID;
48     SkMatrix fMatrix;
49     SkIRect fClipBounds;
50     uint32_t fSrcGenID;
51     bool operator==(const Key& other) const {
52         return fUniqueID == other.fUniqueID
53             && fMatrix == other.fMatrix
54             && fClipBounds == other.fClipBounds
55             && fSrcGenID == other.fSrcGenID;
56     }
57 };
58
59 SkImageFilter::Common::~Common() {
60     for (int i = 0; i < fInputs.count(); ++i) {
61         SkSafeUnref(fInputs[i]);
62     }
63 }
64
65 void SkImageFilter::Common::allocInputs(int count) {
66     const size_t size = count * sizeof(SkImageFilter*);
67     fInputs.reset(count);
68     sk_bzero(fInputs.get(), size);
69 }
70
71 void SkImageFilter::Common::detachInputs(SkImageFilter** inputs) {
72     const size_t size = fInputs.count() * sizeof(SkImageFilter*);
73     memcpy(inputs, fInputs.get(), size);
74     sk_bzero(fInputs.get(), size);
75 }
76
77 bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
78     const int count = buffer.readInt();
79     if (!buffer.validate(count >= 0)) {
80         return false;
81     }
82     if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
83         return false;
84     }
85
86     this->allocInputs(count);
87     for (int i = 0; i < count; i++) {
88         if (buffer.readBool()) {
89             fInputs[i] = buffer.readImageFilter();
90         }
91         if (!buffer.isValid()) {
92             return false;
93         }
94     }
95     SkRect rect;
96     buffer.readRect(&rect);
97     if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
98         return false;
99     }
100     
101     uint32_t flags = buffer.readUInt();
102     fCropRect = CropRect(rect, flags);
103     if (buffer.isVersionLT(SkReadBuffer::kImageFilterUniqueID_Version)) {
104         fUniqueID = next_image_filter_unique_id();
105     } else {
106         fUniqueID = buffer.readUInt();
107     }
108     return buffer.isValid();
109 }
110
111 ///////////////////////////////////////////////////////////////////////////////////////////////////
112
113 SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect, uint32_t uniqueID)
114   : fInputCount(inputCount),
115     fInputs(new SkImageFilter*[inputCount]),
116     fUsesSrcInput(false),
117     fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)),
118     fUniqueID(uniqueID ? uniqueID : next_image_filter_unique_id()) {
119     for (int i = 0; i < inputCount; ++i) {
120         if (NULL == inputs[i] || inputs[i]->usesSrcInput()) {
121             fUsesSrcInput = true;
122         }
123         fInputs[i] = inputs[i];
124         SkSafeRef(fInputs[i]);
125     }
126 }
127
128 SkImageFilter::~SkImageFilter() {
129     for (int i = 0; i < fInputCount; i++) {
130         SkSafeUnref(fInputs[i]);
131     }
132     delete[] fInputs;
133 }
134
135 SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer)
136   : fUsesSrcInput(false) {
137     Common common;
138     if (common.unflatten(buffer, inputCount)) {
139         fCropRect = common.cropRect();
140         fInputCount = common.inputCount();
141         fInputs = SkNEW_ARRAY(SkImageFilter*, fInputCount);
142         common.detachInputs(fInputs);
143         for (int i = 0; i < fInputCount; ++i) {
144             if (NULL == fInputs[i] || fInputs[i]->usesSrcInput()) {
145                 fUsesSrcInput = true;
146             }
147         }
148         fUniqueID = buffer.isCrossProcess() ? next_image_filter_unique_id() : common.uniqueID();
149     } else {
150         fInputCount = 0;
151         fInputs = NULL;
152     }
153 }
154
155 void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
156     buffer.writeInt(fInputCount);
157     for (int i = 0; i < fInputCount; i++) {
158         SkImageFilter* input = getInput(i);
159         buffer.writeBool(input != NULL);
160         if (input != NULL) {
161             buffer.writeFlattenable(input);
162         }
163     }
164     buffer.writeRect(fCropRect.rect());
165     buffer.writeUInt(fCropRect.flags());
166     buffer.writeUInt(fUniqueID);
167 }
168
169 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
170                                 const Context& context,
171                                 SkBitmap* result, SkIPoint* offset) const {
172     SkASSERT(result);
173     SkASSERT(offset);
174     uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0;
175     Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID);
176     if (context.cache()) {
177         if (context.cache()->get(key, result, offset)) {
178             return true;
179         }
180     }
181     /*
182      *  Give the proxy first shot at the filter. If it returns false, ask
183      *  the filter to do it.
184      */
185     if ((proxy && proxy->filterImage(this, src, context, result, offset)) ||
186         this->onFilterImage(proxy, src, context, result, offset)) {
187         if (context.cache()) {
188             context.cache()->set(key, *result, *offset);
189         }
190         return true;
191     }
192     return false;
193 }
194
195 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
196                                  SkIRect* dst) const {
197     SkASSERT(&src);
198     SkASSERT(dst);
199     return this->onFilterBounds(src, ctm, dst);
200 }
201
202 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
203     if (0 == fInputCount) {
204         *dst = src;
205         return;
206     }
207     if (this->getInput(0)) {
208         this->getInput(0)->computeFastBounds(src, dst);
209     } else {
210         *dst = src;
211     }
212     for (int i = 1; i < fInputCount; i++) {
213         SkImageFilter* input = this->getInput(i);
214         if (input) {
215             SkRect bounds;
216             input->computeFastBounds(src, &bounds);
217             dst->join(bounds);
218         } else {
219             dst->join(src);
220         }
221     }
222 }
223
224 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
225                                   SkBitmap*, SkIPoint*) const {
226     return false;
227 }
228
229 bool SkImageFilter::canFilterImageGPU() const {
230     return this->asFragmentProcessor(NULL, NULL, SkMatrix::I(), SkIRect());
231 }
232
233 bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
234                                    SkBitmap* result, SkIPoint* offset) const {
235 #if SK_SUPPORT_GPU
236     SkBitmap input = src;
237     SkASSERT(fInputCount == 1);
238     SkIPoint srcOffset = SkIPoint::Make(0, 0);
239     if (this->getInput(0) &&
240         !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
241         return false;
242     }
243     GrTexture* srcTexture = input.getTexture();
244     SkIRect bounds;
245     if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
246         return false;
247     }
248     SkRect srcRect = SkRect::Make(bounds);
249     SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
250     GrContext* context = srcTexture->getContext();
251
252     GrTextureDesc desc;
253     desc.fFlags = kRenderTarget_GrTextureFlagBit,
254     desc.fWidth = bounds.width();
255     desc.fHeight = bounds.height();
256     desc.fConfig = kRGBA_8888_GrPixelConfig;
257
258     GrAutoScratchTexture dst(context, desc);
259     if (NULL == dst.texture()) {
260         return false;
261     }
262     GrContext::AutoMatrix am;
263     am.setIdentity(context);
264     GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
265     GrContext::AutoClip acs(context, dstRect);
266     GrFragmentProcessor* fp;
267     offset->fX = bounds.left();
268     offset->fY = bounds.top();
269     bounds.offset(-srcOffset);
270     SkMatrix matrix(ctx.ctm());
271     matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
272     this->asFragmentProcessor(&fp, srcTexture, matrix, bounds);
273     SkASSERT(fp);
274     GrPaint paint;
275     paint.addColorProcessor(fp)->unref();
276     context->drawRectToRect(paint, dstRect, srcRect);
277
278     SkAutoTUnref<GrTexture> resultTex(dst.detach());
279     WrapTexture(resultTex, bounds.width(), bounds.height(), result);
280     return true;
281 #else
282     return false;
283 #endif
284 }
285
286 bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
287                                   const SkIPoint& srcOffset, SkIRect* bounds) const {
288     SkIRect srcBounds;
289     src.getBounds(&srcBounds);
290     srcBounds.offset(srcOffset);
291     SkRect cropRect;
292     ctx.ctm().mapRect(&cropRect, fCropRect.rect());
293     SkIRect cropRectI;
294     cropRect.roundOut(&cropRectI);
295     uint32_t flags = fCropRect.flags();
296     if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft;
297     if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop;
298     if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight;
299     if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom;
300     if (!srcBounds.intersect(ctx.clipBounds())) {
301         return false;
302     }
303     *bounds = srcBounds;
304     return true;
305 }
306
307 bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
308                                   SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const {
309     SkIRect srcBounds;
310     src.getBounds(&srcBounds);
311     srcBounds.offset(*srcOffset);
312     SkRect cropRect;
313     ctx.ctm().mapRect(&cropRect, fCropRect.rect());
314     SkIRect cropRectI;
315     cropRect.roundOut(&cropRectI);
316     uint32_t flags = fCropRect.flags();
317     *bounds = srcBounds;
318     if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft;
319     if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop;
320     if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight;
321     if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom;
322     if (!bounds->intersect(ctx.clipBounds())) {
323         return false;
324     }
325     if (srcBounds.contains(*bounds)) {
326         *dst = src;
327         return true;
328     } else {
329         SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
330         if (!device) {
331             return false;
332         }
333         SkCanvas canvas(device);
334         canvas.clear(0x00000000);
335         canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
336         *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
337         *dst = device->accessBitmap(false);
338         return true;
339     }
340 }
341
342 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
343                                    SkIRect* dst) const {
344     if (fInputCount < 1) {
345         return false;
346     }
347
348     SkIRect bounds;
349     for (int i = 0; i < fInputCount; ++i) {
350         SkImageFilter* filter = this->getInput(i);
351         SkIRect rect = src;
352         if (filter && !filter->filterBounds(src, ctm, &rect)) {
353             return false;
354         }
355         if (0 == i) {
356             bounds = rect;
357         } else {
358             bounds.join(rect);
359         }
360     }
361
362     // don't modify dst until now, so we don't accidentally change it in the
363     // loop, but then return false on the next filter.
364     *dst = bounds;
365     return true;
366 }
367
368 bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
369                                         const SkIRect&) const {
370     return false;
371 }
372
373 bool SkImageFilter::asColorFilter(SkColorFilter**) const {
374     return false;
375 }
376
377 #if SK_SUPPORT_GPU
378
379 void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) {
380     SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
381     result->setInfo(info);
382     result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
383 }
384
385 bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy,
386                                       const SkBitmap& src, const Context& ctx,
387                                       SkBitmap* result, SkIPoint* offset) const {
388     // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
389     // matrix with no clip and that the matrix, clip, and render target set before this function was
390     // called are restored before we return to the caller.
391     GrContext* context = src.getTexture()->getContext();
392     GrContext::AutoWideOpenIdentityDraw awoid(context, NULL);
393     if (this->canFilterImageGPU()) {
394         return this->filterImageGPU(proxy, src, ctx, result, offset);
395     } else {
396         if (this->filterImage(proxy, src, ctx, result, offset)) {
397             if (!result->getTexture()) {
398                 const SkImageInfo info = result->info();
399                 if (kUnknown_SkColorType == info.colorType()) {
400                     return false;
401                 }
402                 GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL);
403                 result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref();
404                 GrUnlockAndUnrefCachedBitmapTexture(resultTex);
405             }
406             return true;
407         } else {
408             return false;
409         }
410     }
411 }
412 #endif
413
414 namespace {
415
416 class CacheImpl : public SkImageFilter::Cache {
417 public:
418     CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) {
419     }
420     virtual ~CacheImpl() {
421         SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
422
423         while (!iter.done()) {
424             Value* v = &*iter;
425             ++iter;
426             delete v;
427         }
428     }
429     struct Value {
430         Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
431             : fKey(key), fBitmap(bitmap), fOffset(offset) {}
432         Key fKey;
433         SkBitmap fBitmap;
434         SkIPoint fOffset;
435         static const Key& GetKey(const Value& v) {
436             return v.fKey;
437         }
438         static uint32_t Hash(const Key& key) {
439             return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
440         }
441         SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
442     };
443     virtual bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const {
444         SkAutoMutexAcquire mutex(fMutex);
445         if (Value* v = fLookup.find(key)) {
446             *result = v->fBitmap;
447             *offset = v->fOffset;
448             if (v != fLRU.head()) {
449                 fLRU.remove(v);
450                 fLRU.addToHead(v);
451             }
452             return true;
453         }
454         return false;
455     }
456     virtual void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) {
457         SkAutoMutexAcquire mutex(fMutex);
458         if (Value* v = fLookup.find(key)) {
459             removeInternal(v);
460         }
461         Value* v = new Value(key, result, offset);
462         fLookup.add(v);
463         fLRU.addToHead(v);
464         fCurrentBytes += result.getSize();
465         while (fCurrentBytes > fMaxBytes) {
466             Value* tail = fLRU.tail();
467             SkASSERT(tail);
468             if (tail == v) {
469                 break;
470             }
471             removeInternal(tail);
472         }
473     }
474 private:
475     void removeInternal(Value* v) {
476         fCurrentBytes -= v->fBitmap.getSize();
477         fLRU.remove(v);
478         fLookup.remove(v->fKey);
479         delete v;
480     }
481 private:
482     SkTDynamicHash<Value, Key>         fLookup;
483     mutable SkTInternalLList<Value>    fLRU;
484     size_t                             fMaxBytes;
485     size_t                             fCurrentBytes;
486     mutable SkMutex                    fMutex;
487 };
488
489 SkImageFilter::Cache* CreateCache() {
490     return SkImageFilter::Cache::Create(kDefaultCacheSize);
491 }
492
493 } // namespace
494
495 SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
496     return SkNEW_ARGS(CacheImpl, (maxBytes));
497 }
498
499 SkImageFilter::Cache* SkImageFilter::Cache::Get() {
500     SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache);
501     return cache.get();
502 }