SkMergeImageFilter.cpp revision 9ea3d57fde28a5fe4487a111dc3dd49418235e5e
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
17void 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
31void 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
43SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
44                                       const SkXfermode::Mode modes[],
45                                       const CropRect* cropRect) : INHERITED(count, filters, cropRect) {
46    SkASSERT(count >= 0);
47    this->initModes(modes);
48}
49
50SkMergeImageFilter::~SkMergeImageFilter() {
51
52    if (fModes != SkTCast<uint8_t*>(fStorage)) {
53        sk_free(fModes);
54    }
55}
56
57bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
58                                       const Context& ctx,
59                                       SkBitmap* result, SkIPoint* offset) const {
60    if (countInputs() < 1) {
61        return false;
62    }
63
64    SkIRect bounds;
65    if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
66        return false;
67    }
68
69    const int x0 = bounds.left();
70    const int y0 = bounds.top();
71
72    SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
73    if (NULL == dst) {
74        return false;
75    }
76    SkCanvas canvas(dst);
77    SkPaint paint;
78
79    int inputCount = countInputs();
80    for (int i = 0; i < inputCount; ++i) {
81        SkBitmap tmp;
82        const SkBitmap* srcPtr;
83        SkIPoint pos = SkIPoint::Make(0, 0);
84        SkImageFilter* filter = getInput(i);
85        if (filter) {
86            if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
87                return false;
88            }
89            srcPtr = &tmp;
90        } else {
91            srcPtr = &src;
92        }
93
94        if (fModes) {
95            paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
96        } else {
97            paint.setXfermode(NULL);
98        }
99        canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
100    }
101
102    offset->fX = bounds.left();
103    offset->fY = bounds.top();
104    *result = dst->accessBitmap(false);
105    return true;
106}
107
108void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
109    this->INHERITED::flatten(buffer);
110
111    buffer.writeBool(fModes != NULL);
112    if (fModes) {
113        buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
114    }
115}
116
117SkMergeImageFilter::SkMergeImageFilter(SkReadBuffer& buffer)
118  : INHERITED(-1, buffer) {
119    bool hasModes = buffer.readBool();
120    if (hasModes) {
121        this->initAllocModes();
122        int nbInputs = countInputs();
123        size_t size = nbInputs * sizeof(fModes[0]);
124        SkASSERT(buffer.getArrayCount() == size);
125        if (buffer.validate(buffer.getArrayCount() == size) &&
126            buffer.readByteArray(fModes, size)) {
127            for (int i = 0; i < nbInputs; ++i) {
128                buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
129            }
130        }
131    } else {
132        fModes = 0;
133    }
134}
135