diff options
-rw-r--r-- | include/core/SkBitmap.h | 16 | ||||
-rw-r--r-- | include/core/SkCanvas.h | 5 | ||||
-rw-r--r-- | src/core/SkBitmap.cpp | 21 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 67 |
4 files changed, 109 insertions, 0 deletions
diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index 2d5fc41..e125924 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -551,6 +551,17 @@ public: void flatten(SkFlattenableWriteBuffer&) const; void unflatten(SkFlattenableReadBuffer&); + /** Get the unscaled version of this SkBitmap (may be null; in fact it usually will be) + */ + SkBitmap* unscaledBitmap() const { return fUnscaledBitmap; } + + /** Assign an unscaled bitmap so we can do some transforms with it + * TODO do some basic error-checking (make sure URIs match?) + */ + SkBitmap* setUnscaledBitmap(SkBitmap* unscaledBitmap) { return fUnscaledBitmap = unscaledBitmap; } + + void freeUnscaledBitmap(); + SkDEBUGCODE(void validate() const;) class Allocator : public SkRefCnt { @@ -611,6 +622,11 @@ private: // pixels (e.g. as a gpu texture) mutable int fRawPixelGenerationID; + // Holds shadow copy of this bitmap in cases where it was pre-upscaled, and + // we want to retain the original for possible performance improvements in + // later transformations + mutable SkBitmap* fUnscaledBitmap; + enum Flags { kImageIsOpaque_Flag = 0x01, kImageIsVolatile_Flag = 0x02, diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 1b9f055..97d6800 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -894,6 +894,9 @@ public: void setExternalMatrix(const SkMatrix* = NULL); + virtual void drawBitmapScalarRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint = NULL); + /////////////////////////////////////////////////////////////////////////// /** After calling saveLayer(), there can be any number of devices that make @@ -983,6 +986,8 @@ private: const SkPaint* paint); void internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, const SkRect& dst, const SkPaint* paint); + void internalDrawBitmapScalarRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint); void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint); void internalDrawPaint(const SkPaint& paint); diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index 0b98513..84bb9b2 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -116,6 +116,7 @@ SkBitmap& SkBitmap::operator=(const SkBitmap& src) { } else { // we have a pixelref, so pixels/ctable reflect it // ignore the values from the memcpy fPixels = NULL; + fUnscaledBitmap = NULL; fColorTable = NULL; // Note that what to for genID is somewhat arbitrary. We have no // way to track changes to raw pixels across multiple SkBitmaps. @@ -137,6 +138,7 @@ void SkBitmap::swap(SkBitmap& other) { SkTSwap(fPixelLockCount, other.fPixelLockCount); SkTSwap(fMipMap, other.fMipMap); SkTSwap(fPixels, other.fPixels); + SkTSwap(fUnscaledBitmap, other.fUnscaledBitmap); SkTSwap(fRawPixelGenerationID, other.fRawPixelGenerationID); SkTSwap(fRowBytes, other.fRowBytes); SkTSwap(fWidth, other.fWidth); @@ -291,10 +293,18 @@ void SkBitmap::updatePixelsFromRef() const { p = (char*)p + fPixelRefOffset; } fPixels = p; + if (NULL != fUnscaledBitmap) { + delete fUnscaledBitmap; + fUnscaledBitmap = NULL; + } SkRefCnt_SafeAssign(fColorTable, fPixelRef->colorTable()); } else { SkASSERT(0 == fPixelLockCount); fPixels = NULL; + if (NULL != fUnscaledBitmap) { + delete fUnscaledBitmap; + fUnscaledBitmap = NULL; + } if (fColorTable) { fColorTable->unref(); fColorTable = NULL; @@ -377,6 +387,8 @@ void SkBitmap::freePixels() { fColorTable = NULL; } + freeUnscaledBitmap(); + if (NULL != fPixelRef) { if (fPixelLockCount > 0) { fPixelRef->unlockPixels(); @@ -389,6 +401,13 @@ void SkBitmap::freePixels() { fPixels = NULL; } +void SkBitmap::freeUnscaledBitmap() { + if (NULL != fUnscaledBitmap) { + delete fUnscaledBitmap; + fUnscaledBitmap = NULL; + } +} + void SkBitmap::freeMipMap() { if (fMipMap) { fMipMap->unref(); @@ -888,6 +907,7 @@ bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const { // did we get lucky and we can just return tmpSrc? if (tmpSrc.config() == dstConfig && NULL == alloc) { dst->swap(tmpSrc); + dst->fUnscaledBitmap = NULL; return true; } @@ -950,6 +970,7 @@ bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const { tmpDst.setIsOpaque(src->isOpaque()); dst->swap(tmpDst); + dst->fUnscaledBitmap = NULL; return true; } diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 0e26728..7ee6b94 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1490,12 +1490,79 @@ void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src this->internalDrawBitmap(*bitmapPtr, src, matrix, paint); } +// this one is non-virtual, so it can be called safely by other canvas apis +void SkCanvas::internalDrawBitmapScalarRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint) { + SkIRect srcRounded, *srcRoundedPtr = NULL; + + if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { + return; + } + + if (NULL != src) { + srcRoundedPtr = &srcRounded; + src->roundOut(srcRoundedPtr); + } + + // do this now, to avoid the cost of calling extract for RLE bitmaps + if (NULL == paint || paint->canComputeFastBounds()) { + SkRect storage; + const SkRect* bounds = &dst; + if (paint) { + bounds = &paint->computeFastBounds(dst, &storage); + } + if (this->quickReject(*bounds, paint2EdgeType(paint))) { + return; + } + } + + const SkBitmap* bitmapPtr = &bitmap; + + SkMatrix matrix; + SkRect tmpSrc; + if (src) { + tmpSrc = *src; + // if the extract process clipped off the top or left of the + // original, we adjust for that here to get the position right. + if (tmpSrc.fLeft > 0) { + tmpSrc.fRight -= tmpSrc.fLeft; + tmpSrc.fLeft = 0; + } + if (tmpSrc.fTop > 0) { + tmpSrc.fBottom -= tmpSrc.fTop; + tmpSrc.fTop = 0; + } + } else { + tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), + SkIntToScalar(bitmap.height())); + } + matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); + + // ensure that src is "valid" before we pass it to our internal routines + // and to SkDevice. i.e. sure it is contained inside the original bitmap. + SkIRect tmpISrc; + if (srcRoundedPtr) { + tmpISrc.set(0, 0, bitmap.width(), bitmap.height()); + if (!tmpISrc.intersect(*srcRoundedPtr)) { + return; + } + srcRoundedPtr = &tmpISrc; + } + this->internalDrawBitmap(*bitmapPtr, srcRoundedPtr, matrix, paint); +} + void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, const SkRect& dst, const SkPaint* paint) { SkDEBUGCODE(bitmap.validate();) this->internalDrawBitmapRect(bitmap, src, dst, paint); } +void SkCanvas::drawBitmapScalarRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint) { + SkDEBUGCODE(bitmap.validate();) + this->internalDrawBitmapScalarRect(bitmap, src, dst, paint); +} + void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkDEBUGCODE(bitmap.validate();) |