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 = NULL; 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 = NULL; 40 } 41} 42 43SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second, 44 SkXfermode::Mode mode, 45 const CropRect* cropRect) : INHERITED(first, second, cropRect) { 46 if (SkXfermode::kSrcOver_Mode != mode) { 47 SkXfermode::Mode modes[] = { mode, mode }; 48 this->initModes(modes); 49 } else { 50 fModes = NULL; 51 } 52} 53 54SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count, 55 const SkXfermode::Mode modes[], 56 const CropRect* cropRect) : INHERITED(count, filters, cropRect) { 57 SkASSERT(count >= 0); 58 this->initModes(modes); 59} 60 61SkMergeImageFilter::~SkMergeImageFilter() { 62 63 if (fModes != SkTCast<uint8_t*>(fStorage)) { 64 sk_free(fModes); 65 } 66} 67 68bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, 69 const Context& ctx, 70 SkBitmap* result, SkIPoint* offset) const { 71 if (countInputs() < 1) { 72 return false; 73 } 74 75 SkIRect bounds; 76 if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) { 77 return false; 78 } 79 80 const int x0 = bounds.left(); 81 const int y0 = bounds.top(); 82 83 SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height())); 84 if (NULL == dst) { 85 return false; 86 } 87 SkCanvas canvas(dst); 88 SkPaint paint; 89 90 int inputCount = countInputs(); 91 for (int i = 0; i < inputCount; ++i) { 92 SkBitmap tmp; 93 const SkBitmap* srcPtr; 94 SkIPoint pos = SkIPoint::Make(0, 0); 95 SkImageFilter* filter = getInput(i); 96 if (filter) { 97 if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) { 98 return false; 99 } 100 srcPtr = &tmp; 101 } else { 102 srcPtr = &src; 103 } 104 105 if (fModes) { 106 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]); 107 } else { 108 paint.setXfermode(NULL); 109 } 110 canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint); 111 } 112 113 offset->fX = bounds.left(); 114 offset->fY = bounds.top(); 115 *result = dst->accessBitmap(false); 116 return true; 117} 118 119void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const { 120 this->INHERITED::flatten(buffer); 121 122 buffer.writeBool(fModes != NULL); 123 if (fModes) { 124 buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0])); 125 } 126} 127 128SkMergeImageFilter::SkMergeImageFilter(SkReadBuffer& buffer) 129 : INHERITED(-1, buffer) { 130 bool hasModes = buffer.readBool(); 131 if (hasModes) { 132 this->initAllocModes(); 133 int nbInputs = countInputs(); 134 size_t size = nbInputs * sizeof(fModes[0]); 135 SkASSERT(buffer.getArrayCount() == size); 136 if (buffer.validate(buffer.getArrayCount() == size) && 137 buffer.readByteArray(fModes, size)) { 138 for (int i = 0; i < nbInputs; ++i) { 139 buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i])); 140 } 141 } 142 } else { 143 fModes = 0; 144 } 145} 146