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 "SkReadBuffer.h"
     12 #include "SkWriteBuffer.h"
     13 #include "SkValidationUtils.h"
     14 
     15 ///////////////////////////////////////////////////////////////////////////////
     16 
     17 void SkMergeImageFilter::initAllocModes() {
     18     int inputCount = countInputs();
     19     if (inputCount) {
     20         size_t size = sizeof(uint8_t) * inputCount;
     21         if (size <= sizeof(fStorage)) {
     22             fModes = SkTCast<uint8_t*>(fStorage);
     23         } else {
     24             fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
     25         }
     26     } else {
     27         fModes = NULL;
     28     }
     29 }
     30 
     31 void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
     32     if (modes) {
     33         this->initAllocModes();
     34         int inputCount = countInputs();
     35         for (int i = 0; i < inputCount; ++i) {
     36             fModes[i] = SkToU8(modes[i]);
     37         }
     38     } else {
     39         fModes = NULL;
     40     }
     41 }
     42 
     43 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
     44                                        SkXfermode::Mode mode,
     45                                        const CropRect* cropRect) : INHERITED(first, second, cropRect) {
     46     if (SkXfermode::kSrcOver_Mode != mode) {
     47         SkXfermode::Mode modes[] = { mode, mode };
     48         this->initModes(modes);
     49     } else {
     50         fModes = NULL;
     51     }
     52 }
     53 
     54 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
     55                                        const SkXfermode::Mode modes[],
     56                                        const CropRect* cropRect) : INHERITED(count, filters, cropRect) {
     57     SkASSERT(count >= 0);
     58     this->initModes(modes);
     59 }
     60 
     61 SkMergeImageFilter::~SkMergeImageFilter() {
     62 
     63     if (fModes != SkTCast<uint8_t*>(fStorage)) {
     64         sk_free(fModes);
     65     }
     66 }
     67 
     68 bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
     69                                        const Context& ctx,
     70                                        SkBitmap* result, SkIPoint* offset) const {
     71     if (countInputs() < 1) {
     72         return false;
     73     }
     74 
     75     SkIRect bounds;
     76     if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
     77         return false;
     78     }
     79 
     80     const int x0 = bounds.left();
     81     const int y0 = bounds.top();
     82 
     83     SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
     84     if (NULL == dst) {
     85         return false;
     86     }
     87     SkCanvas canvas(dst);
     88     SkPaint paint;
     89 
     90     int inputCount = countInputs();
     91     for (int i = 0; i < inputCount; ++i) {
     92         SkBitmap tmp;
     93         const SkBitmap* srcPtr;
     94         SkIPoint pos = SkIPoint::Make(0, 0);
     95         SkImageFilter* filter = getInput(i);
     96         if (filter) {
     97             if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
     98                 return false;
     99             }
    100             srcPtr = &tmp;
    101         } else {
    102             srcPtr = &src;
    103         }
    104 
    105         if (fModes) {
    106             paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
    107         } else {
    108             paint.setXfermode(NULL);
    109         }
    110         canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
    111     }
    112 
    113     offset->fX = bounds.left();
    114     offset->fY = bounds.top();
    115     *result = dst->accessBitmap(false);
    116     return true;
    117 }
    118 
    119 void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
    120     this->INHERITED::flatten(buffer);
    121 
    122     buffer.writeBool(fModes != NULL);
    123     if (fModes) {
    124         buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
    125     }
    126 }
    127 
    128 SkMergeImageFilter::SkMergeImageFilter(SkReadBuffer& buffer)
    129   : INHERITED(-1, buffer) {
    130     bool hasModes = buffer.readBool();
    131     if (hasModes) {
    132         this->initAllocModes();
    133         int nbInputs = countInputs();
    134         size_t size = nbInputs * sizeof(fModes[0]);
    135         SkASSERT(buffer.getArrayCount() == size);
    136         if (buffer.validate(buffer.getArrayCount() == size) &&
    137             buffer.readByteArray(fModes, size)) {
    138             for (int i = 0; i < nbInputs; ++i) {
    139                 buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
    140             }
    141         }
    142     } else {
    143         fModes = 0;
    144     }
    145 }
    146