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
This commit is contained in:
parent
43432f333a
commit
4a24398391
@ -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<SkBitmap> inputs(new SkBitmap[inputCount]);
|
||||
SkAutoTDeleteArray<SkIPoint> 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<SkBaseDevice> 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]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -642,6 +642,29 @@ DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
|
||||
REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
|
||||
}
|
||||
|
||||
DEF_TEST(ImageFilterMergeResultSize, reporter) {
|
||||
SkBitmap greenBM;
|
||||
greenBM.allocN32Pixels(20, 20);
|
||||
greenBM.eraseColor(SK_ColorGREEN);
|
||||
SkAutoTUnref<SkImage> greenImage(SkImage::NewFromBitmap(greenBM));
|
||||
SkAutoTUnref<SkImageFilter> source(SkImageSource::Create(greenImage.get()));
|
||||
SkAutoTUnref<SkImageFilter> merge(SkMergeImageFilter::Create(source.get(), source.get()));
|
||||
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocN32Pixels(1, 1);
|
||||
bitmap.eraseColor(0);
|
||||
const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
|
||||
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
|
||||
SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
|
||||
SkImageFilter::DeviceProxy proxy(device);
|
||||
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
|
||||
SkImageFilter::kApprox_SizeConstraint);
|
||||
SkBitmap result;
|
||||
SkIPoint offset;
|
||||
REPORTER_ASSERT(reporter, merge->filterImage(&proxy, bitmap, ctx, &result, &offset));
|
||||
REPORTER_ASSERT(reporter, result.width() == 20 && result.height() == 20);
|
||||
}
|
||||
|
||||
static void draw_blurred_rect(SkCanvas* canvas) {
|
||||
SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
|
||||
SkPaint filterPaint;
|
||||
|
Loading…
Reference in New Issue
Block a user