/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file.
*/
// skbug.com/7813 // To ensure consistency of the threaded backend (a rect that's considered fat in the init-once // phase must also be considered fat in the draw phase), we have to deal with rects with small // heights because the horizontal tiling in the threaded backend may change the height. // // This also implies that we cannot do vertical tiling unless we can blit any rect (not just the // fat one.) if (bounds.height() == 0) { return;
}
int runSize = bounds.width() + 1; // +1 so we can set runs[bounds.width()] = 0 void* storage = this->allocBlitMemory(runSize * (sizeof(int16_t) + sizeof(SkAlpha)));
int16_t* runs = reinterpret_cast<int16_t*>(storage);
SkAlpha* alphas = reinterpret_cast<SkAlpha*>(runs + runSize);
void SkBlitter::blitRect(int x, int y, int width, int height) {
SkASSERT(width > 0); while (--height >= 0) {
this->blitH(x, y++, width);
}
}
/// Default implementation doesn't check for easy optimizations /// such as alpha == 255; also uses blitV(), which some subclasses /// may not support. void SkBlitter::blitAntiRect(int x, int y, int width, int height,
SkAlpha leftAlpha, SkAlpha rightAlpha) { if (leftAlpha > 0) { // we may send in x = -1 with leftAlpha = 0
this->blitV(x, y, height, leftAlpha);
}
x++; if (width > 0) {
this->blitRect(x, y, width, height);
x += width;
} if (rightAlpha > 0) {
this->blitV(x, y, height, rightAlpha);
}
}
staticinlinevoid bits_to_runs(SkBlitter* blitter, int x, int y, const uint8_t bits[],
uint8_t left_mask, ptrdiff_t rowBytes,
uint8_t right_mask) { int inFill = 0; int pos = 0;
while (--rowBytes >= 0) {
uint8_t b = *bits++ & left_mask; if (rowBytes == 0) {
b &= right_mask;
}
for (uint8_t test = 0x80U; test != 0; test >>= 1) { if (b & test) { if (!inFill) {
pos = x;
inFill = true;
}
} else { if (inFill) {
blitter->blitH(pos, y, x - pos);
inFill = false;
}
}
x += 1;
}
left_mask = 0xFFU;
}
// final cleanup if (inFill) {
blitter->blitH(pos, y, x - pos);
}
}
// maskBitCount is the number of 1's to place in the mask. It must be in the range between 1 and 8. static uint8_t generate_right_mask(int maskBitCount) { returnstatic_cast<uint8_t>((0xFF00U >> maskBitCount) & 0xFF);
}
if (mask.fFormat == SkMask::kLCD16_Format) { return; // needs to be handled by subclass
}
if (mask.fFormat == SkMask::kBW_Format) { int cx = clip.fLeft; int cy = clip.fTop; int maskLeft = mask.fBounds.fLeft; int maskRowBytes = mask.fRowBytes; int height = clip.height();
if (cx == maskLeft && clip.fRight == mask.fBounds.fRight) { while (--height >= 0) { int affectedRightBit = mask.fBounds.width() - 1;
ptrdiff_t rowBytes = (affectedRightBit >> 3) + 1;
SkASSERT(bits + rowBytes <= endOfImage);
U8CPU rightMask = generate_right_mask((affectedRightBit & 7) + 1);
bits_to_runs(this, cx, cy, bits, 0xFF, rowBytes, rightMask);
bits += maskRowBytes;
cy += 1;
}
} else { // Bits is calculated as the offset into the mask at the point {cx, cy} therefore, all // addressing into the bit mask is relative to that point. Since this is an address // calculated from a arbitrary bit in that byte, calculate the left most bit. int bitsLeft = cx - ((cx - maskLeft) & 7);
// Everything is relative to the bitsLeft. int leftEdge = cx - bitsLeft;
SkASSERT(leftEdge >= 0); int rightEdge = clip.fRight - bitsLeft;
SkASSERT(rightEdge > leftEdge);
// Calculate left byte and mask const uint8_t* leftByte = bits;
U8CPU leftMask = 0xFFU >> (leftEdge & 7);
// Calculate right byte and mask int affectedRightBit = rightEdge - 1; const uint8_t* rightByte = bits + (affectedRightBit >> 3);
U8CPU rightMask = generate_right_mask((affectedRightBit & 7) + 1);
// leftByte and rightByte are byte locations therefore, to get a count of bytes the // code must add one.
ptrdiff_t rowBytes = rightByte - leftByte + 1;
void SkRgnClipBlitter::blitH(int x, int y, int width) {
SkRegion::Spanerator span(*fRgn, y, x, x + width); int left, right;
while (span.next(&left, &right)) {
SkASSERT(left < right);
fBlitter->blitH(left, y, right - left);
}
}
void SkRgnClipBlitter::blitAntiH(int x, int y, const SkAlpha const_aa[], const int16_t const_runs[]) {
SkAlpha* aa = const_cast<SkAlpha*>(const_aa);
int16_t* runs = const_cast<int16_t*>(const_runs);
int width = compute_anti_width(runs);
SkRegion::Spanerator span(*fRgn, y, x, x + width); int left, right;
SkDEBUGCODE(const SkIRect& bounds = fRgn->getBounds();)
int prevRite = x; while (span.next(&left, &right)) {
SkASSERT(x <= left);
SkASSERT(left < right);
SkASSERT(left >= bounds.fLeft && right <= bounds.fRight);
SkAlphaRuns::Break((int16_t*)runs, (uint8_t*)aa, left - x, right - left);
// now zero before left if (left > prevRite) { int index = prevRite - x;
((uint8_t*)aa)[index] = 0; // skip runs after right
((int16_t*)runs)[index] = SkToS16(left - prevRite);
}
prevRite = right;
}
if (prevRite > x) {
((int16_t*)runs)[prevRite - x] = 0;
if (x < 0) { int skip = runs[0];
SkASSERT(skip >= -x);
aa += skip;
runs += skip;
x += skip;
}
fBlitter->blitAntiH(x, y, aa, runs);
}
}
void SkRgnClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
SkIRect bounds;
bounds.setXYWH(x, y, 1, height);
SkRegion::Cliperator iter(*fRgn, bounds);
while (!iter.done()) { const SkIRect& r = iter.rect();
SkASSERT(bounds.contains(r));
void SkRgnClipBlitter::blitAntiRect(int x, int y, int width, int height,
SkAlpha leftAlpha, SkAlpha rightAlpha) { // The *true* width of the rectangle to blit is width + 2
SkIRect bounds;
bounds.setXYWH(x, y, width + 2, height);
SkRegion::Cliperator iter(*fRgn, bounds);
while (!iter.done()) { const SkIRect& r = iter.rect();
SkASSERT(bounds.contains(r));
SkASSERT(r.fLeft >= x);
SkASSERT(r.fRight <= x + width + 2);
// The legacy blitters cannot handle any of these "complex" features (anymore). if (device.alphaType() == kUnpremul_SkAlphaType ||
!paint.isSrcOver() ||
(mf && mf->getFormat() == SkMask::k3D_Format)) { returnfalse;
}
auto cs = device.colorSpace(); // We check (indirectly via makeContext()) later on if the shader can handle the colorspace // in legacy mode, so here we just focus on if a single color needs raster-pipeline. if (cs && !paint.getShader()) { if (!paint.getColor4f().fitsInBytes() || !cs->isSRGB()) { returnfalse;
}
}
// Only kN32 is handled by legacy blitters now return device.colorType() == kN32_SkColorType; #endif
}
if (kUnknown_SkColorType == device.colorType()) { return alloc->make<SkNullBlitter>();
}
// We may tweak the original paint as we go.
SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
if (auto mode = paint->asBlendMode()) { // We have the most fast-paths for SrcOver, so see if we can act like SrcOver. if (mode.value() != SkBlendMode::kSrcOver) { switch (CheckFastPath(*paint, SkColorTypeIsAlwaysOpaque(device.colorType()))) { case SkBlendFastPath::kSrcOver:
paint.writable()->setBlendMode(SkBlendMode::kSrcOver); break; case SkBlendFastPath::kSkipDrawing: return alloc->make<SkNullBlitter>(); default: break;
}
}
// A Clear blend mode will ignore the entire color pipeline, as if Src mode with 0x00000000. if (mode.value() == SkBlendMode::kClear) {
SkPaint* p = paint.writable();
p->setShader(nullptr);
p->setColorFilter(nullptr);
p->setBlendMode(SkBlendMode::kSrc);
p->setColor(0x00000000);
}
}
if (paint->getColorFilter()) {
SkPaintPriv::RemoveColorFilter(paint.writable(), device.colorSpace());
}
SkASSERT(!paint->getColorFilter());
if (drawCoverage) { if (device.colorType() == kAlpha_8_SkColorType) {
SkASSERT(!paint->getShader());
SkASSERT(paint->isSrcOver()); return alloc->make<SkA8_Coverage_Blitter>(device, *paint);
} return alloc->make<SkNullBlitter>();
}
if (paint->isDither() && !SkPaintPriv::ShouldDither(*paint, device.colorType())) {
paint.writable()->setDither(false);
}
// We'll end here for many interesting cases: color spaces, color filters, most color types. if (clipShader || !UseLegacyBlitter(device, *paint, ctm)) { return CreateSkRPBlitter();
}
// Everything but legacy kN32_SkColorType should already be handled.
SkASSERT(device.colorType() == kN32_SkColorType);
// And we should be blending with SrcOver
SkASSERT(paint->asBlendMode() == SkBlendMode::kSrcOver);
// Legacy blitters keep their shader state on a shader context.
SkShaderBase::Context* shaderContext = nullptr; if (paint->getShader()) {
shaderContext = as_SB(paint->getShader())
->makeContext({paint->getAlpha(),
SkShaders::MatrixRec(ctm),
device.colorType(),
device.colorSpace(),
props},
alloc);
// Creating the context isn't always possible... try fallbacks before giving up. if (!shaderContext) { return CreateSkRPBlitter();
}
}
void SkRectClipCheckBlitter::blitH(int x, int y, int width) {
SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, 1)));
fBlitter->blitH(x, y, width);
}
void SkRectClipCheckBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) { const int16_t* iter = runs; for (; *iter; iter += *iter)
; int width = iter - runs;
SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, 1)));
fBlitter->blitAntiH(x, y, aa, runs);
}
void SkRectClipCheckBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 1, height)));
fBlitter->blitV(x, y, height, alpha);
}
void SkRectClipCheckBlitter::blitRect(int x, int y, int width, int height) {
SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, height)));
fBlitter->blitRect(x, y, width, height);
}
void SkRectClipCheckBlitter::blitAntiRect(int x, int y, int width, int height,
SkAlpha leftAlpha, SkAlpha rightAlpha) { bool skipLeft = !leftAlpha; bool skipRight = !rightAlpha;
SkIRect r = SkIRect::MakeXYWH(x + skipLeft, y, width + 2 - skipRight - skipLeft, height);
SkASSERT(r.isEmpty() || fClipRect.contains(r));
fBlitter->blitAntiRect(x, y, width, height, leftAlpha, rightAlpha);
}
void SkRectClipCheckBlitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 2, 1)));
fBlitter->blitAntiH2(x, y, a0, a1);
}
void SkRectClipCheckBlitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 1, 2)));
fBlitter->blitAntiV2(x, y, a0, a1);
}
#endif
Messung V0.5
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet)
¤
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.