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