Pull SkMergeImageFilter out into its own file.
Review URL: https://codereview.appspot.com/6873052
git-svn-id: http://skia.googlecode.com/svn/trunk@6662 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkMergeImageFilter.cpp b/src/effects/SkMergeImageFilter.cpp
new file mode 100755
index 0000000..0c1388f
--- /dev/null
+++ b/src/effects/SkMergeImageFilter.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMergeImageFilter.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkFlattenableBuffers.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMergeImageFilter::initAllocModes() {
+ int inputCount = countInputs();
+ if (inputCount) {
+ size_t size = sizeof(uint8_t) * inputCount;
+ if (size <= sizeof(fStorage)) {
+ fModes = SkTCast<uint8_t*>(fStorage);
+ } else {
+ fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
+ }
+ } else {
+ fModes = NULL;
+ }
+}
+
+void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
+ if (modes) {
+ this->initAllocModes();
+ int inputCount = countInputs();
+ for (int i = 0; i < inputCount; ++i) {
+ fModes[i] = SkToU8(modes[i]);
+ }
+ } else {
+ fModes = NULL;
+ }
+}
+
+SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
+ SkXfermode::Mode mode) : INHERITED(first, second) {
+ if (SkXfermode::kSrcOver_Mode != mode) {
+ SkXfermode::Mode modes[] = { mode, mode };
+ this->initModes(modes);
+ } else {
+ fModes = NULL;
+ }
+}
+
+SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
+ const SkXfermode::Mode modes[]) : INHERITED(count, filters) {
+ this->initModes(modes);
+}
+
+SkMergeImageFilter::~SkMergeImageFilter() {
+
+ if (fModes != SkTCast<uint8_t*>(fStorage)) {
+ sk_free(fModes);
+ }
+}
+
+bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst) {
+ if (countInputs() < 1) {
+ return false;
+ }
+
+ SkIRect totalBounds;
+
+ int inputCount = countInputs();
+ for (int i = 0; i < inputCount; ++i) {
+ SkImageFilter* filter = getInput(i);
+ SkIRect r;
+ if (filter) {
+ if (!filter->filterBounds(src, ctm, &r)) {
+ return false;
+ }
+ } else {
+ r = src;
+ }
+ if (0 == i) {
+ totalBounds = r;
+ } else {
+ totalBounds.join(r);
+ }
+ }
+
+ // don't modify dst until now, so we don't accidentally change it in the
+ // loop, but then return false on the next filter.
+ *dst = totalBounds;
+ return true;
+}
+
+bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* loc) {
+ if (countInputs() < 1) {
+ return false;
+ }
+
+ const SkIRect srcBounds = SkIRect::MakeXYWH(loc->x(), loc->y(),
+ src.width(), src.height());
+ SkIRect bounds;
+ if (!this->filterBounds(srcBounds, ctm, &bounds)) {
+ return false;
+ }
+
+ const int x0 = bounds.left();
+ const int y0 = bounds.top();
+
+ SkAutoTUnref<SkDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
+ if (NULL == dst) {
+ return false;
+ }
+ SkCanvas canvas(dst);
+ SkPaint paint;
+
+ int inputCount = countInputs();
+ for (int i = 0; i < inputCount; ++i) {
+ SkBitmap tmp;
+ const SkBitmap* srcPtr;
+ SkIPoint pos = *loc;
+ SkImageFilter* filter = getInput(i);
+ if (filter) {
+ if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
+ return false;
+ }
+ srcPtr = &tmp;
+ } else {
+ srcPtr = &src;
+ }
+
+ if (fModes) {
+ paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
+ } else {
+ paint.setXfermode(NULL);
+ }
+ canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
+ }
+
+ loc->set(bounds.left(), bounds.top());
+ *result = dst->accessBitmap(false);
+ return true;
+}
+
+void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+
+ buffer.writeBool(fModes != NULL);
+ if (fModes) {
+ buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
+ }
+}
+
+SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+ bool hasModes = buffer.readBool();
+ if (hasModes) {
+ this->initAllocModes();
+ SkASSERT(buffer.getArrayCount() == countInputs() * sizeof(fModes[0]));
+ buffer.readByteArray(fModes);
+ } else {
+ fModes = 0;
+ }
+}