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)); } } }
void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) { SkASSERT(query.width() == fTileWidth + 2 && query.height() == fTileHeight + 2); SkASSERT((query.left() + 1) % fTileWidth == 0); SkASSERT((query.top() + 1) % fTileHeight == 0); SkASSERT(results); // The +1 is to compensate for the outset in applied SkCanvas::getClipBounds *results = this->tile((query.left() + 1) / fTileWidth, (query.top() + 1) / fTileHeight); }
bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap src = source; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) { return false; } if (src.colorType() != kN32_SkColorType) { return false; } SkIRect bounds; if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) { return false; } if (!fConvolveAlpha && !src.isOpaque()) { src = unpremultiplyBitmap(proxy, src); } SkAutoLockPixels alp(src); if (!src.getPixels()) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); if (!device) { return false; } *result = device->accessBitmap(false); SkAutoLockPixels alp_result(*result); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; bounds.offset(-srcOffset); SkIRect interior = SkIRect::MakeXYWH(bounds.left() + fKernelOffset.fX, bounds.top() + fKernelOffset.fY, bounds.width() - fKernelSize.fWidth + 1, bounds.height() - fKernelSize.fHeight + 1); SkIRect top = SkIRect::MakeLTRB(bounds.left(), bounds.top(), bounds.right(), interior.top()); SkIRect bottom = SkIRect::MakeLTRB(bounds.left(), interior.bottom(), bounds.right(), bounds.bottom()); SkIRect left = SkIRect::MakeLTRB(bounds.left(), interior.top(), interior.left(), interior.bottom()); SkIRect right = SkIRect::MakeLTRB(interior.right(), interior.top(), bounds.right(), interior.bottom()); filterBorderPixels(src, result, top, bounds); filterBorderPixels(src, result, left, bounds); filterInteriorPixels(src, result, interior, bounds); filterBorderPixels(src, result, right, bounds); filterBorderPixels(src, result, bottom, bounds); return true; }
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU SkBitmap input = src; SkASSERT(fInputCount == 1); SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) { return false; } GrTexture* srcTexture = input.getTexture(); SkIRect bounds; if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { return false; } SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrContext* context = srcTexture->getContext(); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag, desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createTexture(desc, GrTextureProvider::FromImageFilter(ctx.sizeConstraint()))); if (!dst) { return false; } // setup new clip GrClip clip(dstRect); GrFragmentProcessor* fp; offset->fX = bounds.left(); offset->fY = bounds.top(); bounds.offset(-srcOffset); SkMatrix matrix(ctx.ctm()); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); GrPaint paint; if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) { SkASSERT(fp); paint.addColorFragmentProcessor(fp)->unref(); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (drawContext) { drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); WrapTexture(dst, bounds.width(), bounds.height(), result); return true; } } #endif return false; }
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; }
static inline SkPMColor fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) { x = (x - bounds.left()) % bounds.width() + bounds.left(); y = (y - bounds.top()) % bounds.height() + bounds.top(); if (x < bounds.left()) { x += bounds.width(); } if (y < bounds.top()) { y += bounds.height(); } return *src.getAddr32(x, y); }
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; }
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { #if SK_SUPPORT_GPU SkBitmap input; SkASSERT(fInputCount == 1); if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, ctm, &input, offset)) { return false; } GrTexture* srcTexture = input.getTexture(); SkIRect bounds; src.getBounds(&bounds); if (!this->applyCropRect(&bounds, ctm)) { return false; } SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrContext* context = srcTexture->getContext(); GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit, desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; GrAutoScratchTexture dst(context, desc); GrContext::AutoMatrix am; am.setIdentity(context); GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget()); GrContext::AutoClip acs(context, dstRect); GrEffectRef* effect; SkMatrix matrix(ctm); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); this->asNewEffect(&effect, srcTexture, matrix, bounds); SkASSERT(effect); SkAutoUnref effectRef(effect); GrPaint paint; paint.addColorEffect(effect); context->drawRectToRect(paint, dstRect, srcRect); SkAutoTUnref<GrTexture> resultTex(dst.detach()); SkImageFilterUtils::WrapTexture(resultTex, bounds.width(), bounds.height(), result); offset->fX += bounds.left(); offset->fY += bounds.top(); return true; #else return false; #endif }
void SkTileGrid::insert(void* data, const SkRect& fbounds, bool) { SkASSERT(!fbounds.isEmpty()); SkIRect dilatedBounds; if (fbounds.isLargest()) { // Dilating the largest SkIRect will overflow. Other nearly-largest rects may overflow too, // but we don't make active use of them like we do the largest. dilatedBounds.setLargest(); } else { fbounds.roundOut(&dilatedBounds); dilatedBounds.outset(fInfo.fMargin.width(), fInfo.fMargin.height()); dilatedBounds.offset(fInfo.fOffset); } const SkIRect gridBounds = { 0, 0, fInfo.fTileInterval.width() * fXTiles, fInfo.fTileInterval.height() * fYTiles }; if (!SkIRect::Intersects(dilatedBounds, gridBounds)) { return; } // Note: SkIRects are non-inclusive of the right() column and bottom() row, // hence the "-1"s in the computations of maxX and maxY. int minX = SkMax32(0, SkMin32(dilatedBounds.left() / fInfo.fTileInterval.width(), fXTiles - 1)); int minY = SkMax32(0, SkMin32(dilatedBounds.top() / fInfo.fTileInterval.height(), fYTiles - 1)); int maxX = SkMax32(0, SkMin32((dilatedBounds.right() - 1) / fInfo.fTileInterval.width(), fXTiles - 1)); int maxY = SkMax32(0, SkMin32((dilatedBounds.bottom() - 1) / fInfo.fTileInterval.height(), fYTiles - 1)); Entry entry = { fCount++, data }; for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { fTiles[y * fXTiles + x].push(entry); } } }
bool SkPaintImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkIRect bounds; if (!this->applyCropRect(ctx, source, SkIPoint::Make(0, 0), &bounds)) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); if (nullptr == device.get()) { return false; } SkCanvas canvas(device.get()); SkMatrix matrix(ctx.ctm()); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); SkRect rect = SkRect::MakeWH(SkIntToScalar(bounds.width()), SkIntToScalar(bounds.height())); SkMatrix inverse; if (matrix.invert(&inverse)) { inverse.mapRect(&rect); } canvas.setMatrix(matrix); canvas.drawRect(rect, fPaint); *result = device.get()->accessBitmap(false); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; return true; }
bool SkRectShaderImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkIRect bounds; if (!this->applyCropRect(ctx, source, SkIPoint::Make(0, 0), &bounds)) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); if (NULL == device.get()) { return false; } SkCanvas canvas(device.get()); SkPaint paint; SkMatrix matrix(ctx.ctm()); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); SkSafeUnref(paint.setShader(SkShader::CreateLocalMatrixShader(fShader, matrix))); SkRect rect = SkRect::MakeWH(SkIntToScalar(bounds.width()), SkIntToScalar(bounds.height())); canvas.drawRect(rect, paint); *result = device.get()->accessBitmap(false); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; return true; }
TiledPipeController::TiledPipeController(const SkBitmap& bitmap, SkPicture::InstallPixelRefProc proc, const SkMatrix* initial) : INHERITED(NULL, proc) { int32_t top = 0; int32_t bottom; int32_t height = bitmap.height() / NumberOfTiles; SkIRect rect; for (int i = 0; i < NumberOfTiles; i++) { bottom = i + 1 == NumberOfTiles ? bitmap.height() : top + height; rect.setLTRB(0, top, bitmap.width(), bottom); top = bottom; SkDEBUGCODE(bool extracted = )bitmap.extractSubset(&fBitmaps[i], rect); SkASSERT(extracted); SkBaseDevice* device = new SkBitmapDevice(fBitmaps[i]); SkCanvas* canvas = new SkCanvas(device); device->unref(); if (initial != NULL) { canvas->setMatrix(*initial); } canvas->translate(SkIntToScalar(-rect.left()), SkIntToScalar(-rect.top())); if (0 == i) { fReader.setCanvas(canvas); } else { fReaders[i - 1].setCanvas(canvas); fReaders[i - 1].setBitmapDecoder(proc); } canvas->unref(); } }
void validateBounds(SkCanvas* canvas) { #ifdef SK_DEBUG SkIRect bounds = canvas->getDeviceClipBounds(); SkASSERT(bounds.right()-bounds.left() >= W); SkASSERT(bounds.bottom()-bounds.top() >= H); #endif }
void SkTileGrid::insert(void* data, const SkIRect& bounds, bool) { SkASSERT(!bounds.isEmpty()); SkIRect dilatedBounds = bounds; dilatedBounds.outset(fInfo.fMargin.width(), fInfo.fMargin.height()); dilatedBounds.offset(fInfo.fOffset); if (!SkIRect::Intersects(dilatedBounds, fGridBounds)) { return; } // Note: SkIRects are non-inclusive of the right() column and bottom() row, // hence the "-1"s in the computations of maxTileX and maxTileY. int minTileX = SkMax32(SkMin32(dilatedBounds.left() / fInfo.fTileInterval.width(), fXTileCount - 1), 0); int maxTileX = SkMax32(SkMin32((dilatedBounds.right() - 1) / fInfo.fTileInterval.width(), fXTileCount - 1), 0); int minTileY = SkMax32(SkMin32(dilatedBounds.top() / fInfo.fTileInterval.height(), fYTileCount -1), 0); int maxTileY = SkMax32(SkMin32((dilatedBounds.bottom() -1) / fInfo.fTileInterval.height(), fYTileCount -1), 0); for (int x = minTileX; x <= maxTileX; x++) { for (int y = minTileY; y <= maxTileY; y++) { this->tile(x, y).push(data); } } fInsertionCount++; }
static void call_proc_X(SkMorphologyImageFilter::Proc procX, const SkBitmap& src, SkBitmap* dst, int radiusX, const SkIRect& bounds) { procX(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0), radiusX, bounds.width(), bounds.height(), src.rowBytesAsPixels(), dst->rowBytesAsPixels()); }
void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { if (mask.fFormat == SkMask::kBW_Format) { // TODO: native BW masks? return INHERITED::blitMask(mask, clip); } int x = clip.left(); for (int y = clip.top(); y < clip.bottom(); y++) { auto dst = fDst.writable_addr(0,y); SkRasterPipeline p; p.extend(fShader); p.extend(fColorFilter); this->append_load_d(&p, dst); p.extend(fXfermode); switch (mask.fFormat) { case SkMask::kA8_Format: p.append<lerp_a8, lerp_a8_1>(mask.getAddr8(x,y)-x); break; case SkMask::kLCD16_Format: p.append<lerp_lcd16, lerp_lcd16_1>(mask.getAddrLCD16(x,y)-x); break; default: break; } this->append_store(&p, dst); p.run(x, clip.width()); } }
Json::Value SkJSONCanvas::MakeIRect(const SkIRect& rect) { Json::Value result(Json::arrayValue); result.append(Json::Value(rect.left())); result.append(Json::Value(rect.top())); result.append(Json::Value(rect.right())); result.append(Json::Value(rect.bottom())); return result; }
void SkExampleWindow::onHandleInval(const SkIRect& rect) { RECT winRect; winRect.top = rect.top(); winRect.bottom = rect.bottom(); winRect.right = rect.right(); winRect.left = rect.left(); InvalidateRect((HWND)this->getHWND(), &winRect, false); }
static void apply_morphology_pass(GrRenderTargetContext* renderTargetContext, const GrClip& clip, sk_sp<GrTextureProxy> textureProxy, const SkIRect& srcRect, const SkIRect& dstRect, int radius, GrMorphologyEffect::Type morphType, GrMorphologyEffect::Direction direction) { float bounds[2] = { 0.0f, 1.0f }; SkIRect lowerSrcRect = srcRect, lowerDstRect = dstRect; SkIRect middleSrcRect = srcRect, middleDstRect = dstRect; SkIRect upperSrcRect = srcRect, upperDstRect = dstRect; if (direction == GrMorphologyEffect::Direction::kX) { bounds[0] = SkIntToScalar(srcRect.left()) + 0.5f; bounds[1] = SkIntToScalar(srcRect.right()) - 0.5f; lowerSrcRect.fRight = srcRect.left() + radius; lowerDstRect.fRight = dstRect.left() + radius; upperSrcRect.fLeft = srcRect.right() - radius; upperDstRect.fLeft = dstRect.right() - radius; middleSrcRect.inset(radius, 0); middleDstRect.inset(radius, 0); } else { bounds[0] = SkIntToScalar(srcRect.top()) + 0.5f; bounds[1] = SkIntToScalar(srcRect.bottom()) - 0.5f; lowerSrcRect.fBottom = srcRect.top() + radius; lowerDstRect.fBottom = dstRect.top() + radius; upperSrcRect.fTop = srcRect.bottom() - radius; upperDstRect.fTop = dstRect.bottom() - radius; middleSrcRect.inset(0, radius); middleDstRect.inset(0, radius); } if (middleSrcRect.width() <= 0) { // radius covers srcRect; use bounds over entire draw apply_morphology_rect(renderTargetContext, clip, std::move(textureProxy), srcRect, dstRect, radius, morphType, bounds, direction); } else { // Draw upper and lower margins with bounds; middle without. apply_morphology_rect(renderTargetContext, clip, textureProxy, lowerSrcRect, lowerDstRect, radius, morphType, bounds, direction); apply_morphology_rect(renderTargetContext, clip, textureProxy, upperSrcRect, upperDstRect, radius, morphType, bounds, direction); apply_morphology_rect_no_bounds(renderTargetContext, clip, std::move(textureProxy), middleSrcRect, middleDstRect, radius, morphType, direction); } }
static void apply_morphology_pass(GrDrawContext* drawContext, const GrClip& clip, GrTexture* texture, const SkIRect& srcRect, const SkIRect& dstRect, int radius, GrMorphologyEffect::MorphologyType morphType, Gr1DKernelEffect::Direction direction) { float bounds[2] = { 0.0f, 1.0f }; SkIRect lowerSrcRect = srcRect, lowerDstRect = dstRect; SkIRect middleSrcRect = srcRect, middleDstRect = dstRect; SkIRect upperSrcRect = srcRect, upperDstRect = dstRect; if (direction == Gr1DKernelEffect::kX_Direction) { bounds[0] = (SkIntToScalar(srcRect.left()) + 0.5f) / texture->width(); bounds[1] = (SkIntToScalar(srcRect.right()) - 0.5f) / texture->width(); lowerSrcRect.fRight = srcRect.left() + radius; lowerDstRect.fRight = dstRect.left() + radius; upperSrcRect.fLeft = srcRect.right() - radius; upperDstRect.fLeft = dstRect.right() - radius; middleSrcRect.inset(radius, 0); middleDstRect.inset(radius, 0); } else { bounds[0] = (SkIntToScalar(srcRect.top()) + 0.5f) / texture->height(); bounds[1] = (SkIntToScalar(srcRect.bottom()) - 0.5f) / texture->height(); lowerSrcRect.fBottom = srcRect.top() + radius; lowerDstRect.fBottom = dstRect.top() + radius; upperSrcRect.fTop = srcRect.bottom() - radius; upperDstRect.fTop = dstRect.bottom() - radius; middleSrcRect.inset(0, radius); middleDstRect.inset(0, radius); } if (middleSrcRect.fLeft - middleSrcRect.fRight >= 0) { // radius covers srcRect; use bounds over entire draw apply_morphology_rect(drawContext, clip, texture, srcRect, dstRect, radius, morphType, bounds, direction); } else { // Draw upper and lower margins with bounds; middle without. apply_morphology_rect(drawContext, clip, texture, lowerSrcRect, lowerDstRect, radius, morphType, bounds, direction); apply_morphology_rect(drawContext, clip, texture, upperSrcRect, upperDstRect, radius, morphType, bounds, direction); apply_morphology_rect_no_bounds(drawContext, clip, texture, middleSrcRect, middleDstRect, radius, morphType, direction); } }
PassRefPtr<JSONObject> LoggingCanvas::objectForSkIRect(const SkIRect& rect) { RefPtr<JSONObject> rectItem = JSONObject::create(); rectItem->setNumber("left", rect.left()); rectItem->setNumber("top", rect.top()); rectItem->setNumber("right", rect.right()); rectItem->setNumber("bottom", rect.bottom()); return rectItem.release(); }
bool SkMorphologyImageFilter::filterImageGPUGeneric(bool dilate, Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap input = src; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (this->getInput(0) && !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) { return false; } SkIRect bounds; if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { return false; } SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()), SkIntToScalar(this->radius().height())); ctx.ctm().mapVectors(&radius, 1); int width = SkScalarFloorToInt(radius.fX); int height = SkScalarFloorToInt(radius.fY); if (width < 0 || height < 0) { return false; } SkIRect srcBounds = bounds; srcBounds.offset(-srcOffset); if (width == 0 && height == 0) { input.extractSubset(result, srcBounds); offset->fX = bounds.left(); offset->fY = bounds.top(); return true; } GrMorphologyEffect::MorphologyType type = dilate ? GrMorphologyEffect::kDilate_MorphologyType : GrMorphologyEffect::kErode_MorphologyType; if (!apply_morphology(input, srcBounds, type, SkISize::Make(width, height), result)) { return false; } offset->fX = bounds.left(); offset->fY = bounds.top(); return true; }
static void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY, const SkIRect& bounds) { SkMorphologyProc erodeYProc = SkMorphologyGetPlatformProc(kErodeY_SkMorphologyProcType); if (!erodeYProc) { erodeYProc = erode<kY>; } erodeYProc(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0), radiusY, bounds.height(), bounds.width(), src.rowBytesAsPixels(), dst->rowBytesAsPixels()); }
static void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX, const SkIRect& bounds) { SkMorphologyProc dilateXProc = SkMorphologyGetPlatformProc(kDilateX_SkMorphologyProcType); if (!dilateXProc) { dilateXProc = dilate<kX>; } dilateXProc(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0), radiusX, bounds.width(), bounds.height(), src.rowBytesAsPixels(), dst->rowBytesAsPixels()); }
void draw(SkCanvas* canvas) { SkIRect rect = { 30, 50, 40, 60 }; SkIRect tests[] = { { 30, 50, 31, 51}, { 39, 49, 40, 50}, { 29, 59, 30, 60} }; for (auto contained : tests) { SkDebugf("rect: (%d, %d, %d, %d) %s (%d, %d, %d, %d)\n", rect.left(), rect.top(), rect.right(), rect.bottom(), rect.contains(contained) ? "contains" : "does not contain", contained.left(), contained.top(), contained.right(), contained.bottom()); } }
void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { if (mask.fFormat == SkMask::kBW_Format) { // TODO: native BW masks? return INHERITED::blitMask(mask, clip); } if (mask.fFormat == SkMask::kA8_Format && !fBlitMaskA8) { SkRasterPipeline p(fAlloc); p.extend(fColorPipeline); if (fBlend == SkBlendMode::kSrcOver) { p.append(SkRasterPipeline::scale_u8, &fMaskPtr); this->append_load_d(&p); this->append_blend(&p); } else { this->append_load_d(&p); this->append_blend(&p); p.append(SkRasterPipeline::lerp_u8, &fMaskPtr); } this->maybe_clamp(&p); this->append_store(&p); fBlitMaskA8 = p.compile(); } if (mask.fFormat == SkMask::kLCD16_Format && !fBlitMaskLCD16) { SkRasterPipeline p(fAlloc); p.extend(fColorPipeline); this->append_load_d(&p); this->append_blend(&p); p.append(SkRasterPipeline::lerp_565, &fMaskPtr); this->maybe_clamp(&p); this->append_store(&p); fBlitMaskLCD16 = p.compile(); } int x = clip.left(); for (int y = clip.top(); y < clip.bottom(); y++) { fDstPtr = fDst.writable_addr(0,y); this->maybe_shade(x,y,clip.width()); switch (mask.fFormat) { case SkMask::kA8_Format: fMaskPtr = mask.getAddr8(x,y)-x; fBlitMaskA8(x,y,clip.width()); break; case SkMask::kLCD16_Format: fMaskPtr = mask.getAddrLCD16(x,y)-x; fBlitMaskLCD16(x,y,clip.width()); break; default: // TODO break; } } }
// Allocate result to be large enough to hold subset, and then draw the picture // into it, offsetting by subset's top/left corner. static void draw(SkPicture* pic, const SkRect& subset, SkBitmap* result) { SkIRect ir; subset.roundOut(&ir); int w = ir.width(); int h = ir.height(); make_bm(result, w, h, 0, false); SkCanvas canvas(*result); canvas.translate(-SkIntToScalar(ir.left()), -SkIntToScalar(ir.top())); canvas.drawPicture(*pic); }
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; }
void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) { SkIRect adjustedQuery = query; // The inset is to counteract the outset that was applied in 'insert' // The outset/inset is to optimize for lookups of size // 'tileInterval + 2 * margin' that are aligned with the tile grid. adjustedQuery.inset(fInfo.fMargin.width(), fInfo.fMargin.height()); adjustedQuery.offset(fInfo.fOffset); adjustedQuery.sort(); // in case the inset inverted the rectangle // Convert the query rectangle from device coordinates to tile coordinates // by rounding outwards to the nearest tile boundary so that the resulting tile // region includes the query rectangle. (using truncating division to "floor") int tileStartX = adjustedQuery.left() / fInfo.fTileInterval.width(); int tileEndX = (adjustedQuery.right() + fInfo.fTileInterval.width() - 1) / fInfo.fTileInterval.width(); int tileStartY = adjustedQuery.top() / fInfo.fTileInterval.height(); int tileEndY = (adjustedQuery.bottom() + fInfo.fTileInterval.height() - 1) / fInfo.fTileInterval.height(); tileStartX = SkPin32(tileStartX, 0, fXTileCount - 1); tileEndX = SkPin32(tileEndX, tileStartX+1, fXTileCount); tileStartY = SkPin32(tileStartY, 0, fYTileCount - 1); tileEndY = SkPin32(tileEndY, tileStartY+1, fYTileCount); int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY); SkASSERT(queryTileCount); if (queryTileCount == 1) { *results = this->tile(tileStartX, tileStartY); } else { results->reset(); SkTDArray<int> curPositions; curPositions.setCount(queryTileCount); // Note: Reserving space for 1024 tile pointers on the stack. If the // malloc becomes a bottleneck, we may consider increasing that number. // Typical large web page, say 2k x 16k, would require 512 tiles of // size 256 x 256 pixels. SkAutoSTArray<1024, SkTDArray<void *>*> storage(queryTileCount); SkTDArray<void *>** tileRange = storage.get(); int tile = 0; for (int x = tileStartX; x < tileEndX; ++x) { for (int y = tileStartY; y < tileEndY; ++y) { tileRange[tile] = &this->tile(x, y); curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished; ++tile; } } void *nextElement; while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) { results->push(nextElement); } } }
bool onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* dst, SkIPoint* offset) const override { SkBitmap source = src; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInputDeprecated(0, proxy, src, ctx, &source, &srcOffset)) { return false; } SkIRect bounds; if (!this->applyCropRectDeprecated(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; }