Fix CTM application in SkResizeImagefilter; implement bounds traversals.
SkResizeImageFilter resizes all the pixels from its input (subject to the input's crop rect), but the offset to be applied was incorrect. It should take the CTM into account, so that the origin of the resize is the world space origin, unaffected by whatever clipping is applied. New GM imageresizetiled exercises the behaviour under impl-side-painting-like conditions, and existing GMs now have resize cases added. R=reed@google.com, robertphillips@google.com Review URL: https://codereview.chromium.org/168283006 git-svn-id: http://skia.googlecode.com/svn/trunk@13506 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
5a6abaa1c9
commit
897b73f62c
@ -50,4 +50,9 @@ complexclip2_rrect_aa
|
||||
rrect_clip_bw
|
||||
rrect_clip_aa
|
||||
rrect_bw
|
||||
rrect_aa
|
||||
rrect_aa
|
||||
|
||||
# Need to rebaseline all platforms due to new test cases added in
|
||||
# https://codereview.chromium.org/168283006/
|
||||
imagefiltersclipped
|
||||
imagefiltersscaled
|
||||
|
@ -14,8 +14,12 @@
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkMorphologyImageFilter.h"
|
||||
#include "SkOffsetImageFilter.h"
|
||||
#include "SkResizeImageFilter.h"
|
||||
#include "SkScalar.h"
|
||||
|
||||
#define RESIZE_FACTOR_X SkIntToScalar(2)
|
||||
#define RESIZE_FACTOR_Y SkIntToScalar(5)
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
class ImageFiltersClippedGM : public GM {
|
||||
@ -96,6 +100,7 @@ protected:
|
||||
new SkDilateImageFilter(2, 2, checkerboard.get()),
|
||||
new SkErodeImageFilter(2, 2, checkerboard.get()),
|
||||
new SkOffsetImageFilter(SkIntToScalar(-16), SkIntToScalar(32)),
|
||||
new SkResizeImageFilter(RESIZE_FACTOR_X, RESIZE_FACTOR_Y, SkPaint::kNone_FilterLevel),
|
||||
};
|
||||
|
||||
SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
|
||||
@ -113,8 +118,11 @@ protected:
|
||||
paint.setAntiAlias(true);
|
||||
canvas->save();
|
||||
canvas->clipRect(bounds);
|
||||
if (i == 5) {
|
||||
if (5 == i) {
|
||||
canvas->translate(SkIntToScalar(16), SkIntToScalar(-32));
|
||||
} else if (6 == i) {
|
||||
canvas->scale(SkScalarInvert(RESIZE_FACTOR_X),
|
||||
SkScalarInvert(RESIZE_FACTOR_Y));
|
||||
}
|
||||
canvas->drawCircle(r.centerX(), r.centerY(),
|
||||
SkScalarDiv(r.width()*2, SkIntToScalar(5)), paint);
|
||||
|
@ -14,8 +14,11 @@
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkMorphologyImageFilter.h"
|
||||
#include "SkOffsetImageFilter.h"
|
||||
#include "SkResizeImageFilter.h"
|
||||
#include "SkScalar.h"
|
||||
|
||||
#define RESIZE_FACTOR SkIntToScalar(4)
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
class ImageFiltersScaledGM : public GM {
|
||||
@ -30,7 +33,7 @@ protected:
|
||||
}
|
||||
|
||||
virtual SkISize onISize() {
|
||||
return make_isize(860, 500);
|
||||
return make_isize(1020, 500);
|
||||
}
|
||||
|
||||
void make_checkerboard() {
|
||||
@ -96,6 +99,7 @@ protected:
|
||||
new SkDilateImageFilter(1, 1, checkerboard.get()),
|
||||
new SkErodeImageFilter(1, 1, checkerboard.get()),
|
||||
new SkOffsetImageFilter(SkIntToScalar(32), 0),
|
||||
new SkResizeImageFilter(RESIZE_FACTOR, RESIZE_FACTOR, SkPaint::kNone_FilterLevel),
|
||||
};
|
||||
|
||||
SkVector scales[] = {
|
||||
@ -122,6 +126,9 @@ protected:
|
||||
canvas->scale(scales[j].fX, scales[j].fY);
|
||||
if (5 == i) {
|
||||
canvas->translate(SkIntToScalar(-32), 0);
|
||||
} else if (6 == i) {
|
||||
canvas->scale(SkScalarInvert(RESIZE_FACTOR),
|
||||
SkScalarInvert(RESIZE_FACTOR));
|
||||
}
|
||||
canvas->drawCircle(r.centerX(), r.centerY(),
|
||||
SkScalarDiv(r.width()*2, SkIntToScalar(5)), paint);
|
||||
|
77
gm/imageresizetiled.cpp
Normal file
77
gm/imageresizetiled.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 "SkResizeImageFilter.h"
|
||||
#include "SkRandom.h"
|
||||
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
|
||||
#define RESIZE_FACTOR SkIntToScalar(2)
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
class ImageResizeTiledGM : public GM {
|
||||
public:
|
||||
ImageResizeTiledGM() {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual SkString onShortName() SK_OVERRIDE {
|
||||
return SkString("imageresizetiled");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() SK_OVERRIDE {
|
||||
return make_isize(WIDTH, HEIGHT);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
|
||||
SkPaint paint;
|
||||
SkAutoTUnref<SkImageFilter> imageFilter(
|
||||
new SkResizeImageFilter(RESIZE_FACTOR, RESIZE_FACTOR, SkPaint::kNone_FilterLevel));
|
||||
paint.setImageFilter(imageFilter.get());
|
||||
const SkScalar tile_size = SkIntToScalar(100);
|
||||
SkRect bounds;
|
||||
canvas->getClipBounds(&bounds);
|
||||
for (SkScalar y = 0; y < HEIGHT; y += tile_size) {
|
||||
for (SkScalar x = 0; x < WIDTH; x += tile_size) {
|
||||
canvas->save();
|
||||
canvas->clipRect(SkRect::MakeXYWH(x, y, tile_size, tile_size));
|
||||
canvas->scale(SkScalarInvert(RESIZE_FACTOR),
|
||||
SkScalarInvert(RESIZE_FACTOR));
|
||||
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:
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_GM(return new ImageResizeTiledGM(); )
|
||||
|
||||
}
|
@ -91,6 +91,7 @@
|
||||
'../gm/imageblur.cpp',
|
||||
'../gm/imageblurtiled.cpp',
|
||||
'../gm/imagemagnifier.cpp',
|
||||
'../gm/imageresizetiled.cpp',
|
||||
'../gm/inversepaths.cpp',
|
||||
'../gm/lerpmode.cpp',
|
||||
'../gm/lighting.cpp',
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
SkResizeImageFilter(SkScalar sx, SkScalar sy, SkPaint::FilterLevel filterLevel,
|
||||
SkImageFilter* input = NULL);
|
||||
virtual ~SkResizeImageFilter();
|
||||
virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkResizeImageFilter)
|
||||
|
||||
@ -41,6 +42,8 @@ protected:
|
||||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) const SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&,
|
||||
SkIRect* dst) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkScalar fSx, fSy;
|
||||
|
@ -42,12 +42,12 @@ SkResizeImageFilter::~SkResizeImageFilter() {
|
||||
|
||||
bool SkResizeImageFilter::onFilterImage(Proxy* proxy,
|
||||
const SkBitmap& source,
|
||||
const SkMatrix& matrix,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result,
|
||||
SkIPoint* offset) const {
|
||||
SkBitmap src = source;
|
||||
SkIPoint srcOffset = SkIPoint::Make(0, 0);
|
||||
if (getInput(0) && !getInput(0)->filterImage(proxy, source, matrix, &src, &srcOffset)) {
|
||||
if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctm, &src, &srcOffset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -56,9 +56,13 @@ bool SkResizeImageFilter::onFilterImage(Proxy* proxy,
|
||||
src.getBounds(&srcBounds);
|
||||
srcBounds.offset(srcOffset);
|
||||
SkRect srcRect = SkRect::Make(srcBounds);
|
||||
SkMatrix dstMatrix;
|
||||
dstMatrix.setScale(fSx, fSy);
|
||||
dstMatrix.mapRect(&dstRect, srcRect);
|
||||
SkMatrix matrix;
|
||||
if (!ctm.invert(&matrix)) {
|
||||
return false;
|
||||
}
|
||||
matrix.postScale(fSx, fSy);
|
||||
matrix.postConcat(ctm);
|
||||
matrix.mapRect(&dstRect, srcRect);
|
||||
dstRect.roundOut(&dstBounds);
|
||||
|
||||
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height()));
|
||||
@ -67,12 +71,11 @@ bool SkResizeImageFilter::onFilterImage(Proxy* proxy,
|
||||
}
|
||||
|
||||
SkCanvas canvas(device.get());
|
||||
canvas.translate(-SkIntToScalar(dstBounds.fLeft), -SkIntToScalar(dstBounds.fTop));
|
||||
canvas.scale(fSx, fSy);
|
||||
SkPaint paint;
|
||||
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
paint.setFilterLevel(fFilterLevel);
|
||||
canvas.concat(dstMatrix);
|
||||
canvas.drawBitmap(src, srcRect.left(), srcRect.top(), &paint);
|
||||
|
||||
*result = device.get()->accessBitmap(false);
|
||||
@ -80,3 +83,31 @@ bool SkResizeImageFilter::onFilterImage(Proxy* proxy,
|
||||
offset->fY = dstBounds.fTop;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkResizeImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
|
||||
SkRect bounds = src;
|
||||
if (getInput(0)) {
|
||||
getInput(0)->computeFastBounds(src, &bounds);
|
||||
}
|
||||
dst->setXYWH(bounds.x(), bounds.y(), bounds.width() * fSx, bounds.height() * fSy);
|
||||
}
|
||||
|
||||
bool SkResizeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) const {
|
||||
SkMatrix matrix;
|
||||
if (!ctm.invert(&matrix)) {
|
||||
return false;
|
||||
}
|
||||
matrix.postScale(SkScalarInvert(fSx), SkScalarInvert(fSy));
|
||||
matrix.postConcat(ctm);
|
||||
SkRect floatBounds;
|
||||
matrix.mapRect(&floatBounds, SkRect::Make(src));
|
||||
SkIRect bounds;
|
||||
floatBounds.roundOut(&bounds);
|
||||
if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*dst = bounds;
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user