blob: a772f64510c137dba9ef7d5b213848e01d509583 [file] [log] [blame]
#include "SkTestImageFilters.h"
#include "SkCanvas.h"
#include "SkDevice.h"
class OwnDeviceCanvas : public SkCanvas {
public:
OwnDeviceCanvas(SkDevice* device) : SkCanvas(device) {
SkSafeUnref(device);
}
};
bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, 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(Proxy* proxy,
const SkBitmap& src,
const SkMatrix& ctm,
SkBitmap* result,
SkIPoint* loc) {
if (!fOuter && !fInner) {
return false;
}
if (!fOuter || !fInner) {
return (fOuter ? fOuter : fInner)->filterImage(proxy, src, ctm, result, loc);
}
SkBitmap tmp;
return fInner->filterImage(proxy, src, ctm, &tmp, loc) &&
fOuter->filterImage(proxy, 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(Proxy* proxy, 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();
SkDevice* dst = proxy->createDevice(bounds.width(), bounds.height());
if (NULL == dst) {
return false;
}
OwnDeviceCanvas 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(proxy, 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 = dst->accessBitmap(false);
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(Proxy* proxy, const SkBitmap& src,
const SkMatrix& matrix,
SkBitmap* result,
SkIPoint* loc) {
SkColorFilter* cf = fColorFilter;
if (NULL == cf) {
*result = src;
return true;
}
SkDevice* dev = proxy->createDevice(src.width(), src.height());
if (NULL == dev) {
return false;
}
OwnDeviceCanvas canvas(dev);
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
paint.setColorFilter(fColorFilter);
canvas.drawSprite(src, 0, 0, &paint);
*result = dev->accessBitmap(false);
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(Proxy* proxy, 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 tmp;
// downsample
{
SkDevice* dev = proxy->createDevice(dstW, dstH);
if (NULL == dev) {
return false;
}
OwnDeviceCanvas canvas(dev);
SkPaint paint;
paint.setFilterBitmap(true);
canvas.scale(scale, scale);
canvas.drawBitmap(src, 0, 0, &paint);
tmp = dev->accessBitmap(false);
}
// upscale
{
SkDevice* dev = proxy->createDevice(src.width(), src.height());
if (NULL == dev) {
return false;
}
OwnDeviceCanvas canvas(dev);
SkRect r = SkRect::MakeWH(SkIntToScalar(src.width()),
SkIntToScalar(src.height()));
canvas.drawBitmapRect(tmp, NULL, r, NULL);
*result = dev->accessBitmap(false);
}
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;
}