зеркало из https://github.com/mozilla/moz-skia.git
initial impl of SkImageFilters : virtual signature will change!
Do not invest too much in other subclasses until this API solidifies. git-svn-id: http://skia.googlecode.com/svn/trunk@2903 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
3287949868
Коммит
32d25b6f5f
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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 "SkTestImageFilters.h"
|
||||
|
||||
#define FILTER_WIDTH SkIntToScalar(150)
|
||||
#define FILTER_HEIGHT SkIntToScalar(200)
|
||||
|
||||
static SkImageFilter* make0() { return new SkDownSampleImageFilter(SK_Scalar1 / 5); }
|
||||
static SkImageFilter* make1() { return new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16)); }
|
||||
static SkImageFilter* make2() {
|
||||
SkColorFilter* cf = SkColorFilter::CreateModeFilter(SK_ColorBLUE,
|
||||
SkXfermode::kSrcIn_Mode);
|
||||
SkAutoUnref aur(cf);
|
||||
return new SkColorFilterImageFilter(cf);
|
||||
}
|
||||
static SkImageFilter* make3() {
|
||||
SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
|
||||
SkImageFilter* inner = new SkDownSampleImageFilter(SK_Scalar1 / 5);
|
||||
SkAutoUnref aur0(outer);
|
||||
SkAutoUnref aur1(inner);
|
||||
return new SkComposeImageFilter(outer, inner);
|
||||
}
|
||||
static SkImageFilter* make4() {
|
||||
SkImageFilter* first = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
|
||||
SkImageFilter* second = new SkDownSampleImageFilter(SK_Scalar1 / 5);
|
||||
SkAutoUnref aur0(first);
|
||||
SkAutoUnref aur1(second);
|
||||
return new SkMergeImageFilter(first, second);
|
||||
}
|
||||
|
||||
static SkImageFilter* make5() {
|
||||
SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
|
||||
SkImageFilter* inner = new SkDownSampleImageFilter(SK_Scalar1 / 5);
|
||||
SkAutoUnref aur0(outer);
|
||||
SkAutoUnref aur1(inner);
|
||||
SkImageFilter* compose = new SkComposeImageFilter(outer, inner);
|
||||
SkAutoUnref aur2(compose);
|
||||
|
||||
SkColorFilter* cf = SkColorFilter::CreateModeFilter(0x880000FF,
|
||||
SkXfermode::kSrcIn_Mode);
|
||||
SkAutoUnref aur3(cf);
|
||||
SkImageFilter* blue = new SkColorFilterImageFilter(cf);
|
||||
SkAutoUnref aur4(blue);
|
||||
|
||||
return new SkMergeImageFilter(compose, blue);
|
||||
}
|
||||
|
||||
static void draw0(SkCanvas* canvas) {
|
||||
SkPaint p;
|
||||
p.setAntiAlias(true);
|
||||
SkRect r = SkRect::MakeWH(FILTER_WIDTH, FILTER_HEIGHT);
|
||||
r.inset(SK_Scalar1, SK_Scalar1);
|
||||
p.setColor(SK_ColorRED);
|
||||
canvas->drawOval(r, p);
|
||||
}
|
||||
|
||||
class TestImageFiltersGM : public skiagm::GM {
|
||||
public:
|
||||
TestImageFiltersGM () {}
|
||||
|
||||
protected:
|
||||
|
||||
virtual SkString onShortName() {
|
||||
return SkString("testimagefilters");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() { return SkISize::Make(640, 480); }
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
static SkImageFilter* (*gFilterProc[])() = {
|
||||
make0, make1, make2, make3, make4, make5
|
||||
};
|
||||
|
||||
const SkRect bounds = SkRect::MakeWH(FILTER_WIDTH, FILTER_HEIGHT);
|
||||
|
||||
const SkScalar dx = bounds.width() * 8 / 7;
|
||||
const SkScalar dy = bounds.height() * 8 / 7;
|
||||
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gFilterProc); ++i) {
|
||||
int ix = i % 3;
|
||||
int iy = i / 3;
|
||||
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(gFilterProc[i]())->unref();
|
||||
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
canvas->translate(ix * dx, iy * dy);
|
||||
|
||||
SkPaint p;
|
||||
p.setColor(0xFFCCCCCC);
|
||||
canvas->drawRect(bounds, p);
|
||||
|
||||
canvas->saveLayer(&bounds, &paint);
|
||||
draw0(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static skiagm::GM* MyFactory(void*) { return new TestImageFiltersGM; }
|
||||
static skiagm::GMRegistry reg(MyFactory);
|
||||
|
||||
|
|
@ -69,6 +69,7 @@
|
|||
'../src/effects/SkPorterDuff.cpp',
|
||||
'../src/effects/SkRadialGradient_Table.h',
|
||||
'../src/effects/SkRectShape.cpp',
|
||||
'../src/effects/SkTestImageFilters.cpp',
|
||||
'../src/effects/SkTransparentShader.cpp',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
'../gm/shapes.cpp',
|
||||
'../gm/strokerects.cpp',
|
||||
'../gm/strokes.cpp',
|
||||
'../gm/testimagefilters.cpp',
|
||||
'../gm/texdata.cpp',
|
||||
'../gm/tilemodes.cpp',
|
||||
'../gm/tinybitmap.cpp',
|
||||
|
|
|
@ -23,7 +23,17 @@ struct SkPoint;
|
|||
* then be handed to the imagefilter, who in turn creates a new bitmap which
|
||||
* is what will finally be drawn to the device (using the original xfermode).
|
||||
*
|
||||
* If the imagefilter returns false, nothing is drawn.
|
||||
* THIS SIGNATURE IS TEMPORARY
|
||||
*
|
||||
* There are several weaknesses in this function signature:
|
||||
* 1. Does not expose the destination/target device, so filters that can draw
|
||||
* directly to it are unable to take advantage of that optimization.
|
||||
* 2. Does not expose a way to create a "compabitible" image (i.e. gpu -> gpu)
|
||||
* 3. As with #1, the filter is unable to "read" the dest (which would be slow)
|
||||
*
|
||||
* Therefore, we should not create any real dependencies on this API yet -- it
|
||||
* is being checked in as a check-point so we can explore these and other
|
||||
* considerations.
|
||||
*/
|
||||
class SK_API SkImageFilter : public SkFlattenable {
|
||||
public:
|
||||
|
@ -41,9 +51,15 @@ public:
|
|||
* If the result image cannot be created, return false, in which case both
|
||||
* the result and offset parameters will be ignored by the caller.
|
||||
*/
|
||||
bool filterImage(const SkBitmap& src, const SkMatrix&,
|
||||
bool filterImage(const SkBitmap& src, const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Experimental.
|
||||
*
|
||||
|
@ -55,8 +71,12 @@ public:
|
|||
protected:
|
||||
SkImageFilter() {}
|
||||
explicit SkImageFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {}
|
||||
|
||||
// Default impl returns false
|
||||
virtual bool onFilterImage(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*);
|
||||
|
||||
private:
|
||||
typedef SkFlattenable INHERITED;
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
#ifndef _SkTestImageFilters_h
|
||||
#define _SkTestImageFilters_h
|
||||
|
||||
#include "SkImageFilter.h"
|
||||
|
||||
class SkOffsetImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkOffsetImageFilter(SkScalar dx, SkScalar dy) {
|
||||
fOffset.set(dx, dy);
|
||||
}
|
||||
|
||||
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
return SkNEW_ARGS(SkOffsetImageFilter, (buffer));
|
||||
}
|
||||
|
||||
protected:
|
||||
SkOffsetImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
|
||||
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
|
||||
// overrides from SkFlattenable
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
|
||||
virtual Factory getFactory() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkVector fOffset;
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
class SkComposeImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkComposeImageFilter(SkImageFilter* outer, SkImageFilter* inner) {
|
||||
fOuter = outer;
|
||||
fInner = inner;
|
||||
SkSafeRef(outer);
|
||||
SkSafeRef(inner);
|
||||
}
|
||||
virtual ~SkComposeImageFilter();
|
||||
|
||||
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
return SkNEW_ARGS(SkComposeImageFilter, (buffer));
|
||||
}
|
||||
|
||||
protected:
|
||||
SkComposeImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
|
||||
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
|
||||
// overrides from SkFlattenable
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
|
||||
virtual Factory getFactory() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkImageFilter* fOuter;
|
||||
SkImageFilter* fInner;
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
#include "SkXfermode.h"
|
||||
|
||||
class SkMergeImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
|
||||
SkXfermode::Mode = SkXfermode::kSrcOver_Mode);
|
||||
SkMergeImageFilter(SkImageFilter* const filters[], int count,
|
||||
const SkXfermode::Mode modes[] = NULL);
|
||||
virtual ~SkMergeImageFilter();
|
||||
|
||||
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
return SkNEW_ARGS(SkMergeImageFilter, (buffer));
|
||||
}
|
||||
|
||||
protected:
|
||||
SkMergeImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
|
||||
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
|
||||
// overrides from SkFlattenable
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
|
||||
virtual Factory getFactory() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkImageFilter** fFilters;
|
||||
uint8_t* fModes; // SkXfermode::Mode
|
||||
int fCount;
|
||||
|
||||
// private storage, to avoid dynamically allocating storage for our copy
|
||||
// of the filters and modes (unless fCount is so large we can't fit).
|
||||
intptr_t fStorage[16];
|
||||
|
||||
void initAlloc(int count, bool hasModes);
|
||||
void init(SkImageFilter* const [], int count, const SkXfermode::Mode []);
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
class SkColorFilter;
|
||||
|
||||
class SkColorFilterImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkColorFilterImageFilter(SkColorFilter* cf) : fColorFilter(cf) {
|
||||
SkSafeRef(cf);
|
||||
}
|
||||
virtual ~SkColorFilterImageFilter();
|
||||
|
||||
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
return SkNEW_ARGS(SkColorFilterImageFilter, (buffer));
|
||||
}
|
||||
|
||||
protected:
|
||||
SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
|
||||
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
// overrides from SkFlattenable
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
|
||||
virtual Factory getFactory() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkColorFilter* fColorFilter;
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fun mode that scales down (only) and then scales back up to look pixelated
|
||||
class SkDownSampleImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkDownSampleImageFilter(SkScalar scale) : fScale(scale) {}
|
||||
|
||||
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
return SkNEW_ARGS(SkDownSampleImageFilter, (buffer));
|
||||
}
|
||||
|
||||
protected:
|
||||
SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
|
||||
virtual bool onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
// overrides from SkFlattenable
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
|
||||
virtual Factory getFactory() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkScalar fScale;
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
#include "SkDevice.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkImageFilter.h"
|
||||
#include "SkMetaData.h"
|
||||
#include "SkRect.h"
|
||||
|
||||
|
@ -353,7 +354,20 @@ void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
|
|||
|
||||
void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
|
||||
int x, int y, const SkPaint& paint) {
|
||||
draw.drawSprite(device->accessBitmap(false), x, y, paint);
|
||||
SkBitmap output;
|
||||
const SkBitmap* src = &device->accessBitmap(false);
|
||||
SkImageFilter* filter = paint.getImageFilter();
|
||||
|
||||
if (filter) {
|
||||
SkIPoint loc;
|
||||
loc.set(x, y);
|
||||
if (filter->filterImage(*src, *draw.fMatrix, &output, &loc)) {
|
||||
src = &output;
|
||||
x = loc.fX;
|
||||
y = loc.fY;
|
||||
}
|
||||
}
|
||||
draw.drawSprite(*src, x, y, paint);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1976,17 +1976,30 @@ bool SkPaint::nothingToDraw() const {
|
|||
//////////// Move these to their own file soon.
|
||||
|
||||
bool SkImageFilter::filterImage(const SkBitmap& src, const SkMatrix& matrix,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
SkBitmap* result, SkIPoint* loc) {
|
||||
SkASSERT(result);
|
||||
SkASSERT(offset);
|
||||
return this->onFilterImage(src, matrix, result, offset);
|
||||
SkASSERT(loc);
|
||||
return this->onFilterImage(src, matrix, result, loc);
|
||||
}
|
||||
|
||||
bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
SkASSERT(&src);
|
||||
SkASSERT(dst);
|
||||
return this->onFilterBounds(src, ctm, dst);
|
||||
}
|
||||
|
||||
bool SkImageFilter::onFilterImage(const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
SkBitmap*, SkIPoint*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
*dst = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkImageFilter::asABlur(SkSize* sigma) const {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,396 @@
|
|||
#include "SkTestImageFilters.h"
|
||||
#include "SkCanvas.h"
|
||||
|
||||
bool SkOffsetImageFilter::onFilterImage(const SkBitmap& src,
|
||||
const SkMatrix& matrix,
|
||||
SkBitmap* result,
|
||||
SkIPoint* loc) {
|
||||
SkVector vec;
|
||||
matrix.mapVectors(&vec, &fOffset, 1);
|
||||
|
||||
loc->fX += SkScalarRoundToInt(vec.fX);
|
||||
loc->fY += SkScalarRoundToInt(vec.fY);
|
||||
*result = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
SkVector vec;
|
||||
ctm.mapVectors(&vec, &fOffset, 1);
|
||||
|
||||
*dst = src;
|
||||
dst->offset(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkOffsetImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeScalar(fOffset.x());
|
||||
buffer.writeScalar(fOffset.y());
|
||||
}
|
||||
|
||||
SkOffsetImageFilter::SkOffsetImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
fOffset.fX = buffer.readScalar();
|
||||
fOffset.fY = buffer.readScalar();
|
||||
}
|
||||
|
||||
SkFlattenable::Factory SkOffsetImageFilter::getFactory() {
|
||||
return CreateProc;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkComposeImageFilter::~SkComposeImageFilter() {
|
||||
SkSafeUnref(fInner);
|
||||
SkSafeUnref(fOuter);
|
||||
}
|
||||
|
||||
bool SkComposeImageFilter::onFilterImage(const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result,
|
||||
SkIPoint* loc) {
|
||||
if (!fOuter && !fInner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fOuter || !fInner) {
|
||||
return (fOuter ? fOuter : fInner)->filterImage(src, ctm, result, loc);
|
||||
}
|
||||
|
||||
SkBitmap tmp;
|
||||
return fInner->filterImage(src, ctm, &tmp, loc) &&
|
||||
fOuter->filterImage(tmp, ctm, result, loc);
|
||||
}
|
||||
|
||||
bool SkComposeImageFilter::onFilterBounds(const SkIRect& src,
|
||||
const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
if (!fOuter && !fInner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fOuter || !fInner) {
|
||||
return (fOuter ? fOuter : fInner)->filterBounds(src, ctm, dst);
|
||||
}
|
||||
|
||||
SkIRect tmp;
|
||||
return fInner->filterBounds(src, ctm, &tmp) &&
|
||||
fOuter->filterBounds(tmp, ctm, dst);
|
||||
}
|
||||
|
||||
void SkComposeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
|
||||
this->INHERITED::flatten(buffer);
|
||||
|
||||
buffer.writeFlattenable(fOuter);
|
||||
buffer.writeFlattenable(fInner);
|
||||
}
|
||||
|
||||
SkComposeImageFilter::SkComposeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
fOuter = (SkImageFilter*)buffer.readFlattenable();
|
||||
fInner = (SkImageFilter*)buffer.readFlattenable();
|
||||
}
|
||||
|
||||
SkFlattenable::Factory SkComposeImageFilter::getFactory() {
|
||||
return CreateProc;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T> T* SkSafeRefReturn(T* obj) {
|
||||
SkSafeRef(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void SkMergeImageFilter::initAlloc(int count, bool hasModes) {
|
||||
if (count < 1) {
|
||||
fFilters = NULL;
|
||||
fModes = NULL;
|
||||
fCount = 0;
|
||||
} else {
|
||||
int modeCount = hasModes ? count : 0;
|
||||
size_t size = sizeof(SkImageFilter*) * count + sizeof(uint8_t) * modeCount;
|
||||
if (size <= sizeof(fStorage)) {
|
||||
fFilters = SkTCast<SkImageFilter**>(fStorage);
|
||||
} else {
|
||||
fFilters = SkTCast<SkImageFilter**>(sk_malloc_throw(size));
|
||||
}
|
||||
fModes = hasModes ? SkTCast<uint8_t*>(fFilters + count) : NULL;
|
||||
fCount = count;
|
||||
}
|
||||
}
|
||||
|
||||
void SkMergeImageFilter::init(SkImageFilter* const filters[], int count,
|
||||
const SkXfermode::Mode modes[]) {
|
||||
this->initAlloc(count, !!modes);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
fFilters[i] = SkSafeRefReturn(filters[i]);
|
||||
if (modes) {
|
||||
fModes[i] = SkToU8(modes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
|
||||
SkXfermode::Mode mode) {
|
||||
SkImageFilter* filters[] = { first, second };
|
||||
SkXfermode::Mode modes[] = { mode, mode };
|
||||
this->init(filters, 2, SkXfermode::kSrcOver_Mode == mode ? NULL : modes);
|
||||
}
|
||||
|
||||
SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* const filters[], int count,
|
||||
const SkXfermode::Mode modes[]) {
|
||||
this->init(filters, count, modes);
|
||||
}
|
||||
|
||||
SkMergeImageFilter::~SkMergeImageFilter() {
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
SkSafeUnref(fFilters[i]);
|
||||
}
|
||||
|
||||
if (fFilters != SkTCast<SkImageFilter**>(fStorage)) {
|
||||
sk_free(fFilters);
|
||||
// fModes is allocated in the same block as fFilters, so no need to
|
||||
// separately free it.
|
||||
}
|
||||
}
|
||||
|
||||
bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
if (fCount < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkIRect totalBounds;
|
||||
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
SkImageFilter* filter = fFilters[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(const SkBitmap& src, const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* loc) {
|
||||
if (fCount < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SkIRect srcBounds = SkIRect::MakeXYWH(loc->x(), loc->y(),
|
||||
src.width(), src.height());
|
||||
SkIRect bounds;
|
||||
if (!this->filterBounds(srcBounds, ctm, &bounds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int x0 = bounds.left();
|
||||
const int y0 = bounds.top();
|
||||
|
||||
SkBitmap dst;
|
||||
dst.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), bounds.height());
|
||||
dst.allocPixels();
|
||||
dst.eraseColor(0);
|
||||
|
||||
SkCanvas canvas(dst);
|
||||
SkPaint paint;
|
||||
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
SkBitmap tmp;
|
||||
const SkBitmap* srcPtr;
|
||||
SkIPoint pos = *loc;
|
||||
SkImageFilter* filter = fFilters[i];
|
||||
if (filter) {
|
||||
if (!filter->filterImage(src, ctm, &tmp, &pos)) {
|
||||
return false;
|
||||
}
|
||||
srcPtr = &tmp;
|
||||
} else {
|
||||
srcPtr = &src;
|
||||
}
|
||||
|
||||
if (fModes) {
|
||||
paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
|
||||
} else {
|
||||
paint.setXfermode(NULL);
|
||||
}
|
||||
canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
|
||||
}
|
||||
|
||||
loc->set(bounds.left(), bounds.top());
|
||||
result->swap(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
|
||||
this->INHERITED::flatten(buffer);
|
||||
|
||||
int storedCount = fCount;
|
||||
if (fModes) {
|
||||
// negative count signals we have modes
|
||||
storedCount = -storedCount;
|
||||
}
|
||||
buffer.write32(storedCount);
|
||||
|
||||
if (fCount) {
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
buffer.writeFlattenable(fFilters[i]);
|
||||
}
|
||||
if (fModes) {
|
||||
buffer.write(fModes, fCount * sizeof(fModes[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
int storedCount = buffer.readS32();
|
||||
this->initAlloc(SkAbs32(storedCount), storedCount < 0);
|
||||
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
fFilters[i] = (SkImageFilter*)buffer.readFlattenable();
|
||||
}
|
||||
|
||||
if (fModes) {
|
||||
SkASSERT(storedCount < 0);
|
||||
buffer.read(fModes, fCount * sizeof(fModes[0]));
|
||||
} else {
|
||||
SkASSERT(storedCount >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
SkFlattenable::Factory SkMergeImageFilter::getFactory() {
|
||||
return CreateProc;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkColorFilter.h"
|
||||
|
||||
SkColorFilterImageFilter::~SkColorFilterImageFilter() {
|
||||
SkSafeUnref(fColorFilter);
|
||||
}
|
||||
|
||||
bool SkColorFilterImageFilter::onFilterImage(const SkBitmap& src,
|
||||
const SkMatrix& matrix,
|
||||
SkBitmap* result,
|
||||
SkIPoint* loc) {
|
||||
if (SkBitmap::kARGB_8888_Config != src.config()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkColorFilter* cf = fColorFilter;
|
||||
if (NULL == cf) {
|
||||
*result = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
SkAutoLockPixels alpsrc(src);
|
||||
if (!src.readyToDraw()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkBitmap dst(src);
|
||||
dst.allocPixels();
|
||||
if (!dst.readyToDraw()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int y = 0; y < src.height(); ++y) {
|
||||
cf->filterSpan(src.getAddr32(0, y), src.width(), dst.getAddr32(0, y));
|
||||
}
|
||||
|
||||
result->swap(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
|
||||
this->INHERITED::flatten(buffer);
|
||||
|
||||
buffer.writeFlattenable(fColorFilter);
|
||||
}
|
||||
|
||||
SkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
fColorFilter = (SkColorFilter*)buffer.readFlattenable();
|
||||
}
|
||||
|
||||
SkFlattenable::Factory SkColorFilterImageFilter::getFactory() {
|
||||
return CreateProc;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkDownSampleImageFilter::onFilterImage(const SkBitmap& src,
|
||||
const SkMatrix& matrix,
|
||||
SkBitmap* result, SkIPoint*) {
|
||||
SkScalar scale = fScale;
|
||||
if (scale > SK_Scalar1 || scale <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int dstW = SkScalarRoundToInt(src.width() * scale);
|
||||
int dstH = SkScalarRoundToInt(src.height() * scale);
|
||||
if (dstW < 1) {
|
||||
dstW = 1;
|
||||
}
|
||||
if (dstH < 1) {
|
||||
dstH = 1;
|
||||
}
|
||||
|
||||
SkBitmap dst;
|
||||
dst.setConfig(SkBitmap::kARGB_8888_Config, dstW, dstH);
|
||||
dst.allocPixels();
|
||||
dst.eraseColor(0);
|
||||
|
||||
// downsample
|
||||
{
|
||||
SkPaint paint;
|
||||
paint.setFilterBitmap(true);
|
||||
|
||||
SkCanvas canvas(dst);
|
||||
canvas.scale(scale, scale);
|
||||
canvas.drawBitmap(src, 0, 0, &paint);
|
||||
}
|
||||
|
||||
result->setConfig(SkBitmap::kARGB_8888_Config, src.width(), src.height());
|
||||
result->allocPixels();
|
||||
result->eraseColor(0);
|
||||
|
||||
// upscale
|
||||
{
|
||||
SkRect r = SkRect::MakeWH(SkIntToScalar(result->width()),
|
||||
SkIntToScalar(result->height()));
|
||||
SkCanvas canvas(*result);
|
||||
canvas.drawBitmapRect(dst, NULL, r, NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkDownSampleImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
|
||||
this->INHERITED::flatten(buffer);
|
||||
|
||||
buffer.writeScalar(fScale);
|
||||
}
|
||||
|
||||
SkDownSampleImageFilter::SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
fScale = buffer.readScalar();
|
||||
}
|
||||
|
||||
SkFlattenable::Factory SkDownSampleImageFilter::getFactory() {
|
||||
return CreateProc;
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче