SkMergeImageFilter.cpp revision c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cf
14a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org/*
24a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org * Copyright 2012 The Android Open Source Project
34a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org *
44a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be
54a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org * found in the LICENSE file.
64a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org */
74a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
84a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org#include "SkMergeImageFilter.h"
94a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org#include "SkCanvas.h"
104a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org#include "SkDevice.h"
114a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org#include "SkFlattenableBuffers.h"
12c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org#include "SkValidationUtils.h"
134a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
144a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
154a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
164a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgvoid SkMergeImageFilter::initAllocModes() {
174a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    int inputCount = countInputs();
184a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (inputCount) {
194a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        size_t size = sizeof(uint8_t) * inputCount;
204a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (size <= sizeof(fStorage)) {
214a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            fModes = SkTCast<uint8_t*>(fStorage);
224a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
234a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
244a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
254a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
264a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = NULL;
274a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
284a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
294a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
304a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgvoid SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
314a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (modes) {
324a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        this->initAllocModes();
334a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        int inputCount = countInputs();
344a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        for (int i = 0; i < inputCount; ++i) {
354a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            fModes[i] = SkToU8(modes[i]);
364a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
374a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
384a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = NULL;
394a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
404a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
414a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
424a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
43962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org                                       SkXfermode::Mode mode,
44b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org                                       const CropRect* cropRect) : INHERITED(first, second, cropRect) {
454a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (SkXfermode::kSrcOver_Mode != mode) {
464a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkXfermode::Mode modes[] = { mode, mode };
474a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        this->initModes(modes);
484a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
494a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = NULL;
504a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
514a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
524a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
534a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
54962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org                                       const SkXfermode::Mode modes[],
55b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org                                       const CropRect* cropRect) : INHERITED(count, filters, cropRect) {
564a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    this->initModes(modes);
574a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
584a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
594a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgSkMergeImageFilter::~SkMergeImageFilter() {
604a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
614a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (fModes != SkTCast<uint8_t*>(fStorage)) {
624a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        sk_free(fModes);
634a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
644a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
654a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
664a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgbool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
674a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org                                        SkIRect* dst) {
684a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (countInputs() < 1) {
694a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
704a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
714a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
724a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkIRect totalBounds;
734a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
744a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    int inputCount = countInputs();
754a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    for (int i = 0; i < inputCount; ++i) {
764a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkImageFilter* filter = getInput(i);
774a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkIRect r;
784a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (filter) {
794a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            if (!filter->filterBounds(src, ctm, &r)) {
804a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org                return false;
814a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            }
824a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
834a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            r = src;
844a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
854a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (0 == i) {
864a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            totalBounds = r;
874a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
884a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            totalBounds.join(r);
894a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
904a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
914a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
924a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    // don't modify dst until now, so we don't accidentally change it in the
934a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    // loop, but then return false on the next filter.
944a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    *dst = totalBounds;
954a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    return true;
964a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
974a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
984a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgbool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
994a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org                                       const SkMatrix& ctm,
1004a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org                                       SkBitmap* result, SkIPoint* loc) {
1014a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (countInputs() < 1) {
1024a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
1034a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1044a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1054a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkIRect bounds;
106962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org    src.getBounds(&bounds);
107962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org    if (!this->applyCropRect(&bounds, ctm)) {
1084a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
1094a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1104a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1114a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    const int x0 = bounds.left();
1124a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    const int y0 = bounds.top();
1134a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1141f2f338e23789f3eef168dcbd8171a28820ba6c1robertphillips@google.com    SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
1154a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (NULL == dst) {
1164a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
1174a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1184a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkCanvas canvas(dst);
1194a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkPaint paint;
1204a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1214a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    int inputCount = countInputs();
1224a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    for (int i = 0; i < inputCount; ++i) {
1234a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkBitmap tmp;
1244a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        const SkBitmap* srcPtr;
125962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org        SkIPoint pos = SkIPoint::Make(0, 0);
1264a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkImageFilter* filter = getInput(i);
1274a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (filter) {
1284a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
1294a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org                return false;
1304a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            }
1314a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            srcPtr = &tmp;
1324a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
1334a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            srcPtr = &src;
1344a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
1354a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1364a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (fModes) {
1374a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
1384a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
1394a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            paint.setXfermode(NULL);
1404a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
1414a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
1424a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1434a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
144962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org    loc->fX += bounds.left();
145962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org    loc->fY += bounds.top();
1464a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    *result = dst->accessBitmap(false);
1474a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    return true;
1484a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
1494a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1504a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgvoid SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
1514a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    this->INHERITED::flatten(buffer);
1524a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1534a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    buffer.writeBool(fModes != NULL);
1544a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (fModes) {
1554a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
1564a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1574a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
1584a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1594a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
1604a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    bool hasModes = buffer.readBool();
1614a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (hasModes) {
1624a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        this->initAllocModes();
163c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        int nbInputs = countInputs();
164c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        SkASSERT(buffer.getArrayCount() == nbInputs * sizeof(fModes[0]));
1654a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        buffer.readByteArray(fModes);
166c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        for (int i = 0; i < nbInputs; ++i) {
167c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org            buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
168c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        }
1694a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
1704a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = 0;
1714a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1724a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
173