| /* libs/graphics/sgl/SkBlitter.cpp |
| ** |
| ** Copyright 2006, The Android Open Source Project |
| ** |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| #include "SkBlitter.h" |
| #include "SkAntiRun.h" |
| #include "SkColor.h" |
| #include "SkColorFilter.h" |
| #include "SkMask.h" |
| #include "SkMaskFilter.h" |
| #include "SkTemplatesPriv.h" |
| #include "SkUtils.h" |
| #include "SkXfermode.h" |
| |
| SkBlitter::~SkBlitter() |
| { |
| } |
| |
| const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) |
| { |
| return NULL; |
| } |
| |
| void SkBlitter::blitH(int x, int y, int width) |
| { |
| SkASSERT(!"unimplemented"); |
| } |
| |
| void SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) |
| { |
| SkASSERT(!"unimplemented"); |
| } |
| |
| void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) |
| { |
| if (alpha == 255) |
| this->blitRect(x, y, 1, height); |
| else |
| { |
| int16_t runs[2]; |
| runs[0] = 1; |
| runs[1] = 0; |
| |
| while (--height >= 0) |
| this->blitAntiH(x, y++, &alpha, runs); |
| } |
| } |
| |
| void SkBlitter::blitRect(int x, int y, int width, int height) |
| { |
| while (--height >= 0) |
| this->blitH(x, y++, width); |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| static inline void bits_to_runs(SkBlitter* blitter, int x, int y, const uint8_t bits[], |
| U8CPU left_mask, int rowBytes, U8CPU right_mask) |
| { |
| int inFill = 0; |
| int pos = 0; |
| |
| while (--rowBytes >= 0) |
| { |
| unsigned b = *bits++ & left_mask; |
| if (rowBytes == 0) |
| b &= right_mask; |
| |
| for (unsigned test = 0x80; 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 = 0xFF; |
| } |
| |
| // final cleanup |
| if (inFill) |
| blitter->blitH(pos, y, x - pos); |
| } |
| |
| void SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) |
| { |
| SkASSERT(mask.fBounds.contains(clip)); |
| |
| if (mask.fFormat == SkMask::kBW_Format) |
| { |
| int cx = clip.fLeft; |
| int cy = clip.fTop; |
| int maskLeft = mask.fBounds.fLeft; |
| int mask_rowBytes = mask.fRowBytes; |
| int height = clip.height(); |
| |
| const uint8_t* bits = mask.getAddr1(cx, cy); |
| |
| if (cx == maskLeft && clip.fRight == mask.fBounds.fRight) |
| { |
| while (--height >= 0) |
| { |
| bits_to_runs(this, cx, cy, bits, 0xFF, mask_rowBytes, 0xFF); |
| bits += mask_rowBytes; |
| cy += 1; |
| } |
| } |
| else |
| { |
| int left_edge = cx - maskLeft; |
| SkASSERT(left_edge >= 0); |
| int rite_edge = clip.fRight - maskLeft; |
| SkASSERT(rite_edge > left_edge); |
| |
| int left_mask = 0xFF >> (left_edge & 7); |
| int rite_mask = 0xFF << (8 - (rite_edge & 7)); |
| int full_runs = (rite_edge >> 3) - ((left_edge + 7) >> 3); |
| |
| // check for empty right mask, so we don't read off the end (or go slower than we need to) |
| if (rite_mask == 0) |
| { |
| SkASSERT(full_runs >= 0); |
| full_runs -= 1; |
| rite_mask = 0xFF; |
| } |
| if (left_mask == 0xFF) |
| full_runs -= 1; |
| |
| // back up manually so we can keep in sync with our byte-aligned src |
| // have cx reflect our actual starting x-coord |
| cx -= left_edge & 7; |
| |
| if (full_runs < 0) |
| { |
| SkASSERT((left_mask & rite_mask) != 0); |
| while (--height >= 0) |
| { |
| bits_to_runs(this, cx, cy, bits, left_mask, 1, rite_mask); |
| bits += mask_rowBytes; |
| cy += 1; |
| } |
| } |
| else |
| { |
| while (--height >= 0) |
| { |
| bits_to_runs(this, cx, cy, bits, left_mask, full_runs + 2, rite_mask); |
| bits += mask_rowBytes; |
| cy += 1; |
| } |
| } |
| } |
| } |
| else |
| { |
| int width = clip.width(); |
| SkAutoSTMalloc<64, int16_t> runStorage(width + 1); |
| int16_t* runs = runStorage.get(); |
| const uint8_t* aa = mask.getAddr(clip.fLeft, clip.fTop); |
| |
| sk_memset16((uint16_t*)runs, 1, width); |
| runs[width] = 0; |
| |
| int height = clip.height(); |
| int y = clip.fTop; |
| while (--height >= 0) |
| { |
| this->blitAntiH(clip.fLeft, y, aa, runs); |
| aa += mask.fRowBytes; |
| y += 1; |
| } |
| } |
| } |
| |
| /////////////////////// these guys are not virtual, just a helpers |
| |
| void SkBlitter::blitMaskRegion(const SkMask& mask, const SkRegion& clip) { |
| if (clip.quickReject(mask.fBounds)) { |
| return; |
| } |
| |
| SkRegion::Cliperator clipper(clip, mask.fBounds); |
| |
| while (!clipper.done()) { |
| const SkIRect& cr = clipper.rect(); |
| this->blitMask(mask, cr); |
| clipper.next(); |
| } |
| } |
| |
| void SkBlitter::blitRectRegion(const SkIRect& rect, const SkRegion& clip) { |
| SkRegion::Cliperator clipper(clip, rect); |
| |
| while (!clipper.done()) { |
| const SkIRect& cr = clipper.rect(); |
| this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height()); |
| clipper.next(); |
| } |
| } |
| |
| void SkBlitter::blitRegion(const SkRegion& clip) { |
| SkRegion::Iterator iter(clip); |
| |
| while (!iter.done()) { |
| const SkIRect& cr = iter.rect(); |
| this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height()); |
| iter.next(); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////////////// |
| |
| void SkNullBlitter::blitH(int x, int y, int width) |
| { |
| } |
| |
| void SkNullBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) |
| { |
| } |
| |
| void SkNullBlitter::blitV(int x, int y, int height, SkAlpha alpha) |
| { |
| } |
| |
| void SkNullBlitter::blitRect(int x, int y, int width, int height) |
| { |
| } |
| |
| void SkNullBlitter::blitMask(const SkMask& mask, const SkIRect& clip) |
| { |
| } |
| |
| const SkBitmap* SkNullBlitter::justAnOpaqueColor(uint32_t* value) |
| { |
| return NULL; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////////////// |
| |
| static int compute_anti_width(const int16_t runs[]) |
| { |
| int width = 0; |
| |
| for (;;) |
| { |
| int count = runs[0]; |
| |
| SkASSERT(count >= 0); |
| if (count == 0) |
| break; |
| width += count; |
| runs += count; |
| |
| SkASSERT(width < 20000); |
| } |
| return width; |
| } |
| |
| static inline bool y_in_rect(int y, const SkIRect& rect) |
| { |
| return (unsigned)(y - rect.fTop) < (unsigned)rect.height(); |
| } |
| |
| static inline bool x_in_rect(int x, const SkIRect& rect) |
| { |
| return (unsigned)(x - rect.fLeft) < (unsigned)rect.width(); |
| } |
| |
| void SkRectClipBlitter::blitH(int left, int y, int width) |
| { |
| SkASSERT(width > 0); |
| |
| if (!y_in_rect(y, fClipRect)) |
| return; |
| |
| int right = left + width; |
| |
| if (left < fClipRect.fLeft) |
| left = fClipRect.fLeft; |
| if (right > fClipRect.fRight) |
| right = fClipRect.fRight; |
| |
| width = right - left; |
| if (width > 0) |
| fBlitter->blitH(left, y, width); |
| } |
| |
| void SkRectClipBlitter::blitAntiH(int left, int y, const SkAlpha aa[], const int16_t runs[]) |
| { |
| if (!y_in_rect(y, fClipRect) || left >= fClipRect.fRight) |
| return; |
| |
| int x0 = left; |
| int x1 = left + compute_anti_width(runs); |
| |
| if (x1 <= fClipRect.fLeft) |
| return; |
| |
| SkASSERT(x0 < x1); |
| if (x0 < fClipRect.fLeft) |
| { |
| int dx = fClipRect.fLeft - x0; |
| SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, dx); |
| runs += dx; |
| aa += dx; |
| x0 = fClipRect.fLeft; |
| } |
| |
| SkASSERT(x0 < x1 && runs[x1 - x0] == 0); |
| if (x1 > fClipRect.fRight) |
| { |
| x1 = fClipRect.fRight; |
| SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, x1 - x0); |
| ((int16_t*)runs)[x1 - x0] = 0; |
| } |
| |
| SkASSERT(x0 < x1 && runs[x1 - x0] == 0); |
| SkASSERT(compute_anti_width(runs) == x1 - x0); |
| |
| fBlitter->blitAntiH(x0, y, aa, runs); |
| } |
| |
| void SkRectClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) |
| { |
| SkASSERT(height > 0); |
| |
| if (!x_in_rect(x, fClipRect)) |
| return; |
| |
| int y0 = y; |
| int y1 = y + height; |
| |
| if (y0 < fClipRect.fTop) |
| y0 = fClipRect.fTop; |
| if (y1 > fClipRect.fBottom) |
| y1 = fClipRect.fBottom; |
| |
| if (y0 < y1) |
| fBlitter->blitV(x, y0, y1 - y0, alpha); |
| } |
| |
| void SkRectClipBlitter::blitRect(int left, int y, int width, int height) |
| { |
| SkIRect r; |
| |
| r.set(left, y, left + width, y + height); |
| if (r.intersect(fClipRect)) |
| fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height()); |
| } |
| |
| void SkRectClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) |
| { |
| SkASSERT(mask.fBounds.contains(clip)); |
| |
| SkIRect r = clip; |
| |
| if (r.intersect(fClipRect)) |
| fBlitter->blitMask(mask, r); |
| } |
| |
| const SkBitmap* SkRectClipBlitter::justAnOpaqueColor(uint32_t* value) |
| { |
| return fBlitter->justAnOpaqueColor(value); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////////////// |
| |
| 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 aa[], const int16_t 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.set(x, y, x + 1, y + height); |
| |
| SkRegion::Cliperator iter(*fRgn, bounds); |
| |
| while (!iter.done()) |
| { |
| const SkIRect& r = iter.rect(); |
| SkASSERT(bounds.contains(r)); |
| |
| fBlitter->blitV(x, r.fTop, r.height(), alpha); |
| iter.next(); |
| } |
| } |
| |
| void SkRgnClipBlitter::blitRect(int x, int y, int width, int height) |
| { |
| SkIRect bounds; |
| bounds.set(x, y, x + width, y + height); |
| |
| SkRegion::Cliperator iter(*fRgn, bounds); |
| |
| while (!iter.done()) |
| { |
| const SkIRect& r = iter.rect(); |
| SkASSERT(bounds.contains(r)); |
| |
| fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height()); |
| iter.next(); |
| } |
| } |
| |
| void SkRgnClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) |
| { |
| SkASSERT(mask.fBounds.contains(clip)); |
| |
| SkRegion::Cliperator iter(*fRgn, clip); |
| const SkIRect& r = iter.rect(); |
| SkBlitter* blitter = fBlitter; |
| |
| while (!iter.done()) |
| { |
| blitter->blitMask(mask, r); |
| iter.next(); |
| } |
| } |
| |
| const SkBitmap* SkRgnClipBlitter::justAnOpaqueColor(uint32_t* value) |
| { |
| return fBlitter->justAnOpaqueColor(value); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////////////// |
| |
| SkBlitter* SkBlitterClipper::apply(SkBlitter* blitter, const SkRegion* clip, const SkIRect* ir) |
| { |
| if (clip) |
| { |
| const SkIRect& clipR = clip->getBounds(); |
| |
| if (clip->isEmpty() || (ir && !SkIRect::Intersects(clipR, *ir))) |
| blitter = &fNullBlitter; |
| else if (clip->isRect()) |
| { |
| if (ir == NULL || !clipR.contains(*ir)) |
| { |
| fRectBlitter.init(blitter, clipR); |
| blitter = &fRectBlitter; |
| } |
| } |
| else |
| { |
| fRgnBlitter.init(blitter, clip); |
| blitter = &fRgnBlitter; |
| } |
| } |
| return blitter; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////////////// |
| |
| #include "SkColorShader.h" |
| #include "SkColorPriv.h" |
| |
| class Sk3DShader : public SkShader { |
| public: |
| Sk3DShader(SkShader* proxy) : fProxy(proxy) |
| { |
| proxy->safeRef(); |
| fMask = NULL; |
| } |
| virtual ~Sk3DShader() |
| { |
| fProxy->safeUnref(); |
| } |
| void setMask(const SkMask* mask) { fMask = mask; } |
| |
| virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix) |
| { |
| if (fProxy) |
| return fProxy->setContext(device, paint, matrix); |
| else |
| { |
| fPMColor = SkPreMultiplyColor(paint.getColor()); |
| return this->INHERITED::setContext(device, paint, matrix); |
| } |
| } |
| virtual void shadeSpan(int x, int y, SkPMColor span[], int count) |
| { |
| if (fProxy) |
| fProxy->shadeSpan(x, y, span, count); |
| |
| if (fMask == NULL) |
| { |
| if (fProxy == NULL) |
| sk_memset32(span, fPMColor, count); |
| return; |
| } |
| |
| SkASSERT(fMask->fBounds.contains(x, y)); |
| SkASSERT(fMask->fBounds.contains(x + count - 1, y)); |
| |
| size_t size = fMask->computeImageSize(); |
| const uint8_t* alpha = fMask->getAddr(x, y); |
| const uint8_t* mulp = alpha + size; |
| const uint8_t* addp = mulp + size; |
| |
| if (fProxy) |
| { |
| for (int i = 0; i < count; i++) |
| { |
| if (alpha[i]) |
| { |
| SkPMColor c = span[i]; |
| if (c) |
| { |
| unsigned a = SkGetPackedA32(c); |
| unsigned r = SkGetPackedR32(c); |
| unsigned g = SkGetPackedG32(c); |
| unsigned b = SkGetPackedB32(c); |
| |
| unsigned mul = SkAlpha255To256(mulp[i]); |
| unsigned add = addp[i]; |
| |
| r = SkFastMin32(SkAlphaMul(r, mul) + add, a); |
| g = SkFastMin32(SkAlphaMul(g, mul) + add, a); |
| b = SkFastMin32(SkAlphaMul(b, mul) + add, a); |
| |
| span[i] = SkPackARGB32(a, r, g, b); |
| } |
| } |
| else |
| span[i] = 0; |
| } |
| } |
| else // color |
| { |
| unsigned a = SkGetPackedA32(fPMColor); |
| unsigned r = SkGetPackedR32(fPMColor); |
| unsigned g = SkGetPackedG32(fPMColor); |
| unsigned b = SkGetPackedB32(fPMColor); |
| for (int i = 0; i < count; i++) |
| { |
| if (alpha[i]) |
| { |
| unsigned mul = SkAlpha255To256(mulp[i]); |
| unsigned add = addp[i]; |
| |
| span[i] = SkPackARGB32( a, |
| SkFastMin32(SkAlphaMul(r, mul) + add, a), |
| SkFastMin32(SkAlphaMul(g, mul) + add, a), |
| SkFastMin32(SkAlphaMul(b, mul) + add, a)); |
| } |
| else |
| span[i] = 0; |
| } |
| } |
| } |
| |
| virtual void beginSession() |
| { |
| this->INHERITED::beginSession(); |
| if (fProxy) |
| fProxy->beginSession(); |
| } |
| |
| virtual void endSession() |
| { |
| if (fProxy) |
| fProxy->endSession(); |
| this->INHERITED::endSession(); |
| } |
| |
| protected: |
| Sk3DShader(SkFlattenableReadBuffer& buffer) : |
| INHERITED(buffer) |
| { |
| fProxy = static_cast<SkShader*>(buffer.readFlattenable()); |
| fPMColor = buffer.readU32(); |
| fMask = NULL; |
| } |
| |
| virtual void flatten(SkFlattenableWriteBuffer& buffer) |
| { |
| this->INHERITED::flatten(buffer); |
| buffer.writeFlattenable(fProxy); |
| buffer.write32(fPMColor); |
| } |
| |
| virtual Factory getFactory() |
| { |
| return CreateProc; |
| } |
| |
| private: |
| static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) |
| { |
| return SkNEW_ARGS(Sk3DShader, (buffer)); |
| } |
| |
| SkShader* fProxy; |
| SkPMColor fPMColor; |
| const SkMask* fMask; |
| |
| typedef SkShader INHERITED; |
| }; |
| |
| class Sk3DBlitter : public SkBlitter { |
| public: |
| Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader, void (*killProc)(void*)) |
| : fProxy(proxy), f3DShader(shader), fKillProc(killProc) |
| { |
| shader->ref(); |
| } |
| virtual ~Sk3DBlitter() |
| { |
| f3DShader->unref(); |
| fKillProc(fProxy); |
| } |
| |
| virtual void blitH(int x, int y, int width) |
| { |
| fProxy->blitH(x, y, width); |
| } |
| virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) |
| { |
| fProxy->blitAntiH(x, y, antialias, runs); |
| } |
| virtual void blitV(int x, int y, int height, SkAlpha alpha) |
| { |
| fProxy->blitV(x, y, height, alpha); |
| } |
| virtual void blitRect(int x, int y, int width, int height) |
| { |
| fProxy->blitRect(x, y, width, height); |
| } |
| virtual void blitMask(const SkMask& mask, const SkIRect& clip) |
| { |
| if (mask.fFormat == SkMask::k3D_Format) |
| { |
| f3DShader->setMask(&mask); |
| |
| ((SkMask*)&mask)->fFormat = SkMask::kA8_Format; |
| fProxy->blitMask(mask, clip); |
| ((SkMask*)&mask)->fFormat = SkMask::k3D_Format; |
| |
| f3DShader->setMask(NULL); |
| } |
| else |
| fProxy->blitMask(mask, clip); |
| } |
| private: |
| SkBlitter* fProxy; |
| Sk3DShader* f3DShader; |
| void (*fKillProc)(void*); |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////////////// |
| |
| #include "SkCoreBlitters.h" |
| |
| class SkAutoRestoreShader { |
| public: |
| SkAutoRestoreShader(const SkPaint& p) : fPaint((SkPaint*)&p) |
| { |
| fShader = fPaint->getShader(); |
| fShader->safeRef(); |
| } |
| ~SkAutoRestoreShader() |
| { |
| fPaint->setShader(fShader); |
| fShader->safeUnref(); |
| } |
| private: |
| SkPaint* fPaint; |
| SkShader* fShader; |
| }; |
| |
| class SkAutoCallProc { |
| public: |
| typedef void (*Proc)(void*); |
| SkAutoCallProc(void* obj, Proc proc) |
| : fObj(obj), fProc(proc) |
| { |
| } |
| ~SkAutoCallProc() |
| { |
| if (fObj && fProc) |
| fProc(fObj); |
| } |
| void* get() const { return fObj; } |
| void* detach() |
| { |
| void* obj = fObj; |
| fObj = NULL; |
| return obj; |
| } |
| private: |
| void* fObj; |
| Proc fProc; |
| }; |
| |
| static void destroy_blitter(void* blitter) |
| { |
| ((SkBlitter*)blitter)->~SkBlitter(); |
| } |
| |
| static void delete_blitter(void* blitter) |
| { |
| SkDELETE((SkBlitter*)blitter); |
| } |
| |
| static bool just_solid_color(const SkPaint& paint) { |
| if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) { |
| SkShader* shader = paint.getShader(); |
| if (NULL == shader || |
| (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** By analyzing the paint (with an xfermode), we may decide we can take |
| special action. This enum lists our possible actions |
| */ |
| enum XferInterp { |
| kNormal_XferInterp, // no special interpretation, draw normally |
| kSrcOver_XferInterp, // draw as if in srcover mode |
| kSkipDrawing_XferInterp // draw nothing |
| }; |
| |
| static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer, |
| SkBitmap::Config deviceConfig) { |
| SkPorterDuff::Mode mode; |
| |
| if (SkPorterDuff::IsMode(xfer, &mode)) { |
| switch (mode) { |
| case SkPorterDuff::kSrc_Mode: |
| if (just_solid_color(paint)) { |
| return kSrcOver_XferInterp; |
| } |
| break; |
| case SkPorterDuff::kDst_Mode: |
| return kSkipDrawing_XferInterp; |
| case SkPorterDuff::kSrcOver_Mode: |
| return kSrcOver_XferInterp; |
| case SkPorterDuff::kDstOver_Mode: |
| if (SkBitmap::kRGB_565_Config == deviceConfig) { |
| return kSkipDrawing_XferInterp; |
| } |
| break; |
| case SkPorterDuff::kSrcIn_Mode: |
| if (SkBitmap::kRGB_565_Config == deviceConfig && |
| just_solid_color(paint)) { |
| return kSrcOver_XferInterp; |
| } |
| break; |
| case SkPorterDuff::kDstIn_Mode: |
| if (just_solid_color(paint)) { |
| return kSkipDrawing_XferInterp; |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| return kNormal_XferInterp; |
| } |
| |
| SkBlitter* SkBlitter::Choose(const SkBitmap& device, |
| const SkMatrix& matrix, |
| const SkPaint& paint, |
| void* storage, size_t storageSize) |
| { |
| SkASSERT(storageSize == 0 || storage != NULL); |
| |
| SkBlitter* blitter = NULL; |
| |
| // which check, in case we're being called by a client with a dummy device |
| // (e.g. they have a bounder that always aborts the draw) |
| if (SkBitmap::kNo_Config == device.getConfig()) |
| { |
| SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); |
| return blitter; |
| } |
| |
| SkAutoRestoreShader restore(paint); |
| SkShader* shader = paint.getShader(); |
| |
| Sk3DShader* shader3D = NULL; |
| if (paint.getMaskFilter() != NULL && paint.getMaskFilter()->getFormat() == SkMask::k3D_Format) |
| { |
| shader3D = SkNEW_ARGS(Sk3DShader, (shader)); |
| ((SkPaint*)&paint)->setShader(shader3D)->unref(); |
| shader = shader3D; |
| } |
| |
| SkXfermode* mode = paint.getXfermode(); |
| if (NULL != mode) { |
| switch (interpret_xfermode(paint, mode, device.config())) { |
| case kSrcOver_XferInterp: |
| mode = NULL; |
| break; |
| case kSkipDrawing_XferInterp: |
| SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); |
| return blitter; |
| default: |
| break; |
| } |
| } |
| |
| if (NULL == shader && (NULL != mode || paint.getColorFilter() != NULL)) |
| { |
| // xfermodes require shaders for our current set of blitters |
| shader = SkNEW(SkColorShader); |
| ((SkPaint*)&paint)->setShader(shader)->unref(); |
| } |
| |
| if (paint.getColorFilter() != NULL) |
| { |
| SkASSERT(shader); |
| shader = SkNEW_ARGS(SkFilterShader, (shader, paint.getColorFilter())); |
| ((SkPaint*)&paint)->setShader(shader)->unref(); |
| } |
| |
| bool doDither = paint.isDither(); |
| |
| if (shader) |
| { |
| if (!shader->setContext(device, paint, matrix)) |
| return SkNEW(SkNullBlitter); |
| |
| // disable dither if our shader is natively 16bit (no need to upsample) |
| if (shader->getFlags() & SkShader::kIntrinsicly16_Flag) |
| doDither = false; |
| } |
| |
| switch (device.getConfig()) { |
| case SkBitmap::kA1_Config: |
| SK_PLACEMENT_NEW_ARGS(blitter, SkA1_Blitter, storage, storageSize, (device, paint)); |
| break; |
| |
| case SkBitmap::kA8_Config: |
| if (shader) |
| SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Shader_Blitter, storage, storageSize, (device, paint)); |
| else |
| SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Blitter, storage, storageSize, (device, paint)); |
| break; |
| |
| case SkBitmap::kARGB_4444_Config: |
| blitter = SkBlitter_ChooseD4444(device, paint, storage, storageSize); |
| break; |
| |
| case SkBitmap::kRGB_565_Config: |
| if (shader) |
| { |
| if (mode) |
| SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Xfermode_Blitter, storage, storageSize, (device, paint)); |
| else if (SkShader::CanCallShadeSpan16(shader->getFlags()) && !doDither) |
| SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader16_Blitter, storage, storageSize, (device, paint)); |
| else |
| SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Blitter, storage, storageSize, (device, paint)); |
| } |
| else if (paint.getColor() == SK_ColorBLACK) |
| SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Black_Blitter, storage, storageSize, (device, paint)); |
| else |
| SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Blitter, storage, storageSize, (device, paint)); |
| break; |
| |
| case SkBitmap::kARGB_8888_Config: |
| if (shader) |
| SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Shader_Blitter, storage, storageSize, (device, paint)); |
| else if (paint.getColor() == SK_ColorBLACK) |
| SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Black_Blitter, storage, storageSize, (device, paint)); |
| else if (paint.getAlpha() == 0xFF) |
| SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Opaque_Blitter, storage, storageSize, (device, paint)); |
| else |
| SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Blitter, storage, storageSize, (device, paint)); |
| break; |
| |
| default: |
| SkASSERT(!"unsupported device config"); |
| SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); |
| } |
| |
| if (shader3D) |
| { |
| void (*proc)(void*) = ((void*)storage == (void*)blitter) ? destroy_blitter : delete_blitter; |
| SkAutoCallProc tmp(blitter, proc); |
| |
| blitter = SkNEW_ARGS(Sk3DBlitter, (blitter, shader3D, proc)); |
| (void)tmp.detach(); |
| } |
| return blitter; |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| const uint16_t gMask_0F0F = 0xF0F; |
| const uint32_t gMask_00FF00FF = 0xFF00FF; |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint) |
| : INHERITED(device) |
| { |
| fShader = paint.getShader(); |
| SkASSERT(fShader); |
| |
| fShader->ref(); |
| fShader->beginSession(); |
| } |
| |
| SkShaderBlitter::~SkShaderBlitter() |
| { |
| fShader->endSession(); |
| fShader->unref(); |
| } |
| |