Implement computeFastBounds in SkLocalMatrixImageFilter

This also adds a GM based on Jim's fiddle: https://fiddle.skia.org/c/781234e35c208ee03f79b90613117b91
I confirmed that it never flickers when animating in viewer.

Patchset 1 shows the GM being blank (with the computeFastBounds fix
disabled). Patchset 3 shows that with the fix enabled, the GM is not
blank.

Bug: skia:9282
Change-Id: I206f7150c395b0a35ecf0455e4905f72ae057e6b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/295558
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Michael Ludwig 2020-06-11 10:57:37 -04:00 committed by Skia Commit-Bot
parent 4598fa1b1a
commit 1c07aa7d8d
3 changed files with 69 additions and 0 deletions

View File

@ -25,7 +25,9 @@
#include "include/core/SkTypes.h"
#include "include/effects/SkGradientShader.h"
#include "include/effects/SkImageFilters.h"
#include "tools/Resources.h"
#include "tools/ToolUtils.h"
#include "tools/timer/TimeUtils.h"
#include <utility>
@ -161,3 +163,56 @@ DEF_SIMPLE_GM(rotate_imagefilter, canvas, 500, 500) {
canvas->translate(0, 150);
}
}
class ImageFilterMatrixWLocalMatrix : public skiagm::GM {
public:
// Start at 132 degrees, since that resulted in a skipped draw before the fix to
// SkLocalMatrixImageFilter's computeFastBounds() function.
ImageFilterMatrixWLocalMatrix() : fDegrees(132.f) {}
protected:
SkString onShortName() override {
return SkString("imagefilter_matrix_localmatrix");
}
SkISize onISize() override {
return SkISize::Make(512, 512);
}
bool onAnimate(double nanos) override {
// Animate the rotation angle to ensure the local matrix bounds modifications work
// for a variety of transformations.
fDegrees = TimeUtils::Scaled(1e-9f * nanos, 360.f);
return true;
}
void onOnceBeforeDraw() override {
fImage = GetResourceAsImage("images/mandrill_256.png");
}
void onDraw(SkCanvas* canvas) override {
SkMatrix localMatrix;
localMatrix.preTranslate(128, 128);
localMatrix.preScale(2.0f, 2.0f);
// This matrix applies a rotate around the center of the image (prior to the simulated
// hi-dpi 2x device scale).
SkMatrix filterMatrix;
filterMatrix.setRotate(fDegrees, 64, 64);
sk_sp<SkImageFilter> filter =
SkImageFilter::MakeMatrixFilter(filterMatrix, kLow_SkFilterQuality, nullptr)
->makeWithLocalMatrix(localMatrix);
SkPaint p;
p.setImageFilter(filter);
canvas->drawImage(fImage.get(), 128, 128, &p);
}
private:
SkScalar fDegrees;
sk_sp<SkImage> fImage;
};
DEF_GM(return new ImageFilterMatrixWLocalMatrix();)

View File

@ -53,3 +53,15 @@ SkIRect SkLocalMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMat
MapDirection dir, const SkIRect* inputRect) const {
return this->getInput(0)->filterBounds(src, SkMatrix::Concat(ctm, fLocalM), dir, inputRect);
}
SkRect SkLocalMatrixImageFilter::computeFastBounds(const SkRect& bounds) const {
// In order to match the behavior of onFilterBounds, we map 'bounds' by the inverse of our
// local matrix, pass that to our child, and then map the result by our local matrix.
SkMatrix localInv;
if (!fLocalM.invert(&localInv)) {
return this->getInput(0)->computeFastBounds(bounds);
}
SkRect localBounds = localInv.mapRect(bounds);
return fLocalM.mapRect(this->getInput(0)->computeFastBounds(localBounds));
}

View File

@ -19,6 +19,8 @@ class SkLocalMatrixImageFilter : public SkImageFilter_Base {
public:
static sk_sp<SkImageFilter> Make(const SkMatrix& localM, sk_sp<SkImageFilter> input);
SkRect computeFastBounds(const SkRect&) const override;
protected:
void flatten(SkWriteBuffer&) const override;
sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;