void computeDisplacement(Extractor ex, const SkVector& scale, SkBitmap* dst, const SkBitmap& displ, const SkIPoint& offset, const SkBitmap& src, const SkIRect& bounds) { static const SkScalar Inv8bit = SkScalarInvert(255); const int srcW = src.width(); const int srcH = src.height(); const SkVector scaleForColor = SkVector::Make(scale.fX * Inv8bit, scale.fY * Inv8bit); const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - scale.fX * SK_ScalarHalf, SK_ScalarHalf - scale.fY * SK_ScalarHalf); SkPMColor* dstPtr = dst->getAddr32(0, 0); for (int y = bounds.top(); y < bounds.bottom(); ++y) { const SkPMColor* displPtr = displ.getAddr32(bounds.left() + offset.fX, y + offset.fY); for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) { SkPMColor c = unpremul_pm(*displPtr); SkScalar displX = scaleForColor.fX * ex.getX(c) + scaleAdj.fX; SkScalar displY = scaleForColor.fY * ex.getY(c) + scaleAdj.fY; // Truncate the displacement values const int32_t srcX = Sk32_sat_add(x, SkScalarTruncToInt(displX)); const int32_t srcY = Sk32_sat_add(y, SkScalarTruncToInt(displY)); *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ? 0 : *(src.getAddr32(srcX, srcY)); } } }
sk_sp<SkSpecialImage> SkOffsetImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint srcOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &srcOffset)); if (!input) { return nullptr; } SkIPoint vec = map_offset_vector(ctx.ctm(), fOffset); if (!this->cropRectIsSet()) { offset->fX = Sk32_sat_add(srcOffset.fX, vec.fX); offset->fY = Sk32_sat_add(srcOffset.fY, vec.fY); return input; } else { SkIRect bounds; SkIRect srcBounds = SkIRect::MakeWH(input->width(), input->height()); srcBounds.offset(srcOffset); if (!this->applyCropRect(ctx, srcBounds, &bounds)) { return nullptr; } sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); if (!surf) { return nullptr; } SkCanvas* canvas = surf->getCanvas(); SkASSERT(canvas); // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075) canvas->clear(0x0); SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); canvas->translate(SkIntToScalar(srcOffset.fX - bounds.fLeft), SkIntToScalar(srcOffset.fY - bounds.fTop)); input->draw(canvas, vec.fX, vec.fY, &paint); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; return surf->makeImageSnapshot(); } }