senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 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" |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 9 | |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 10 | #include "SkCanvas.h" |
commit-bot@chromium.org | 8b0e8ac | 2014-01-30 18:58:24 +0000 | [diff] [blame] | 11 | #include "SkReadBuffer.h" |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 12 | #include "SkSpecialImage.h" |
| 13 | #include "SkSpecialSurface.h" |
commit-bot@chromium.org | 8b0e8ac | 2014-01-30 18:58:24 +0000 | [diff] [blame] | 14 | #include "SkWriteBuffer.h" |
commit-bot@chromium.org | c0b7e10 | 2013-10-23 17:06:21 +0000 | [diff] [blame] | 15 | #include "SkValidationUtils.h" |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 16 | |
| 17 | /////////////////////////////////////////////////////////////////////////////// |
| 18 | |
| 19 | void SkMergeImageFilter::initAllocModes() { |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 20 | int inputCount = this->countInputs(); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 21 | if (inputCount) { |
| 22 | size_t size = sizeof(uint8_t) * inputCount; |
| 23 | if (size <= sizeof(fStorage)) { |
| 24 | fModes = SkTCast<uint8_t*>(fStorage); |
| 25 | } else { |
| 26 | fModes = SkTCast<uint8_t*>(sk_malloc_throw(size)); |
| 27 | } |
| 28 | } else { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 29 | fModes = nullptr; |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 30 | } |
| 31 | } |
| 32 | |
| 33 | void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) { |
| 34 | if (modes) { |
| 35 | this->initAllocModes(); |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 36 | int inputCount = this->countInputs(); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 37 | for (int i = 0; i < inputCount; ++i) { |
| 38 | fModes[i] = SkToU8(modes[i]); |
| 39 | } |
| 40 | } else { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 41 | fModes = nullptr; |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 42 | } |
| 43 | } |
| 44 | |
robertphillips | 2238c9d | 2016-03-30 13:34:16 -0700 | [diff] [blame^] | 45 | SkMergeImageFilter::SkMergeImageFilter(sk_sp<SkImageFilter> filters[], int count, |
senorblanco@chromium.org | 962c886 | 2013-09-19 17:26:47 +0000 | [diff] [blame] | 46 | const SkXfermode::Mode modes[], |
senorblanco | 24e06d5 | 2015-03-18 12:11:33 -0700 | [diff] [blame] | 47 | const CropRect* cropRect) |
robertphillips | 2238c9d | 2016-03-30 13:34:16 -0700 | [diff] [blame^] | 48 | : INHERITED(filters, count, cropRect) { |
commit-bot@chromium.org | c84728d | 2013-12-04 20:07:47 +0000 | [diff] [blame] | 49 | SkASSERT(count >= 0); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 50 | this->initModes(modes); |
| 51 | } |
| 52 | |
| 53 | SkMergeImageFilter::~SkMergeImageFilter() { |
| 54 | |
| 55 | if (fModes != SkTCast<uint8_t*>(fStorage)) { |
| 56 | sk_free(fModes); |
| 57 | } |
| 58 | } |
| 59 | |
robertphillips | 2302de9 | 2016-03-24 07:26:32 -0700 | [diff] [blame] | 60 | sk_sp<SkSpecialImage> SkMergeImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, |
| 61 | SkIPoint* offset) const { |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 62 | int inputCount = this->countInputs(); |
| 63 | if (inputCount < 1) { |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 64 | return nullptr; |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 65 | } |
| 66 | |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 67 | SkIRect bounds; |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 68 | bounds.setEmpty(); |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 69 | |
robertphillips | 2302de9 | 2016-03-24 07:26:32 -0700 | [diff] [blame] | 70 | SkAutoTDeleteArray<sk_sp<SkSpecialImage>> inputs(new sk_sp<SkSpecialImage>[inputCount]); |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 71 | SkAutoTDeleteArray<SkIPoint> offsets(new SkIPoint[inputCount]); |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 72 | |
| 73 | // Filter all of the inputs. |
| 74 | for (int i = 0; i < inputCount; ++i) { |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 75 | offsets[i].setZero(); |
robertphillips | 2302de9 | 2016-03-24 07:26:32 -0700 | [diff] [blame] | 76 | inputs[i] = this->filterInput(i, source, ctx, &offsets[i]); |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 77 | if (!inputs[i]) { |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 78 | continue; |
| 79 | } |
halcanary | 9d524f2 | 2016-03-29 09:03:52 -0700 | [diff] [blame] | 80 | const SkIRect inputBounds = SkIRect::MakeXYWH(offsets[i].fX, offsets[i].fY, |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 81 | inputs[i]->width(), inputs[i]->height()); |
| 82 | bounds.join(inputBounds); |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 83 | } |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 84 | if (bounds.isEmpty()) { |
| 85 | return nullptr; |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | // Apply the crop rect to the union of the inputs' bounds. |
senorblanco | d8ff5b3 | 2016-01-28 08:23:02 -0800 | [diff] [blame] | 89 | this->getCropRect().applyTo(bounds, ctx.ctm(), &bounds); |
| 90 | if (!bounds.intersect(ctx.clipBounds())) { |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 91 | return nullptr; |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | const int x0 = bounds.left(); |
| 95 | const int y0 = bounds.top(); |
| 96 | |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 97 | SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(), |
| 98 | kPremul_SkAlphaType); |
| 99 | |
robertphillips | 37bd7c3 | 2016-03-17 14:31:39 -0700 | [diff] [blame] | 100 | sk_sp<SkSpecialSurface> surf(source->makeSurface(info)); |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 101 | if (!surf) { |
| 102 | return nullptr; |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 103 | } |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 104 | |
| 105 | SkCanvas* canvas = surf->getCanvas(); |
| 106 | SkASSERT(canvas); |
| 107 | |
| 108 | canvas->clear(0x0); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 109 | |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 110 | // Composite all of the filter inputs. |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 111 | for (int i = 0; i < inputCount; ++i) { |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 112 | if (!inputs[i]) { |
| 113 | continue; |
| 114 | } |
| 115 | |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 116 | SkPaint paint; |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 117 | if (fModes) { |
| 118 | paint.setXfermodeMode((SkXfermode::Mode)fModes[i]); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 119 | } |
robertphillips | 393aa36 | 2016-03-10 04:44:20 -0800 | [diff] [blame] | 120 | |
| 121 | inputs[i]->draw(canvas, |
| 122 | SkIntToScalar(offsets[i].x() - x0), SkIntToScalar(offsets[i].y() - y0), |
| 123 | &paint); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 124 | } |
| 125 | |
senorblanco@chromium.org | 6776b82 | 2014-01-03 21:48:22 +0000 | [diff] [blame] | 126 | offset->fX = bounds.left(); |
| 127 | offset->fY = bounds.top(); |
robertphillips | 2302de9 | 2016-03-24 07:26:32 -0700 | [diff] [blame] | 128 | return surf->makeImageSnapshot(); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 129 | } |
| 130 | |
reed | 9fa60da | 2014-08-21 07:59:51 -0700 | [diff] [blame] | 131 | SkFlattenable* SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) { |
| 132 | Common common; |
| 133 | if (!common.unflatten(buffer, -1)) { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 134 | return nullptr; |
reed | 9fa60da | 2014-08-21 07:59:51 -0700 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | const int count = common.inputCount(); |
| 138 | bool hasModes = buffer.readBool(); |
| 139 | if (hasModes) { |
| 140 | SkAutoSTArray<4, SkXfermode::Mode> modes(count); |
| 141 | SkAutoSTArray<4, uint8_t> modes8(count); |
| 142 | if (!buffer.readByteArray(modes8.get(), count)) { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 143 | return nullptr; |
reed | 9fa60da | 2014-08-21 07:59:51 -0700 | [diff] [blame] | 144 | } |
| 145 | for (int i = 0; i < count; ++i) { |
| 146 | modes[i] = (SkXfermode::Mode)modes8[i]; |
| 147 | buffer.validate(SkIsValidMode(modes[i])); |
| 148 | } |
| 149 | if (!buffer.isValid()) { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 150 | return nullptr; |
reed | 9fa60da | 2014-08-21 07:59:51 -0700 | [diff] [blame] | 151 | } |
robertphillips | 2238c9d | 2016-03-30 13:34:16 -0700 | [diff] [blame^] | 152 | return Make(common.inputs(), count, modes.get(), &common.cropRect()).release(); |
reed | 9fa60da | 2014-08-21 07:59:51 -0700 | [diff] [blame] | 153 | } |
robertphillips | 2238c9d | 2016-03-30 13:34:16 -0700 | [diff] [blame^] | 154 | return Make(common.inputs(), count, nullptr, &common.cropRect()).release(); |
reed | 9fa60da | 2014-08-21 07:59:51 -0700 | [diff] [blame] | 155 | } |
| 156 | |
commit-bot@chromium.org | 8b0e8ac | 2014-01-30 18:58:24 +0000 | [diff] [blame] | 157 | void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const { |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 158 | this->INHERITED::flatten(buffer); |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 159 | buffer.writeBool(fModes != nullptr); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 160 | if (fModes) { |
senorblanco | 4a24398 | 2015-11-25 07:06:55 -0800 | [diff] [blame] | 161 | buffer.writeByteArray(fModes, this->countInputs() * sizeof(fModes[0])); |
senorblanco@chromium.org | 4a9a612 | 2012-12-04 14:18:50 +0000 | [diff] [blame] | 162 | } |
| 163 | } |
robertphillips | f3f5bad | 2014-12-19 13:49:15 -0800 | [diff] [blame] | 164 | |
| 165 | #ifndef SK_IGNORE_TO_STRING |
| 166 | void SkMergeImageFilter::toString(SkString* str) const { |
| 167 | str->appendf("SkMergeImageFilter: ("); |
halcanary | 9d524f2 | 2016-03-29 09:03:52 -0700 | [diff] [blame] | 168 | |
robertphillips | f3f5bad | 2014-12-19 13:49:15 -0800 | [diff] [blame] | 169 | for (int i = 0; i < this->countInputs(); ++i) { |
| 170 | SkImageFilter* filter = this->getInput(i); |
| 171 | str->appendf("%d: (", i); |
| 172 | filter->toString(str); |
| 173 | str->appendf(")"); |
| 174 | } |
| 175 | |
| 176 | str->append(")"); |
| 177 | } |
| 178 | #endif |