Apply matrix early in draw bitmap
R=robertphillips@google.com, senorblanco@chromium.org
Author: bsalomon@google.com
Review URL: https://codereview.chromium.org/30593003
git-svn-id: http://skia.googlecode.com/svn/trunk@11930 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 561ac6b..2c38df0 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -31,3 +31,5 @@
# ('Poppler random failures'): ignore any Poppler failures, for now
pdf-poppler
+# Added by bsalomon, test case added in https://codereview.chromium.org/30593003
+imagefiltersgraph
\ No newline at end of file
diff --git a/gm/imagefiltersgraph.cpp b/gm/imagefiltersgraph.cpp
index 363a414..0b88b93 100644
--- a/gm/imagefiltersgraph.cpp
+++ b/gm/imagefiltersgraph.cpp
@@ -7,11 +7,13 @@
#include "gm.h"
+#include "SkArithmeticMode.h"
#include "SkBitmapSource.h"
#include "SkBlurImageFilter.h"
#include "SkColorFilter.h"
#include "SkColorMatrixFilter.h"
#include "SkColorFilterImageFilter.h"
+#include "SkFlattenableBuffers.h"
#include "SkMergeImageFilter.h"
#include "SkMorphologyImageFilter.h"
#include "SkXfermodeImageFilter.h"
@@ -20,6 +22,59 @@
///////////////////////////////////////////////////////////////////////////////
+// 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:
+ SimpleOffsetFilter(SkScalar dx, SkScalar dy, SkImageFilter* input)
+ : SkImageFilter(input), fDX(dx), fDY(dy) {}
+
+ virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
+ SkBitmap* dst, SkIPoint* offset) SK_OVERRIDE {
+ SkBitmap source = src;
+ SkImageFilter* input = getInput(0);
+ SkIPoint srcOffset = SkIPoint::Make(0, 0);
+ if (NULL != input && !input->filterImage(proxy, src, ctm, &source, &srcOffset)) {
+ return false;
+ }
+
+ SkIRect bounds;
+ source.getBounds(&bounds);
+
+ if (!this->applyCropRect(&bounds, ctm)) {
+ 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;
+ }
+
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SimpleOffsetFilter);
+
+protected:
+ explicit SimpleOffsetFilter(SkFlattenableReadBuffer& buffer)
+ : SkImageFilter(buffer) {
+ fDX = buffer.readScalar();
+ fDY = buffer.readScalar();
+ }
+
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
+ this->SkImageFilter::flatten(buffer);
+ buffer.writeScalar(fDX);
+ buffer.writeScalar(fDY);
+ }
+
+private:
+ SkScalar fDX, fDY;
+};
+
class ImageFiltersGraphGM : public skiagm::GM {
public:
ImageFiltersGraphGM() : fInitialized(false) {}
@@ -43,7 +98,7 @@
canvas.drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
}
- virtual SkISize onISize() { return SkISize::Make(200, 100); }
+ virtual SkISize onISize() { return SkISize::Make(500, 150); }
virtual void onDraw(SkCanvas* canvas) {
if (!fInitialized) {
@@ -81,6 +136,22 @@
paint.setImageFilter(blendColor);
canvas->drawBitmap(fBitmap, 100, 0, &paint);
}
+ {
+ SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
+ 0, SK_Scalar1, 0, 0, 0,
+ 0, 0, SK_Scalar1, 0, 0,
+ 0, 0, 0, SkFloatToScalar(0.5f), 0 };
+ SkColorMatrixFilter matrixCF(matrix);
+ SkAutoTUnref<SkImageFilter> matrixFilter(SkColorFilterImageFilter::Create(&matrixCF));
+ SimpleOffsetFilter offsetFilter(SkIntToScalar(10), SkIntToScalar(10), matrixFilter);
+
+ SkAutoTUnref<SkXfermode> arith(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0));
+ SkXfermodeImageFilter arithFilter(arith, matrixFilter, &offsetFilter);
+
+ SkPaint paint;
+ paint.setImageFilter(&arithFilter);
+ canvas->drawSprite(fBitmap, 200, 0, &paint);
+ }
}
private:
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 5d669e4..debfd37 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -191,13 +191,11 @@
const SkRect* srcRectPtr) const;
void internalDrawBitmap(const SkBitmap&,
const SkRect&,
- const SkMatrix&,
const GrTextureParams& params,
const SkPaint& paint,
SkCanvas::DrawBitmapRectFlags flags);
void drawTiledBitmap(const SkBitmap& bitmap,
const SkRect& srcRect,
- const SkMatrix& m,
const GrTextureParams& params,
const SkPaint& paint,
SkCanvas::DrawBitmapRectFlags flags);
diff --git a/src/core/SkImageFilterUtils.cpp b/src/core/SkImageFilterUtils.cpp
index a4ce51e..8385fb4 100644
--- a/src/core/SkImageFilterUtils.cpp
+++ b/src/core/SkImageFilterUtils.cpp
@@ -23,6 +23,11 @@
bool SkImageFilterUtils::GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy,
const SkBitmap& src, const SkMatrix& ctm,
SkBitmap* result, SkIPoint* offset) {
+ // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
+ // matrix with no clip and that the matrix, clip, and render target set before this function was
+ // called are restored before we return to the caller.
+ GrContext* context = src.getTexture()->getContext();
+ GrContext::AutoWideOpenIdentityDraw awoid(context, NULL);
if (!filter) {
*result = src;
return true;
@@ -31,9 +36,7 @@
} else {
if (filter->filterImage(proxy, src, ctm, result, offset)) {
if (!result->getTexture()) {
- GrContext* context = ((GrTexture *) src.getTexture())->getContext();
- GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context,
- *result, NULL);
+ GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL);
result->setPixelRef(new SkGrPixelRef(resultTex))->unref();
GrUnlockAndUnrefCachedBitmapTexture(resultTex);
}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 47ddd52..6617989 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1164,6 +1164,8 @@
return;
}
+ fContext->concatMatrix(m);
+
GrTextureParams params;
SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
GrTextureParams::FilterMode textureFilterMode;
@@ -1195,9 +1197,9 @@
if (!this->shouldTileBitmap(bitmap, params, srcRectPtr)) {
// take the simple case
- this->internalDrawBitmap(bitmap, srcRect, m, params, paint, flags);
+ this->internalDrawBitmap(bitmap, srcRect, params, paint, flags);
} else {
- this->drawTiledBitmap(bitmap, srcRect, m, params, paint, flags);
+ this->drawTiledBitmap(bitmap, srcRect, params, paint, flags);
}
}
@@ -1205,7 +1207,6 @@
// been determined to be too large to fit in VRAM
void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
const SkRect& srcRect,
- const SkMatrix& m,
const GrTextureParams& params,
const SkPaint& paint,
SkCanvas::DrawBitmapRectFlags flags) {
@@ -1226,9 +1227,8 @@
if (!fContext->getClip()->fClipStack->intersectRectWithClip(&clipRect)) {
return;
}
- SkMatrix matrix, inverse;
- matrix.setConcat(fContext->getMatrix(), m);
- if (!matrix.invert(&inverse)) {
+ SkMatrix inverse;
+ if (!fContext->getMatrix().invert(&inverse)) {
return;
}
inverse.mapRect(&clipRect);
@@ -1278,10 +1278,11 @@
if (bitmap.extractSubset(&tmpB, iTileR)) {
// now offset it to make it "local" to our tmp bitmap
tileR.offset(-offset.fX, -offset.fY);
- SkMatrix tmpM(m);
- tmpM.preTranslate(offset.fX, offset.fY);
-
- this->internalDrawBitmap(tmpB, tileR, tmpM, params, paint, flags);
+ SkMatrix tmpM;
+ tmpM.setTranslate(offset.fX, offset.fY);
+ GrContext::AutoMatrix am;
+ am.setPreConcat(fContext, tmpM);
+ this->internalDrawBitmap(tmpB, tileR, params, paint, flags);
}
}
}
@@ -1338,7 +1339,6 @@
*/
void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
const SkRect& srcRect,
- const SkMatrix& m,
const GrTextureParams& params,
const SkPaint& paint,
SkCanvas::DrawBitmapRectFlags flags) {
@@ -1366,19 +1366,18 @@
// Need texture domain if drawing a sub rect.
needsTextureDomain = srcRect.width() < bitmap.width() ||
srcRect.height() < bitmap.height();
- if (needsTextureDomain && m.rectStaysRect() && fContext->getMatrix().rectStaysRect()) {
+ if (needsTextureDomain && fContext->getMatrix().rectStaysRect()) {
+ const SkMatrix& matrix = fContext->getMatrix();
// sampling is axis-aligned
SkRect transformedRect;
- SkMatrix srcToDeviceMatrix(m);
- srcToDeviceMatrix.postConcat(fContext->getMatrix());
- srcToDeviceMatrix.mapRect(&transformedRect, srcRect);
-
+ matrix.mapRect(&transformedRect, srcRect);
+
if (has_aligned_samples(srcRect, transformedRect)) {
// We could also turn off filtering here (but we already did a cache lookup with
// params).
needsTextureDomain = false;
} else {
- needsTextureDomain = may_color_bleed(srcRect, transformedRect, m);
+ needsTextureDomain = may_color_bleed(srcRect, transformedRect, matrix);
}
}
}
@@ -1421,7 +1420,7 @@
return;
}
- fContext->drawRectToRect(grPaint, dstRect, paintRect, &m);
+ fContext->drawRectToRect(grPaint, dstRect, paintRect, NULL);
}
static bool filter_texture(SkBaseDevice* device, GrContext* context,