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