2013-07-24 22:19:24 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2013 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
Fixed issues found by fuzzer
Last week, the fuzzer found a few numerical issue with filters and I had written some fixes for them. Here are the fixes with some unit tests.
For senorblanco : So I figured out what was asserting when we'd get a 0 width "result" in SkBicubicImageFilter::onFilterImage(). Basically, if the "result" SkBitmap object calls SkBitmap::setConfig() with "width" and/or "height" set to 0, then the SkBitmap object will call SkBitmap::reset(), making the SkBitmap object's config invalid. At this point, calling SkBitmap::getAddr32() will assert, even without attempting to dereference the data pointer, because the SkBitmap's config is invalid. If height is valid, but width is 0, then this call to SkBitmap::getAddr32() happens directly in SkBicubicImageFilter::onFilterImage() a few lines lower and asserts right away.
BUG=
R=senorblanco@google.com, senorblanco@chromium.org, bsalomon@google.com
Author: sugoi@chromium.org
Review URL: https://chromiumcodereview.appspot.com/23533042
git-svn-id: http://skia.googlecode.com/svn/trunk@11249 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-09-13 12:40:02 +00:00
|
|
|
#include "SkBicubicImageFilter.h"
|
|
|
|
#include "SkBitmap.h"
|
|
|
|
#include "SkBitmapDevice.h"
|
|
|
|
#include "SkBitmapSource.h"
|
2014-01-24 20:56:26 +00:00
|
|
|
#include "SkBlurImageFilter.h"
|
Fixed issues found by fuzzer
Last week, the fuzzer found a few numerical issue with filters and I had written some fixes for them. Here are the fixes with some unit tests.
For senorblanco : So I figured out what was asserting when we'd get a 0 width "result" in SkBicubicImageFilter::onFilterImage(). Basically, if the "result" SkBitmap object calls SkBitmap::setConfig() with "width" and/or "height" set to 0, then the SkBitmap object will call SkBitmap::reset(), making the SkBitmap object's config invalid. At this point, calling SkBitmap::getAddr32() will assert, even without attempting to dereference the data pointer, because the SkBitmap's config is invalid. If height is valid, but width is 0, then this call to SkBitmap::getAddr32() happens directly in SkBicubicImageFilter::onFilterImage() a few lines lower and asserts right away.
BUG=
R=senorblanco@google.com, senorblanco@chromium.org, bsalomon@google.com
Author: sugoi@chromium.org
Review URL: https://chromiumcodereview.appspot.com/23533042
git-svn-id: http://skia.googlecode.com/svn/trunk@11249 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-09-13 12:40:02 +00:00
|
|
|
#include "SkCanvas.h"
|
2013-07-24 22:19:24 +00:00
|
|
|
#include "SkColorFilterImageFilter.h"
|
2014-01-24 20:56:26 +00:00
|
|
|
#include "SkColorMatrixFilter.h"
|
Fixed issues found by fuzzer
Last week, the fuzzer found a few numerical issue with filters and I had written some fixes for them. Here are the fixes with some unit tests.
For senorblanco : So I figured out what was asserting when we'd get a 0 width "result" in SkBicubicImageFilter::onFilterImage(). Basically, if the "result" SkBitmap object calls SkBitmap::setConfig() with "width" and/or "height" set to 0, then the SkBitmap object will call SkBitmap::reset(), making the SkBitmap object's config invalid. At this point, calling SkBitmap::getAddr32() will assert, even without attempting to dereference the data pointer, because the SkBitmap's config is invalid. If height is valid, but width is 0, then this call to SkBitmap::getAddr32() happens directly in SkBicubicImageFilter::onFilterImage() a few lines lower and asserts right away.
BUG=
R=senorblanco@google.com, senorblanco@chromium.org, bsalomon@google.com
Author: sugoi@chromium.org
Review URL: https://chromiumcodereview.appspot.com/23533042
git-svn-id: http://skia.googlecode.com/svn/trunk@11249 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-09-13 12:40:02 +00:00
|
|
|
#include "SkDeviceImageFilterProxy.h"
|
Make SkImageFilter crop rects relative to the primitive origin, instead of relative to their parent's crop rect. This is required by SVG semantics, and is more sane anyway.
To do this, this patch changes the "offset/loc" parameter in filterImage() / onFilterImage() from an inout-param to an out-param only, so that the calling filter can know how much the input filter wants its result offset (and doesn't include the original primitive position). This offset can then be applied to the current filter's crop rect. (I've renamed the parameter "offset" in all cases to make this clear.) This makes the call sites in SkCanvas/SkGpuDevice responsible for applying the resulting offset to the primitive's position, which is actually a fairly small change.
This change also fixes SkTileImageFilter and SkOffsetImageFilter to correctly handle an input offset, which they weren't before. This required modifying the GM's, since they assumed the broken behaviour.
NOTE: this will require rebaselining the imagefiltersgraph test, since it has a new test case.
NOTE: this will "break" the Blink layout tests css3/filters/effect-reference-subregion-chained-hw.html and css3/filters/effect-reference-subregion-hw.html, but it actually makes them give correct results. It should be suppressed on the skia roll, and I'll rebaseline it.
R=reed@google.com
Review URL: https://codereview.chromium.org/112803004
git-svn-id: http://skia.googlecode.com/svn/trunk@12895 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-01-03 21:48:22 +00:00
|
|
|
#include "SkDisplacementMapEffect.h"
|
|
|
|
#include "SkDropShadowImageFilter.h"
|
2014-02-05 22:36:31 +00:00
|
|
|
#include "SkFlattenableBuffers.h"
|
Fixed issues found by fuzzer
Last week, the fuzzer found a few numerical issue with filters and I had written some fixes for them. Here are the fixes with some unit tests.
For senorblanco : So I figured out what was asserting when we'd get a 0 width "result" in SkBicubicImageFilter::onFilterImage(). Basically, if the "result" SkBitmap object calls SkBitmap::setConfig() with "width" and/or "height" set to 0, then the SkBitmap object will call SkBitmap::reset(), making the SkBitmap object's config invalid. At this point, calling SkBitmap::getAddr32() will assert, even without attempting to dereference the data pointer, because the SkBitmap's config is invalid. If height is valid, but width is 0, then this call to SkBitmap::getAddr32() happens directly in SkBicubicImageFilter::onFilterImage() a few lines lower and asserts right away.
BUG=
R=senorblanco@google.com, senorblanco@chromium.org, bsalomon@google.com
Author: sugoi@chromium.org
Review URL: https://chromiumcodereview.appspot.com/23533042
git-svn-id: http://skia.googlecode.com/svn/trunk@11249 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-09-13 12:40:02 +00:00
|
|
|
#include "SkLightingImageFilter.h"
|
2014-01-24 20:56:26 +00:00
|
|
|
#include "SkMatrixConvolutionImageFilter.h"
|
Make SkImageFilter crop rects relative to the primitive origin, instead of relative to their parent's crop rect. This is required by SVG semantics, and is more sane anyway.
To do this, this patch changes the "offset/loc" parameter in filterImage() / onFilterImage() from an inout-param to an out-param only, so that the calling filter can know how much the input filter wants its result offset (and doesn't include the original primitive position). This offset can then be applied to the current filter's crop rect. (I've renamed the parameter "offset" in all cases to make this clear.) This makes the call sites in SkCanvas/SkGpuDevice responsible for applying the resulting offset to the primitive's position, which is actually a fairly small change.
This change also fixes SkTileImageFilter and SkOffsetImageFilter to correctly handle an input offset, which they weren't before. This required modifying the GM's, since they assumed the broken behaviour.
NOTE: this will require rebaselining the imagefiltersgraph test, since it has a new test case.
NOTE: this will "break" the Blink layout tests css3/filters/effect-reference-subregion-chained-hw.html and css3/filters/effect-reference-subregion-hw.html, but it actually makes them give correct results. It should be suppressed on the skia roll, and I'll rebaseline it.
R=reed@google.com
Review URL: https://codereview.chromium.org/112803004
git-svn-id: http://skia.googlecode.com/svn/trunk@12895 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-01-03 21:48:22 +00:00
|
|
|
#include "SkMergeImageFilter.h"
|
|
|
|
#include "SkMorphologyImageFilter.h"
|
|
|
|
#include "SkOffsetImageFilter.h"
|
2014-02-05 22:36:31 +00:00
|
|
|
#include "SkPicture.h"
|
2014-01-24 20:56:26 +00:00
|
|
|
#include "SkRect.h"
|
Make SkImageFilter crop rects relative to the primitive origin, instead of relative to their parent's crop rect. This is required by SVG semantics, and is more sane anyway.
To do this, this patch changes the "offset/loc" parameter in filterImage() / onFilterImage() from an inout-param to an out-param only, so that the calling filter can know how much the input filter wants its result offset (and doesn't include the original primitive position). This offset can then be applied to the current filter's crop rect. (I've renamed the parameter "offset" in all cases to make this clear.) This makes the call sites in SkCanvas/SkGpuDevice responsible for applying the resulting offset to the primitive's position, which is actually a fairly small change.
This change also fixes SkTileImageFilter and SkOffsetImageFilter to correctly handle an input offset, which they weren't before. This required modifying the GM's, since they assumed the broken behaviour.
NOTE: this will require rebaselining the imagefiltersgraph test, since it has a new test case.
NOTE: this will "break" the Blink layout tests css3/filters/effect-reference-subregion-chained-hw.html and css3/filters/effect-reference-subregion-hw.html, but it actually makes them give correct results. It should be suppressed on the skia roll, and I'll rebaseline it.
R=reed@google.com
Review URL: https://codereview.chromium.org/112803004
git-svn-id: http://skia.googlecode.com/svn/trunk@12895 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-01-03 21:48:22 +00:00
|
|
|
#include "SkTileImageFilter.h"
|
|
|
|
#include "SkXfermodeImageFilter.h"
|
2014-01-24 20:56:26 +00:00
|
|
|
#include "Test.h"
|
2013-07-24 22:19:24 +00:00
|
|
|
|
2014-02-03 22:22:16 +00:00
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
#include "GrContextFactory.h"
|
|
|
|
#include "SkGpuDevice.h"
|
|
|
|
#endif
|
|
|
|
|
2013-12-18 22:15:12 +00:00
|
|
|
static const int kBitmapSize = 4;
|
|
|
|
|
2014-02-05 22:36:31 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class MatrixTestImageFilter : public SkImageFilter {
|
|
|
|
public:
|
|
|
|
MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
|
|
|
|
: SkImageFilter(0), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
|
|
|
|
}
|
|
|
|
|
2014-03-14 15:44:01 +00:00
|
|
|
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
|
2014-02-05 23:04:28 +00:00
|
|
|
SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE {
|
2014-03-14 15:44:01 +00:00
|
|
|
REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
|
2014-02-05 22:36:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
explicit MatrixTestImageFilter(SkReadBuffer& buffer) : SkImageFilter(0) {
|
|
|
|
fReporter = static_cast<skiatest::Reporter*>(buffer.readFunctionPtr());
|
|
|
|
buffer.readMatrix(&fExpectedMatrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
|
|
|
|
buffer.writeFunctionPtr(fReporter);
|
|
|
|
buffer.writeMatrix(fExpectedMatrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
skiatest::Reporter* fReporter;
|
|
|
|
SkMatrix fExpectedMatrix;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-12-18 22:15:12 +00:00
|
|
|
static void make_small_bitmap(SkBitmap& bitmap) {
|
2014-02-13 14:41:43 +00:00
|
|
|
bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
|
|
|
|
SkCanvas canvas(bitmap);
|
2013-12-18 22:15:12 +00:00
|
|
|
canvas.clear(0x00000000);
|
|
|
|
SkPaint darkPaint;
|
|
|
|
darkPaint.setColor(0xFF804020);
|
|
|
|
SkPaint lightPaint;
|
|
|
|
lightPaint.setColor(0xFF244484);
|
|
|
|
const int i = kBitmapSize / 4;
|
|
|
|
for (int y = 0; y < kBitmapSize; y += i) {
|
|
|
|
for (int x = 0; x < kBitmapSize; x += i) {
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
|
|
|
|
canvas.drawRect(SkRect::MakeXYWH(0, 0,
|
|
|
|
SkIntToScalar(i),
|
|
|
|
SkIntToScalar(i)), darkPaint);
|
|
|
|
canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
|
|
|
|
0,
|
|
|
|
SkIntToScalar(i),
|
|
|
|
SkIntToScalar(i)), lightPaint);
|
|
|
|
canvas.drawRect(SkRect::MakeXYWH(0,
|
|
|
|
SkIntToScalar(i),
|
|
|
|
SkIntToScalar(i),
|
|
|
|
SkIntToScalar(i)), lightPaint);
|
|
|
|
canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
|
|
|
|
SkIntToScalar(i),
|
|
|
|
SkIntToScalar(i),
|
|
|
|
SkIntToScalar(i)), darkPaint);
|
|
|
|
canvas.restore();
|
Fixed issues found by fuzzer
Last week, the fuzzer found a few numerical issue with filters and I had written some fixes for them. Here are the fixes with some unit tests.
For senorblanco : So I figured out what was asserting when we'd get a 0 width "result" in SkBicubicImageFilter::onFilterImage(). Basically, if the "result" SkBitmap object calls SkBitmap::setConfig() with "width" and/or "height" set to 0, then the SkBitmap object will call SkBitmap::reset(), making the SkBitmap object's config invalid. At this point, calling SkBitmap::getAddr32() will assert, even without attempting to dereference the data pointer, because the SkBitmap's config is invalid. If height is valid, but width is 0, then this call to SkBitmap::getAddr32() happens directly in SkBicubicImageFilter::onFilterImage() a few lines lower and asserts right away.
BUG=
R=senorblanco@google.com, senorblanco@chromium.org, bsalomon@google.com
Author: sugoi@chromium.org
Review URL: https://chromiumcodereview.appspot.com/23533042
git-svn-id: http://skia.googlecode.com/svn/trunk@11249 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-09-13 12:40:02 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-18 22:15:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
|
|
|
|
SkScalar s = amount;
|
|
|
|
SkScalar matrix[20] = { s, 0, 0, 0, 0,
|
|
|
|
0, s, 0, 0, 0,
|
|
|
|
0, 0, s, 0, 0,
|
|
|
|
0, 0, 0, s, 0 };
|
2014-02-21 18:46:30 +00:00
|
|
|
SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
|
2013-12-18 22:15:12 +00:00
|
|
|
return SkColorFilterImageFilter::Create(filter, input);
|
|
|
|
}
|
|
|
|
|
|
|
|
static SkImageFilter* make_grayscale(SkImageFilter* input = NULL, const SkImageFilter::CropRect* cropRect = NULL) {
|
|
|
|
SkScalar matrix[20];
|
|
|
|
memset(matrix, 0, 20 * sizeof(SkScalar));
|
|
|
|
matrix[0] = matrix[5] = matrix[10] = 0.2126f;
|
|
|
|
matrix[1] = matrix[6] = matrix[11] = 0.7152f;
|
|
|
|
matrix[2] = matrix[7] = matrix[12] = 0.0722f;
|
|
|
|
matrix[18] = 1.0f;
|
2014-02-21 18:46:30 +00:00
|
|
|
SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
|
2013-12-18 22:15:12 +00:00
|
|
|
return SkColorFilterImageFilter::Create(filter, input, cropRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(ImageFilter, reporter) {
|
|
|
|
{
|
|
|
|
// Check that two non-clipping color matrices concatenate into a single filter.
|
|
|
|
SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
|
|
|
|
SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
|
|
|
|
REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
|
2013-07-24 22:19:24 +00:00
|
|
|
}
|
|
|
|
|
2013-12-18 22:15:12 +00:00
|
|
|
{
|
|
|
|
// Check that a clipping color matrix followed by a grayscale does not concatenate into a single filter.
|
|
|
|
SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
|
|
|
|
SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
|
|
|
|
REPORTER_ASSERT(reporter, NULL != halfBrightness->getInput(0));
|
2013-07-24 22:19:24 +00:00
|
|
|
}
|
|
|
|
|
2013-12-18 22:15:12 +00:00
|
|
|
{
|
|
|
|
// Check that a color filter image filter without a crop rect can be
|
|
|
|
// expressed as a color filter.
|
|
|
|
SkAutoTUnref<SkImageFilter> gray(make_grayscale());
|
|
|
|
REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
|
2013-07-24 22:19:24 +00:00
|
|
|
}
|
|
|
|
|
2013-12-18 22:15:12 +00:00
|
|
|
{
|
|
|
|
// Check that a color filter image filter with a crop rect cannot
|
|
|
|
// be expressed as a color filter.
|
|
|
|
SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
|
|
|
|
SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
|
|
|
|
REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
|
|
|
|
}
|
2013-07-24 22:19:24 +00:00
|
|
|
|
2013-12-18 22:15:12 +00:00
|
|
|
{
|
|
|
|
// Tests pass by not asserting
|
|
|
|
SkBitmap bitmap, result;
|
|
|
|
make_small_bitmap(bitmap);
|
2014-02-13 14:41:43 +00:00
|
|
|
result.allocN32Pixels(kBitmapSize, kBitmapSize);
|
2013-07-24 22:19:24 +00:00
|
|
|
|
|
|
|
{
|
2013-12-18 22:15:12 +00:00
|
|
|
// This tests for :
|
|
|
|
// 1 ) location at (0,0,1)
|
|
|
|
SkPoint3 location(0, 0, SK_Scalar1);
|
|
|
|
// 2 ) location and target at same value
|
|
|
|
SkPoint3 target(location.fX, location.fY, location.fZ);
|
|
|
|
// 3 ) large negative specular exponent value
|
|
|
|
SkScalar specularExponent = -1000;
|
|
|
|
|
2014-03-10 10:51:58 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
|
2013-12-18 22:15:12 +00:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
|
|
|
|
location, target, specularExponent, 180,
|
|
|
|
0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
|
|
|
|
bmSrc))->unref();
|
|
|
|
SkCanvas canvas(result);
|
|
|
|
SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
|
|
|
|
SkIntToScalar(kBitmapSize));
|
|
|
|
canvas.drawRect(r, paint);
|
2013-07-24 22:19:24 +00:00
|
|
|
}
|
Fixed issues found by fuzzer
Last week, the fuzzer found a few numerical issue with filters and I had written some fixes for them. Here are the fixes with some unit tests.
For senorblanco : So I figured out what was asserting when we'd get a 0 width "result" in SkBicubicImageFilter::onFilterImage(). Basically, if the "result" SkBitmap object calls SkBitmap::setConfig() with "width" and/or "height" set to 0, then the SkBitmap object will call SkBitmap::reset(), making the SkBitmap object's config invalid. At this point, calling SkBitmap::getAddr32() will assert, even without attempting to dereference the data pointer, because the SkBitmap's config is invalid. If height is valid, but width is 0, then this call to SkBitmap::getAddr32() happens directly in SkBicubicImageFilter::onFilterImage() a few lines lower and asserts right away.
BUG=
R=senorblanco@google.com, senorblanco@chromium.org, bsalomon@google.com
Author: sugoi@chromium.org
Review URL: https://chromiumcodereview.appspot.com/23533042
git-svn-id: http://skia.googlecode.com/svn/trunk@11249 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-09-13 12:40:02 +00:00
|
|
|
|
|
|
|
{
|
2013-12-18 22:15:12 +00:00
|
|
|
// This tests for scale bringing width to 0
|
|
|
|
SkSize scale = SkSize::Make(-0.001f, SK_Scalar1);
|
2014-03-10 10:51:58 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
|
2013-12-18 22:15:12 +00:00
|
|
|
SkAutoTUnref<SkBicubicImageFilter> bicubic(
|
|
|
|
SkBicubicImageFilter::CreateMitchell(scale, bmSrc));
|
|
|
|
SkBitmapDevice device(bitmap);
|
|
|
|
SkDeviceImageFilterProxy proxy(&device);
|
|
|
|
SkIPoint loc = SkIPoint::Make(0, 0);
|
|
|
|
// An empty input should early return and return false
|
2014-03-14 15:44:01 +00:00
|
|
|
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeEmpty());
|
2013-12-18 22:15:12 +00:00
|
|
|
REPORTER_ASSERT(reporter,
|
2014-03-14 15:44:01 +00:00
|
|
|
!bicubic->filterImage(&proxy, bitmap, ctx, &result, &loc));
|
Fixed issues found by fuzzer
Last week, the fuzzer found a few numerical issue with filters and I had written some fixes for them. Here are the fixes with some unit tests.
For senorblanco : So I figured out what was asserting when we'd get a 0 width "result" in SkBicubicImageFilter::onFilterImage(). Basically, if the "result" SkBitmap object calls SkBitmap::setConfig() with "width" and/or "height" set to 0, then the SkBitmap object will call SkBitmap::reset(), making the SkBitmap object's config invalid. At this point, calling SkBitmap::getAddr32() will assert, even without attempting to dereference the data pointer, because the SkBitmap's config is invalid. If height is valid, but width is 0, then this call to SkBitmap::getAddr32() happens directly in SkBicubicImageFilter::onFilterImage() a few lines lower and asserts right away.
BUG=
R=senorblanco@google.com, senorblanco@chromium.org, bsalomon@google.com
Author: sugoi@chromium.org
Review URL: https://chromiumcodereview.appspot.com/23533042
git-svn-id: http://skia.googlecode.com/svn/trunk@11249 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-09-13 12:40:02 +00:00
|
|
|
}
|
2013-07-24 22:19:24 +00:00
|
|
|
}
|
2014-02-03 22:22:16 +00:00
|
|
|
}
|
Make SkImageFilter crop rects relative to the primitive origin, instead of relative to their parent's crop rect. This is required by SVG semantics, and is more sane anyway.
To do this, this patch changes the "offset/loc" parameter in filterImage() / onFilterImage() from an inout-param to an out-param only, so that the calling filter can know how much the input filter wants its result offset (and doesn't include the original primitive position). This offset can then be applied to the current filter's crop rect. (I've renamed the parameter "offset" in all cases to make this clear.) This makes the call sites in SkCanvas/SkGpuDevice responsible for applying the resulting offset to the primitive's position, which is actually a fairly small change.
This change also fixes SkTileImageFilter and SkOffsetImageFilter to correctly handle an input offset, which they weren't before. This required modifying the GM's, since they assumed the broken behaviour.
NOTE: this will require rebaselining the imagefiltersgraph test, since it has a new test case.
NOTE: this will "break" the Blink layout tests css3/filters/effect-reference-subregion-chained-hw.html and css3/filters/effect-reference-subregion-hw.html, but it actually makes them give correct results. It should be suppressed on the skia roll, and I'll rebaseline it.
R=reed@google.com
Review URL: https://codereview.chromium.org/112803004
git-svn-id: http://skia.googlecode.com/svn/trunk@12895 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-01-03 21:48:22 +00:00
|
|
|
|
2014-02-03 22:22:16 +00:00
|
|
|
static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter) {
|
|
|
|
// Check that all filters offset to their absolute crop rect,
|
|
|
|
// unaffected by the input crop rect.
|
|
|
|
// Tests pass by not asserting.
|
|
|
|
SkBitmap bitmap;
|
2014-02-13 14:41:43 +00:00
|
|
|
bitmap.allocN32Pixels(100, 100);
|
2014-02-03 22:22:16 +00:00
|
|
|
bitmap.eraseARGB(0, 0, 0, 0);
|
|
|
|
SkDeviceImageFilterProxy proxy(device);
|
|
|
|
|
|
|
|
SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
|
|
|
|
SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
|
|
|
|
SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));
|
|
|
|
|
|
|
|
SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
|
|
|
|
SkPoint3 location(0, 0, SK_Scalar1);
|
|
|
|
SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
|
|
|
|
SkScalar kernel[9] = {
|
|
|
|
SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
|
|
|
|
SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
|
|
|
|
SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
|
|
|
|
};
|
|
|
|
SkISize kernelSize = SkISize::Make(3, 3);
|
|
|
|
SkScalar gain = SK_Scalar1, bias = 0;
|
|
|
|
|
|
|
|
SkImageFilter* filters[] = {
|
|
|
|
SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
|
2014-03-10 10:51:58 +00:00
|
|
|
SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
|
|
|
|
SkDisplacementMapEffect::kB_ChannelSelectorType,
|
|
|
|
40.0f, input.get(), input.get(), &cropRect),
|
|
|
|
SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
|
|
|
|
SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input.get(), &cropRect),
|
2014-02-03 22:22:16 +00:00
|
|
|
SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
|
|
|
|
SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
|
2014-03-10 10:51:58 +00:00
|
|
|
SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
|
|
|
|
SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
|
|
|
|
SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
|
|
|
|
SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
|
|
|
|
SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
|
|
|
|
SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
|
|
|
|
SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
|
|
|
|
SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
|
2014-02-03 22:22:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
|
|
|
|
SkImageFilter* filter = filters[i];
|
|
|
|
SkBitmap result;
|
|
|
|
SkIPoint offset;
|
|
|
|
SkString str;
|
2014-02-04 00:28:46 +00:00
|
|
|
str.printf("filter %d", static_cast<int>(i));
|
2014-03-14 17:44:41 +00:00
|
|
|
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest());
|
2014-03-14 15:44:01 +00:00
|
|
|
REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(&proxy, bitmap, ctx, &result, &offset), str.c_str());
|
2014-02-03 22:22:16 +00:00
|
|
|
REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
|
|
|
|
}
|
Make SkImageFilter crop rects relative to the primitive origin, instead of relative to their parent's crop rect. This is required by SVG semantics, and is more sane anyway.
To do this, this patch changes the "offset/loc" parameter in filterImage() / onFilterImage() from an inout-param to an out-param only, so that the calling filter can know how much the input filter wants its result offset (and doesn't include the original primitive position). This offset can then be applied to the current filter's crop rect. (I've renamed the parameter "offset" in all cases to make this clear.) This makes the call sites in SkCanvas/SkGpuDevice responsible for applying the resulting offset to the primitive's position, which is actually a fairly small change.
This change also fixes SkTileImageFilter and SkOffsetImageFilter to correctly handle an input offset, which they weren't before. This required modifying the GM's, since they assumed the broken behaviour.
NOTE: this will require rebaselining the imagefiltersgraph test, since it has a new test case.
NOTE: this will "break" the Blink layout tests css3/filters/effect-reference-subregion-chained-hw.html and css3/filters/effect-reference-subregion-hw.html, but it actually makes them give correct results. It should be suppressed on the skia roll, and I'll rebaseline it.
R=reed@google.com
Review URL: https://codereview.chromium.org/112803004
git-svn-id: http://skia.googlecode.com/svn/trunk@12895 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-01-03 21:48:22 +00:00
|
|
|
|
2014-02-03 22:22:16 +00:00
|
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
|
|
|
|
SkSafeUnref(filters[i]);
|
Make SkImageFilter crop rects relative to the primitive origin, instead of relative to their parent's crop rect. This is required by SVG semantics, and is more sane anyway.
To do this, this patch changes the "offset/loc" parameter in filterImage() / onFilterImage() from an inout-param to an out-param only, so that the calling filter can know how much the input filter wants its result offset (and doesn't include the original primitive position). This offset can then be applied to the current filter's crop rect. (I've renamed the parameter "offset" in all cases to make this clear.) This makes the call sites in SkCanvas/SkGpuDevice responsible for applying the resulting offset to the primitive's position, which is actually a fairly small change.
This change also fixes SkTileImageFilter and SkOffsetImageFilter to correctly handle an input offset, which they weren't before. This required modifying the GM's, since they assumed the broken behaviour.
NOTE: this will require rebaselining the imagefiltersgraph test, since it has a new test case.
NOTE: this will "break" the Blink layout tests css3/filters/effect-reference-subregion-chained-hw.html and css3/filters/effect-reference-subregion-hw.html, but it actually makes them give correct results. It should be suppressed on the skia roll, and I'll rebaseline it.
R=reed@google.com
Review URL: https://codereview.chromium.org/112803004
git-svn-id: http://skia.googlecode.com/svn/trunk@12895 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-01-03 21:48:22 +00:00
|
|
|
}
|
2013-12-18 22:15:12 +00:00
|
|
|
}
|
2014-02-03 22:22:16 +00:00
|
|
|
|
|
|
|
DEF_TEST(ImageFilterCropRect, reporter) {
|
|
|
|
SkBitmap temp;
|
2014-02-13 14:41:43 +00:00
|
|
|
temp.allocN32Pixels(100, 100);
|
2014-02-03 22:22:16 +00:00
|
|
|
SkBitmapDevice device(temp);
|
|
|
|
test_crop_rects(&device, reporter);
|
|
|
|
}
|
|
|
|
|
2014-02-05 22:36:31 +00:00
|
|
|
DEF_TEST(ImageFilterMatrixTest, reporter) {
|
|
|
|
SkBitmap temp;
|
2014-02-13 14:41:43 +00:00
|
|
|
temp.allocN32Pixels(100, 100);
|
2014-02-05 22:36:31 +00:00
|
|
|
SkBitmapDevice device(temp);
|
|
|
|
SkCanvas canvas(&device);
|
|
|
|
canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
|
|
|
|
|
|
|
|
SkMatrix expectedMatrix = canvas.getTotalMatrix();
|
|
|
|
|
|
|
|
SkPicture picture;
|
|
|
|
SkCanvas* recordingCanvas = picture.beginRecording(100, 100,
|
|
|
|
SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
SkAutoTUnref<MatrixTestImageFilter> imageFilter(
|
|
|
|
new MatrixTestImageFilter(reporter, expectedMatrix));
|
|
|
|
paint.setImageFilter(imageFilter.get());
|
|
|
|
SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(
|
|
|
|
SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
|
|
|
|
recordingCanvas->saveLayer(NULL, &paint, saveFlags);
|
|
|
|
SkPaint solidPaint;
|
|
|
|
solidPaint.setColor(0xFFFFFFFF);
|
|
|
|
recordingCanvas->save();
|
|
|
|
recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
|
|
|
|
recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
|
|
|
|
recordingCanvas->restore(); // scale
|
|
|
|
recordingCanvas->restore(); // saveLayer
|
|
|
|
picture.endRecording();
|
|
|
|
|
|
|
|
canvas.drawPicture(picture);
|
|
|
|
}
|
|
|
|
|
2014-03-24 21:32:28 +00:00
|
|
|
static void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
|
2014-03-24 20:50:59 +00:00
|
|
|
SkCanvas canvas(device);
|
|
|
|
|
|
|
|
SkBitmap bitmap;
|
|
|
|
bitmap.allocN32Pixels(100, 100);
|
|
|
|
bitmap.eraseARGB(0, 0, 0, 0);
|
|
|
|
|
|
|
|
// Check that a blur with an insane radius does not crash or assert.
|
|
|
|
SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setImageFilter(blur);
|
|
|
|
canvas.drawSprite(bitmap, 0, 0, &paint);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(HugeBlurImageFilter, reporter) {
|
|
|
|
SkBitmap temp;
|
|
|
|
temp.allocN32Pixels(100, 100);
|
|
|
|
SkBitmapDevice device(temp);
|
|
|
|
test_huge_blur(&device, reporter);
|
|
|
|
}
|
|
|
|
|
Fix SkXfermodeImageFilter when an input is cropped out.
If one of inputs to SkXfermodeImageFilter draws nothing, either due to
it being cropped out upstream, or within the filter itself, the filter
should still draw the other input, since otherwise the result will be incorrect.
For the GPU path, since we can't detect this case in
canFilterImageGPU() without recursing, we'll just drop to
the generic path if either input is empty, since we can't use the effect in that case anyway.
While we're at it, let's drop to the generic path if the
xfermode can't be expressed as an effect, since the code
here was doing a 2-pass render in that case anyway, which
is equivalent to what the (xfermode == NULL) case was doing
anyway.
R=bsalomon@google.com, sugoi@chromium.org
Review URL: https://codereview.chromium.org/220723007
git-svn-id: http://skia.googlecode.com/svn/trunk@14016 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-04-01 19:15:23 +00:00
|
|
|
static void test_xfermode_cropped_input(SkBaseDevice* device, skiatest::Reporter* reporter) {
|
|
|
|
SkCanvas canvas(device);
|
|
|
|
canvas.clear(0);
|
|
|
|
|
|
|
|
SkBitmap bitmap;
|
|
|
|
bitmap.allocN32Pixels(1, 1);
|
|
|
|
bitmap.eraseARGB(255, 255, 255, 255);
|
|
|
|
|
|
|
|
SkAutoTUnref<SkColorFilter> green(
|
|
|
|
SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode));
|
|
|
|
SkAutoTUnref<SkColorFilterImageFilter> greenFilter(
|
|
|
|
SkColorFilterImageFilter::Create(green.get()));
|
|
|
|
SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
|
|
|
|
SkAutoTUnref<SkColorFilterImageFilter> croppedOut(
|
|
|
|
SkColorFilterImageFilter::Create(green.get(), NULL, &cropRect));
|
|
|
|
|
|
|
|
// Check that an xfermode image filter whose input has been cropped out still draws the other
|
|
|
|
// input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
|
|
|
|
SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcOver_Mode);
|
|
|
|
SkAutoTUnref<SkImageFilter> xfermodeNoFg(
|
|
|
|
SkXfermodeImageFilter::Create(mode, greenFilter, croppedOut));
|
|
|
|
SkAutoTUnref<SkImageFilter> xfermodeNoBg(
|
|
|
|
SkXfermodeImageFilter::Create(mode, croppedOut, greenFilter));
|
|
|
|
SkAutoTUnref<SkImageFilter> xfermodeNoFgNoBg(
|
|
|
|
SkXfermodeImageFilter::Create(mode, croppedOut, croppedOut));
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setImageFilter(xfermodeNoFg);
|
|
|
|
canvas.drawSprite(bitmap, 0, 0, &paint);
|
|
|
|
|
|
|
|
uint32_t pixel;
|
|
|
|
SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
|
|
|
|
canvas.readPixels(info, &pixel, 4, 0, 0);
|
|
|
|
REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
|
|
|
|
|
|
|
|
paint.setImageFilter(xfermodeNoBg);
|
|
|
|
canvas.drawSprite(bitmap, 0, 0, &paint);
|
|
|
|
canvas.readPixels(info, &pixel, 4, 0, 0);
|
|
|
|
REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
|
|
|
|
|
|
|
|
paint.setImageFilter(xfermodeNoFgNoBg);
|
|
|
|
canvas.drawSprite(bitmap, 0, 0, &paint);
|
|
|
|
canvas.readPixels(info, &pixel, 4, 0, 0);
|
|
|
|
REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
|
|
|
|
SkBitmap temp;
|
|
|
|
temp.allocN32Pixels(100, 100);
|
|
|
|
SkBitmapDevice device(temp);
|
|
|
|
test_xfermode_cropped_input(&device, reporter);
|
|
|
|
}
|
2014-03-24 20:50:59 +00:00
|
|
|
|
2014-02-03 22:36:39 +00:00
|
|
|
#if SK_SUPPORT_GPU
|
2014-02-03 22:22:16 +00:00
|
|
|
DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
|
|
|
|
GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
|
2014-02-16 00:59:25 +00:00
|
|
|
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
|
|
|
|
SkImageInfo::MakeN32Premul(100, 100),
|
|
|
|
0));
|
|
|
|
test_crop_rects(device, reporter);
|
2014-02-03 22:22:16 +00:00
|
|
|
}
|
2014-03-24 20:50:59 +00:00
|
|
|
|
|
|
|
DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
|
|
|
|
GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
|
|
|
|
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
|
|
|
|
SkImageInfo::MakeN32Premul(100, 100),
|
|
|
|
0));
|
|
|
|
test_huge_blur(device, reporter);
|
|
|
|
}
|
Fix SkXfermodeImageFilter when an input is cropped out.
If one of inputs to SkXfermodeImageFilter draws nothing, either due to
it being cropped out upstream, or within the filter itself, the filter
should still draw the other input, since otherwise the result will be incorrect.
For the GPU path, since we can't detect this case in
canFilterImageGPU() without recursing, we'll just drop to
the generic path if either input is empty, since we can't use the effect in that case anyway.
While we're at it, let's drop to the generic path if the
xfermode can't be expressed as an effect, since the code
here was doing a 2-pass render in that case anyway, which
is equivalent to what the (xfermode == NULL) case was doing
anyway.
R=bsalomon@google.com, sugoi@chromium.org
Review URL: https://codereview.chromium.org/220723007
git-svn-id: http://skia.googlecode.com/svn/trunk@14016 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-04-01 19:15:23 +00:00
|
|
|
|
|
|
|
DEF_GPUTEST(XfermodeImageFilterCroppedInputGPU, reporter, factory) {
|
|
|
|
GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
|
|
|
|
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
|
|
|
|
SkImageInfo::MakeN32Premul(1, 1),
|
|
|
|
0));
|
|
|
|
test_xfermode_cropped_input(device, reporter);
|
|
|
|
}
|
2014-02-03 22:36:39 +00:00
|
|
|
#endif
|