Implement srcRect and dstRect functionality in SkBitmapSource. This is required for the "preserveAspectRatio" options of SVG's feImage. Covered by new GM "bitmapsource".
This also includes some changes to the xfermodeimagefilter and tileimagefilter GMs to properly handle the CTM. This worked before only because SkBitmapSource was ignoring the CTM. Now that it respects it, we need to give the correct transform. This also means the GMs now work while zoomed. R=reed@google.com Author: senorblanco@chromium.org Review URL: https://codereview.chromium.org/106933002 git-svn-id: http://skia.googlecode.com/svn/trunk@12528 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
80bd0c995d
commit
094147d522
95
gm/bitmapsource.cpp
Normal file
95
gm/bitmapsource.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2013 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 "SkBitmapSource.h"
|
||||
|
||||
class BitmapSourceGM : public skiagm::GM {
|
||||
public:
|
||||
BitmapSourceGM() : fInitialized(false) {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual SkString onShortName() {
|
||||
return SkString("bitmapsource");
|
||||
}
|
||||
|
||||
void make_bitmap() {
|
||||
fBitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
|
||||
fBitmap.allocPixels();
|
||||
SkBitmapDevice device(fBitmap);
|
||||
SkCanvas canvas(&device);
|
||||
canvas.clear(0x00000000);
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(0xFFFFFFFF);
|
||||
paint.setTextSize(SkIntToScalar(96));
|
||||
const char* str = "e";
|
||||
canvas.drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
|
||||
}
|
||||
|
||||
virtual SkISize onISize() { return SkISize::Make(500, 150); }
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
if (!fInitialized) {
|
||||
this->make_bitmap();
|
||||
fInitialized = true;
|
||||
}
|
||||
canvas->clear(0x00000000);
|
||||
{
|
||||
SkRect srcRect = SkRect::MakeXYWH(20, 20, 30, 30);
|
||||
SkRect dstRect = SkRect::MakeXYWH(0, 10, 60, 60);
|
||||
SkRect clipRect = SkRect::MakeXYWH(0, 0, 100, 100);
|
||||
SkRect bounds;
|
||||
fBitmap.getBounds(&bounds);
|
||||
SkAutoTUnref<SkImageFilter> bitmapSource(new SkBitmapSource(fBitmap));
|
||||
SkAutoTUnref<SkImageFilter> bitmapSourceSrcRect(new SkBitmapSource(fBitmap, srcRect, srcRect));
|
||||
SkAutoTUnref<SkImageFilter> bitmapSourceSrcRectDstRect(new SkBitmapSource(fBitmap, srcRect, dstRect));
|
||||
SkAutoTUnref<SkImageFilter> bitmapSourceDstRectOnly(new SkBitmapSource(fBitmap, bounds, dstRect));
|
||||
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(bitmapSource);
|
||||
canvas->save();
|
||||
canvas->clipRect(clipRect);
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
canvas->translate(SkIntToScalar(100), 0);
|
||||
|
||||
paint.setImageFilter(bitmapSourceSrcRect);
|
||||
canvas->save();
|
||||
canvas->clipRect(clipRect);
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
canvas->translate(SkIntToScalar(100), 0);
|
||||
|
||||
paint.setImageFilter(bitmapSourceSrcRectDstRect);
|
||||
canvas->save();
|
||||
canvas->clipRect(clipRect);
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
canvas->translate(SkIntToScalar(100), 0);
|
||||
|
||||
paint.setImageFilter(bitmapSourceDstRectOnly);
|
||||
canvas->save();
|
||||
canvas->clipRect(clipRect);
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
canvas->translate(SkIntToScalar(100), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GM INHERITED;
|
||||
SkBitmap fBitmap;
|
||||
bool fInitialized;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static skiagm::GM* MyFactory(void*) { return new BitmapSourceGM; }
|
||||
static skiagm::GMRegistry reg(MyFactory);
|
@ -70,9 +70,10 @@ protected:
|
||||
void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
|
||||
SkScalar x, SkScalar y) {
|
||||
canvas->save();
|
||||
canvas->clipRect(SkRect::MakeXYWH(x, y,
|
||||
canvas->translate(x, y);
|
||||
canvas->clipRect(SkRect::MakeXYWH(0, 0,
|
||||
SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
|
||||
canvas->drawBitmap(bitmap, x, y, &paint);
|
||||
canvas->drawBitmap(bitmap, 0, 0, &paint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
|
@ -72,9 +72,19 @@ protected:
|
||||
void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
|
||||
SkScalar x, SkScalar y) {
|
||||
canvas->save();
|
||||
canvas->clipRect(SkRect::MakeXYWH(x, y,
|
||||
canvas->translate(x, y);
|
||||
canvas->clipRect(SkRect::MakeXYWH(0, 0,
|
||||
SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
|
||||
canvas->drawBitmap(bitmap, x, y, &paint);
|
||||
canvas->drawBitmap(bitmap, 0, 0, &paint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
void drawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint,
|
||||
SkScalar x, SkScalar y) {
|
||||
canvas->save();
|
||||
canvas->translate(x, y);
|
||||
canvas->clipRect(rect);
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
@ -156,6 +166,8 @@ protected:
|
||||
x = 0;
|
||||
y += fBitmap.height() + MARGIN;
|
||||
}
|
||||
SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4),
|
||||
SkIntToScalar(fBitmap.height() + 4));
|
||||
// Test offsets on SrcMode (uses fixed-function blend)
|
||||
SkAutoTUnref<SkImageFilter> foreground(SkNEW_ARGS(SkBitmapSource, (fBitmap)));
|
||||
SkAutoTUnref<SkImageFilter> offsetForeground(SkNEW_ARGS(SkOffsetImageFilter,
|
||||
@ -166,13 +178,7 @@ protected:
|
||||
filter.reset(SkNEW_ARGS(SkXfermodeImageFilter,
|
||||
(mode, offsetBackground, offsetForeground)));
|
||||
paint.setImageFilter(filter);
|
||||
canvas->save();
|
||||
canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x),
|
||||
SkIntToScalar(y),
|
||||
SkIntToScalar(fBitmap.width() + 4),
|
||||
SkIntToScalar(fBitmap.height() + 4)));
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
drawClippedPaint(canvas, clipRect, paint, x, y);
|
||||
x += fBitmap.width() + MARGIN;
|
||||
if (x + fBitmap.width() > WIDTH) {
|
||||
x = 0;
|
||||
@ -182,13 +188,7 @@ protected:
|
||||
mode.reset(SkXfermode::Create(SkXfermode::kDarken_Mode));
|
||||
filter.reset(SkNEW_ARGS(SkXfermodeImageFilter, (mode, offsetBackground, offsetForeground)));
|
||||
paint.setImageFilter(filter);
|
||||
canvas->save();
|
||||
canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x),
|
||||
SkIntToScalar(y),
|
||||
SkIntToScalar(fBitmap.width() + 4),
|
||||
SkIntToScalar(fBitmap.height() + 4)));
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
drawClippedPaint(canvas, clipRect, paint, x, y);
|
||||
x += fBitmap.width() + MARGIN;
|
||||
if (x + fBitmap.width() > WIDTH) {
|
||||
x = 0;
|
||||
@ -203,8 +203,8 @@ protected:
|
||||
{ 10, 10, 10, 10},
|
||||
{-10, -10, -6, -6}};
|
||||
for (size_t i = 0; i < nbSamples; ++i) {
|
||||
SkIRect cropRect = SkIRect::MakeXYWH(x + offsets[i][0],
|
||||
y + offsets[i][1],
|
||||
SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
|
||||
offsets[i][1],
|
||||
fBitmap.width() + offsets[i][2],
|
||||
fBitmap.height() + offsets[i][3]);
|
||||
SkImageFilter::CropRect rect(SkRect::Make(cropRect));
|
||||
@ -212,13 +212,7 @@ protected:
|
||||
filter.reset(SkNEW_ARGS(SkXfermodeImageFilter,
|
||||
(mode, offsetBackground, offsetForeground, &rect)));
|
||||
paint.setImageFilter(filter);
|
||||
canvas->save();
|
||||
canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x),
|
||||
SkIntToScalar(y),
|
||||
SkIntToScalar(fBitmap.width() + 4),
|
||||
SkIntToScalar(fBitmap.height() + 4)));
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
drawClippedPaint(canvas, clipRect, paint, x, y);
|
||||
x += fBitmap.width() + MARGIN;
|
||||
if (x + fBitmap.width() > WIDTH) {
|
||||
x = 0;
|
||||
|
@ -20,6 +20,7 @@
|
||||
'../gm/bitmaprect.cpp',
|
||||
'../gm/bitmaprecttest.cpp',
|
||||
'../gm/bitmapscroll.cpp',
|
||||
'../gm/bitmapsource.cpp',
|
||||
'../gm/bleed.cpp',
|
||||
'../gm/blurs.cpp',
|
||||
'../gm/blurquickreject.cpp',
|
||||
|
@ -14,6 +14,7 @@
|
||||
class SK_API SkBitmapSource : public SkImageFilter {
|
||||
public:
|
||||
explicit SkBitmapSource(const SkBitmap& bitmap);
|
||||
SkBitmapSource(const SkBitmap& bitmap, const SkRect& srcRect, const SkRect& dstRect);
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBitmapSource)
|
||||
|
||||
@ -25,6 +26,7 @@ protected:
|
||||
|
||||
private:
|
||||
SkBitmap fBitmap;
|
||||
SkRect fSrcRect, fDstRect;
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
|
@ -6,24 +6,71 @@
|
||||
*/
|
||||
|
||||
#include "SkBitmapSource.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkValidationUtils.h"
|
||||
|
||||
SkBitmapSource::SkBitmapSource(const SkBitmap& bitmap)
|
||||
: INHERITED(0, 0),
|
||||
fBitmap(bitmap) {
|
||||
fBitmap(bitmap),
|
||||
fSrcRect(SkRect::MakeWH(SkIntToScalar(bitmap.width()),
|
||||
SkIntToScalar(bitmap.height()))),
|
||||
fDstRect(fSrcRect) {
|
||||
}
|
||||
|
||||
SkBitmapSource::SkBitmapSource(const SkBitmap& bitmap, const SkRect& srcRect, const SkRect& dstRect)
|
||||
: INHERITED(0, 0),
|
||||
fBitmap(bitmap),
|
||||
fSrcRect(srcRect),
|
||||
fDstRect(dstRect) {
|
||||
}
|
||||
|
||||
SkBitmapSource::SkBitmapSource(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(0, buffer) {
|
||||
fBitmap.unflatten(buffer);
|
||||
buffer.readRect(&fSrcRect);
|
||||
buffer.readRect(&fDstRect);
|
||||
buffer.validate(SkIsValidRect(fSrcRect) && SkIsValidRect(fDstRect));
|
||||
}
|
||||
|
||||
void SkBitmapSource::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
fBitmap.flatten(buffer);
|
||||
buffer.writeRect(fSrcRect);
|
||||
buffer.writeRect(fDstRect);
|
||||
}
|
||||
|
||||
bool SkBitmapSource::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
|
||||
bool SkBitmapSource::onFilterImage(Proxy* proxy, const SkBitmap&, const SkMatrix& matrix,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
*result = fBitmap;
|
||||
SkRect bounds, dstRect;
|
||||
fBitmap.getBounds(&bounds);
|
||||
matrix.mapRect(&dstRect, fDstRect);
|
||||
if (fSrcRect == bounds && dstRect == bounds) {
|
||||
*result = fBitmap;
|
||||
return true;
|
||||
}
|
||||
SkIRect dstIRect;
|
||||
dstRect.roundOut(&dstIRect);
|
||||
|
||||
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstIRect.width(), dstIRect.height()));
|
||||
if (NULL == device.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkCanvas canvas(device.get());
|
||||
SkPaint paint;
|
||||
|
||||
// Subtract off the integer component of the translation (will be applied in loc, below).
|
||||
dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
// FIXME: this probably shouldn't be necessary, but drawBitmapRectToRect asserts
|
||||
// None filtering when it's translate-only
|
||||
paint.setFilterLevel(fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ? SkPaint::kNone_FilterLevel : SkPaint::kMedium_FilterLevel);
|
||||
canvas.drawBitmapRectToRect(fBitmap, &fSrcRect, dstRect, &paint);
|
||||
|
||||
*result = device.get()->accessBitmap(false);
|
||||
offset->fX += dstIRect.fLeft;
|
||||
offset->fY += dstIRect.fTop;
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user