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 "SkFlattenableBuffers.h" 12#include "SkValidationUtils.h" 13 14/////////////////////////////////////////////////////////////////////////////// 15 16void SkMergeImageFilter::initAllocModes() { 17 int inputCount = countInputs(); 18 if (inputCount) { 19 size_t size = sizeof(uint8_t) * inputCount; 20 if (size <= sizeof(fStorage)) { 21 fModes = SkTCast<uint8_t*>(fStorage); 22 } else { 23 fModes = SkTCast<uint8_t*>(sk_malloc_throw(size)); 24 } 25 } else { 26 fModes = NULL; 27 } 28} 29 30void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) { 31 if (modes) { 32 this->initAllocModes(); 33 int inputCount = countInputs(); 34 for (int i = 0; i < inputCount; ++i) { 35 fModes[i] = SkToU8(modes[i]); 36 } 37 } else { 38 fModes = NULL; 39 } 40} 41 42SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second, 43 SkXfermode::Mode mode, 44 const CropRect* cropRect) : INHERITED(first, second, cropRect) { 45 if (SkXfermode::kSrcOver_Mode != mode) { 46 SkXfermode::Mode modes[] = { mode, mode }; 47 this->initModes(modes); 48 } else { 49 fModes = NULL; 50 } 51} 52 53SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count, 54 const SkXfermode::Mode modes[], 55 const CropRect* cropRect) : INHERITED(count, filters, cropRect) { 56 SkASSERT(count >= 0); 57 this->initModes(modes); 58} 59 60SkMergeImageFilter::~SkMergeImageFilter() { 61 62 if (fModes != SkTCast<uint8_t*>(fStorage)) { 63 sk_free(fModes); 64 } 65} 66 67bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 68 SkIRect* dst) { 69 if (countInputs() < 1) { 70 return false; 71 } 72 73 SkIRect totalBounds; 74 75 int inputCount = countInputs(); 76 for (int i = 0; i < inputCount; ++i) { 77 SkImageFilter* filter = getInput(i); 78 SkIRect r; 79 if (filter) { 80 if (!filter->filterBounds(src, ctm, &r)) { 81 return false; 82 } 83 } else { 84 r = src; 85 } 86 if (0 == i) { 87 totalBounds = r; 88 } else { 89 totalBounds.join(r); 90 } 91 } 92 93 // don't modify dst until now, so we don't accidentally change it in the 94 // loop, but then return false on the next filter. 95 *dst = totalBounds; 96 return true; 97} 98 99bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, 100 const SkMatrix& ctm, 101 SkBitmap* result, SkIPoint* loc) { 102 if (countInputs() < 1) { 103 return false; 104 } 105 106 SkIRect bounds; 107 src.getBounds(&bounds); 108 if (!this->applyCropRect(&bounds, ctm)) { 109 return false; 110 } 111 112 const int x0 = bounds.left(); 113 const int y0 = bounds.top(); 114 115 SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height())); 116 if (NULL == dst) { 117 return false; 118 } 119 SkCanvas canvas(dst); 120 SkPaint paint; 121 122 int inputCount = countInputs(); 123 for (int i = 0; i < inputCount; ++i) { 124 SkBitmap tmp; 125 const SkBitmap* srcPtr; 126 SkIPoint pos = SkIPoint::Make(0, 0); 127 SkImageFilter* filter = getInput(i); 128 if (filter) { 129 if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) { 130 return false; 131 } 132 srcPtr = &tmp; 133 } else { 134 srcPtr = &src; 135 } 136 137 if (fModes) { 138 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]); 139 } else { 140 paint.setXfermode(NULL); 141 } 142 canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint); 143 } 144 145 loc->fX += bounds.left(); 146 loc->fY += bounds.top(); 147 *result = dst->accessBitmap(false); 148 return true; 149} 150 151void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 152 this->INHERITED::flatten(buffer); 153 154 buffer.writeBool(fModes != NULL); 155 if (fModes) { 156 buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0])); 157 } 158} 159 160SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) 161 : INHERITED(-1, buffer) { 162 bool hasModes = buffer.readBool(); 163 if (hasModes) { 164 this->initAllocModes(); 165 int nbInputs = countInputs(); 166 size_t size = nbInputs * sizeof(fModes[0]); 167 SkASSERT(buffer.getArrayCount() == size); 168 if (buffer.readByteArray(fModes, size)) { 169 for (int i = 0; i < nbInputs; ++i) { 170 buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i])); 171 } 172 } 173 } else { 174 fModes = 0; 175 } 176} 177