From 4a24398391536f7b176b44a8c45dc288655b4adb Mon Sep 17 00:00:00 2001 From: senorblanco Date: Wed, 25 Nov 2015 07:06:55 -0800 Subject: Fix SkMergeImageFilter crop rect computation. The crop rect should be applied to the union of the input bounds, not to the src input's bounds. These are often the same, since the saveLayer offscreen size is computed as the union of all the required bounds, but is not correct if the input primitive is not used (e.g., if all inputs are connected to SkImageSources). But this will change as we move to more accurate intermediate bounds computations (getting rid of the join() hacks as described in skbug.com/3194). Since we can't know this without actually processing the inputs, split SkMergeImageFilter processing into: - filter all inputs - applyCropRect to the union'ed bounds - allocate the destination - do the merge BUG=3194 Review URL: https://codereview.chromium.org/1475793002 --- src/effects/SkMergeImageFilter.cpp | 60 +++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 21 deletions(-) (limited to 'src/effects/SkMergeImageFilter.cpp') diff --git a/src/effects/SkMergeImageFilter.cpp b/src/effects/SkMergeImageFilter.cpp index d6f0eaa794..2ae8b35cd0 100755 --- a/src/effects/SkMergeImageFilter.cpp +++ b/src/effects/SkMergeImageFilter.cpp @@ -15,7 +15,7 @@ /////////////////////////////////////////////////////////////////////////////// void SkMergeImageFilter::initAllocModes() { - int inputCount = countInputs(); + int inputCount = this->countInputs(); if (inputCount) { size_t size = sizeof(uint8_t) * inputCount; if (size <= sizeof(fStorage)) { @@ -31,7 +31,7 @@ void SkMergeImageFilter::initAllocModes() { void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) { if (modes) { this->initAllocModes(); - int inputCount = countInputs(); + int inputCount = this->countInputs(); for (int i = 0; i < inputCount; ++i) { fModes[i] = SkToU8(modes[i]); } @@ -58,46 +58,64 @@ SkMergeImageFilter::~SkMergeImageFilter() { bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { - if (countInputs() < 1) { + int inputCount = this->countInputs(); + if (inputCount < 1) { return false; } SkIRect bounds; - if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) { + + SkAutoTDeleteArray inputs(new SkBitmap[inputCount]); + SkAutoTDeleteArray offsets(new SkIPoint[inputCount]); + bool didProduceResult = false; + + // Filter all of the inputs. + for (int i = 0; i < inputCount; ++i) { + inputs[i] = src; + offsets[i].setZero(); + if (!this->filterInput(i, proxy, src, ctx, &inputs[i], &offsets[i])) { + inputs[i].reset(); + continue; + } + SkIRect srcBounds; + inputs[i].getBounds(&srcBounds); + srcBounds.offset(offsets[i]); + if (!didProduceResult) { + bounds = srcBounds; + didProduceResult = true; + } else { + bounds.join(srcBounds); + } + } + if (!didProduceResult) { + return false; + } + + // Apply the crop rect to the union of the inputs' bounds. + if (!this->getCropRect().applyTo(bounds, ctx, &bounds)) { return false; } const int x0 = bounds.left(); const int y0 = bounds.top(); + // Allocate the destination buffer. SkAutoTUnref dst(proxy->createDevice(bounds.width(), bounds.height())); if (nullptr == dst) { return false; } SkCanvas canvas(dst); - SkPaint paint; - bool didProduceResult = false; - int inputCount = countInputs(); + // Composite all of the filter inputs. for (int i = 0; i < inputCount; ++i) { - SkBitmap tmp; - SkBitmap input = src; - SkIPoint pos = SkIPoint::Make(0, 0); - if (!this->filterInput(i, proxy, src, ctx, &input, &pos)) { - continue; - } + SkPaint paint; if (fModes) { paint.setXfermodeMode((SkXfermode::Mode)fModes[i]); - } else { - paint.setXfermode(nullptr); } - canvas.drawBitmap(input, SkIntToScalar(pos.x() - x0), SkIntToScalar(pos.y() - y0), &paint); - didProduceResult = true; + canvas.drawBitmap(inputs[i], SkIntToScalar(offsets[i].x() - x0), + SkIntToScalar(offsets[i].y() - y0), &paint); } - if (!didProduceResult) - return false; - offset->fX = bounds.left(); offset->fY = bounds.top(); *result = dst->accessBitmap(false); @@ -134,7 +152,7 @@ void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); buffer.writeBool(fModes != nullptr); if (fModes) { - buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0])); + buffer.writeByteArray(fModes, this->countInputs() * sizeof(fModes[0])); } } -- cgit v1.2.3