blob: 07b2c1cf3e9ef8de8309144c6c89c72407b8763c [file] [log] [blame]
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +00001/*
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"
robertphillips393aa362016-03-10 04:44:20 -08009
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000010#include "SkCanvas.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
robertphillips393aa362016-03-10 04:44:20 -080012#include "SkSpecialImage.h"
13#include "SkSpecialSurface.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkWriteBuffer.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000015#include "SkValidationUtils.h"
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000016
17///////////////////////////////////////////////////////////////////////////////
18
19void SkMergeImageFilter::initAllocModes() {
senorblanco4a243982015-11-25 07:06:55 -080020 int inputCount = this->countInputs();
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000021 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 {
halcanary96fcdcc2015-08-27 07:41:13 -070029 fModes = nullptr;
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000030 }
31}
32
33void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
34 if (modes) {
35 this->initAllocModes();
senorblanco4a243982015-11-25 07:06:55 -080036 int inputCount = this->countInputs();
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000037 for (int i = 0; i < inputCount; ++i) {
38 fModes[i] = SkToU8(modes[i]);
39 }
40 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070041 fModes = nullptr;
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000042 }
43}
44
robertphillips2238c9d2016-03-30 13:34:16 -070045SkMergeImageFilter::SkMergeImageFilter(sk_sp<SkImageFilter> filters[], int count,
senorblanco@chromium.org962c8862013-09-19 17:26:47 +000046 const SkXfermode::Mode modes[],
senorblanco24e06d52015-03-18 12:11:33 -070047 const CropRect* cropRect)
robertphillips2238c9d2016-03-30 13:34:16 -070048 : INHERITED(filters, count, cropRect) {
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +000049 SkASSERT(count >= 0);
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000050 this->initModes(modes);
51}
52
53SkMergeImageFilter::~SkMergeImageFilter() {
54
55 if (fModes != SkTCast<uint8_t*>(fStorage)) {
56 sk_free(fModes);
57 }
58}
59
robertphillips2302de92016-03-24 07:26:32 -070060sk_sp<SkSpecialImage> SkMergeImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx,
61 SkIPoint* offset) const {
senorblanco4a243982015-11-25 07:06:55 -080062 int inputCount = this->countInputs();
63 if (inputCount < 1) {
robertphillips393aa362016-03-10 04:44:20 -080064 return nullptr;
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000065 }
66
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000067 SkIRect bounds;
robertphillips393aa362016-03-10 04:44:20 -080068 bounds.setEmpty();
senorblanco4a243982015-11-25 07:06:55 -080069
robertphillips2302de92016-03-24 07:26:32 -070070 SkAutoTDeleteArray<sk_sp<SkSpecialImage>> inputs(new sk_sp<SkSpecialImage>[inputCount]);
senorblanco4a243982015-11-25 07:06:55 -080071 SkAutoTDeleteArray<SkIPoint> offsets(new SkIPoint[inputCount]);
senorblanco4a243982015-11-25 07:06:55 -080072
73 // Filter all of the inputs.
74 for (int i = 0; i < inputCount; ++i) {
senorblanco4a243982015-11-25 07:06:55 -080075 offsets[i].setZero();
robertphillips2302de92016-03-24 07:26:32 -070076 inputs[i] = this->filterInput(i, source, ctx, &offsets[i]);
robertphillips393aa362016-03-10 04:44:20 -080077 if (!inputs[i]) {
senorblanco4a243982015-11-25 07:06:55 -080078 continue;
79 }
halcanary9d524f22016-03-29 09:03:52 -070080 const SkIRect inputBounds = SkIRect::MakeXYWH(offsets[i].fX, offsets[i].fY,
robertphillips393aa362016-03-10 04:44:20 -080081 inputs[i]->width(), inputs[i]->height());
82 bounds.join(inputBounds);
senorblanco4a243982015-11-25 07:06:55 -080083 }
robertphillips393aa362016-03-10 04:44:20 -080084 if (bounds.isEmpty()) {
85 return nullptr;
senorblanco4a243982015-11-25 07:06:55 -080086 }
87
88 // Apply the crop rect to the union of the inputs' bounds.
senorblancod8ff5b32016-01-28 08:23:02 -080089 this->getCropRect().applyTo(bounds, ctx.ctm(), &bounds);
90 if (!bounds.intersect(ctx.clipBounds())) {
robertphillips393aa362016-03-10 04:44:20 -080091 return nullptr;
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000092 }
93
94 const int x0 = bounds.left();
95 const int y0 = bounds.top();
96
robertphillips393aa362016-03-10 04:44:20 -080097 SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
98 kPremul_SkAlphaType);
99
robertphillips37bd7c32016-03-17 14:31:39 -0700100 sk_sp<SkSpecialSurface> surf(source->makeSurface(info));
robertphillips393aa362016-03-10 04:44:20 -0800101 if (!surf) {
102 return nullptr;
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000103 }
robertphillips393aa362016-03-10 04:44:20 -0800104
105 SkCanvas* canvas = surf->getCanvas();
106 SkASSERT(canvas);
107
108 canvas->clear(0x0);
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000109
senorblanco4a243982015-11-25 07:06:55 -0800110 // Composite all of the filter inputs.
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000111 for (int i = 0; i < inputCount; ++i) {
robertphillips393aa362016-03-10 04:44:20 -0800112 if (!inputs[i]) {
113 continue;
114 }
115
senorblanco4a243982015-11-25 07:06:55 -0800116 SkPaint paint;
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000117 if (fModes) {
118 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000119 }
robertphillips393aa362016-03-10 04:44:20 -0800120
121 inputs[i]->draw(canvas,
122 SkIntToScalar(offsets[i].x() - x0), SkIntToScalar(offsets[i].y() - y0),
123 &paint);
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000124 }
125
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000126 offset->fX = bounds.left();
127 offset->fY = bounds.top();
robertphillips2302de92016-03-24 07:26:32 -0700128 return surf->makeImageSnapshot();
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000129}
130
reed9fa60da2014-08-21 07:59:51 -0700131SkFlattenable* SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) {
132 Common common;
133 if (!common.unflatten(buffer, -1)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700134 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700135 }
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)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700143 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700144 }
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()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700150 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700151 }
robertphillips2238c9d2016-03-30 13:34:16 -0700152 return Make(common.inputs(), count, modes.get(), &common.cropRect()).release();
reed9fa60da2014-08-21 07:59:51 -0700153 }
robertphillips2238c9d2016-03-30 13:34:16 -0700154 return Make(common.inputs(), count, nullptr, &common.cropRect()).release();
reed9fa60da2014-08-21 07:59:51 -0700155}
156
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000157void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000158 this->INHERITED::flatten(buffer);
halcanary96fcdcc2015-08-27 07:41:13 -0700159 buffer.writeBool(fModes != nullptr);
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000160 if (fModes) {
senorblanco4a243982015-11-25 07:06:55 -0800161 buffer.writeByteArray(fModes, this->countInputs() * sizeof(fModes[0]));
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +0000162 }
163}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800164
165#ifndef SK_IGNORE_TO_STRING
166void SkMergeImageFilter::toString(SkString* str) const {
167 str->appendf("SkMergeImageFilter: (");
halcanary9d524f22016-03-29 09:03:52 -0700168
robertphillipsf3f5bad2014-12-19 13:49:15 -0800169 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