10cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org/*
20cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org * Copyright 2012 The Android Open Source Project
30cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org *
40cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be
50cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org * found in the LICENSE file.
60cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org */
70cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
80cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org#include "SkMergeImageFilter.h"
90cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org#include "SkCanvas.h"
100cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org#include "SkDevice.h"
110cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org#include "SkFlattenableBuffers.h"
123218b023674b5d0bfc3eca0a6bd6800e24660b8ecommit-bot@chromium.org#include "SkValidationUtils.h"
130cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
140cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
150cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
160cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.orgvoid SkMergeImageFilter::initAllocModes() {
170cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    int inputCount = countInputs();
180cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (inputCount) {
190cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        size_t size = sizeof(uint8_t) * inputCount;
200cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        if (size <= sizeof(fStorage)) {
210cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            fModes = SkTCast<uint8_t*>(fStorage);
220cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        } else {
230cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
240cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        }
250cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    } else {
260cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        fModes = NULL;
270cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
280cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
290cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
300cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.orgvoid SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
310cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (modes) {
320cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        this->initAllocModes();
330cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        int inputCount = countInputs();
340cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        for (int i = 0; i < inputCount; ++i) {
350cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            fModes[i] = SkToU8(modes[i]);
360cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        }
370cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    } else {
380cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        fModes = NULL;
390cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
400cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
410cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
420cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
433822393952bf5e8aa60fb69ceb21300be37819dfsenorblanco@chromium.org                                       SkXfermode::Mode mode,
44a308293b09f3e34492eac153a1c3ddd3e639831asenorblanco@chromium.org                                       const CropRect* cropRect) : INHERITED(first, second, cropRect) {
450cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (SkXfermode::kSrcOver_Mode != mode) {
460cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        SkXfermode::Mode modes[] = { mode, mode };
470cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        this->initModes(modes);
480cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    } else {
490cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        fModes = NULL;
500cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
510cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
520cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
530cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
543822393952bf5e8aa60fb69ceb21300be37819dfsenorblanco@chromium.org                                       const SkXfermode::Mode modes[],
55a308293b09f3e34492eac153a1c3ddd3e639831asenorblanco@chromium.org                                       const CropRect* cropRect) : INHERITED(count, filters, cropRect) {
56ca21698b7babb16f59c516ecb59ef7de4b15e412commit-bot@chromium.org    SkASSERT(count >= 0);
570cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    this->initModes(modes);
580cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
590cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
600cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.orgSkMergeImageFilter::~SkMergeImageFilter() {
610cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
620cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (fModes != SkTCast<uint8_t*>(fStorage)) {
630cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        sk_free(fModes);
640cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
650cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
660cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
670cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.orgbool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
680cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org                                        SkIRect* dst) {
690cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (countInputs() < 1) {
700cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        return false;
710cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
720cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
730cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    SkIRect totalBounds;
740cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
750cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    int inputCount = countInputs();
760cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    for (int i = 0; i < inputCount; ++i) {
770cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        SkImageFilter* filter = getInput(i);
780cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        SkIRect r;
790cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        if (filter) {
800cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            if (!filter->filterBounds(src, ctm, &r)) {
810cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org                return false;
820cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            }
830cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        } else {
840cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            r = src;
850cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        }
860cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        if (0 == i) {
870cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            totalBounds = r;
880cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        } else {
890cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            totalBounds.join(r);
900cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        }
910cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
920cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
930cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    // don't modify dst until now, so we don't accidentally change it in the
940cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    // loop, but then return false on the next filter.
950cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    *dst = totalBounds;
960cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    return true;
970cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
980cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
990cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.orgbool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
1000cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org                                       const SkMatrix& ctm,
1010cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org                                       SkBitmap* result, SkIPoint* loc) {
1020cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (countInputs() < 1) {
1030cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        return false;
1040cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
1050cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1060cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    SkIRect bounds;
1073822393952bf5e8aa60fb69ceb21300be37819dfsenorblanco@chromium.org    src.getBounds(&bounds);
1083822393952bf5e8aa60fb69ceb21300be37819dfsenorblanco@chromium.org    if (!this->applyCropRect(&bounds, ctm)) {
1090cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        return false;
1100cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
1110cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1120cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    const int x0 = bounds.left();
1130cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    const int y0 = bounds.top();
1140cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1152fd2390b98908719dd1e94662706ffe6b0dfc659robertphillips@google.com    SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
1160cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (NULL == dst) {
1170cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        return false;
1180cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
1190cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    SkCanvas canvas(dst);
1200cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    SkPaint paint;
1210cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1220cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    int inputCount = countInputs();
1230cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    for (int i = 0; i < inputCount; ++i) {
1240cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        SkBitmap tmp;
1250cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        const SkBitmap* srcPtr;
1263822393952bf5e8aa60fb69ceb21300be37819dfsenorblanco@chromium.org        SkIPoint pos = SkIPoint::Make(0, 0);
1270cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        SkImageFilter* filter = getInput(i);
1280cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        if (filter) {
1290cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
1300cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org                return false;
1310cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            }
1320cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            srcPtr = &tmp;
1330cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        } else {
1340cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            srcPtr = &src;
1350cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        }
1360cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1370cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        if (fModes) {
1380cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
1390cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        } else {
1400cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org            paint.setXfermode(NULL);
1410cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        }
1420cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
1430cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
1440cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1453822393952bf5e8aa60fb69ceb21300be37819dfsenorblanco@chromium.org    loc->fX += bounds.left();
1463822393952bf5e8aa60fb69ceb21300be37819dfsenorblanco@chromium.org    loc->fY += bounds.top();
1470cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    *result = dst->accessBitmap(false);
1480cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    return true;
1490cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
1500cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1510cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.orgvoid SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
1520cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    this->INHERITED::flatten(buffer);
1530cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1540cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    buffer.writeBool(fModes != NULL);
1550cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (fModes) {
1560cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
1570cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
1580cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
1590cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org
1603c6b25d019f8a2f79ad09934c85dc5ec55ceeaaccommit-bot@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer)
161ca21698b7babb16f59c516ecb59ef7de4b15e412commit-bot@chromium.org  : INHERITED(-1, buffer) {
1620cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    bool hasModes = buffer.readBool();
1630cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    if (hasModes) {
1640cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        this->initAllocModes();
1653218b023674b5d0bfc3eca0a6bd6800e24660b8ecommit-bot@chromium.org        int nbInputs = countInputs();
166863cb3951e8da2d2eb8efd57c94d8f5ba069123ccommit-bot@chromium.org        size_t size = nbInputs * sizeof(fModes[0]);
167863cb3951e8da2d2eb8efd57c94d8f5ba069123ccommit-bot@chromium.org        SkASSERT(buffer.getArrayCount() == size);
168ce9b6b24ac76aa0494ca27509a215d4abb5640e2commit-bot@chromium.org        if (buffer.readByteArray(fModes, size)) {
169ce9b6b24ac76aa0494ca27509a215d4abb5640e2commit-bot@chromium.org            for (int i = 0; i < nbInputs; ++i) {
170ce9b6b24ac76aa0494ca27509a215d4abb5640e2commit-bot@chromium.org                buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
171ce9b6b24ac76aa0494ca27509a215d4abb5640e2commit-bot@chromium.org            }
1723218b023674b5d0bfc3eca0a6bd6800e24660b8ecommit-bot@chromium.org        }
1730cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    } else {
1740cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org        fModes = 0;
1750cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org    }
1760cef3808fc44c7a4e5eef30f9604517776e61975senorblanco@chromium.org}
177