// we need fDst to be set, and if we're actually drawing, to dirty the genID if (!dev->accessPixels(&fRootPixmap)) { // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
fRootPixmap.reset(dev->imageInfo(), nullptr, 0);
}
// do a quick check, so we don't even have to process "bounds" if there is no need const SkIRect clipR = dev->fRCStack.rc().getBounds();
fNeedsTiling = clipR.right() > kMaxDim || clipR.bottom() > kMaxDim; if (fNeedsTiling) { if (bounds) { // Make sure we round first, and then intersect. We can't rely on promoting the // clipR to floats (and then intersecting with devBounds) since promoting // int --> float can make the float larger than the int. // rounding(out) first runs the risk of clamping if the float is larger an intmax // but our roundOut() is saturating, which is fine for this use case // // e.g. the older version of this code did this: // devBounds = mapRect(bounds); // if (devBounds.intersect(SkRect::Make(clipR))) { // fSrcBounds = devBounds.roundOut(); // The problem being that the promotion of clipR to SkRect was unreliable //
fSrcBounds = dev->localToDevice().mapRect(*bounds).roundOut(); if (fSrcBounds.intersect(clipR)) { // Check again, now that we have computed srcbounds.
fNeedsTiling = fSrcBounds.right() > kMaxDim || fSrcBounds.bottom() > kMaxDim;
} else {
fNeedsTiling = false;
fDone = true;
}
} else {
fSrcBounds = clipR;
}
}
if (fNeedsTiling) { // fDraw.fDst and fCTM are reset each time in setupTileDraw()
fDraw.fRC = &fTileRC; // we'll step/increase it before using it
fOrigin.set(fSrcBounds.fLeft - kMaxDim, fSrcBounds.fTop);
} else { // don't reference fSrcBounds, as it may not have been set
fDraw.fDst = fRootPixmap;
fDraw.fCTM = &dev->localToDevice();
fDraw.fRC = &dev->fRCStack.rc();
fOrigin.set(0, 0);
}
fDraw.fProps = &fDevice->surfaceProps();
}
bool needsTiling() const { return fNeedsTiling; }
const SkDraw* next() { if (fDone) { return nullptr;
} if (fNeedsTiling) { do {
this->stepAndSetupTileDraw(); // might set the clip to empty and fDone to true
} while (!fDone && fTileRC.isEmpty()); // if we exit the loop and we're still empty, we're (past) done if (fTileRC.isEmpty()) {
SkASSERT(fDone); return nullptr;
}
SkASSERT(!fTileRC.isEmpty());
} else {
fDone = true; // only draw untiled once
} return &fDraw;
}
// We do fRootPixmap.width() - kMaxDim instead of fOrigin.fX + kMaxDim to avoid overflow. if (fOrigin.fX >= fSrcBounds.fRight - kMaxDim) { // too far
fOrigin.fX = fSrcBounds.fLeft;
fOrigin.fY += kMaxDim;
} else {
fOrigin.fX += kMaxDim;
} // fDone = next origin will be invalid.
fDone = fOrigin.fX >= fSrcBounds.fRight - kMaxDim &&
fOrigin.fY >= fSrcBounds.fBottom - kMaxDim;
SkIRect bounds = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), kMaxDim, kMaxDim);
SkASSERT(!bounds.isEmpty()); bool success = fRootPixmap.extractSubset(&fDraw.fDst, bounds);
SkASSERT_RELEASE(success); // now don't use bounds, since fDst has the clipped dimensions.
// Passing a bounds allows the tiler to only visit the dst-tiles that might intersect the // drawing. If null is passed, the tiler has to visit everywhere. The bounds is expected to be // in local coordinates, as the tiler itself will transform that into device coordinates. // #define LOOP_TILER(code, boundsPtr) \
SkDrawTiler priv_tiler(this, boundsPtr); \ while (const SkDraw* priv_draw = priv_tiler.next()) { \
priv_draw->code; \
}
// Helper to create an SkDraw from a device class SkBitmapDevice::BDDraw : public SkDraw { public:
BDDraw(SkBitmapDevice* dev) { // we need fDst to be set, and if we're actually drawing, to dirty the genID if (!dev->accessPixels(&fDst)) { // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
fDst.reset(dev->imageInfo(), nullptr, 0);
}
fCTM = &dev->localToDevice();
fRC = &dev->fRCStack.rc();
}
};
if (kUnknown_SkColorType == info.colorType()) { if (!bitmap.setInfo(info)) { return nullptr;
}
} elseif (allocator) {
hndl = allocator->allocBitmap(info, &bitmap); if (!hndl) { return nullptr;
}
} elseif (info.isOpaque()) { // If this bitmap is opaque, we don't have any sensible default color, // so we just return uninitialized pixels. if (!bitmap.tryAllocPixels(info)) { return nullptr;
}
} else { // This bitmap has transparency, so we'll zero the pixels (to transparent). // We use the flag as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT). if (!bitmap.tryAllocPixelsFlags(info, SkBitmap::kZeroPixels_AllocFlag)) { return nullptr;
}
}
// Need to force L32 for now if we have an image filter. // If filters ever support other colortypes, e.g. F16, we can modify this check.
SkImageInfo info = cinfo.fInfo; if (layerPaint && layerPaint->getImageFilter()) { // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always // use N32 when the layer itself was float)?
info = info.makeColorType(kN32_SkColorType);
}
bool SkBitmapDevice::onWritePixels(const SkPixmap& pm, int x, int y) { // since we don't stop creating un-pixeled devices yet, check for no pixels here if (nullptr == fBitmap.getPixels()) { returnfalse;
}
if (fBitmap.writePixels(pm, x, y)) {
fBitmap.notifyPixelsChanged(); returntrue;
} returnfalse;
}
bool SkBitmapDevice::onReadPixels(const SkPixmap& pm, int x, int y) { return fBitmap.readPixels(pm, x, y);
}
void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) { // call the VIRTUAL version, so any subclasses who do handle drawPath aren't // required to override drawOval.
this->drawPath(SkPath::Oval(oval), paint, true);
}
void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) { #ifdef SK_IGNORE_BLURRED_RRECT_OPT // call the VIRTUAL version, so any subclasses who do handle drawPath aren't // required to override drawRRect.
this->drawPath(SkPath::RRect(rrect), paint, true); #else
LOOP_TILER( drawRRect(rrect, paint), Bounder(rrect.getBounds(), paint)) #endif
}
SkBitmap bitmap; // TODO: Elevate direct context requirement to public API and remove cheat. auto dContext = as_IB(image)->directContext(); if (!as_IB(image)->getROPixels(dContext, &bitmap)) { return;
}
// clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if // needed (if the src was clipped). No check needed if src==null. bool srcIsSubset = false; if (src) { if (!bitmapBounds.contains(*src)) { if (!tmpSrc.intersect(bitmapBounds)) { return; // nothing to draw
} // recompute dst, based on the smaller tmpSrc
matrix.mapRect(&tmpDst, tmpSrc); if (!tmpDst.isFinite()) { return;
}
dstPtr = &tmpDst;
}
srcIsSubset = !tmpSrc.contains(bitmapBounds);
}
if (srcIsSubset &&
SkCanvas::kFast_SrcRectConstraint == constraint &&
sampling != SkSamplingOptions()) { // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap, // but we must use a shader w/ dst bounds (which can access all of the bitmap needed). goto USE_SHADER;
}
if (srcIsSubset) { // since we may need to clamp to the borders of the src rect within // the bitmap, we extract a subset. const SkIRect srcIR = tmpSrc.roundOut(); if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { return;
}
bitmapPtr = &tmpBitmap;
// Since we did an extract, we need to adjust the matrix accordingly
SkScalar dx = 0, dy = 0; if (srcIR.fLeft > 0) {
dx = SkIntToScalar(srcIR.fLeft);
} if (srcIR.fTop > 0) {
dy = SkIntToScalar(srcIR.fTop);
} if (dx || dy) {
matrix.preTranslate(dx, dy);
}
#ifdef SK_DRAWBITMAPRECT_FAST_OFFSET
SkRect extractedBitmapBounds = SkRect::MakeXYWH(dx, dy,
SkIntToScalar(bitmapPtr->width()),
SkIntToScalar(bitmapPtr->height())); #else
SkRect extractedBitmapBounds;
extractedBitmapBounds.setIWH(bitmapPtr->width(), bitmapPtr->height()); #endif if (extractedBitmapBounds == tmpSrc) { // no fractional part in src, we can just call drawBitmap goto USE_DRAWBITMAP;
}
} else {
USE_DRAWBITMAP: // We can go faster by just calling drawBitmap, which will concat the // matrix with the CTM, and try to call drawSprite if it can. If not, // it will make a shader and call drawRect, as we do below. if (CanApplyDstMatrixAsCTM(matrix, paint)) {
this->drawBitmap(*bitmapPtr, matrix, dstPtr, sampling, paint); return;
}
}
USE_SHADER:
// construct a shader, so we can call drawRect with the dst auto s = SkMakeBitmapShaderForPaint(paint, *bitmapPtr, SkTileMode::kClamp, SkTileMode::kClamp,
sampling, &matrix, kNever_SkCopyPixelsMode); if (!s) { return;
}
// Call ourself, in case the subclass wanted to share this setup code // but handle the drawRect code themselves.
this->drawRect(*dstPtr, paintWithShader);
}
void SkBitmapDevice::drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) { // TODO: Implement, maybe with a subclass of BitmapDevice that has SkSL support.
}
void SkBitmapDevice::drawAtlas(const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count,
sk_sp<SkBlender> blender, const SkPaint& paint) { // set this to true for performance comparisons with the old drawVertices way if ((false)) {
this->SkDevice::drawAtlas(xform, tex, colors, count, std::move(blender), paint); return;
}
BDDraw(this).drawAtlas(xform, tex, colors, count, std::move(blender), paint);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.