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 = this->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 = this->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::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src, 59 const Context& ctx, 60 SkBitmap* result, SkIPoint* offset) const { 61 int inputCount = this->countInputs(); 62 if (inputCount < 1) { 63 return false; 64 } 65 66 SkIRect bounds; 67 68 SkAutoTDeleteArray<SkBitmap> inputs(new SkBitmap[inputCount]); 69 SkAutoTDeleteArray<SkIPoint> offsets(new SkIPoint[inputCount]); 70 bool didProduceResult = false; 71 72 // Filter all of the inputs. 73 for (int i = 0; i < inputCount; ++i) { 74 inputs[i] = src; 75 offsets[i].setZero(); 76 if (!this->filterInputDeprecated(i, proxy, src, ctx, &inputs[i], &offsets[i])) { 77 inputs[i].reset(); 78 continue; 79 } 80 SkIRect srcBounds; 81 inputs[i].getBounds(&srcBounds); 82 srcBounds.offset(offsets[i]); 83 if (!didProduceResult) { 84 bounds = srcBounds; 85 didProduceResult = true; 86 } else { 87 bounds.join(srcBounds); 88 } 89 } 90 if (!didProduceResult) { 91 return false; 92 } 93 94 // Apply the crop rect to the union of the inputs' bounds. 95 this->getCropRect().applyTo(bounds, ctx.ctm(), &bounds); 96 if (!bounds.intersect(ctx.clipBounds())) { 97 return false; 98 } 99 100 const int x0 = bounds.left(); 101 const int y0 = bounds.top(); 102 103 // Allocate the destination buffer. 104 SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height())); 105 if (nullptr == dst) { 106 return false; 107 } 108 SkCanvas canvas(dst); 109 110 // Composite all of the filter inputs. 111 for (int i = 0; i < inputCount; ++i) { 112 SkPaint paint; 113 if (fModes) { 114 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]); 115 } 116 canvas.drawBitmap(inputs[i], SkIntToScalar(offsets[i].x() - x0), 117 SkIntToScalar(offsets[i].y() - y0), &paint); 118 } 119 120 offset->fX = bounds.left(); 121 offset->fY = bounds.top(); 122 *result = dst->accessBitmap(false); 123 return true; 124} 125 126SkFlattenable* SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) { 127 Common common; 128 if (!common.unflatten(buffer, -1)) { 129 return nullptr; 130 } 131 132 const int count = common.inputCount(); 133 bool hasModes = buffer.readBool(); 134 if (hasModes) { 135 SkAutoSTArray<4, SkXfermode::Mode> modes(count); 136 SkAutoSTArray<4, uint8_t> modes8(count); 137 if (!buffer.readByteArray(modes8.get(), count)) { 138 return nullptr; 139 } 140 for (int i = 0; i < count; ++i) { 141 modes[i] = (SkXfermode::Mode)modes8[i]; 142 buffer.validate(SkIsValidMode(modes[i])); 143 } 144 if (!buffer.isValid()) { 145 return nullptr; 146 } 147 return Create(common.inputs(), count, modes.get(), &common.cropRect()); 148 } 149 return Create(common.inputs(), count, nullptr, &common.cropRect()); 150} 151 152void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const { 153 this->INHERITED::flatten(buffer); 154 buffer.writeBool(fModes != nullptr); 155 if (fModes) { 156 buffer.writeByteArray(fModes, this->countInputs() * sizeof(fModes[0])); 157 } 158} 159 160#ifndef SK_IGNORE_TO_STRING 161void SkMergeImageFilter::toString(SkString* str) const { 162 str->appendf("SkMergeImageFilter: ("); 163 164 for (int i = 0; i < this->countInputs(); ++i) { 165 SkImageFilter* filter = this->getInput(i); 166 str->appendf("%d: (", i); 167 filter->toString(str); 168 str->appendf(")"); 169 } 170 171 str->append(")"); 172} 173#endif 174