зеркало из https://github.com/mozilla/moz-skia.git
apply imagefilter to all draw calls
Review URL: https://codereview.appspot.com/5856048 git-svn-id: http://skia.googlecode.com/svn/trunk@3476 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
c3a0d2e4c5
Коммит
8926b169f6
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright 2011 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 "SkBlurImageFilter.h"
|
||||
#include "SkTestImageFilters.h"
|
||||
|
||||
class FailImageFilter : public SkImageFilter {
|
||||
public:
|
||||
FailImageFilter() {}
|
||||
virtual Factory getFactory() SK_OVERRIDE { return CreateProc; };
|
||||
|
||||
protected:
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FailImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
return new FailImageFilter(buffer);
|
||||
}
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
class IdentityImageFilter : public SkImageFilter {
|
||||
public:
|
||||
IdentityImageFilter() {}
|
||||
virtual Factory getFactory() SK_OVERRIDE { return CreateProc; };
|
||||
|
||||
protected:
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
*result = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
IdentityImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
return new IdentityImageFilter(buffer);
|
||||
}
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void draw_paint(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(imf);
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
canvas->save();
|
||||
canvas->clipRect(r);
|
||||
canvas->drawPaint(paint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
static void draw_line(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorBLUE);
|
||||
paint.setImageFilter(imf);
|
||||
paint.setStrokeWidth(r.width()/10);
|
||||
canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
|
||||
}
|
||||
|
||||
static void draw_rect(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorYELLOW);
|
||||
paint.setImageFilter(imf);
|
||||
SkRect rr(r);
|
||||
rr.inset(r.width()/10, r.height()/10);
|
||||
canvas->drawRect(rr, paint);
|
||||
}
|
||||
|
||||
static void draw_path(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorMAGENTA);
|
||||
paint.setImageFilter(imf);
|
||||
paint.setAntiAlias(true);
|
||||
canvas->drawCircle(r.centerX(), r.centerY(), r.width()*2/5, paint);
|
||||
}
|
||||
|
||||
static void draw_text(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(imf);
|
||||
paint.setColor(SK_ColorCYAN);
|
||||
paint.setAntiAlias(true);
|
||||
paint.setTextSize(r.height()/2);
|
||||
paint.setTextAlign(SkPaint::kCenter_Align);
|
||||
canvas->drawText("Text", 4, r.centerX(), r.centerY(), paint);
|
||||
}
|
||||
|
||||
static void draw_bitmap(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(imf);
|
||||
|
||||
SkIRect bounds;
|
||||
r.roundOut(&bounds);
|
||||
|
||||
SkBitmap bm;
|
||||
bm.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), bounds.height());
|
||||
bm.allocPixels();
|
||||
bm.eraseColor(0);
|
||||
SkCanvas c(bm);
|
||||
draw_path(&c, r, NULL);
|
||||
|
||||
canvas->drawBitmap(bm, 0, 0, &paint);
|
||||
}
|
||||
|
||||
static void draw_sprite(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) {
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(imf);
|
||||
|
||||
SkIRect bounds;
|
||||
r.roundOut(&bounds);
|
||||
|
||||
SkBitmap bm;
|
||||
bm.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), bounds.height());
|
||||
bm.allocPixels();
|
||||
bm.eraseColor(0);
|
||||
SkCanvas c(bm);
|
||||
draw_path(&c, r, NULL);
|
||||
|
||||
SkPoint loc = { r.fLeft, r.fTop };
|
||||
canvas->getTotalMatrix().mapPoints(&loc, 1);
|
||||
canvas->drawSprite(bm,
|
||||
SkScalarRoundToInt(loc.fX), SkScalarRoundToInt(loc.fY),
|
||||
&paint);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ImageFiltersBaseGM : public skiagm::GM {
|
||||
public:
|
||||
ImageFiltersBaseGM () {}
|
||||
|
||||
protected:
|
||||
|
||||
virtual SkString onShortName() {
|
||||
return SkString("imagefiltersbase");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() { return SkISize::Make(700, 460); }
|
||||
|
||||
void draw_frame(SkCanvas* canvas, const SkRect& r) {
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setColor(SK_ColorRED);
|
||||
canvas->drawRect(r, paint);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
void (*drawProc[])(SkCanvas*, const SkRect&, SkImageFilter*) = {
|
||||
draw_paint,
|
||||
draw_line, draw_rect, draw_path, draw_text,
|
||||
draw_bitmap,
|
||||
draw_sprite
|
||||
};
|
||||
|
||||
SkColorFilter* cf = SkColorFilter::CreateModeFilter(SK_ColorRED,
|
||||
SkXfermode::kSrcIn_Mode);
|
||||
SkImageFilter* filters[] = {
|
||||
#if 1
|
||||
NULL,
|
||||
new IdentityImageFilter,
|
||||
new FailImageFilter,
|
||||
new SkColorFilterImageFilter(cf),
|
||||
#endif
|
||||
new SkBlurImageFilter(12.0f, 0.0f),
|
||||
};
|
||||
cf->unref();
|
||||
|
||||
SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
|
||||
SkScalar MARGIN = SkIntToScalar(16);
|
||||
SkScalar DX = r.width() + MARGIN;
|
||||
SkScalar DY = r.height() + MARGIN;
|
||||
|
||||
canvas->translate(MARGIN, MARGIN);
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(drawProc); ++i) {
|
||||
canvas->save();
|
||||
for (size_t j = 0; j < SK_ARRAY_COUNT(filters); ++j) {
|
||||
drawProc[i](canvas, r, filters[j]);
|
||||
|
||||
draw_frame(canvas, r);
|
||||
canvas->translate(0, DY);
|
||||
}
|
||||
canvas->restore();
|
||||
canvas->translate(DX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static skiagm::GM* MyFactory(void*) { return new ImageFiltersBaseGM; }
|
||||
static skiagm::GMRegistry reg(MyFactory);
|
||||
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
'../gm/gradtext.cpp',
|
||||
'../gm/hairmodes.cpp',
|
||||
'../gm/imageblur.cpp',
|
||||
'../gm/imagefiltersbase.cpp',
|
||||
'../gm/lcdtext.cpp',
|
||||
'../gm/linepaths.cpp',
|
||||
'../gm/morphology.cpp',
|
||||
|
|
|
@ -977,6 +977,7 @@ private:
|
|||
void updateDeviceCMCache();
|
||||
|
||||
friend class SkDrawIter; // needs setupDrawForLayerDevice()
|
||||
friend class AutoDrawLooper;
|
||||
|
||||
SkDevice* createLayerDevice(SkBitmap::Config, int width, int height,
|
||||
bool isOpaque);
|
||||
|
@ -992,9 +993,10 @@ private:
|
|||
void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
|
||||
const SkRect& dst, const SkPaint* paint);
|
||||
void internalDrawPaint(const SkPaint& paint);
|
||||
int internalSaveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
SaveFlags, bool justForImageFilter);
|
||||
void internalDrawDevice(SkDevice*, int x, int y, const SkPaint*);
|
||||
|
||||
|
||||
void drawDevice(SkDevice*, int x, int y, const SkPaint*);
|
||||
// shared by save() and saveLayer()
|
||||
int internalSave(SaveFlags flags);
|
||||
void internalRestore();
|
||||
|
|
|
@ -321,13 +321,22 @@ protected:
|
|||
virtual bool allowImageFilter(SkImageFilter*);
|
||||
|
||||
/**
|
||||
* Override and return true for filters that the device handles
|
||||
* intrinsically. Returning false means call the filter.
|
||||
* Default impl returns false. This will only be called if allowImageFilter()
|
||||
* returned true.
|
||||
* Override and return true for filters that the device can handle
|
||||
* intrinsically. Doing so means that SkCanvas will pass-through this
|
||||
* filter to drawSprite and drawDevice (and potentially filterImage).
|
||||
* Returning false means the SkCanvas will have apply the filter itself,
|
||||
* and just pass the resulting image to the device.
|
||||
*/
|
||||
virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
virtual bool canHandleImageFilter(SkImageFilter*);
|
||||
|
||||
/**
|
||||
* Related (but not required) to canHandleImageFilter, this method returns
|
||||
* true if the device could apply the filter to the src bitmap and return
|
||||
* the result (and updates offset as needed).
|
||||
* If the device does not recognize or support this filter,
|
||||
* it just returns false and leaves result and offset unchanged.
|
||||
*/
|
||||
virtual bool filterImage(SkImageFilter*, const SkBitmap&, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset);
|
||||
|
||||
// This is equal kBGRA_Premul_Config8888 or kRGBA_Premul_Config8888 if
|
||||
|
|
|
@ -40,14 +40,16 @@ class SK_API SkImageFilter : public SkFlattenable {
|
|||
public:
|
||||
class Proxy {
|
||||
public:
|
||||
virtual ~Proxy() {};
|
||||
|
||||
virtual SkDevice* createDevice(int width, int height) = 0;
|
||||
|
||||
// returns true if the proxy can handle this filter natively
|
||||
virtual bool canHandleImageFilter(SkImageFilter*) = 0;
|
||||
// returns true if the proxy handled the filter itself. if this returns
|
||||
// false then the filter's code will be called.
|
||||
virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) = 0;
|
||||
virtual ~Proxy() {};
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -110,9 +110,9 @@ public:
|
|||
*/
|
||||
virtual void makeRenderTargetCurrent();
|
||||
|
||||
virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
virtual bool canHandleImageFilter(SkImageFilter*) SK_OVERRIDE;
|
||||
virtual bool filterImage(SkImageFilter*, const SkBitmap&, const SkMatrix&,
|
||||
SkBitmap*, SkIPoint*) SK_OVERRIDE;
|
||||
|
||||
class SkAutoCachedTexture; // used internally
|
||||
|
||||
|
|
|
@ -277,20 +277,36 @@ private:
|
|||
|
||||
class AutoDrawLooper {
|
||||
public:
|
||||
AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint) : fOrigPaint(paint) {
|
||||
AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
|
||||
bool skipLayerForImageFilter = false) : fOrigPaint(paint) {
|
||||
fCanvas = canvas;
|
||||
fLooper = paint.getLooper();
|
||||
fFilter = canvas->getDrawFilter();
|
||||
fPaint = NULL;
|
||||
fSaveCount = canvas->getSaveCount();
|
||||
fDoClearImageFilter = false;
|
||||
fDone = false;
|
||||
|
||||
if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
|
||||
SkPaint tmp;
|
||||
tmp.setImageFilter(fOrigPaint.getImageFilter());
|
||||
// it would be nice if we had a guess at the bounds, instead of null
|
||||
(void)canvas->internalSaveLayer(NULL, &tmp,
|
||||
SkCanvas::kARGB_ClipLayer_SaveFlag, true);
|
||||
// we'll clear the imageFilter for the actual draws in next(), so
|
||||
// it will only be applied during the restore().
|
||||
fDoClearImageFilter = true;
|
||||
}
|
||||
|
||||
if (fLooper) {
|
||||
fLooper->init(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
~AutoDrawLooper() {
|
||||
if (fDoClearImageFilter) {
|
||||
fCanvas->internalRestore();
|
||||
}
|
||||
SkASSERT(fCanvas->getSaveCount() == fSaveCount);
|
||||
}
|
||||
|
||||
|
@ -309,6 +325,7 @@ private:
|
|||
SkDrawFilter* fFilter;
|
||||
const SkPaint* fPaint;
|
||||
int fSaveCount;
|
||||
bool fDoClearImageFilter;
|
||||
bool fDone;
|
||||
};
|
||||
|
||||
|
@ -318,8 +335,13 @@ bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (fLooper || fFilter) {
|
||||
if (fLooper || fFilter || fDoClearImageFilter) {
|
||||
SkPaint* paint = fLazyPaint.set(fOrigPaint);
|
||||
|
||||
if (fDoClearImageFilter) {
|
||||
paint->setImageFilter(NULL);
|
||||
}
|
||||
|
||||
if (fLooper && !fLooper->next(fCanvas, paint)) {
|
||||
fDone = true;
|
||||
return false;
|
||||
|
@ -332,6 +354,11 @@ bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
|
|||
}
|
||||
}
|
||||
fPaint = paint;
|
||||
|
||||
// if we only came in here for the imagefilter, mark us as done
|
||||
if (!fLooper && !fFilter) {
|
||||
fDone = true;
|
||||
}
|
||||
} else {
|
||||
fDone = true;
|
||||
fPaint = &fOrigPaint;
|
||||
|
@ -386,6 +413,13 @@ private:
|
|||
|
||||
////////// macros to place around the internal draw calls //////////////////
|
||||
|
||||
#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
|
||||
/* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \
|
||||
AutoDrawLooper looper(this, paint, true); \
|
||||
while (looper.next(type)) { \
|
||||
SkAutoBounderCommit ac(fBounder); \
|
||||
SkDrawIter iter(this);
|
||||
|
||||
#define LOOPER_BEGIN(paint, type) \
|
||||
/* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \
|
||||
AutoDrawLooper looper(this, paint); \
|
||||
|
@ -749,6 +783,11 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
|
|||
|
||||
int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
SaveFlags flags) {
|
||||
return this->internalSaveLayer(bounds, paint, flags, false);
|
||||
}
|
||||
|
||||
int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
SaveFlags flags, bool justForImageFilter) {
|
||||
// do this before we create the layer. We don't call the public save() since
|
||||
// that would invoke a possibly overridden virtual
|
||||
int count = this->internalSave(flags);
|
||||
|
@ -764,6 +803,10 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
|||
SkLazyPaint lazyP;
|
||||
if (paint && paint->getImageFilter()) {
|
||||
if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
|
||||
if (justForImageFilter) {
|
||||
// early exit if the layer was just for the imageFilter
|
||||
return count;
|
||||
}
|
||||
SkPaint* p = lazyP.set(*paint);
|
||||
p->setImageFilter(NULL);
|
||||
paint = p;
|
||||
|
@ -841,9 +884,9 @@ void SkCanvas::internalRestore() {
|
|||
if (NULL != layer) {
|
||||
if (layer->fNext) {
|
||||
const SkIPoint& origin = layer->fDevice->getOrigin();
|
||||
this->drawDevice(layer->fDevice, origin.x(), origin.y(),
|
||||
layer->fPaint);
|
||||
// reset this, since drawDevice will have set it to true
|
||||
this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
|
||||
layer->fPaint);
|
||||
// reset this, since internalDrawDevice will have set it to true
|
||||
fDeviceCMDirty = true;
|
||||
|
||||
SkASSERT(fLayerCount > 0);
|
||||
|
@ -905,43 +948,38 @@ class DeviceImageFilterProxy : public SkImageFilter::Proxy {
|
|||
public:
|
||||
DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
|
||||
|
||||
virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE;
|
||||
virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
|
||||
virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE {
|
||||
return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
|
||||
w, h, false);
|
||||
}
|
||||
virtual bool canHandleImageFilter(SkImageFilter* filter) SK_OVERRIDE {
|
||||
return fDevice->canHandleImageFilter(filter);
|
||||
}
|
||||
virtual bool filterImage(SkImageFilter* filter, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
|
||||
return fDevice->filterImage(filter, src, ctm, result, offset);
|
||||
}
|
||||
|
||||
private:
|
||||
SkDevice* fDevice;
|
||||
};
|
||||
|
||||
SkDevice* DeviceImageFilterProxy::createDevice(int w, int h) {
|
||||
return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
|
||||
w, h, false);
|
||||
}
|
||||
|
||||
bool DeviceImageFilterProxy::filterImage(SkImageFilter* filter,
|
||||
const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result,
|
||||
SkIPoint* offset) {
|
||||
return fDevice->filterImage(filter, src, ctm, result, offset);
|
||||
}
|
||||
|
||||
void SkCanvas::drawDevice(SkDevice* srcDev, int x, int y,
|
||||
const SkPaint* paint) {
|
||||
void SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y,
|
||||
const SkPaint* paint) {
|
||||
SkPaint tmp;
|
||||
if (NULL == paint) {
|
||||
tmp.setDither(true);
|
||||
paint = &tmp;
|
||||
}
|
||||
|
||||
LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
|
||||
LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
|
||||
while (iter.next()) {
|
||||
SkDevice* dstDev = iter.fDevice;
|
||||
paint = &looper.paint();
|
||||
SkImageFilter* filter = paint->getImageFilter();
|
||||
SkIPoint pos = { x - iter.getX(), y - iter.getY() };
|
||||
if (filter) {
|
||||
if (filter && !dstDev->canHandleImageFilter(filter)) {
|
||||
DeviceImageFilterProxy proxy(dstDev);
|
||||
SkBitmap dst;
|
||||
const SkBitmap& src = srcDev->accessBitmap(false);
|
||||
|
@ -957,6 +995,40 @@ void SkCanvas::drawDevice(SkDevice* srcDev, int x, int y,
|
|||
LOOPER_END
|
||||
}
|
||||
|
||||
void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
|
||||
const SkPaint* paint) {
|
||||
SkDEBUGCODE(bitmap.validate();)
|
||||
|
||||
if (reject_bitmap(bitmap)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkPaint tmp;
|
||||
if (NULL == paint) {
|
||||
paint = &tmp;
|
||||
}
|
||||
|
||||
LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
|
||||
|
||||
while (iter.next()) {
|
||||
paint = &looper.paint();
|
||||
SkImageFilter* filter = paint->getImageFilter();
|
||||
SkIPoint pos = { x - iter.getX(), y - iter.getY() };
|
||||
if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
|
||||
DeviceImageFilterProxy proxy(iter.fDevice);
|
||||
SkBitmap dst;
|
||||
if (filter->filterImage(&proxy, bitmap, *iter.fMatrix, &dst, &pos)) {
|
||||
SkPaint tmp(*paint);
|
||||
tmp.setImageFilter(NULL);
|
||||
iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(), tmp);
|
||||
}
|
||||
} else {
|
||||
iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
|
||||
}
|
||||
}
|
||||
LOOPER_END
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
|
||||
|
@ -1575,28 +1647,6 @@ void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
|
|||
this->internalDrawBitmapNine(bitmap, center, dst, paint);
|
||||
}
|
||||
|
||||
void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
|
||||
const SkPaint* paint) {
|
||||
SkDEBUGCODE(bitmap.validate();)
|
||||
|
||||
if (reject_bitmap(bitmap)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkPaint tmp;
|
||||
if (NULL == paint) {
|
||||
paint = &tmp;
|
||||
}
|
||||
|
||||
LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
|
||||
|
||||
while (iter.next()) {
|
||||
iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
|
||||
looper.paint());
|
||||
}
|
||||
LOOPER_END
|
||||
}
|
||||
|
||||
class SkDeviceFilteredPaint {
|
||||
public:
|
||||
SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
|
||||
|
|
|
@ -101,9 +101,13 @@ void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
|
|||
const SkClipStack& clipStack) {
|
||||
}
|
||||
|
||||
bool SkDevice::filterImage(SkImageFilter*, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
bool SkDevice::canHandleImageFilter(SkImageFilter*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
|
||||
const SkMatrix& ctm, SkBitmap* result,
|
||||
SkIPoint* offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1398,11 +1398,50 @@ void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
|
|||
fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
|
||||
}
|
||||
|
||||
static GrTexture* filter_texture(GrContext* context, GrTexture* texture,
|
||||
SkImageFilter* filter, const GrRect& rect) {
|
||||
GrAssert(filter);
|
||||
|
||||
SkSize blurSize;
|
||||
SkISize radius;
|
||||
|
||||
const GrTextureDesc desc = {
|
||||
kRenderTarget_GrTextureFlagBit,
|
||||
rect.width(),
|
||||
rect.height(),
|
||||
kRGBA_8888_PM_GrPixelConfig,
|
||||
{0} // samples
|
||||
};
|
||||
|
||||
if (filter->asABlur(&blurSize)) {
|
||||
GrAutoScratchTexture temp1, temp2;
|
||||
texture = context->gaussianBlur(texture, &temp1, &temp2, rect,
|
||||
blurSize.width(),
|
||||
blurSize.height());
|
||||
texture->ref();
|
||||
} else if (filter->asADilate(&radius)) {
|
||||
GrAutoScratchTexture temp1(context, desc), temp2(context, desc);
|
||||
texture = context->applyMorphology(texture, rect,
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kDilate_Filter,
|
||||
radius);
|
||||
texture->ref();
|
||||
} else if (filter->asAnErode(&radius)) {
|
||||
GrAutoScratchTexture temp1(context, desc), temp2(context, desc);
|
||||
texture = context->applyMorphology(texture, rect,
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kErode_Filter,
|
||||
radius);
|
||||
texture->ref();
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
||||
int left, int top, const SkPaint& paint) {
|
||||
CHECK_SHOULD_DRAW(draw);
|
||||
|
||||
SkAutoLockPixels alp(bitmap);
|
||||
SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
|
||||
if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1422,50 +1461,19 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
|||
GrTexture* texture;
|
||||
sampler->reset();
|
||||
SkAutoCachedTexture act(this, bitmap, sampler, &texture);
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
|
||||
SkImageFilter* imageFilter = paint.getImageFilter();
|
||||
SkSize blurSize;
|
||||
SkISize radius;
|
||||
if (NULL != imageFilter && imageFilter->asABlur(&blurSize)) {
|
||||
GrAutoScratchTexture temp1, temp2;
|
||||
GrTexture* blurTexture = fContext->gaussianBlur(texture, &temp1, &temp2,
|
||||
GrRect::MakeWH(w, h),
|
||||
blurSize.width(),
|
||||
blurSize.height());
|
||||
texture = blurTexture;
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
} else if (NULL != imageFilter && imageFilter->asADilate(&radius)) {
|
||||
const GrTextureDesc desc = {
|
||||
kRenderTarget_GrTextureFlagBit,
|
||||
w,
|
||||
h,
|
||||
kRGBA_8888_PM_GrPixelConfig,
|
||||
{0} // samples
|
||||
};
|
||||
GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc);
|
||||
texture = fContext->applyMorphology(texture, GrRect::MakeWH(w, h),
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kDilate_Filter,
|
||||
radius);
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
} else if (NULL != imageFilter && imageFilter->asAnErode(&radius)) {
|
||||
const GrTextureDesc desc = {
|
||||
kRenderTarget_GrTextureFlagBit,
|
||||
w,
|
||||
h,
|
||||
kRGBA_8888_PM_GrPixelConfig,
|
||||
{0} // samples
|
||||
};
|
||||
GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc);
|
||||
texture = fContext->applyMorphology(texture, GrRect::MakeWH(w, h),
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kErode_Filter,
|
||||
radius);
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
} else {
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
SkImageFilter* filter = paint.getImageFilter();
|
||||
if (NULL != filter) {
|
||||
GrTexture* filteredTexture = filter_texture(fContext, texture, filter,
|
||||
GrRect::MakeWH(w, h));
|
||||
if (filteredTexture) {
|
||||
grPaint.setTexture(kBitmapTextureIdx, filteredTexture);
|
||||
texture = filteredTexture;
|
||||
filteredTexture->unref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fContext->drawRectToRect(grPaint,
|
||||
GrRect::MakeXYWH(GrIntToScalar(left),
|
||||
GrIntToScalar(top),
|
||||
|
@ -1488,6 +1496,18 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
|
|||
GrTexture* devTex = grPaint.getTexture(0);
|
||||
SkASSERT(NULL != devTex);
|
||||
|
||||
SkImageFilter* filter = paint.getImageFilter();
|
||||
if (NULL != filter) {
|
||||
GrRect rect = GrRect::MakeWH(devTex->width(), devTex->height());
|
||||
GrTexture* filteredTexture = filter_texture(fContext, devTex, filter,
|
||||
rect);
|
||||
if (filteredTexture) {
|
||||
grPaint.setTexture(kBitmapTextureIdx, filteredTexture);
|
||||
devTex = filteredTexture;
|
||||
filteredTexture->unref();
|
||||
}
|
||||
}
|
||||
|
||||
const SkBitmap& bm = dev->accessBitmap(false);
|
||||
int w = bm.width();
|
||||
int h = bm.height();
|
||||
|
@ -1509,27 +1529,43 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
|
|||
fContext->drawRectToRect(grPaint, dstRect, srcRect);
|
||||
}
|
||||
|
||||
bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
bool SkGpuDevice::canHandleImageFilter(SkImageFilter* filter) {
|
||||
SkSize size;
|
||||
SkISize radius;
|
||||
if (!filter->asABlur(&size) && !filter->asADilate(&radius) && !filter->asAnErode(&radius)) {
|
||||
return false;
|
||||
}
|
||||
SkDevice* dev = this->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
|
||||
src.width(),
|
||||
src.height(),
|
||||
false);
|
||||
if (NULL == dev) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
// want explicitly our impl, so guard against a subclass of us overriding it
|
||||
if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
|
||||
return false;
|
||||
}
|
||||
SkAutoUnref aur(dev);
|
||||
SkCanvas canvas(dev);
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(filter);
|
||||
canvas.drawSprite(src, 0, 0, &paint);
|
||||
*result = dev->accessBitmap(false);
|
||||
|
||||
SkAutoLockPixels alp(src, !src.getTexture());
|
||||
if (!src.getTexture() && !src.readyToDraw()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrPaint paint;
|
||||
paint.reset();
|
||||
|
||||
GrSamplerState* sampler = paint.textureSampler(kBitmapTextureIdx);
|
||||
|
||||
GrTexture* texture;
|
||||
SkAutoCachedTexture act(this, src, sampler, &texture);
|
||||
|
||||
result->setConfig(src.config(), src.width(), src.height());
|
||||
GrRect rect = GrRect::MakeWH(src.width(), src.height());
|
||||
GrTexture* resultTexture = filter_texture(fContext, texture, filter, rect);
|
||||
if (resultTexture) {
|
||||
result->setPixelRef(new SkGrTexturePixelRef(resultTexture))->unref();
|
||||
resultTexture->unref();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче