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* filters[], int count,
44962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org                                       const SkXfermode::Mode modes[],
455e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco                                       const CropRect* cropRect,
465e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco                                       uint32_t uniqueID)
475e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco  : INHERITED(count, filters, cropRect, uniqueID) {
48c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org    SkASSERT(count >= 0);
494a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    this->initModes(modes);
504a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
514a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
524a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgSkMergeImageFilter::~SkMergeImageFilter() {
534a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
544a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (fModes != SkTCast<uint8_t*>(fStorage)) {
554a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        sk_free(fModes);
564a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
574a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
584a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
594a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.orgbool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
604cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org                                       const Context& ctx,
61ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                       SkBitmap* result, SkIPoint* offset) const {
624a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (countInputs() < 1) {
634a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
644a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
654a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
664a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkIRect bounds;
67118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org    if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
684a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
694a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
704a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
714a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    const int x0 = bounds.left();
724a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    const int y0 = bounds.top();
734a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
741f2f338e23789f3eef168dcbd8171a28820ba6c1robertphillips@google.com    SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
754a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (NULL == dst) {
764a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        return false;
774a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
784a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkCanvas canvas(dst);
794a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    SkPaint paint;
804a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
814a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    int inputCount = countInputs();
824a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    for (int i = 0; i < inputCount; ++i) {
834a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkBitmap tmp;
844a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        const SkBitmap* srcPtr;
85962c8864e4cf0cfbaf8ea3d17eda83261733362asenorblanco@chromium.org        SkIPoint pos = SkIPoint::Make(0, 0);
864a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        SkImageFilter* filter = getInput(i);
874a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (filter) {
884cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org            if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
894a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org                return false;
904a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            }
914a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            srcPtr = &tmp;
924a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
934a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            srcPtr = &src;
944a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
954a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
964a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        if (fModes) {
974a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
984a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        } else {
994a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org            paint.setXfermode(NULL);
1004a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
1014a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
1024a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1034a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1046776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fX = bounds.left();
1056776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fY = bounds.top();
1064a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    *result = dst->accessBitmap(false);
1074a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    return true;
1084a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
1094a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1109fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) {
1119fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    Common common;
1129fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (!common.unflatten(buffer, -1)) {
1139fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        return NULL;
1149fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
1159fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
1169fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const int count = common.inputCount();
1179fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    bool hasModes = buffer.readBool();
1189fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (hasModes) {
1199fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        SkAutoSTArray<4, SkXfermode::Mode> modes(count);
1209fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        SkAutoSTArray<4, uint8_t> modes8(count);
1219fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        if (!buffer.readByteArray(modes8.get(), count)) {
1229fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            return NULL;
1239fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        }
1249fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        for (int i = 0; i < count; ++i) {
1259fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            modes[i] = (SkXfermode::Mode)modes8[i];
1269fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            buffer.validate(SkIsValidMode(modes[i]));
1279fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        }
1289fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        if (!buffer.isValid()) {
1299fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed            return NULL;
1309fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        }
1315e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco        return Create(common.inputs(), count, modes.get(), &common.cropRect(), common.uniqueID());
1329fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
1335e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco    return Create(common.inputs(), count, NULL, &common.cropRect(), common.uniqueID());
1349fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
1359fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
1368b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
1374a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    this->INHERITED::flatten(buffer);
1384a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    buffer.writeBool(fModes != NULL);
1394a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (fModes) {
1404a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
1414a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1424a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
1434a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org
1449fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
1458b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgSkMergeImageFilter::SkMergeImageFilter(SkReadBuffer& buffer)
146c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org  : INHERITED(-1, buffer) {
1474a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    bool hasModes = buffer.readBool();
1484a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    if (hasModes) {
1494a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        this->initAllocModes();
150c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        int nbInputs = countInputs();
151025128811219dc45fd99b6c4d1d14f833cf7a26ecommit-bot@chromium.org        size_t size = nbInputs * sizeof(fModes[0]);
152025128811219dc45fd99b6c4d1d14f833cf7a26ecommit-bot@chromium.org        SkASSERT(buffer.getArrayCount() == size);
153ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org        if (buffer.validate(buffer.getArrayCount() == size) &&
154ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org            buffer.readByteArray(fModes, size)) {
155c2e9db30d393862bd3485cfe57b4ac06433f2f32commit-bot@chromium.org            for (int i = 0; i < nbInputs; ++i) {
156c2e9db30d393862bd3485cfe57b4ac06433f2f32commit-bot@chromium.org                buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
157c2e9db30d393862bd3485cfe57b4ac06433f2f32commit-bot@chromium.org            }
158c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        }
1594a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    } else {
1604a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        fModes = 0;
1614a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org    }
1624a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org}
1639fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif
164