aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/core/SkBitmap.h16
-rw-r--r--include/core/SkCanvas.h5
-rw-r--r--src/core/SkBitmap.cpp21
-rw-r--r--src/core/SkCanvas.cpp67
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();)