SkMergeImageFilter.cpp revision 18fa6421e9cb7ac2ea6b1a97112a115d6643c0fc
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 10#include "SkCanvas.h" 11#include "SkReadBuffer.h" 12#include "SkSpecialImage.h" 13#include "SkSpecialSurface.h" 14#include "SkWriteBuffer.h" 15#include "SkValidationUtils.h" 16 17sk_sp<SkImageFilter> SkMergeImageFilter::Make(sk_sp<SkImageFilter> first, 18 sk_sp<SkImageFilter> second, 19 SkXfermode::Mode mode, 20 const CropRect* cropRect) { 21 sk_sp<SkImageFilter> inputs[2] = { first, second }; 22 SkXfermode::Mode modes[2] = { mode, mode }; 23 return sk_sp<SkImageFilter>(new SkMergeImageFilter(inputs, 2, modes, cropRect)); 24} 25 26sk_sp<SkImageFilter> SkMergeImageFilter::Make(sk_sp<SkImageFilter> filters[], 27 int count, 28 const SkXfermode::Mode modes[], 29 const CropRect* cropRect) { 30 return sk_sp<SkImageFilter>(new SkMergeImageFilter(filters, count, modes, cropRect)); 31} 32 33/////////////////////////////////////////////////////////////////////////////// 34 35void SkMergeImageFilter::initAllocModes() { 36 int inputCount = this->countInputs(); 37 if (inputCount) { 38 size_t size = sizeof(uint8_t) * inputCount; 39 if (size <= sizeof(fStorage)) { 40 fModes = SkTCast<uint8_t*>(fStorage); 41 } else { 42 fModes = SkTCast<uint8_t*>(sk_malloc_throw(size)); 43 } 44 } else { 45 fModes = nullptr; 46 } 47} 48 49void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) { 50 if (modes) { 51 this->initAllocModes(); 52 int inputCount = this->countInputs(); 53 for (int i = 0; i < inputCount; ++i) { 54 fModes[i] = SkToU8(modes[i]); 55 } 56 } else { 57 fModes = nullptr; 58 } 59} 60 61SkMergeImageFilter::SkMergeImageFilter(sk_sp<SkImageFilter> filters[], int count, 62 const SkXfermode::Mode modes[], 63 const CropRect* cropRect) 64 : INHERITED(filters, count, cropRect) { 65 SkASSERT(count >= 0); 66 this->initModes(modes); 67} 68 69SkMergeImageFilter::~SkMergeImageFilter() { 70 71 if (fModes != SkTCast<uint8_t*>(fStorage)) { 72 sk_free(fModes); 73 } 74} 75 76sk_sp<SkSpecialImage> SkMergeImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, 77 SkIPoint* offset) const { 78 int inputCount = this->countInputs(); 79 if (inputCount < 1) { 80 return nullptr; 81 } 82 83 SkIRect bounds; 84 bounds.setEmpty(); 85 86 SkAutoTDeleteArray<sk_sp<SkSpecialImage>> inputs(new sk_sp<SkSpecialImage>[inputCount]); 87 SkAutoTDeleteArray<SkIPoint> offsets(new SkIPoint[inputCount]); 88 89 // Filter all of the inputs. 90 for (int i = 0; i < inputCount; ++i) { 91 offsets[i].setZero(); 92 inputs[i] = this->filterInput(i, source, ctx, &offsets[i]); 93 if (!inputs[i]) { 94 continue; 95 } 96 const SkIRect inputBounds = SkIRect::MakeXYWH(offsets[i].fX, offsets[i].fY, 97 inputs[i]->width(), inputs[i]->height()); 98 bounds.join(inputBounds); 99 } 100 if (bounds.isEmpty()) { 101 return nullptr; 102 } 103 104 // Apply the crop rect to the union of the inputs' bounds. 105 // Note that the crop rect can only reduce the bounds, since this 106 // filter does not affect transparent black. 107 bool embiggen = false; 108 this->getCropRect().applyTo(bounds, ctx.ctm(), embiggen, &bounds); 109 if (!bounds.intersect(ctx.clipBounds())) { 110 return nullptr; 111 } 112 113 const int x0 = bounds.left(); 114 const int y0 = bounds.top(); 115 116 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); 117 if (!surf) { 118 return nullptr; 119 } 120 121 SkCanvas* canvas = surf->getCanvas(); 122 SkASSERT(canvas); 123 124 canvas->clear(0x0); 125 126 // Composite all of the filter inputs. 127 for (int i = 0; i < inputCount; ++i) { 128 if (!inputs[i]) { 129 continue; 130 } 131 132 SkPaint paint; 133 if (fModes) { 134 paint.setBlendMode((SkBlendMode)fModes[i]); 135 } 136 137 inputs[i]->draw(canvas, 138 SkIntToScalar(offsets[i].x() - x0), SkIntToScalar(offsets[i].y() - y0), 139 &paint); 140 } 141 142 offset->fX = bounds.left(); 143 offset->fY = bounds.top(); 144 return surf->makeImageSnapshot(); 145} 146 147sk_sp<SkFlattenable> SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) { 148 Common common; 149 if (!common.unflatten(buffer, -1)) { 150 return nullptr; 151 } 152 153 const int count = common.inputCount(); 154 bool hasModes = buffer.readBool(); 155 if (hasModes) { 156 SkAutoSTArray<4, SkXfermode::Mode> modes(count); 157 SkAutoSTArray<4, uint8_t> modes8(count); 158 if (!buffer.readByteArray(modes8.get(), count)) { 159 return nullptr; 160 } 161 for (int i = 0; i < count; ++i) { 162 modes[i] = (SkXfermode::Mode)modes8[i]; 163 buffer.validate(SkIsValidMode(modes[i])); 164 } 165 if (!buffer.isValid()) { 166 return nullptr; 167 } 168 return Make(common.inputs(), count, modes.get(), &common.cropRect()); 169 } 170 return Make(common.inputs(), count, nullptr, &common.cropRect()); 171} 172 173void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const { 174 this->INHERITED::flatten(buffer); 175 buffer.writeBool(fModes != nullptr); 176 if (fModes) { 177 buffer.writeByteArray(fModes, this->countInputs() * sizeof(fModes[0])); 178 } 179} 180 181#ifndef SK_IGNORE_TO_STRING 182void SkMergeImageFilter::toString(SkString* str) const { 183 str->appendf("SkMergeImageFilter: ("); 184 185 for (int i = 0; i < this->countInputs(); ++i) { 186 SkImageFilter* filter = this->getInput(i); 187 str->appendf("%d: (", i); 188 filter->toString(str); 189 str->appendf(")"); 190 } 191 192 str->append(")"); 193} 194#endif 195