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"
118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
13c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org#include "SkValidationUtils.h"
144a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
154a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
164a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
174a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgvoid SkMergeImageFilter::initAllocModes() {
184a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    int inputCount = countInputs();
194a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (inputCount) {
204a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        size_t size = sizeof(uint8_t) * inputCount;
214a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (size <= sizeof(fStorage)) {
224a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            fModes = SkTCast<uint8_t*>(fStorage);
234a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
244a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
254a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
264a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
274a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = NULL;
284a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
294a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
304a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
314a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgvoid SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
324a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (modes) {
334a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        this->initAllocModes();
344a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        int inputCount = countInputs();
354a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        for (int i = 0; i < inputCount; ++i) {
364a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            fModes[i] = SkToU8(modes[i]);
374a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
384a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
394a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = NULL;
404a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
414a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
424a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
434a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
44962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org                                       SkXfermode::Mode mode,
45b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org                                       const CropRect* cropRect) : INHERITED(first, second, cropRect) {
464a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (SkXfermode::kSrcOver_Mode != mode) {
474a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkXfermode::Mode modes[] = { mode, mode };
484a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        this->initModes(modes);
494a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
504a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = NULL;
514a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
524a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
534a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
544a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
55962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org                                       const SkXfermode::Mode modes[],
56b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org                                       const CropRect* cropRect) : INHERITED(count, filters, cropRect) {
57c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org    SkASSERT(count >= 0);
584a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    this->initModes(modes);
594a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
604a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
614a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgSkMergeImageFilter::~SkMergeImageFilter() {
624a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
634a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (fModes != SkTCast<uint8_t*>(fStorage)) {
644a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        sk_free(fModes);
654a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
664a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
674a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
684a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgbool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
694cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org                                       const Context& ctx,
70ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                       SkBitmap* result, SkIPoint* offset) const {
714a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (countInputs() < 1) {
724a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
734a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
744a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
754a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkIRect bounds;
76118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org    if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
774a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
784a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
794a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
804a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    const int x0 = bounds.left();
814a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    const int y0 = bounds.top();
824a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
831f2f338e23789f3eef168dcbd8171a28820ba6c1robertphillips@google.com    SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
844a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (NULL == dst) {
854a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
864a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
874a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkCanvas canvas(dst);
884a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkPaint paint;
894a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
904a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    int inputCount = countInputs();
914a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    for (int i = 0; i < inputCount; ++i) {
924a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkBitmap tmp;
934a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        const SkBitmap* srcPtr;
94962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org        SkIPoint pos = SkIPoint::Make(0, 0);
954a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkImageFilter* filter = getInput(i);
964a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (filter) {
974cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org            if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
984a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org                return false;
994a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            }
1004a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            srcPtr = &tmp;
1014a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
1024a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            srcPtr = &src;
1034a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
1044a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1054a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (fModes) {
1064a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
1074a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
1084a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            paint.setXfermode(NULL);
1094a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
1104a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
1114a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1124a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1136776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fX = bounds.left();
1146776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fY = bounds.top();
1154a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    *result = dst->accessBitmap(false);
1164a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    return true;
1174a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
1184a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1198b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
1204a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    this->INHERITED::flatten(buffer);
1214a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1224a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    buffer.writeBool(fModes != NULL);
1234a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (fModes) {
1244a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
1254a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1264a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
1274a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1288b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkReadBuffer& buffer)
129c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org  : INHERITED(-1, buffer) {
1304a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    bool hasModes = buffer.readBool();
1314a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (hasModes) {
1324a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        this->initAllocModes();
133c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        int nbInputs = countInputs();
134025128811219dc45fd99b6c4d1d14f833cf7a26ecommit-bot@chromium.org        size_t size = nbInputs * sizeof(fModes[0]);
135025128811219dc45fd99b6c4d1d14f833cf7a26ecommit-bot@chromium.org        SkASSERT(buffer.getArrayCount() == size);
136ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org        if (buffer.validate(buffer.getArrayCount() == size) &&
137ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org            buffer.readByteArray(fModes, size)) {
138c2e9db30d393862bd3485cfe57b4ac06433f2f32commit-bot@chromium.org            for (int i = 0; i < nbInputs; ++i) {
139c2e9db30d393862bd3485cfe57b4ac06433f2f32commit-bot@chromium.org                buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
140c2e9db30d393862bd3485cfe57b4ac06433f2f32commit-bot@chromium.org            }
141c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        }
1424a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
1434a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = 0;
1444a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1454a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
146