Home | History | Annotate | Download | only in effects
      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 "SkMergeImageFilter.h"
      9 #include "SkCanvas.h"
     10 #include "SkDevice.h"
     11 #include "SkFlattenableBuffers.h"
     12 
     13 ///////////////////////////////////////////////////////////////////////////////
     14 
     15 void SkMergeImageFilter::initAllocModes() {
     16     int inputCount = countInputs();
     17     if (inputCount) {
     18         size_t size = sizeof(uint8_t) * inputCount;
     19         if (size <= sizeof(fStorage)) {
     20             fModes = SkTCast<uint8_t*>(fStorage);
     21         } else {
     22             fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
     23         }
     24     } else {
     25         fModes = NULL;
     26     }
     27 }
     28 
     29 void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
     30     if (modes) {
     31         this->initAllocModes();
     32         int inputCount = countInputs();
     33         for (int i = 0; i < inputCount; ++i) {
     34             fModes[i] = SkToU8(modes[i]);
     35         }
     36     } else {
     37         fModes = NULL;
     38     }
     39 }
     40 
     41 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
     42                                        SkXfermode::Mode mode) : INHERITED(first, second) {
     43     if (SkXfermode::kSrcOver_Mode != mode) {
     44         SkXfermode::Mode modes[] = { mode, mode };
     45         this->initModes(modes);
     46     } else {
     47         fModes = NULL;
     48     }
     49 }
     50 
     51 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
     52                                        const SkXfermode::Mode modes[]) : INHERITED(count, filters) {
     53     this->initModes(modes);
     54 }
     55 
     56 SkMergeImageFilter::~SkMergeImageFilter() {
     57 
     58     if (fModes != SkTCast<uint8_t*>(fStorage)) {
     59         sk_free(fModes);
     60     }
     61 }
     62 
     63 bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
     64                                         SkIRect* dst) {
     65     if (countInputs() < 1) {
     66         return false;
     67     }
     68 
     69     SkIRect totalBounds;
     70 
     71     int inputCount = countInputs();
     72     for (int i = 0; i < inputCount; ++i) {
     73         SkImageFilter* filter = getInput(i);
     74         SkIRect r;
     75         if (filter) {
     76             if (!filter->filterBounds(src, ctm, &r)) {
     77                 return false;
     78             }
     79         } else {
     80             r = src;
     81         }
     82         if (0 == i) {
     83             totalBounds = r;
     84         } else {
     85             totalBounds.join(r);
     86         }
     87     }
     88 
     89     // don't modify dst until now, so we don't accidentally change it in the
     90     // loop, but then return false on the next filter.
     91     *dst = totalBounds;
     92     return true;
     93 }
     94 
     95 bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
     96                                        const SkMatrix& ctm,
     97                                        SkBitmap* result, SkIPoint* loc) {
     98     if (countInputs() < 1) {
     99         return false;
    100     }
    101 
    102     const SkIRect srcBounds = SkIRect::MakeXYWH(loc->x(), loc->y(),
    103                                                 src.width(), src.height());
    104     SkIRect bounds;
    105     if (!this->filterBounds(srcBounds, ctm, &bounds)) {
    106         return false;
    107     }
    108 
    109     const int x0 = bounds.left();
    110     const int y0 = bounds.top();
    111 
    112     SkAutoTUnref<SkDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
    113     if (NULL == dst) {
    114         return false;
    115     }
    116     SkCanvas canvas(dst);
    117     SkPaint paint;
    118 
    119     int inputCount = countInputs();
    120     for (int i = 0; i < inputCount; ++i) {
    121         SkBitmap tmp;
    122         const SkBitmap* srcPtr;
    123         SkIPoint pos = *loc;
    124         SkImageFilter* filter = getInput(i);
    125         if (filter) {
    126             if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
    127                 return false;
    128             }
    129             srcPtr = &tmp;
    130         } else {
    131             srcPtr = &src;
    132         }
    133 
    134         if (fModes) {
    135             paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
    136         } else {
    137             paint.setXfermode(NULL);
    138         }
    139         canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
    140     }
    141 
    142     loc->set(bounds.left(), bounds.top());
    143     *result = dst->accessBitmap(false);
    144     return true;
    145 }
    146 
    147 void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
    148     this->INHERITED::flatten(buffer);
    149 
    150     buffer.writeBool(fModes != NULL);
    151     if (fModes) {
    152         buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
    153     }
    154 }
    155 
    156 SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
    157     bool hasModes = buffer.readBool();
    158     if (hasModes) {
    159         this->initAllocModes();
    160         SkASSERT(buffer.getArrayCount() == countInputs() * sizeof(fModes[0]));
    161         buffer.readByteArray(fModes);
    162     } else {
    163         fModes = 0;
    164     }
    165 }
    166