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