From 0ef0501baf615149d6d84398d7594cd89f6e928d Mon Sep 17 00:00:00 2001 From: "senorblanco@chromium.org" Date: Fri, 14 Mar 2014 16:35:08 +0000 Subject: Implement support for expanding crop rects in image filters NOTE: this patch set is based on https://codereview.chromium.org/189913021/, and needs that patch to land first. Until now, crop rects in Skia have only been able to reduce the size of the destination bounds, but not expand them. SVG semantics require the latter as well. The heart of the change is in applyCropRect(), which now assigns each edge, instead of doing an intersection with the crop rect. In order to support this (and still work well with tiled drawing) we need to clip the resulting crop rect to the clipping region of the filters. This uses the Context struct previously landed from https://codereview.chromium.org/189913021/. Many of the pixel loops are not yet ready to handle a destination rect larger than the source rect. So we provide a convenience version of applyCropRect() which creates an offscreen and pads it out with transparent black. Once the pixel loops and shaders have been fixed to support larger destination bounds, they should be switched back to the non-drawing version of applyCropRect(). BUG=skia: R=bsalomon@google.com, reed@google.com Review URL: https://codereview.chromium.org/198003008 git-svn-id: http://skia.googlecode.com/svn/trunk@13805 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gm/imagefilterscropexpand.cpp | 170 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 gm/imagefilterscropexpand.cpp (limited to 'gm/imagefilterscropexpand.cpp') diff --git a/gm/imagefilterscropexpand.cpp b/gm/imagefilterscropexpand.cpp new file mode 100644 index 0000000000..9373696773 --- /dev/null +++ b/gm/imagefilterscropexpand.cpp @@ -0,0 +1,170 @@ +/* + * Copyright 2014 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" +#include "SkCanvas.h" +#include "SkColorFilter.h" +#include "SkColorPriv.h" +#include "SkShader.h" + +#include "SkBitmapSource.h" +#include "SkBlurImageFilter.h" +#include "SkColorMatrixFilter.h" +#include "SkDisplacementMapEffect.h" +#include "SkDropShadowImageFilter.h" +#include "SkGradientShader.h" +#include "SkMorphologyImageFilter.h" +#include "SkColorFilterImageFilter.h" +#include "SkMergeImageFilter.h" +#include "SkOffsetImageFilter.h" + +/////////////////////////////////////////////////////////////////////////////// + +class ImageFiltersCropExpandGM : public skiagm::GM { +public: + ImageFiltersCropExpandGM () {} + +protected: + + virtual SkString onShortName() { + return SkString("imagefilterscropexpand"); + } + + virtual SkISize onISize() { return SkISize::Make(570, 650); } + + void make_checkerboard(SkBitmap* bitmap) { + bitmap->allocN32Pixels(64, 64); + SkCanvas canvas(*bitmap); + canvas.clear(0xFFFF0000); + SkPaint darkPaint; + darkPaint.setColor(0xFF404040); + SkPaint lightPaint; + lightPaint.setColor(0xFFA0A0A0); + for (int y = 8; y < 48; y += 16) { + for (int x = 8; x < 48; x += 16) { + canvas.save(); + canvas.translate(SkIntToScalar(x), SkIntToScalar(y)); + canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint); + canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint); + canvas.restore(); + } + } + } + + void make_gradient_circle(int width, int height, SkBitmap* bitmap) { + SkScalar x = SkIntToScalar(width / 2); + SkScalar y = SkIntToScalar(height / 2); + SkScalar radius = SkMinScalar(x, y) * 0.8f; + bitmap->allocN32Pixels(width, height); + SkCanvas canvas(*bitmap); + canvas.clear(0x00000000); + SkColor colors[2]; + colors[0] = SK_ColorWHITE; + colors[1] = SK_ColorBLACK; + SkAutoTUnref shader( + SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2, + SkShader::kClamp_TileMode) + ); + SkPaint paint; + paint.setShader(shader); + canvas.drawCircle(x, y, radius, paint); + } + + static void draw(SkCanvas* canvas, const SkBitmap& bitmap, const SkRect& rect, SkImageFilter* filter) { + SkPaint paint; + paint.setImageFilter(filter)->unref(); + canvas->saveLayer(&rect, &paint); + canvas->drawBitmap(bitmap, 0, 0); + canvas->restore(); + + SkPaint strokePaint; + strokePaint.setColor(0xFFFF0000); + strokePaint.setStyle(SkPaint::kStroke_Style); + canvas->drawRect(rect, strokePaint); + + canvas->translate(SkIntToScalar(80), 0); + } + + virtual void onDraw(SkCanvas* canvas) { + SkAutoTUnref cf( + SkColorFilter::CreateModeFilter(SK_ColorBLUE, SkXfermode::kSrcIn_Mode)); + SkImageFilter::CropRect crop_rect( + SkRect::Make(SkIRect::MakeXYWH(10, 10, 44, 44)), + SkImageFilter::CropRect::kHasAll_CropEdge); + + SkBitmap gradient_circle, checkerboard; + make_gradient_circle(64, 64, &gradient_circle); + make_checkerboard(&checkerboard); + + SkAutoTUnref gradient_circle_source( + SkBitmapSource::Create(gradient_circle)); + SkAutoTUnref noop_cropped( + SkOffsetImageFilter::Create(0, 0, NULL, &crop_rect)); + SkScalar sk255 = SkIntToScalar(255); + SkScalar matrix[20] = { 1, 0, 0, 0, 0, + 0, 1, 0, 0, sk255, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, sk255 }; + SkAutoTUnref cf_alpha_trans(SkColorMatrixFilter::Create(matrix)); + + SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64)); + SkScalar MARGIN = SkIntToScalar(12); + + SkIRect bounds; + r.roundOut(&bounds); + + SkPaint paint; + canvas->translate(MARGIN, MARGIN); + for (int outset = -15; outset <= 20; outset += 5) { + canvas->save(); + SkRect rect = crop_rect.rect(); + rect.outset(SkIntToScalar(outset), + SkIntToScalar(outset)); + SkImageFilter::CropRect big_rect(rect, SkImageFilter::CropRect::kHasAll_CropEdge); + + draw(canvas, checkerboard, rect, SkColorFilterImageFilter::Create( + cf_alpha_trans, noop_cropped.get(), &big_rect)); + + draw(canvas, checkerboard, rect, SkBlurImageFilter::Create( + 8.0f, 8.0f, noop_cropped.get(), &big_rect)); + + draw(canvas, checkerboard, rect, SkDilateImageFilter::Create( + 2, 2, noop_cropped.get(), &big_rect)); + + draw(canvas, checkerboard, rect, SkErodeImageFilter::Create( + 2, 2, noop_cropped.get(), &big_rect)); + + draw(canvas, checkerboard, rect, SkDropShadowImageFilter::Create( + SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(3), SkIntToScalar(3), + SK_ColorBLUE, noop_cropped.get(), &big_rect)); + + draw(canvas, checkerboard, rect, SkDisplacementMapEffect::Create( + SkDisplacementMapEffect::kR_ChannelSelectorType, + SkDisplacementMapEffect::kR_ChannelSelectorType, + SkIntToScalar(12), + gradient_circle_source.get(), + noop_cropped.get(), + &big_rect)); + + draw(canvas, checkerboard, rect, SkOffsetImageFilter::Create( + SkIntToScalar(-8), SkIntToScalar(16), noop_cropped.get(), &big_rect)); + + canvas->restore(); + canvas->translate(0, SkIntToScalar(80)); + } + } + +private: + typedef GM INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static skiagm::GM* MyFactory(void*) { return new ImageFiltersCropExpandGM; } +static skiagm::GMRegistry reg(MyFactory); -- cgit v1.2.3