зеркало из https://github.com/mozilla/moz-skia.git
Implement correct clipping for image filters.
Image filters in Skia currently clip the size of the the offscreen bitmap used for filtering to the device clip bounds. This means that any pixel-moving filter (e.g., blur) has edge artifacts at the clip boundaries. This is problematic for tiling, where a single SkPicture is played back with a clip set to the tile boundaries. By implementing the onFilterBounds() traversal, and using it in saveLayer() when a filter is present, we can clip the layer to the expanded clip rect. Note that this requires that the traversal be performed in reverse as compared to computeFastBounds(). (It's also done in device space, unlike computeFastBounds()). New test imagefiltersclipped tests pixel-moving filters when clipped by various clip rects. New test imageblurtiled tests tiled (compositor-style) rendering of blurred text. There should be no artifacts at the tile boundaries. BUG=337831 R=reed@google.com Review URL: https://codereview.chromium.org/23011012 git-svn-id: http://skia.googlecode.com/svn/trunk@13323 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
495157b991
Коммит
c4b12f19a4
|
@ -40,3 +40,17 @@ filltypespersp
|
|||
# deprecated calling pattern.
|
||||
# https://codereview.chromium.org/154163002/
|
||||
extractbitmap
|
||||
|
||||
# Added by senorblanco as part of https://codereview.chromium.org/23011012/
|
||||
colorfilterimagefilter
|
||||
dropshadowimagefilter
|
||||
imageblur
|
||||
imageblur_large
|
||||
imagefiltersbase
|
||||
imagefilterscropped
|
||||
imagefiltersgraph
|
||||
imagefiltersscaled
|
||||
morphology
|
||||
offsetimagefilter
|
||||
spritebitmap
|
||||
xfermodeimagefilter
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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 "SkBlurImageFilter.h"
|
||||
#include "SkRandom.h"
|
||||
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
class ImageBlurTiledGM : public GM {
|
||||
public:
|
||||
ImageBlurTiledGM(SkScalar sigmaX, SkScalar sigmaY)
|
||||
: fSigmaX(sigmaX), fSigmaY(sigmaY) {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual SkString onShortName() {
|
||||
return SkString("imageblurtiled");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() {
|
||||
return make_isize(WIDTH, HEIGHT);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(new SkBlurImageFilter(fSigmaX, fSigmaY))->unref();
|
||||
const SkScalar tile_size = SkIntToScalar(128);
|
||||
SkRect bounds;
|
||||
canvas->getClipBounds(&bounds);
|
||||
for (SkScalar y = bounds.top(); y < bounds.bottom(); y += tile_size) {
|
||||
for (SkScalar x = bounds.left(); x < bounds.right(); x += tile_size) {
|
||||
canvas->save();
|
||||
canvas->clipRect(SkRect::MakeXYWH(x, y, tile_size, tile_size));
|
||||
canvas->saveLayer(NULL, &paint);
|
||||
const char* str[] = {
|
||||
"The quick",
|
||||
"brown fox",
|
||||
"jumped over",
|
||||
"the lazy dog.",
|
||||
};
|
||||
SkPaint textPaint;
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setTextSize(SkIntToScalar(100));
|
||||
int posY = 0;
|
||||
for (unsigned i = 0; i < SK_ARRAY_COUNT(str); i++) {
|
||||
posY += 100;
|
||||
canvas->drawText(str[i], strlen(str[i]), SkIntToScalar(0),
|
||||
SkIntToScalar(posY), textPaint);
|
||||
}
|
||||
canvas->restore();
|
||||
canvas->restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkScalar fSigmaX;
|
||||
SkScalar fSigmaY;
|
||||
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static GM* MyFactory1(void*) { return new ImageBlurTiledGM(3.0f, 3.0f); }
|
||||
static GMRegistry reg1(MyFactory1);
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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 "SkColor.h"
|
||||
#include "SkBitmapSource.h"
|
||||
#include "SkBlurImageFilter.h"
|
||||
#include "SkDisplacementMapEffect.h"
|
||||
#include "SkDropShadowImageFilter.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkMorphologyImageFilter.h"
|
||||
#include "SkOffsetImageFilter.h"
|
||||
#include "SkScalar.h"
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
class ImageFiltersClippedGM : public GM {
|
||||
public:
|
||||
ImageFiltersClippedGM() : fInitialized(false) {
|
||||
this->setBGColor(0x00000000);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual SkString onShortName() {
|
||||
return SkString("imagefiltersclipped");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() {
|
||||
return make_isize(860, 500);
|
||||
}
|
||||
|
||||
void make_checkerboard() {
|
||||
fCheckerboard.allocN32Pixels(64, 64);
|
||||
SkBitmapDevice device(fCheckerboard);
|
||||
SkCanvas canvas(&device);
|
||||
canvas.clear(0x00000000);
|
||||
SkPaint darkPaint;
|
||||
darkPaint.setColor(0xFF404040);
|
||||
SkPaint lightPaint;
|
||||
lightPaint.setColor(0xFFA0A0A0);
|
||||
for (int y = 0; y < 64; y += 16) {
|
||||
for (int x = 0; x < 64; 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) {
|
||||
SkScalar x = SkIntToScalar(width / 2);
|
||||
SkScalar y = SkIntToScalar(height / 2);
|
||||
SkScalar radius = SkScalarMul(SkMinScalar(x, y), SkIntToScalar(4) / SkIntToScalar(5));
|
||||
fGradientCircle.allocN32Pixels(width, height);
|
||||
SkBitmapDevice device(fGradientCircle);
|
||||
SkCanvas canvas(&device);
|
||||
canvas.clear(0x00000000);
|
||||
SkColor colors[2];
|
||||
colors[0] = SK_ColorWHITE;
|
||||
colors[1] = SK_ColorBLACK;
|
||||
SkAutoTUnref<SkShader> 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);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
if (!fInitialized) {
|
||||
this->make_checkerboard();
|
||||
this->make_gradient_circle(64, 64);
|
||||
fInitialized = true;
|
||||
}
|
||||
canvas->clear(0x00000000);
|
||||
|
||||
SkAutoTUnref<SkImageFilter> gradient(new SkBitmapSource(fGradientCircle));
|
||||
SkAutoTUnref<SkImageFilter> checkerboard(new SkBitmapSource(fCheckerboard));
|
||||
|
||||
SkImageFilter* filters[] = {
|
||||
new SkBlurImageFilter(SkIntToScalar(12), SkIntToScalar(12)),
|
||||
new SkDropShadowImageFilter(SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(3),
|
||||
SK_ColorGREEN),
|
||||
new SkDisplacementMapEffect(SkDisplacementMapEffect::kR_ChannelSelectorType,
|
||||
SkDisplacementMapEffect::kR_ChannelSelectorType,
|
||||
SkIntToScalar(12),
|
||||
gradient.get(),
|
||||
checkerboard.get()),
|
||||
new SkDilateImageFilter(2, 2, checkerboard.get()),
|
||||
new SkErodeImageFilter(2, 2, checkerboard.get()),
|
||||
new SkOffsetImageFilter(SkIntToScalar(-16), SkIntToScalar(32)),
|
||||
};
|
||||
|
||||
SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
|
||||
SkScalar margin = SkIntToScalar(16);
|
||||
SkRect bounds = r;
|
||||
bounds.outset(margin, margin);
|
||||
|
||||
for (int xOffset = 0; xOffset < 80; xOffset += 16) {
|
||||
canvas->save();
|
||||
bounds.fLeft = SkIntToScalar(xOffset);
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorWHITE);
|
||||
paint.setImageFilter(filters[i]);
|
||||
paint.setAntiAlias(true);
|
||||
canvas->save();
|
||||
canvas->clipRect(bounds);
|
||||
if (i == 5) {
|
||||
canvas->translate(SkIntToScalar(16), SkIntToScalar(-32));
|
||||
}
|
||||
canvas->drawCircle(r.centerX(), r.centerY(),
|
||||
SkScalarDiv(r.width()*2, SkIntToScalar(5)), paint);
|
||||
canvas->restore();
|
||||
canvas->translate(r.width() + margin, 0);
|
||||
}
|
||||
canvas->restore();
|
||||
canvas->translate(0, r.height() + margin);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool fInitialized;
|
||||
SkBitmap fCheckerboard;
|
||||
SkBitmap fGradientCircle;
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static GM* MyFactory(void*) { return new ImageFiltersClippedGM; }
|
||||
static GMRegistry reg(MyFactory);
|
||||
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
#include "SkDropShadowImageFilter.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkMorphologyImageFilter.h"
|
||||
#include "SkOffsetImageFilter.h"
|
||||
#include "SkScalar.h"
|
||||
|
||||
namespace skiagm {
|
||||
|
@ -96,6 +97,7 @@ protected:
|
|||
checkerboard.get()),
|
||||
new SkDilateImageFilter(1, 1, checkerboard.get()),
|
||||
new SkErodeImageFilter(1, 1, checkerboard.get()),
|
||||
new SkOffsetImageFilter(SkIntToScalar(32), 0),
|
||||
};
|
||||
|
||||
SkVector scales[] = {
|
||||
|
@ -120,7 +122,9 @@ protected:
|
|||
paint.setAntiAlias(true);
|
||||
canvas->save();
|
||||
canvas->scale(scales[j].fX, scales[j].fY);
|
||||
canvas->clipRect(bounds);
|
||||
if (5 == i) {
|
||||
canvas->translate(SkIntToScalar(-32), 0);
|
||||
}
|
||||
canvas->drawCircle(r.centerX(), r.centerY(),
|
||||
SkScalarDiv(r.width()*2, SkIntToScalar(5)), paint);
|
||||
canvas->restore();
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
'../gm/hittestpath.cpp',
|
||||
'../gm/imagealphathreshold.cpp',
|
||||
'../gm/imageblur.cpp',
|
||||
'../gm/imageblurtiled.cpp',
|
||||
'../gm/imagemagnifier.cpp',
|
||||
'../gm/inversepaths.cpp',
|
||||
'../gm/lerpmode.cpp',
|
||||
|
@ -95,6 +96,7 @@
|
|||
'../gm/lumafilter.cpp',
|
||||
'../gm/image.cpp',
|
||||
'../gm/imagefiltersbase.cpp',
|
||||
'../gm/imagefiltersclipped.cpp',
|
||||
'../gm/imagefilterscropped.cpp',
|
||||
'../gm/imagefiltersgraph.cpp',
|
||||
'../gm/imagefiltersscaled.cpp',
|
||||
|
|
|
@ -1039,8 +1039,11 @@ protected:
|
|||
|
||||
// Clip rectangle bounds. Called internally by saveLayer.
|
||||
// returns false if the entire rectangle is entirely clipped out
|
||||
// If non-NULL, The imageFilter parameter will be used to expand the clip
|
||||
// and offscreen bounds for any margin required by the filter DAG.
|
||||
bool clipRectBounds(const SkRect* bounds, SaveFlags flags,
|
||||
SkIRect* intersection);
|
||||
SkIRect* intersection,
|
||||
const SkImageFilter* imageFilter = NULL);
|
||||
|
||||
// Called by child classes that override clipPath and clipRRect to only
|
||||
// track fast conservative clip bounds, rather than exact clips.
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
* Given the src bounds of an image, this returns the bounds of the result
|
||||
* image after the filter has been applied.
|
||||
*/
|
||||
bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst);
|
||||
bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const;
|
||||
|
||||
/**
|
||||
* Returns true if the filter can be processed on the GPU. This is most
|
||||
|
@ -188,8 +188,14 @@ protected:
|
|||
*/
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset);
|
||||
// Default impl copies src into dst and returns true
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*);
|
||||
// Given the bounds of the destination rect to be filled in device
|
||||
// coordinates (first parameter), and the CTM, compute (conservatively)
|
||||
// which rect of the source image would be required (third parameter).
|
||||
// Used for clipping and temp-buffer allocations, so the result need not
|
||||
// be exact, but should never be smaller than the real answer. The default
|
||||
// implementation recursively unions all input bounds, or returns false if
|
||||
// no inputs.
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const;
|
||||
|
||||
// Applies "matrix" to the crop rect, and sets "rect" to the intersection of
|
||||
// "rect" and the transformed crop rect. If there is no overlap, returns
|
||||
|
|
|
@ -24,6 +24,7 @@ protected:
|
|||
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkBitmap fBitmap;
|
||||
|
|
|
@ -27,6 +27,8 @@ protected:
|
|||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&,
|
||||
SkIRect* dst) const SK_OVERRIDE;
|
||||
|
||||
bool canFilterImageGPU() const SK_OVERRIDE { return true; }
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
|
||||
|
|
|
@ -22,7 +22,7 @@ protected:
|
|||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef SkImageFilter INHERITED;
|
||||
|
|
|
@ -39,6 +39,9 @@ public:
|
|||
SkIPoint* offset) SK_OVERRIDE;
|
||||
virtual void computeFastBounds(const SkRect& src, SkRect* dst) const SK_OVERRIDE;
|
||||
|
||||
virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&,
|
||||
SkIRect* dst) const SK_OVERRIDE;
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
|
||||
|
|
|
@ -20,6 +20,10 @@ protected:
|
|||
explicit SkDropShadowImageFilter(SkReadBuffer&);
|
||||
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& source, const SkMatrix&, SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&,
|
||||
SkIRect* dst) const SK_OVERRIDE;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
SkScalar fDx, fDy, fSigmaX, fSigmaY;
|
||||
|
|
|
@ -30,8 +30,6 @@ protected:
|
|||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
uint8_t* fModes; // SkXfermode::Mode
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ class SK_API SkMorphologyImageFilter : public SkImageFilter {
|
|||
public:
|
||||
SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input, const CropRect* cropRect);
|
||||
virtual void computeFastBounds(const SkRect& src, SkRect* dst) const SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const SK_OVERRIDE;
|
||||
|
||||
/**
|
||||
* All morphology procs have the same signature: src is the source buffer, dst the
|
||||
|
|
|
@ -26,7 +26,7 @@ protected:
|
|||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkVector fOffset;
|
||||
|
|
|
@ -791,11 +791,18 @@ static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
|
|||
}
|
||||
|
||||
bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
|
||||
SkIRect* intersection) {
|
||||
SkIRect* intersection, const SkImageFilter* imageFilter) {
|
||||
SkIRect clipBounds;
|
||||
SkRegion::Op op = SkRegion::kIntersect_Op;
|
||||
if (!this->getClipDeviceBounds(&clipBounds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageFilter) {
|
||||
imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds);
|
||||
// Filters may grow the bounds beyond the device bounds.
|
||||
op = SkRegion::kReplace_Op;
|
||||
}
|
||||
SkIRect ir;
|
||||
if (NULL != bounds) {
|
||||
SkRect r;
|
||||
|
@ -813,11 +820,11 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
|
|||
ir = clipBounds;
|
||||
}
|
||||
|
||||
fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
|
||||
fClipStack.clipDevRect(ir, op);
|
||||
|
||||
// early exit if the clip is now empty
|
||||
if (bounds_affects_clip(flags) &&
|
||||
!fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
|
||||
!fMCRec->fRasterClip->op(ir, op)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -861,7 +868,7 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint,
|
|||
fDeviceCMDirty = true;
|
||||
|
||||
SkIRect ir;
|
||||
if (!this->clipRectBounds(bounds, flags, &ir)) {
|
||||
if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
|
|||
}
|
||||
|
||||
bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
SkIRect* dst) const {
|
||||
SkASSERT(&src);
|
||||
SkASSERT(dst);
|
||||
return this->onFilterBounds(src, ctm, dst);
|
||||
|
@ -210,8 +210,28 @@ bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const {
|
|||
}
|
||||
|
||||
bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
*dst = src;
|
||||
SkIRect* dst) const {
|
||||
if (fInputCount < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkIRect bounds;
|
||||
for (int i = 0; i < fInputCount; ++i) {
|
||||
SkImageFilter* filter = this->getInput(i);
|
||||
SkIRect rect = src;
|
||||
if (filter && !filter->filterBounds(src, ctm, &rect)) {
|
||||
return false;
|
||||
}
|
||||
if (0 == i) {
|
||||
bounds = rect;
|
||||
} else {
|
||||
bounds.join(rect);
|
||||
}
|
||||
}
|
||||
|
||||
// don't modify dst until now, so we don't accidentally change it in the
|
||||
// loop, but then return false on the next filter.
|
||||
*dst = bounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,3 +83,9 @@ bool SkBitmapSource::onFilterImage(Proxy* proxy, const SkBitmap&, const SkMatrix
|
|||
void SkBitmapSource::computeFastBounds(const SkRect&, SkRect* dst) const {
|
||||
*dst = fDstRect;
|
||||
}
|
||||
|
||||
bool SkBitmapSource::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) const {
|
||||
*dst = src;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,21 @@ void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const
|
|||
dst->outset(SkScalarMul(fSigma.width(), SkIntToScalar(3)),
|
||||
SkScalarMul(fSigma.height(), SkIntToScalar(3)));
|
||||
}
|
||||
|
||||
bool SkBlurImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) const {
|
||||
SkIRect bounds = src;
|
||||
if (getInput(0) && !getInput(0)->filterBounds(src, ctm, &bounds)) {
|
||||
return false;
|
||||
}
|
||||
SkVector sigma, localSigma = SkVector::Make(fSigma.width(), fSigma.height());
|
||||
ctm.mapVectors(&sigma, &localSigma, 1);
|
||||
bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
|
||||
SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
|
||||
*dst = bounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
#if SK_SUPPORT_GPU
|
||||
|
|
|
@ -36,7 +36,7 @@ bool SkComposeImageFilter::onFilterImage(Proxy* proxy,
|
|||
|
||||
bool SkComposeImageFilter::onFilterBounds(const SkIRect& src,
|
||||
const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
SkIRect* dst) const {
|
||||
SkImageFilter* outer = getInput(0);
|
||||
SkImageFilter* inner = getInput(1);
|
||||
|
||||
|
|
|
@ -255,6 +255,15 @@ void SkDisplacementMapEffect::computeFastBounds(const SkRect& src, SkRect* dst)
|
|||
}
|
||||
}
|
||||
|
||||
bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) const {
|
||||
if (getColorInput()) {
|
||||
return getColorInput()->filterBounds(src, ctm, dst);
|
||||
}
|
||||
*dst = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
|
|
@ -112,3 +112,22 @@ void SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst)
|
|||
SkScalarMul(fSigmaY, SkIntToScalar(3)));
|
||||
dst->join(shadowBounds);
|
||||
}
|
||||
|
||||
bool SkDropShadowImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) const {
|
||||
SkIRect bounds = src;
|
||||
if (getInput(0) && !getInput(0)->filterBounds(src, ctm, &bounds)) {
|
||||
return false;
|
||||
}
|
||||
SkVector offsetVec, localOffsetVec = SkVector::Make(fDx, fDy);
|
||||
ctm.mapVectors(&offsetVec, &localOffsetVec, 1);
|
||||
bounds.offset(-SkScalarCeilToInt(offsetVec.x()),
|
||||
-SkScalarCeilToInt(offsetVec.y()));
|
||||
SkVector sigma, localSigma = SkVector::Make(fSigmaX, fSigmaY);
|
||||
ctm.mapVectors(&sigma, &localSigma, 1);
|
||||
bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
|
||||
SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
|
||||
bounds.join(src);
|
||||
*dst = bounds;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -65,38 +65,6 @@ SkMergeImageFilter::~SkMergeImageFilter() {
|
|||
}
|
||||
}
|
||||
|
||||
bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
if (countInputs() < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkIRect totalBounds;
|
||||
|
||||
int inputCount = countInputs();
|
||||
for (int i = 0; i < inputCount; ++i) {
|
||||
SkImageFilter* filter = getInput(i);
|
||||
SkIRect r;
|
||||
if (filter) {
|
||||
if (!filter->filterBounds(src, ctm, &r)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
r = src;
|
||||
}
|
||||
if (0 == i) {
|
||||
totalBounds = r;
|
||||
} else {
|
||||
totalBounds.join(r);
|
||||
}
|
||||
}
|
||||
|
||||
// don't modify dst until now, so we don't accidentally change it in the
|
||||
// loop, but then return false on the next filter.
|
||||
*dst = totalBounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
|
|
|
@ -249,6 +249,20 @@ void SkMorphologyImageFilter::computeFastBounds(const SkRect& src, SkRect* dst)
|
|||
dst->outset(SkIntToScalar(fRadius.width()), SkIntToScalar(fRadius.height()));
|
||||
}
|
||||
|
||||
bool SkMorphologyImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) const {
|
||||
SkIRect bounds = src;
|
||||
if (getInput(0) && !getInput(0)->filterBounds(src, ctm, &bounds)) {
|
||||
return false;
|
||||
}
|
||||
SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
|
||||
SkIntToScalar(this->radius().height()));
|
||||
ctm.mapVectors(&radius, 1);
|
||||
bounds.outset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y()));
|
||||
*dst = bounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -72,16 +72,19 @@ void SkOffsetImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) cons
|
|||
} else {
|
||||
*dst = src;
|
||||
}
|
||||
SkRect copy = *dst;
|
||||
dst->offset(fOffset.fX, fOffset.fY);
|
||||
dst->join(copy);
|
||||
}
|
||||
|
||||
bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
SkIRect* dst) const {
|
||||
SkVector vec;
|
||||
ctm.mapVectors(&vec, &fOffset, 1);
|
||||
|
||||
*dst = src;
|
||||
dst->offset(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
|
||||
dst->offset(-SkScalarCeilToInt(vec.fX), -SkScalarCeilToInt(vec.fY));
|
||||
dst->join(src);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче