2012-08-20 14:53:21 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2012 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gm.h"
|
|
|
|
|
2013-10-24 01:46:11 +00:00
|
|
|
#include "SkArithmeticMode.h"
|
2014-02-13 17:14:46 +00:00
|
|
|
#include "SkDevice.h"
|
2012-08-20 14:53:21 +00:00
|
|
|
#include "SkBlurImageFilter.h"
|
2012-08-20 19:23:24 +00:00
|
|
|
#include "SkColorFilter.h"
|
|
|
|
#include "SkColorFilterImageFilter.h"
|
2013-11-20 21:32:10 +00:00
|
|
|
#include "SkColorMatrixFilter.h"
|
2015-09-15 18:26:13 +00:00
|
|
|
#include "SkImage.h"
|
|
|
|
#include "SkImageSource.h"
|
2016-01-26 16:41:02 +00:00
|
|
|
#include "SkMatrixConvolutionImageFilter.h"
|
2014-01-30 18:58:24 +00:00
|
|
|
#include "SkReadBuffer.h"
|
|
|
|
#include "SkWriteBuffer.h"
|
2012-12-04 14:18:50 +00:00
|
|
|
#include "SkMergeImageFilter.h"
|
2012-08-20 14:53:21 +00:00
|
|
|
#include "SkMorphologyImageFilter.h"
|
|
|
|
#include "SkTestImageFilters.h"
|
2013-11-20 21:32:10 +00:00
|
|
|
#include "SkXfermodeImageFilter.h"
|
2012-08-20 14:53:21 +00:00
|
|
|
|
2013-10-24 01:46:11 +00:00
|
|
|
// More closely models how Blink's OffsetFilter works as of 10/23/13. SkOffsetImageFilter doesn't
|
|
|
|
// perform a draw and this one does.
|
|
|
|
class SimpleOffsetFilter : public SkImageFilter {
|
|
|
|
public:
|
2014-08-21 17:53:34 +00:00
|
|
|
class Registrar {
|
|
|
|
public:
|
|
|
|
Registrar() {
|
|
|
|
SkFlattenable::Register("SimpleOffsetFilter",
|
|
|
|
SimpleOffsetFilter::CreateProc,
|
|
|
|
SimpleOffsetFilter::GetFlattenableType());
|
|
|
|
}
|
|
|
|
};
|
2014-03-18 10:28:27 +00:00
|
|
|
static SkImageFilter* Create(SkScalar dx, SkScalar dy, SkImageFilter* input) {
|
2015-08-26 20:07:48 +00:00
|
|
|
return new SimpleOffsetFilter(dx, dy, input);
|
2014-03-18 10:28:27 +00:00
|
|
|
}
|
2013-10-24 01:46:11 +00:00
|
|
|
|
2014-03-14 15:44:01 +00:00
|
|
|
virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx,
|
2015-03-26 01:17:31 +00:00
|
|
|
SkBitmap* dst, SkIPoint* offset) const override {
|
2013-10-24 01:46:11 +00:00
|
|
|
SkBitmap source = src;
|
|
|
|
SkIPoint srcOffset = SkIPoint::Make(0, 0);
|
2015-10-15 19:15:13 +00:00
|
|
|
if (!this->filterInput(0, proxy, src, ctx, &source, &srcOffset)) {
|
2013-10-24 01:46:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkIRect bounds;
|
2014-03-14 17:44:41 +00:00
|
|
|
if (!this->applyCropRect(ctx, proxy, source, &srcOffset, &bounds, &source)) {
|
2013-10-24 01:46:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
|
|
|
|
SkCanvas canvas(device);
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
|
|
|
canvas.drawBitmap(source, fDX - bounds.left(), fDY - bounds.top(), &paint);
|
|
|
|
*dst = device->accessBitmap(false);
|
|
|
|
offset->fX += bounds.left();
|
|
|
|
offset->fY += bounds.top();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-19 21:49:15 +00:00
|
|
|
SK_TO_STRING_OVERRIDE()
|
2013-10-24 01:46:11 +00:00
|
|
|
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SimpleOffsetFilter);
|
|
|
|
|
|
|
|
protected:
|
2015-03-26 01:17:31 +00:00
|
|
|
void flatten(SkWriteBuffer& buffer) const override {
|
2014-08-21 14:59:51 +00:00
|
|
|
this->INHERITED::flatten(buffer);
|
2013-10-24 01:46:11 +00:00
|
|
|
buffer.writeScalar(fDX);
|
|
|
|
buffer.writeScalar(fDY);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2014-03-18 10:28:27 +00:00
|
|
|
SimpleOffsetFilter(SkScalar dx, SkScalar dy, SkImageFilter* input)
|
2014-08-21 17:53:34 +00:00
|
|
|
: SkImageFilter(1, &input), fDX(dx), fDY(dy) {}
|
2014-03-18 10:28:27 +00:00
|
|
|
|
2013-10-24 01:46:11 +00:00
|
|
|
SkScalar fDX, fDY;
|
2014-08-21 14:59:51 +00:00
|
|
|
|
|
|
|
typedef SkImageFilter INHERITED;
|
2013-10-24 01:46:11 +00:00
|
|
|
};
|
|
|
|
|
2014-08-21 17:53:34 +00:00
|
|
|
static SimpleOffsetFilter::Registrar gReg;
|
|
|
|
|
2014-08-21 14:59:51 +00:00
|
|
|
SkFlattenable* SimpleOffsetFilter::CreateProc(SkReadBuffer& buffer) {
|
|
|
|
SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
|
|
|
|
SkScalar dx = buffer.readScalar();
|
|
|
|
SkScalar dy = buffer.readScalar();
|
|
|
|
return Create(dx, dy, common.getInput(0));
|
|
|
|
}
|
2013-10-24 01:46:11 +00:00
|
|
|
|
2014-12-19 21:49:15 +00:00
|
|
|
#ifndef SK_IGNORE_TO_STRING
|
|
|
|
void SimpleOffsetFilter::toString(SkString* str) const {
|
|
|
|
str->appendf("SimpleOffsetFilter: (");
|
|
|
|
str->append(")");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-08-20 14:53:21 +00:00
|
|
|
class ImageFiltersGraphGM : public skiagm::GM {
|
|
|
|
public:
|
2014-05-27 16:28:43 +00:00
|
|
|
ImageFiltersGraphGM() {}
|
2012-08-20 14:53:21 +00:00
|
|
|
|
|
|
|
protected:
|
2014-04-30 13:20:45 +00:00
|
|
|
|
2015-09-03 20:32:33 +00:00
|
|
|
SkString onShortName() override {
|
2012-08-20 14:53:21 +00:00
|
|
|
return SkString("imagefiltersgraph");
|
|
|
|
}
|
|
|
|
|
2016-01-26 16:41:02 +00:00
|
|
|
SkISize onISize() override { return SkISize::Make(600, 150); }
|
2012-08-20 14:53:21 +00:00
|
|
|
|
2015-09-03 20:32:33 +00:00
|
|
|
void onOnceBeforeDraw() override {
|
2015-09-15 18:26:13 +00:00
|
|
|
fImage.reset(SkImage::NewFromBitmap(
|
|
|
|
sk_tool_utils::create_string_bitmap(100, 100, SK_ColorWHITE, 20, 70, 96, "e")));
|
2014-05-27 16:28:43 +00:00
|
|
|
}
|
|
|
|
|
2015-09-03 20:32:33 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2015-03-27 19:33:46 +00:00
|
|
|
canvas->clear(SK_ColorBLACK);
|
2012-10-24 15:14:26 +00:00
|
|
|
{
|
2015-09-15 18:26:13 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> bitmapSource(SkImageSource::Create(fImage));
|
2012-10-24 15:14:26 +00:00
|
|
|
SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED,
|
|
|
|
SkXfermode::kSrcIn_Mode));
|
2014-03-10 10:51:58 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(4.0f, 4.0f, bitmapSource));
|
|
|
|
SkAutoTUnref<SkImageFilter> erode(SkErodeImageFilter::Create(4, 4, blur));
|
2012-10-26 19:37:00 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> color(SkColorFilterImageFilter::Create(cf, erode));
|
2014-03-10 10:51:58 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> merge(SkMergeImageFilter::Create(blur, color));
|
2012-10-24 15:14:26 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setImageFilter(merge);
|
|
|
|
canvas->drawPaint(paint);
|
2013-10-24 15:59:31 +00:00
|
|
|
canvas->translate(SkIntToScalar(100), 0);
|
2012-10-24 15:14:26 +00:00
|
|
|
}
|
|
|
|
{
|
2014-03-10 10:51:58 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> morph(SkDilateImageFilter::Create(5, 5));
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-10-24 15:14:26 +00:00
|
|
|
SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
|
|
|
|
0, SK_Scalar1, 0, 0, 0,
|
|
|
|
0, 0, SK_Scalar1, 0, 0,
|
2013-11-25 19:44:07 +00:00
|
|
|
0, 0, 0, 0.5f, 0 };
|
2012-08-20 14:53:21 +00:00
|
|
|
|
2014-02-21 18:46:30 +00:00
|
|
|
SkAutoTUnref<SkColorFilter> matrixFilter(SkColorMatrixFilter::Create(matrix));
|
2012-10-26 19:37:00 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> colorMorph(SkColorFilterImageFilter::Create(matrixFilter, morph));
|
2013-08-01 14:59:05 +00:00
|
|
|
SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
|
2014-03-10 10:51:58 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> blendColor(SkXfermodeImageFilter::Create(mode, colorMorph));
|
2012-08-20 14:53:21 +00:00
|
|
|
|
2012-10-24 15:14:26 +00:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setImageFilter(blendColor);
|
2015-09-15 18:26:13 +00:00
|
|
|
DrawClippedImage(canvas, fImage, paint);
|
2013-10-24 15:59:31 +00:00
|
|
|
canvas->translate(SkIntToScalar(100), 0);
|
2012-10-24 15:14:26 +00:00
|
|
|
}
|
2013-10-24 01:46:11 +00:00
|
|
|
{
|
|
|
|
SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
|
|
|
|
0, SK_Scalar1, 0, 0, 0,
|
|
|
|
0, 0, SK_Scalar1, 0, 0,
|
2013-11-25 19:44:07 +00:00
|
|
|
0, 0, 0, 0.5f, 0 };
|
2015-12-21 16:52:45 +00:00
|
|
|
SkAutoTUnref<SkColorFilter> matrixCF(SkColorMatrixFilter::Create(matrix));
|
2014-02-21 18:46:30 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> matrixFilter(SkColorFilterImageFilter::Create(matrixCF));
|
2014-03-18 10:28:27 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> offsetFilter(
|
|
|
|
SimpleOffsetFilter::Create(10.0f, 10.f, matrixFilter));
|
2013-10-24 01:46:11 +00:00
|
|
|
|
|
|
|
SkAutoTUnref<SkXfermode> arith(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0));
|
2015-12-21 16:52:45 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> arithFilter(
|
2014-03-18 10:28:27 +00:00
|
|
|
SkXfermodeImageFilter::Create(arith, matrixFilter, offsetFilter));
|
2013-10-24 01:46:11 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
2014-03-10 10:51:58 +00:00
|
|
|
paint.setImageFilter(arithFilter);
|
2015-09-15 18:26:13 +00:00
|
|
|
DrawClippedImage(canvas, fImage, paint);
|
2013-10-24 15:59:31 +00:00
|
|
|
canvas->translate(SkIntToScalar(100), 0);
|
|
|
|
}
|
|
|
|
{
|
2014-03-10 10:51:58 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(
|
2013-10-24 15:59:31 +00:00
|
|
|
SkIntToScalar(10), SkIntToScalar(10)));
|
|
|
|
|
|
|
|
SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcIn_Mode));
|
|
|
|
SkImageFilter::CropRect cropRect(SkRect::MakeWH(SkIntToScalar(95), SkIntToScalar(100)));
|
2014-03-10 10:51:58 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> blend(
|
2015-08-27 14:41:13 +00:00
|
|
|
SkXfermodeImageFilter::Create(mode, blur, nullptr, &cropRect));
|
2013-10-24 15:59:31 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setImageFilter(blend);
|
2015-09-15 18:26:13 +00:00
|
|
|
DrawClippedImage(canvas, fImage, paint);
|
2013-10-24 15:59:31 +00:00
|
|
|
canvas->translate(SkIntToScalar(100), 0);
|
2013-10-24 01:46:11 +00:00
|
|
|
}
|
2016-01-26 16:41:02 +00:00
|
|
|
{
|
|
|
|
// Dilate -> matrix convolution.
|
|
|
|
// This tests that a filter using asFragmentProcessor (matrix
|
|
|
|
// convolution) correctly handles a non-zero source offset
|
|
|
|
// (supplied by the dilate).
|
|
|
|
SkAutoTUnref<SkImageFilter> dilate(SkDilateImageFilter::Create(5, 5));
|
|
|
|
|
|
|
|
SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcIn_Mode));
|
|
|
|
|
|
|
|
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 = 1.0f, bias = SkIntToScalar(0);
|
|
|
|
SkIPoint kernelOffset = SkIPoint::Make(1, 1);
|
|
|
|
auto tileMode = SkMatrixConvolutionImageFilter::kClamp_TileMode;
|
|
|
|
bool convolveAlpha = false;
|
|
|
|
SkAutoTUnref<SkImageFilter> convolve(
|
|
|
|
SkMatrixConvolutionImageFilter::Create(kernelSize,
|
|
|
|
kernel,
|
|
|
|
gain,
|
|
|
|
bias,
|
|
|
|
kernelOffset,
|
|
|
|
tileMode,
|
|
|
|
convolveAlpha,
|
|
|
|
dilate));
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setImageFilter(convolve);
|
|
|
|
DrawClippedImage(canvas, fImage, paint);
|
|
|
|
canvas->translate(SkIntToScalar(100), 0);
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
// Test that crop offsets are absolute, not relative to the parent's crop rect.
|
|
|
|
SkAutoTUnref<SkColorFilter> cf1(SkColorFilter::CreateModeFilter(SK_ColorBLUE,
|
|
|
|
SkXfermode::kSrcIn_Mode));
|
|
|
|
SkAutoTUnref<SkColorFilter> cf2(SkColorFilter::CreateModeFilter(SK_ColorGREEN,
|
|
|
|
SkXfermode::kSrcIn_Mode));
|
|
|
|
SkImageFilter::CropRect outerRect(SkRect::MakeXYWH(SkIntToScalar(10), SkIntToScalar(10),
|
|
|
|
SkIntToScalar(80), SkIntToScalar(80)));
|
|
|
|
SkImageFilter::CropRect innerRect(SkRect::MakeXYWH(SkIntToScalar(20), SkIntToScalar(20),
|
|
|
|
SkIntToScalar(60), SkIntToScalar(60)));
|
2015-08-27 14:41:13 +00:00
|
|
|
SkAutoTUnref<SkImageFilter> color1(SkColorFilterImageFilter::Create(cf1, nullptr, &outerRect));
|
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
|
|
|
SkAutoTUnref<SkImageFilter> color2(SkColorFilterImageFilter::Create(cf2, color1, &innerRect));
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setImageFilter(color2);
|
2015-03-27 19:33:46 +00:00
|
|
|
paint.setColor(SK_ColorRED);
|
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
|
|
|
canvas->drawRect(SkRect::MakeXYWH(0, 0, 100, 100), paint);
|
|
|
|
canvas->translate(SkIntToScalar(100), 0);
|
|
|
|
}
|
2012-08-20 14:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-09-15 18:26:13 +00:00
|
|
|
static void DrawClippedImage(SkCanvas* canvas, const SkImage* image, const SkPaint& paint) {
|
|
|
|
canvas->save();
|
|
|
|
canvas->clipRect(SkRect::MakeIWH(image->width(), image->height()));
|
|
|
|
canvas->drawImage(image, 0, 0, &paint);
|
|
|
|
canvas->restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
SkAutoTUnref<SkImage> fImage;
|
|
|
|
|
2012-08-20 14:53:21 +00:00
|
|
|
typedef GM INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-09-03 20:32:33 +00:00
|
|
|
DEF_GM(return new ImageFiltersGraphGM;)
|