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 SkDisplacementMapEffect::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* dst, SkIPoint* offset) const { SkBitmap displ = src, color = src; SkIPoint colorOffset = SkIPoint::Make(0, 0), displOffset = SkIPoint::Make(0, 0); if (!this->filterInput(1, proxy, src, ctx, &color, &colorOffset) || !this->filterInput(0, proxy, src, ctx, &displ, &displOffset)) { return false; } if ((displ.colorType() != kN32_SkColorType) || (color.colorType() != kN32_SkColorType)) { return false; } SkIRect bounds; // Since computeDisplacement does bounds checking on color pixel access, we don't need to pad // the color bitmap to bounds here. SkIRect srcBounds = color.bounds(); srcBounds.offset(colorOffset); if (!this->applyCropRect(ctx, srcBounds, &bounds)) { return false; } SkIRect displBounds; if (!this->applyCropRect(ctx, proxy, displ, &displOffset, &displBounds, &displ)) { return false; } if (!bounds.intersect(displBounds)) { return false; } SkAutoLockPixels alp_displacement(displ), alp_color(color); if (!displ.getPixels() || !color.getPixels()) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); if (!device) { return false; } *dst = device->accessBitmap(false); SkAutoLockPixels alp_dst(*dst); SkVector scale = SkVector::Make(fScale, fScale); ctx.ctm().mapVectors(&scale, 1); SkIRect colorBounds = bounds; colorBounds.offset(-colorOffset); computeDisplacement(fXChannelSelector, fYChannelSelector, scale, dst, &displ, colorOffset - displOffset, &color, colorBounds); offset->fX = bounds.left(); offset->fY = bounds.top(); return true; }
sk_sp<SkSpecialImage> SkDisplacementMapEffect::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint colorOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> color(this->filterInput(1, source, ctx, &colorOffset)); if (!color) { return nullptr; } SkIPoint displOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> displ(this->filterInput(0, source, ctx, &displOffset)); if (!displ) { return nullptr; } const SkIRect srcBounds = SkIRect::MakeXYWH(colorOffset.x(), colorOffset.y(), color->width(), color->height()); // Both paths do bounds checking on color pixel access, we don't need to // pad the color bitmap to bounds here. SkIRect bounds; if (!this->applyCropRect(ctx, srcBounds, &bounds)) { return nullptr; } SkIRect displBounds; displ = this->applyCropRect(ctx, displ.get(), &displOffset, &displBounds); if (!displ) { return nullptr; } if (!bounds.intersect(displBounds)) { return nullptr; } const SkIRect colorBounds = bounds.makeOffset(-colorOffset.x(), -colorOffset.y()); SkVector scale = SkVector::Make(fScale, fScale); ctx.ctm().mapVectors(&scale, 1); #if SK_SUPPORT_GPU if (source->isTextureBacked()) { GrContext* context = source->getContext(); sk_sp<GrTexture> colorTexture(color->asTextureRef(context)); sk_sp<GrTexture> displTexture(displ->asTextureRef(context)); if (!colorTexture || !displTexture) { return nullptr; } GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return nullptr; } GrPaint paint; SkMatrix offsetMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(displTexture.get()); offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displOffset.fX), SkIntToScalar(colorOffset.fY - displOffset.fY)); paint.addColorFragmentProcessor( GrDisplacementMapEffect::Create(fXChannelSelector, fYChannelSelector, scale, displTexture.get(), offsetMatrix, colorTexture.get(), SkISize::Make(color->width(), color->height())))->unref(); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkMatrix matrix; matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y())); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return nullptr; } drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(colorBounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), kNeedNewImageUniqueID_SpecialImage, dst); } #endif SkBitmap colorBM, displBM; if (!color->getROPixels(&colorBM) || !displ->getROPixels(&displBM)) { return nullptr; } if ((colorBM.colorType() != kN32_SkColorType) || (displBM.colorType() != kN32_SkColorType)) { return nullptr; } SkAutoLockPixels colorLock(colorBM), displLock(displBM); if (!colorBM.getPixels() || !displBM.getPixels()) { return nullptr; } SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(), colorBM.alphaType()); SkBitmap dst; if (!dst.tryAllocPixels(info)) { return nullptr; } SkAutoLockPixels dstLock(dst); computeDisplacement(fXChannelSelector, fYChannelSelector, scale, &dst, displBM, colorOffset - displOffset, colorBM, colorBounds); offset->fX = bounds.left(); offset->fY = bounds.top(); return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst); }