SkMergeImageFilter.cpp revision 96fcdcc219d2a0d3579719b84b28bede76efba64
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 = nullptr;
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 = nullptr;
40    }
41}
42
43SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
44                                       const SkXfermode::Mode modes[],
45                                       const CropRect* cropRect)
46  : INHERITED(count, filters, cropRect) {
47    SkASSERT(count >= 0);
48    this->initModes(modes);
49}
50
51SkMergeImageFilter::~SkMergeImageFilter() {
52
53    if (fModes != SkTCast<uint8_t*>(fStorage)) {
54        sk_free(fModes);
55    }
56}
57
58bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
59                                       const Context& ctx,
60                                       SkBitmap* result, SkIPoint* offset) const {
61    if (countInputs() < 1) {
62        return false;
63    }
64
65    SkIRect bounds;
66    if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
67        return false;
68    }
69
70    const int x0 = bounds.left();
71    const int y0 = bounds.top();
72
73    SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
74    if (nullptr == dst) {
75        return false;
76    }
77    SkCanvas canvas(dst);
78    SkPaint paint;
79
80    bool didProduceResult = false;
81    int inputCount = countInputs();
82    for (int i = 0; i < inputCount; ++i) {
83        SkBitmap tmp;
84        const SkBitmap* srcPtr;
85        SkIPoint pos = SkIPoint::Make(0, 0);
86        SkImageFilter* filter = getInput(i);
87        if (filter) {
88            if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
89                continue;
90            }
91            srcPtr = &tmp;
92        } else {
93            srcPtr = &src;
94        }
95
96        if (fModes) {
97            paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
98        } else {
99            paint.setXfermode(nullptr);
100        }
101        canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
102        didProduceResult = true;
103    }
104
105    if (!didProduceResult)
106        return false;
107
108    offset->fX = bounds.left();
109    offset->fY = bounds.top();
110    *result = dst->accessBitmap(false);
111    return true;
112}
113
114SkFlattenable* SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) {
115    Common common;
116    if (!common.unflatten(buffer, -1)) {
117        return nullptr;
118    }
119
120    const int count = common.inputCount();
121    bool hasModes = buffer.readBool();
122    if (hasModes) {
123        SkAutoSTArray<4, SkXfermode::Mode> modes(count);
124        SkAutoSTArray<4, uint8_t> modes8(count);
125        if (!buffer.readByteArray(modes8.get(), count)) {
126            return nullptr;
127        }
128        for (int i = 0; i < count; ++i) {
129            modes[i] = (SkXfermode::Mode)modes8[i];
130            buffer.validate(SkIsValidMode(modes[i]));
131        }
132        if (!buffer.isValid()) {
133            return nullptr;
134        }
135        return Create(common.inputs(), count, modes.get(), &common.cropRect());
136    }
137    return Create(common.inputs(), count, nullptr, &common.cropRect());
138}
139
140void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
141    this->INHERITED::flatten(buffer);
142    buffer.writeBool(fModes != nullptr);
143    if (fModes) {
144        buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
145    }
146}
147
148#ifndef SK_IGNORE_TO_STRING
149void SkMergeImageFilter::toString(SkString* str) const {
150    str->appendf("SkMergeImageFilter: (");
151
152    for (int i = 0; i < this->countInputs(); ++i) {
153        SkImageFilter* filter = this->getInput(i);
154        str->appendf("%d: (", i);
155        filter->toString(str);
156        str->appendf(")");
157    }
158
159    str->append(")");
160}
161#endif
162