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 SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const SkMatrix& matrix, 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, matrix, &src, &srcOffset)) { return false; } SkVector vec; matrix.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, matrix, &src, &srcOffset)) { return false; } SkIRect bounds; src.getBounds(&bounds); bounds.offset(srcOffset); if (!applyCropRect(&bounds, matrix)) { 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)); canvas.drawBitmap(src, fOffset.x(), fOffset.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); *dst = src; dst->offset(-SkScalarCeilToInt(vec.fX), -SkScalarCeilToInt(vec.fY)); dst->join(src); return true; }