void SkRecorder::reset(SkRecord* record, const SkRect& bounds, DrawPictureMode dpm, SkMiniRecorder* mr) { this->forgetRecord(); fDrawPictureMode = dpm; fRecord = record; this->resetForNextPicture(bounds.roundOut()); fMiniRecorder = mr; }
void SkRecorder::reset(SkRecord* record, const SkRect& bounds, DrawPictureMode dpm, SkMiniRecorder* mr) { this->forgetRecord(); fDrawPictureMode = dpm; fRecord = record; SkIRect rounded = bounds.roundOut(); this->resetCanvas(rounded.right(), rounded.bottom()); fMiniRecorder = mr; }
void SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst, MapDirection direction) const { SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect; ctm.mapRect(&rect); rect.roundOut(dst); #ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS dst->join(src); #endif }
void SkRTree::search(const SkRect& fquery, SkTDArray<void*>* results) const { SkIRect query; fquery.roundOut(&query); this->validate(); SkASSERT(0 == fDeferredInserts.count()); // If this fails, you should have flushed. if (!this->isEmpty() && SkIRect::IntersectsNoEmptyCheck(fRoot.fBounds, query)) { this->search(fRoot.fChild.subtree, query, results); } this->validate(); }
static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds, const SkPaint& paint) { SkRect r; SkIRect ir; paint.measureText(text, count << 1, &r); r.roundOut(&ir); GraphicsJNI::irect_to_jrect(ir, env, bounds); }
void preBenchSetup(const SkRect& r) override { SkMask::FreeImage(fSrcMask.fImage); r.roundOut(&fSrcMask.fBounds); fSrcMask.fFormat = SkMask::kA8_Format; fSrcMask.fRowBytes = fSrcMask.fBounds.width(); fSrcMask.fImage = SkMask::AllocImage(fSrcMask.computeTotalImageSize()); memset(fSrcMask.fImage, 0xff, fSrcMask.computeTotalImageSize()); }
bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { SkRect srcRect; ctm.mapRect(&srcRect, fSrcRect); SkIRect srcIRect; srcRect.roundOut(&srcIRect); srcIRect.join(src); *dst = srcIRect; return true; }
static void test_blur_drawing(skiatest::Reporter* reporter) { SkPaint paint; paint.setColor(SK_ColorGRAY); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(strokeWidth)); SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5)); for (int style = 0; style <= kLastEnum_SkBlurStyle; ++style) { SkBlurStyle blurStyle = static_cast<SkBlurStyle>(style); const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag; for (uint32_t flags = 0; flags < flagPermutations; ++flags) { SkMaskFilter* filter; filter = SkBlurMaskFilter::Create(blurStyle, sigma, flags); paint.setMaskFilter(filter); filter->unref(); for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) { SkPath path; tests[test].addPath(&path); SkPath strokedPath; paint.getFillPath(path, &strokedPath); SkRect refBound = strokedPath.getBounds(); SkIRect iref; refBound.roundOut(&iref); iref.inset(-outset, -outset); SkBitmap refBitmap; create(&refBitmap, iref); SkCanvas refCanvas(refBitmap); refCanvas.translate(SkIntToScalar(-iref.fLeft), SkIntToScalar(-iref.fTop)); drawBG(&refCanvas); refCanvas.drawPath(path, paint); for (int view = 0; view < tests[test].viewLen; ++view) { SkIRect itest = tests[test].views[view]; SkBitmap testBitmap; create(&testBitmap, itest); SkCanvas testCanvas(testBitmap); testCanvas.translate(SkIntToScalar(-itest.fLeft), SkIntToScalar(-itest.fTop)); drawBG(&testCanvas); testCanvas.drawPath(path, paint); REPORTER_ASSERT(reporter, compare(refBitmap, iref, testBitmap, itest)); } } } } }
// 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 SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) { SkRegion::Op op; if (isInverse) { op = SkRegion::kDifference_Op; } else { op = SkRegion::kIntersect_Op; } fBW.setRect(clipR); fBW.op(r.roundOut(), op); return this->updateCacheAndReturnNonEmpty(); }
sk_sp<SkSpecialImage> SkImageSource::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkRect dstRect; ctx.ctm().mapRect(&dstRect, fDstRect); SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height()); if (fSrcRect == bounds) { int iLeft = dstRect.fLeft; int iTop = dstRect.fTop; // TODO: this seems to be a very noise-prone way to determine this (esp. the floating-point // widths & heights). if (dstRect.width() == bounds.width() && dstRect.height() == bounds.height() && iLeft == dstRect.fLeft && iTop == dstRect.fTop) { // The dest is just an un-scaled integer translation of the entire image; return it offset->fX = iLeft; offset->fY = iTop; return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(fImage->width(), fImage->height()), fImage, ctx.outputProperties().colorSpace(), &source->props()); } } const SkIRect dstIRect = dstRect.roundOut(); sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), dstIRect.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; // Subtract off the integer component of the translation (will be applied in offset, below). dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop)); paint.setBlendMode(SkBlendMode::kSrc); // FIXME: this probably shouldn't be necessary, but drawImageRect asserts // None filtering when it's translate-only paint.setFilterQuality( fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ? kNone_SkFilterQuality : fFilterQuality); canvas->drawImageRect(fImage.get(), fSrcRect, dstRect, &paint, SkCanvas::kStrict_SrcRectConstraint); offset->fX = dstIRect.fLeft; offset->fY = dstIRect.fTop; return surf->makeImageSnapshot(); }
bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const { SkRect cropRect; matrix.mapRect(&cropRect, fCropRect.rect()); SkIRect cropRectI; cropRect.roundOut(&cropRectI); uint32_t flags = fCropRect.flags(); // If the original crop rect edges were unset, max out the new crop edges if (!(flags & CropRect::kHasLeft_CropEdge)) cropRectI.fLeft = SK_MinS32; if (!(flags & CropRect::kHasTop_CropEdge)) cropRectI.fTop = SK_MinS32; if (!(flags & CropRect::kHasRight_CropEdge)) cropRectI.fRight = SK_MaxS32; if (!(flags & CropRect::kHasBottom_CropEdge)) cropRectI.fBottom = SK_MaxS32; return rect->intersect(cropRectI); }
bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& bounds, SkRegion::Op op, bool doAA) { AUTO_RASTERCLIP_VALIDATE(*this); SkRect devRect; if (fForceConservativeRects) { SkIRect ir; switch (mutate_conservative_op(&op, false)) { case kDoNothing_MutateResult: return !this->isEmpty(); case kReplaceClippedAgainstGlobalBounds_MutateResult: ir = bounds; break; case kContinue_MutateResult: matrix.mapRect(&devRect, localRect); ir = devRect.roundOut(); break; } return this->op(ir, op); } const bool isScaleTrans = matrix.isScaleTranslate(); if (!isScaleTrans) { SkPath path; path.addRect(localRect); path.setIsVolatile(true); return this->op(path, matrix, bounds, op, doAA); } matrix.mapRect(&devRect, localRect); if (fIsBW && doAA) { // check that the rect really needs aa, or is it close enought to // integer boundaries that we can just treat it as a BW rect? if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) && nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) { doAA = false; } } if (fIsBW && !doAA) { SkIRect ir; devRect.round(&ir); (void)fBW.op(ir, op); } else { if (fIsBW) { this->convertToAA(); } (void)fAA.op(devRect, op, doAA); } return this->updateCacheAndReturnNonEmpty(); }
// Atlased layers must be small enough to fit in the atlas, not have a // paint with an image filter and be neither nested nor nesting. // TODO: allow leaf nested layers to appear in the atlas. void GrLayerHoister::FindLayersToAtlas(GrContext* context, const SkPicture* topLevelPicture, const SkRect& query, SkTDArray<GrHoistedLayer>* atlased, SkTDArray<GrHoistedLayer>* recycled) { GrLayerCache* layerCache = context->getLayerCache(); layerCache->processDeletedPictures(); SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key); if (!topLevelData) { return; } const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData); if (0 == topLevelGPUData->numSaveLayers()) { return; } atlased->setReserve(atlased->count() + topLevelGPUData->numSaveLayers()); for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i); // TODO: ignore perspective projected layers here? bool disallowAtlasing = info.fHasNestedLayers || info.fIsNested || (info.fPaint && info.fPaint->getImageFilter()); if (disallowAtlasing) { continue; } SkRect layerRect = info.fBounds; if (!layerRect.intersect(query)) { continue; } SkIRect ir; layerRect.roundOut(&ir); if (!GrLayerCache::PlausiblyAtlasable(ir.width(), ir.height())) { continue; } prepare_for_hoisting(layerCache, topLevelPicture, info, ir, atlased, recycled, true); } }
const SkPicture::OperationList* SkPicturePlayback::getActiveOps(const SkCanvas* canvas) { if (fUseBBH) { SkRect clipBounds; if (canvas->getClipBounds(&clipBounds)) { SkIRect query; clipBounds.roundOut(&query); return fPictureData->getActiveOps(query); } } return NULL; }
void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devResult, bool* isIntersectionOfRects) const { if (!fStack) { devResult->setXYWH(0, 0, width, height); if (isIntersectionOfRects) { *isIntersectionOfRects = true; } return; } SkRect devBounds; fStack->getConservativeBounds(-fOrigin.x(), -fOrigin.y(), width, height, &devBounds, isIntersectionOfRects); devBounds.roundOut(devResult); }
void SkMaskFilterBase::computeFastBounds(const SkRect& src, SkRect* dst) const { SkMask srcM, dstM; srcM.fBounds = src.roundOut(); srcM.fRowBytes = 0; srcM.fFormat = SkMask::kA8_Format; SkIPoint margin; // ignored if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) { dst->set(dstM.fBounds); } else { dst->set(srcM.fBounds); } }
bool makeMask(SkMask *m, const SkRect& r) override { SkMask src; r.roundOut(&src.fBounds); src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop); // move to origin src.fFormat = SkMask::kA8_Format; src.fRowBytes = src.fBounds.width(); src.fImage = SkMask::AllocImage(src.computeTotalImageSize()); SkAutoMaskFreeImage amfi(src.fImage); memset(src.fImage, 0xff, src.computeTotalImageSize()); return SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()), m, src, this->style()); }
void SkPictureImageFilter::drawPictureAtLocalResolution(SkSpecialImage* source, SkCanvas* canvas, const SkIRect& deviceBounds, const Context& ctx) const { SkMatrix inverseCtm; if (!ctx.ctm().invert(&inverseCtm)) { return; } SkRect localBounds = SkRect::Make(ctx.clipBounds()); inverseCtm.mapRect(&localBounds); if (!localBounds.intersect(fCropRect)) { return; } SkIRect localIBounds = localBounds.roundOut(); sk_sp<SkSpecialImage> localImg; { const SkImageInfo info = SkImageInfo::MakeN32(localIBounds.width(), localIBounds.height(), kPremul_SkAlphaType); sk_sp<SkSpecialSurface> localSurface(source->makeSurface(info)); if (!localSurface) { return; } SkCanvas* localCanvas = localSurface->getCanvas(); SkASSERT(localCanvas); localCanvas->translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop)); localCanvas->drawPicture(fPicture); localImg = localSurface->makeImageSnapshot(); SkASSERT(localImg); } { canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop)); canvas->concat(ctx.ctm()); SkPaint paint; paint.setFilterQuality(fFilterQuality); localImg->draw(canvas, SkIntToScalar(localIBounds.fLeft), SkIntToScalar(localIBounds.fTop), &paint); } }
void GrLayerHoister::FindLayersToHoist(GrContext* context, const SkPicture* topLevelPicture, const SkMatrix& initialMat, const SkRect& query, SkTDArray<GrHoistedLayer>* needRendering, SkTDArray<GrHoistedLayer>* recycled, int numSamples) { GrLayerCache* layerCache = context->getLayerCache(); layerCache->processDeletedPictures(); const SkBigPicture::AccelData* topLevelData = nullptr; if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) { topLevelData = bp->accelData(); } if (!topLevelData) { return; } const SkLayerInfo *topLevelGPUData = static_cast<const SkLayerInfo*>(topLevelData); if (0 == topLevelGPUData->numBlocks()) { return; } // Find and prepare for hoisting all the layers that intersect the query rect for (int i = 0; i < topLevelGPUData->numBlocks(); ++i) { const SkLayerInfo::BlockInfo& info = topLevelGPUData->block(i); if (info.fIsNested) { // Parent layers are currently hoisted while nested layers are not. continue; } SkRect layerRect; initialMat.mapRect(&layerRect, info.fBounds); if (!layerRect.intersect(query)) { continue; } const SkIRect dstIR = layerRect.roundOut(); SkIRect srcIR; if (!compute_source_rect(info, initialMat, dstIR, &srcIR)) { continue; } prepare_for_hoisting(layerCache, topLevelPicture, initialMat, info, srcIR, dstIR, needRendering, recycled, false, numSamples); } }
static void draw_bitmap(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imf) { SkPaint paint; SkIRect bounds; r.roundOut(&bounds); SkBitmap bm; bm.allocN32Pixels(bounds.width(), bounds.height()); bm.eraseColor(SK_ColorTRANSPARENT); SkCanvas c(bm); draw_path(&c, r, nullptr); paint.setImageFilter(std::move(imf)); canvas->drawBitmap(bm, 0, 0, &paint); }
GrTextContext::GrTextContext(GrContext* context, const GrPaint& paint) : fPaint(paint) { fContext = context; const GrClipData* clipData = context->getClip(); SkRect devConservativeBound; clipData->fClipStack->getConservativeBounds( -clipData->fOrigin.fX, -clipData->fOrigin.fY, context->getRenderTarget()->width(), context->getRenderTarget()->height(), &devConservativeBound); devConservativeBound.roundOut(&fClipRect); fDrawTarget = fContext->getTextTarget(); }
/* * Class: org_skia_canvasproof_GaneshPictureRenderer * Method: GetCullRect * Signature: (Landroid/graphics/Rect;J)V */ JNIEXPORT void JNICALL Java_org_skia_canvasproof_GaneshPictureRenderer_GetCullRect (JNIEnv *env, jclass, jobject androidGraphicsRect, jlong picturePtr) { SkASSERT(androidGraphicsRect); const SkPicture* picture = reinterpret_cast<SkPicture*>(picturePtr); SkRect rect = SkRect::MakeEmpty(); if (picture) { rect = picture->cullRect(); } SkIRect iRect; rect.roundOut(&iRect); static AndroidRectHelper help; help.config(env); env->SetIntField(androidGraphicsRect, help.fLeft, (jint)(iRect.left())); env->SetIntField(androidGraphicsRect, help.fTop, (jint)(iRect.top())); env->SetIntField(androidGraphicsRect, help.fRight, (jint)(iRect.right())); env->SetIntField(androidGraphicsRect, help.fBottom, (jint)(iRect.bottom())); }
void SkConservativeClip::opRect(const SkRect& localRect, const SkMatrix& ctm, const SkIRect& devBounds, SkRegion::Op op, bool doAA) { SkIRect ir; switch (mutate_conservative_op(&op, false)) { case kDoNothing_MutateResult: return; case kReplaceClippedAgainstGlobalBounds_MutateResult: ir = devBounds; break; case kContinue_MutateResult: { SkRect devRect; ctm.mapRect(&devRect, localRect); ir = doAA ? devRect.roundOut() : devRect.round(); } break; } this->opIRect(ir, op); }
void SkConservativeClip::opPath(const SkPath& path, const SkMatrix& ctm, const SkIRect& devBounds, SkRegion::Op op, bool doAA) { SkIRect ir; switch (mutate_conservative_op(&op, path.isInverseFillType())) { case kDoNothing_MutateResult: return; case kReplaceClippedAgainstGlobalBounds_MutateResult: ir = devBounds; break; case kContinue_MutateResult: { SkRect bounds = path.getBounds(); ctm.mapRect(&bounds); ir = bounds.roundOut(); break; } } return this->opIRect(ir, op); }
// Regular JNI static void nGetBounds(JNIEnv* env, jobject, jlong ptr, jcharArray javaText, jint start, jint end, jobject bounds) { ScopedCharArrayRO text(env, javaText); const minikin::U16StringPiece textBuffer(text.get(), text.size()); const minikin::Range range(start, end); minikin::MinikinRect rect = toMeasuredParagraph(ptr)->getBounds(textBuffer, range); SkRect r; r.fLeft = rect.mLeft; r.fTop = rect.mTop; r.fRight = rect.mRight; r.fBottom = rect.mBottom; SkIRect ir; r.roundOut(&ir); GraphicsJNI::irect_to_jrect(ir, env, bounds); }
static void draw_bitmap(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) { SkPaint paint; SkIRect bounds; r.roundOut(&bounds); SkBitmap bm; bm.allocN32Pixels(bounds.width(), bounds.height()); bm.eraseColor(SK_ColorTRANSPARENT); SkCanvas c(bm); draw_path(&c, r, NULL); paint.setImageFilter(imf); canvas->save(); canvas->clipRect(r); canvas->drawBitmap(bm, 0, 0, &paint); canvas->restore(); }
void SkRTree::insert(void* data, const SkRect& fbounds, bool defer) { SkIRect bounds; if (fbounds.isLargest()) { bounds.setLargest(); } else { fbounds.roundOut(&bounds); } this->validate(); if (bounds.isEmpty()) { SkASSERT(false); return; } Branch newBranch; newBranch.fBounds = bounds; newBranch.fChild.data = data; if (this->isEmpty()) { // since a bulk-load into an existing tree is as of yet unimplemented (and arguably not // of vital importance right now), we only batch up inserts if the tree is empty. if (defer) { fDeferredInserts.push(newBranch); return; } else { fRoot.fChild.subtree = allocateNode(0); fRoot.fChild.subtree->fNumChildren = 0; } } Branch* newSibling = insert(fRoot.fChild.subtree, &newBranch); fRoot.fBounds = this->computeBounds(fRoot.fChild.subtree); if (NULL != newSibling) { Node* oldRoot = fRoot.fChild.subtree; Node* newRoot = this->allocateNode(oldRoot->fLevel + 1); newRoot->fNumChildren = 2; *newRoot->child(0) = fRoot; *newRoot->child(1) = *newSibling; fRoot.fChild.subtree = newRoot; fRoot.fBounds = this->computeBounds(fRoot.fChild.subtree); } ++fCount; this->validate(); }
bool SkMatrixImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap src = source; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) { return false; } SkRect dstRect; SkIRect srcBounds, dstBounds; src.getBounds(&srcBounds); srcBounds.offset(srcOffset); SkRect srcRect = SkRect::Make(srcBounds); SkMatrix matrix; if (!ctx.ctm().invert(&matrix)) { return false; } matrix.postConcat(fTransform); matrix.postConcat(ctx.ctm()); matrix.mapRect(&dstRect, srcRect); dstRect.roundOut(&dstBounds); SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height())); if (NULL == device.get()) { return false; } SkCanvas canvas(device.get()); canvas.translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y())); canvas.concat(matrix); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); paint.setFilterLevel(fFilterLevel); canvas.drawBitmap(src, srcRect.x(), srcRect.y(), &paint); *result = device.get()->accessBitmap(false); offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; return true; }
void GrLayerHoister::FindLayersToHoist(GrContext* context, const SkPicture* topLevelPicture, const SkRect& query, SkTDArray<GrHoistedLayer>* needRendering, SkTDArray<GrHoistedLayer>* recycled) { GrLayerCache* layerCache = context->getLayerCache(); layerCache->processDeletedPictures(); SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key); if (!topLevelData) { return; } const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData); if (0 == topLevelGPUData->numSaveLayers()) { return; } // Find and prepare for hoisting all the layers that intersect the query rect for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i); if (info.fIsNested) { // Parent layers are currently hoisted while nested layers are not. continue; } SkRect layerRect = info.fBounds; if (!layerRect.intersect(query)) { continue; } SkIRect ir; layerRect.roundOut(&ir); prepare_for_hoisting(layerCache, topLevelPicture, info, ir, needRendering, recycled, false); } }