bool SkDisplacementMapEffect::onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* dst, SkIPoint* offset) { SkBitmap displ, color = src; SkImageFilter* colorInput = getColorInput(); SkImageFilter* displacementInput = getDisplacementInput(); SkASSERT(NULL != displacementInput); if ((colorInput && !colorInput->filterImage(proxy, src, ctm, &color, offset)) || !displacementInput->filterImage(proxy, src, ctm, &displ, offset)) { return false; } if ((displ.config() != SkBitmap::kARGB_8888_Config) || (color.config() != SkBitmap::kARGB_8888_Config)) { return false; } SkAutoLockPixels alp_displacement(displ), alp_color(color); if (!displ.getPixels() || !color.getPixels()) { return false; } dst->setConfig(displ.config(), displ.width(), displ.height()); dst->allocPixels(); if (!dst->getPixels()) { return false; } computeDisplacement(fXChannelSelector, fYChannelSelector, fScale, dst, &displ, &color); return true; }
bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* dst, SkIPoint* offset) const { SkBitmap background = src, foreground = src; SkImageFilter* backgroundInput = getInput(0); SkImageFilter* foregroundInput = getInput(1); SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (backgroundInput && !backgroundInput->filterImage(proxy, src, ctx, &background, &backgroundOffset)) { background.reset(); } SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (foregroundInput && !foregroundInput->filterImage(proxy, src, ctx, &foreground, &foregroundOffset)) { foreground.reset(); } SkIRect bounds, foregroundBounds; if (!applyCropRect(ctx, foreground, foregroundOffset, &foregroundBounds)) { foregroundBounds.setEmpty(); foreground.reset(); } if (!applyCropRect(ctx, background, backgroundOffset, &bounds)) { bounds.setEmpty(); background.reset(); } bounds.join(foregroundBounds); if (bounds.isEmpty()) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); if (NULL == device.get()) { return false; } SkCanvas canvas(device); canvas.translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); canvas.drawBitmap(background, SkIntToScalar(backgroundOffset.fX), SkIntToScalar(backgroundOffset.fY), &paint); paint.setXfermode(fMode); canvas.drawBitmap(foreground, SkIntToScalar(foregroundOffset.fX), SkIntToScalar(foregroundOffset.fY), &paint); canvas.clipRect(SkRect::Make(foregroundBounds), SkRegion::kDifference_Op); paint.setColor(SK_ColorTRANSPARENT); canvas.drawPaint(paint); *dst = device->accessBitmap(false); offset->fX = bounds.left(); offset->fY = bounds.top(); return true; }
bool SkImageFilter::filterInputGPU(int index, SkImageFilter::Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkImageFilter* input = this->getInput(index); if (!input) { return true; } // 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(); if (input->filterImage(proxy, src, this->mapContext(ctx), result, offset)) { if (!result->getTexture()) { const SkImageInfo info = result->info(); if (kUnknown_SkColorType == info.colorType()) { return false; } SkAutoTUnref<GrTexture> resultTex( GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter())); if (!resultTex) { return false; } result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref(); } return true; } else { return false; } }
void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y, const SkPaint& paint) { SkASSERT(!srcImg->isTextureBacked()); SkBitmap resultBM; SkImageFilter* filter = paint.getImageFilter(); if (filter) { SkIPoint offset = SkIPoint::Make(0, 0); SkMatrix matrix = *draw.fMatrix; matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); SkAutoTUnref<SkImageFilterCache> cache(this->getImageFilterCache()); SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace()); SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties); sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset)); if (resultImg) { SkPaint tmpUnfiltered(paint); tmpUnfiltered.setImageFilter(nullptr); if (resultImg->getROPixels(&resultBM)) { this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); } } } else { if (srcImg->getROPixels(&resultBM)) { this->drawSprite(draw, resultBM, x, y, paint); } } }
void SkBaseDevice::drawSpriteWithFilter(const SkDraw& draw, const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { SkImageFilter* filter = paint.getImageFilter(); SkASSERT(filter); SkIPoint offset = SkIPoint::Make(0, 0); SkMatrix matrix = *draw.fMatrix; matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); SkAutoTUnref<SkImageFilterCache> cache(this->getImageFilterCache()); SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); sk_sp<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(bitmap, &this->surfaceProps())); if (!srcImg) { return; // something disastrous happened } sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset)); if (resultImg) { SkPaint tmpUnfiltered(paint); tmpUnfiltered.setImageFilter(nullptr); SkBitmap resultBM; if (resultImg->internal_getBM(&resultBM)) { // TODO: add drawSprite(SkSpecialImage) to SkDevice? (see skbug.com/5073) this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); } } }
bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* dst, SkIPoint* offset) const { SkBitmap source = src; SkImageFilter* input = getInput(0); SkIPoint srcOffset = SkIPoint::Make(0, 0); if (input && !input->filterImage(proxy, src, ctx, &source, &srcOffset)) { return false; } SkRect dstRect; ctx.ctm().mapRect(&dstRect, fDstRect); const SkIRect dstIRect = dstRect.roundOut(); int w = dstIRect.width(); int h = dstIRect.height(); if (!fSrcRect.width() || !fSrcRect.height() || !w || !h) { return false; } SkRect srcRect; ctx.ctm().mapRect(&srcRect, fSrcRect); SkIRect srcIRect; srcRect.roundOut(&srcIRect); srcIRect.offset(-srcOffset); SkBitmap subset; SkIRect bounds; source.getBounds(&bounds); if (!srcIRect.intersect(bounds)) { offset->fX = offset->fY = 0; return true; } else if (!source.extractSubset(&subset, srcIRect)) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h)); if (NULL == device.get()) { return false; } SkCanvas canvas(device); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); SkMatrix shaderMatrix; shaderMatrix.setTranslate(SkIntToScalar(srcOffset.fX), SkIntToScalar(srcOffset.fY)); SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix)); paint.setShader(shader); canvas.translate(-dstRect.fLeft, -dstRect.fTop); canvas.drawRect(dstRect, paint); *dst = device->accessBitmap(false); offset->fX = dstIRect.fLeft; offset->fY = dstIRect.fTop; return true; }
bool SkImageFilter::filterInput(int index, Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkImageFilter* input = this->getInput(index); if (!input) { return true; } return input->filterImage(proxy, src, this->mapContext(ctx), result, offset); }
bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { if (countInputs() < 1) { return false; } SkIRect bounds; if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) { return false; } const int x0 = bounds.left(); const int y0 = bounds.top(); SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height())); if (nullptr == dst) { return false; } SkCanvas canvas(dst); SkPaint paint; bool didProduceResult = false; int inputCount = countInputs(); for (int i = 0; i < inputCount; ++i) { SkBitmap tmp; const SkBitmap* srcPtr; SkIPoint pos = SkIPoint::Make(0, 0); SkImageFilter* filter = getInput(i); if (filter) { if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) { continue; } srcPtr = &tmp; } else { srcPtr = &src; } if (fModes) { paint.setXfermodeMode((SkXfermode::Mode)fModes[i]); } else { paint.setXfermode(nullptr); } canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint); didProduceResult = true; } if (!didProduceResult) return false; offset->fX = bounds.left(); offset->fY = bounds.top(); *result = dst->accessBitmap(false); return true; }
bool SkComposeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { SkImageFilter* outer = getInput(0); SkImageFilter* inner = getInput(1); if (!outer && !inner) { return false; } if (!outer || !inner) { return (outer ? outer : inner)->filterImage(proxy, src, ctm, result, offset); } SkBitmap tmp; return inner->filterImage(proxy, src, ctm, &tmp, offset) && outer->filterImage(proxy, tmp, ctm, result, offset); }
SkBitmap SkImageFilter::getInputResult(int index, Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkIPoint* loc) { SkASSERT(index < fInputCount); SkImageFilter* input = getInput(index); SkBitmap result; if (input && input->filterImage(proxy, src, ctm, &result, loc)) { return result; } else { return src; } }
bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* loc) { if (countInputs() < 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(); SkAutoTUnref<SkDevice> dst(proxy->createDevice(bounds.width(), bounds.height())); if (NULL == dst) { return false; } SkCanvas canvas(dst); SkPaint paint; int inputCount = countInputs(); for (int i = 0; i < inputCount; ++i) { SkBitmap tmp; const SkBitmap* srcPtr; SkIPoint pos = *loc; SkImageFilter* filter = getInput(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; }
sk_sp<SkSpecialImage> SkImageFilter::filterInput(int index, SkSpecialImage* src, const Context& ctx, SkIPoint* offset) const { SkImageFilter* input = this->getInput(index); if (!input) { return sk_sp<SkSpecialImage>(SkRef(src)); } sk_sp<SkSpecialImage> result(input->filterImage(src, this->mapContext(ctx), offset)); SkASSERT(!result || src->isTextureBacked() == result->isTextureBacked()); return result; }
bool SkBlendImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* dst, SkIPoint* offset) { SkBitmap background, foreground = src; SkImageFilter* backgroundInput = getBackgroundInput(); SkImageFilter* foregroundInput = getForegroundInput(); SkASSERT(NULL != backgroundInput); if (!backgroundInput->filterImage(proxy, src, ctm, &background, offset)) { return false; } if (foregroundInput && !foregroundInput->filterImage(proxy, src, ctm, &foreground, offset)) { return false; } SkAutoLockPixels alp_foreground(foreground), alp_background(background); if (!foreground.getPixels() || !background.getPixels()) { return false; } dst->setConfig(background.config(), background.width(), background.height()); dst->allocPixels(); SkCanvas canvas(*dst); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); canvas.drawBitmap(background, 0, 0, &paint); // FEBlend's multiply mode is (1 - Sa) * Da + (1 - Da) * Sc + Sc * Dc // Skia's is just Sc * Dc. So we use a custom proc to implement FEBlend's // version. if (fMode == SkBlendImageFilter::kMultiply_Mode) { paint.setXfermode(new SkProcXfermode(multiply_proc))->unref(); } else { paint.setXfermodeMode(modeToXfermode(fMode)); } canvas.drawBitmap(foreground, 0, 0, &paint); return true; }
bool SkComposeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkImageFilter* outer = getInput(0); SkImageFilter* inner = getInput(1); SkBitmap tmp; SkIPoint innerOffset = SkIPoint::Make(0, 0); SkIPoint outerOffset = SkIPoint::Make(0, 0); if (!inner->filterImage(proxy, src, ctx, &tmp, &innerOffset)) return false; SkMatrix outerMatrix(ctx.ctm()); outerMatrix.postTranslate(SkIntToScalar(-innerOffset.x()), SkIntToScalar(-innerOffset.y())); Context outerContext(outerMatrix, ctx.clipBounds(), ctx.cache()); if (!outer->filterImage(proxy, tmp, outerContext, result, &outerOffset)) { return false; } *offset = innerOffset + outerOffset; return true; }
bool SkImageFilter::filterInput(int index, Proxy* proxy, const SkBitmap& src, const Context& origCtx, SkBitmap* result, SkIPoint* offset, bool relaxSizeConstraint) const { SkImageFilter* input = this->getInput(index); if (!input) { return true; } SizeConstraint constraint = origCtx.sizeConstraint(); if (relaxSizeConstraint && (kExact_SizeConstraint == constraint)) { constraint = kApprox_SizeConstraint; } Context ctx(origCtx.ctm(), origCtx.clipBounds(), origCtx.cache(), constraint); return input->filterImage(proxy, src, this->mapContext(ctx), result, offset); }
virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* dst, SkIPoint* offset) const override { SkBitmap source = src; SkImageFilter* input = getInput(0); SkIPoint srcOffset = SkIPoint::Make(0, 0); if (input && !input->filterImage(proxy, src, ctx, &source, &srcOffset)) { return false; } SkIRect bounds; if (!this->applyCropRect(ctx, proxy, source, &srcOffset, &bounds, &source)) { 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; }
bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkImageFilter* input = getInput(0); SkBitmap src = source; SkIPoint srcOffset = SkIPoint::Make(0, 0); #ifdef SK_DISABLE_OFFSETIMAGEFILTER_OPTIMIZATION if (false) { #else if (!cropRectIsSet()) { #endif if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) { return false; } SkVector vec; ctx.ctm().mapVectors(&vec, &fOffset, 1); offset->fX = srcOffset.fX + SkScalarRoundToInt(vec.fX); offset->fY = srcOffset.fY + SkScalarRoundToInt(vec.fY); *result = src; } else { if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) { return false; } SkIRect bounds; if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); if (NULL == device.get()) { return false; } SkCanvas canvas(device); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft), SkIntToScalar(srcOffset.fY - bounds.fTop)); SkVector vec; ctx.ctm().mapVectors(&vec, &fOffset, 1); canvas.drawBitmap(src, vec.x(), vec.y(), &paint); *result = device->accessBitmap(false); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; } return true; } void SkOffsetImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { if (getInput(0)) { getInput(0)->computeFastBounds(src, dst); } else { *dst = src; } SkRect copy = *dst; dst->offset(fOffset.fX, fOffset.fY); dst->join(copy); } bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { SkVector vec; ctm.mapVectors(&vec, &fOffset, 1); SkIRect bounds = src; bounds.offset(-SkScalarCeilToInt(vec.fX), -SkScalarCeilToInt(vec.fY)); bounds.join(src); if (getInput(0)) { return getInput(0)->filterBounds(bounds, ctm, dst); } *dst = bounds; return true; }