diff options
author | Derek Sollenberger <djsollen@google.com> | 2014-08-14 10:31:26 -0400 |
---|---|---|
committer | Derek Sollenberger <djsollen@google.com> | 2014-08-14 10:40:13 -0400 |
commit | 4e4a89dab47d74874d6a79c4b34d89ffbfb386af (patch) | |
tree | f901914eb9bf246253079529dc6fbb79c80c41d8 | |
parent | d9bff96e7785b872e2dc701256e3ac7d7b563b30 (diff) | |
download | skia-4e4a89dab47d74874d6a79c4b34d89ffbfb386af.tar.gz |
Merge changes from Skia's m37 branch into lmp-dev.
This merge includes the following CLs...
0d78ac2 Set maximum output size for scaled-image-cache images
0c1c911 Adding 64 bit checks
f2d87ba Get additional DW font metrics when available.
Bug: 17024392
Change-Id: I7956f50e5b95b1e012cf56614b12f1d834b423c1
-rw-r--r-- | bench/ImageCacheBench.cpp | 2 | ||||
-rw-r--r-- | dm/Android.mk | 1 | ||||
-rw-r--r-- | gyp/tests.gypi | 1 | ||||
-rw-r--r-- | include/core/SkGraphics.h | 44 | ||||
-rw-r--r-- | src/core/SkBitmapProcState.cpp | 19 | ||||
-rw-r--r-- | src/core/SkConvolver.cpp | 2 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.cpp | 85 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.h | 35 | ||||
-rw-r--r-- | src/effects/SkColorMatrixFilter.cpp | 4 | ||||
-rw-r--r-- | src/ports/SkScalerContext_win_dw.cpp | 32 | ||||
-rw-r--r-- | src/ports/SkTypeface_win_dw.h | 10 | ||||
-rw-r--r-- | tests/Android.mk | 1 | ||||
-rw-r--r-- | tests/ImageCacheTest.cpp | 2 | ||||
-rw-r--r-- | tests/ScaledImageCache.cpp | 60 |
14 files changed, 246 insertions, 52 deletions
diff --git a/bench/ImageCacheBench.cpp b/bench/ImageCacheBench.cpp index 5f1715fc31..e65d1fc3e8 100644 --- a/bench/ImageCacheBench.cpp +++ b/bench/ImageCacheBench.cpp @@ -37,7 +37,7 @@ protected: } virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { - if (fCache.getBytesUsed() == 0) { + if (fCache.getTotalBytesUsed() == 0) { this->populateCache(); } diff --git a/dm/Android.mk b/dm/Android.mk index f6a3219c84..f751f3fa50 100644 --- a/dm/Android.mk +++ b/dm/Android.mk @@ -447,6 +447,7 @@ LOCAL_SRC_FILES := \ ../tests/RuntimeConfigTest.cpp \ ../tests/SHA1Test.cpp \ ../tests/ScalarTest.cpp \ + ../tests/ScaledImageCache.cpp \ ../tests/SerializationTest.cpp \ ../tests/ShaderImageFilterTest.cpp \ ../tests/ShaderOpacityTest.cpp \ diff --git a/gyp/tests.gypi b/gyp/tests.gypi index f135107c34..bb3092d50d 100644 --- a/gyp/tests.gypi +++ b/gyp/tests.gypi @@ -155,6 +155,7 @@ '../tests/RuntimeConfigTest.cpp', '../tests/SHA1Test.cpp', '../tests/ScalarTest.cpp', + '../tests/ScaledImageCache.cpp', '../tests/SerializationTest.cpp', '../tests/ShaderImageFilterTest.cpp', '../tests/ShaderOpacityTest.cpp', diff --git a/include/core/SkGraphics.h b/include/core/SkGraphics.h index 2667a388d2..e7865ca5af 100644 --- a/include/core/SkGraphics.h +++ b/include/core/SkGraphics.h @@ -79,9 +79,47 @@ public: */ static void PurgeFontCache(); - static size_t GetImageCacheBytesUsed(); - static size_t GetImageCacheByteLimit(); - static size_t SetImageCacheByteLimit(size_t newLimit); + /** + * Scaling bitmaps with the SkPaint::kHigh_FilterLevel setting is + * expensive, so the result is saved in the global Scaled Image + * Cache. + * + * This function returns the memory usage of the Scaled Image Cache. + */ + static size_t GetImageCacheTotalBytesUsed(); + /** + * These functions get/set the memory usage limit for the Scaled + * Image Cache. Bitmaps are purged from the cache when the + * memory useage exceeds this limit. + */ + static size_t GetImageCacheTotalByteLimit(); + static size_t SetImageCacheTotalByteLimit(size_t newLimit); + + // DEPRECATED + static size_t GetImageCacheBytesUsed() { + return GetImageCacheTotalBytesUsed(); + } + // DEPRECATED + static size_t GetImageCacheByteLimit() { + return GetImageCacheTotalByteLimit(); + } + // DEPRECATED + static size_t SetImageCacheByteLimit(size_t newLimit) { + return SetImageCacheTotalByteLimit(newLimit); + } + + /** + * Scaling bitmaps with the SkPaint::kHigh_FilterLevel setting is + * expensive, so the result is saved in the global Scaled Image + * Cache. When the resulting bitmap is too large, this can + * overload the cache. If the ImageCacheSingleAllocationByteLimit + * is set to a non-zero number, and the resulting bitmap would be + * larger than that value, the bitmap scaling algorithm falls + * back onto a cheaper algorithm and does not cache the result. + * Zero is the default value. + */ + static size_t GetImageCacheSingleAllocationByteLimit(); + static size_t SetImageCacheSingleAllocationByteLimit(size_t newLimit); /** * Applications with command line options may pass optional state, such diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index f6f9f3fa06..137bcda91f 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -127,6 +127,21 @@ private: }; #define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocker) +// Check to see that the size of the bitmap that would be produced by +// scaling by the given inverted matrix is less than the maximum allowed. +static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { + size_t maximumAllocation + = SkScaledImageCache::GetSingleAllocationByteLimit(); + if (0 == maximumAllocation) { + return true; + } + // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY); + // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize); + // Skip the division step: + return bm.info().getSafeSize(bm.info().minRowBytes()) + < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY()); +} + // TODO -- we may want to pass the clip into this function so we only scale // the portion of the image that we're going to need. This will complicate // the interface to the cache, but might be well worth it. @@ -140,14 +155,14 @@ bool SkBitmapProcState::possiblyScaleImage() { if (fFilterLevel <= SkPaint::kLow_FilterLevel) { return false; } - // Check to see if the transformation matrix is simple, and if we're // doing high quality scaling. If so, do the bitmap scale here and // remove the scaling component from the matrix. if (SkPaint::kHigh_FilterLevel == fFilterLevel && fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) && - kN32_SkColorType == fOrigBitmap.colorType()) { + kN32_SkColorType == fOrigBitmap.colorType() && + cache_size_okay(fOrigBitmap, fInvMatrix)) { SkScalar invScaleX = fInvMatrix.getScaleX(); SkScalar invScaleY = fInvMatrix.getScaleY(); diff --git a/src/core/SkConvolver.cpp b/src/core/SkConvolver.cpp index 0e97fac07f..0f5cf9021b 100644 --- a/src/core/SkConvolver.cpp +++ b/src/core/SkConvolver.cpp @@ -434,7 +434,7 @@ void BGRAConvolve2D(const unsigned char* sourceData, } // Compute where in the output image this row of final data will go. - unsigned char* curOutputRow = &output[outY * outputByteRowStride]; + unsigned char* curOutputRow = &output[(uint64_t)outY * outputByteRowStride]; // Get the list of rows that the circular buffer has, in order. int firstRowInCircularBuffer; diff --git a/src/core/SkScaledImageCache.cpp b/src/core/SkScaledImageCache.cpp index f266f97171..43ff7ef890 100644 --- a/src/core/SkScaledImageCache.cpp +++ b/src/core/SkScaledImageCache.cpp @@ -165,12 +165,13 @@ void SkScaledImageCache::init() { #else fHash = NULL; #endif - fBytesUsed = 0; + fTotalBytesUsed = 0; fCount = 0; + fSingleAllocationByteLimit = 0; fAllocator = NULL; // One of these should be explicit set by the caller after we return. - fByteLimit = 0; + fTotalByteLimit = 0; fDiscardableFactory = NULL; } @@ -266,7 +267,8 @@ private: bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { size_t size = bitmap->getSize(); - if (0 == size) { + uint64_t size64 = bitmap->computeSize64(); + if (0 == size || size64 > (uint64_t)size) { return false; } @@ -296,7 +298,7 @@ SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) { SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { this->init(); - fByteLimit = byteLimit; + fTotalByteLimit = byteLimit; } SkScaledImageCache::~SkScaledImageCache() { @@ -501,10 +503,10 @@ void SkScaledImageCache::purgeAsNeeded() { byteLimit = SK_MaxU32; // no limit based on bytes } else { countLimit = SK_MaxS32; // no limit based on count - byteLimit = fByteLimit; + byteLimit = fTotalByteLimit; } - size_t bytesUsed = fBytesUsed; + size_t bytesUsed = fTotalBytesUsed; int countUsed = fCount; Rec* rec = fTail; @@ -530,13 +532,13 @@ void SkScaledImageCache::purgeAsNeeded() { rec = prev; } - fBytesUsed = bytesUsed; + fTotalBytesUsed = bytesUsed; fCount = countUsed; } -size_t SkScaledImageCache::setByteLimit(size_t newLimit) { - size_t prevLimit = fByteLimit; - fByteLimit = newLimit; +size_t SkScaledImageCache::setTotalByteLimit(size_t newLimit) { + size_t prevLimit = fTotalByteLimit; + fTotalByteLimit = newLimit; if (newLimit < prevLimit) { this->purgeAsNeeded(); } @@ -596,7 +598,7 @@ void SkScaledImageCache::addToHead(Rec* rec) { if (!fTail) { fTail = rec; } - fBytesUsed += rec->bytesUsed(); + fTotalBytesUsed += rec->bytesUsed(); fCount += 1; this->validate(); @@ -608,14 +610,14 @@ void SkScaledImageCache::addToHead(Rec* rec) { void SkScaledImageCache::validate() const { if (NULL == fHead) { SkASSERT(NULL == fTail); - SkASSERT(0 == fBytesUsed); + SkASSERT(0 == fTotalBytesUsed); return; } if (fHead == fTail) { SkASSERT(NULL == fHead->fPrev); SkASSERT(NULL == fHead->fNext); - SkASSERT(fHead->bytesUsed() == fBytesUsed); + SkASSERT(fHead->bytesUsed() == fTotalBytesUsed); return; } @@ -630,7 +632,7 @@ void SkScaledImageCache::validate() const { while (rec) { count += 1; used += rec->bytesUsed(); - SkASSERT(used <= fBytesUsed); + SkASSERT(used <= fTotalBytesUsed); rec = rec->fNext; } SkASSERT(fCount == count); @@ -660,10 +662,20 @@ void SkScaledImageCache::dump() const { } SkDebugf("SkScaledImageCache: count=%d bytes=%d locked=%d %s\n", - fCount, fBytesUsed, locked, + fCount, fTotalBytesUsed, locked, fDiscardableFactory ? "discardable" : "malloc"); } +size_t SkScaledImageCache::setSingleAllocationByteLimit(size_t newLimit) { + size_t oldLimit = fSingleAllocationByteLimit; + fSingleAllocationByteLimit = newLimit; + return oldLimit; +} + +size_t SkScaledImageCache::getSingleAllocationByteLimit() const { + return fSingleAllocationByteLimit; +} + /////////////////////////////////////////////////////////////////////////////// #include "SkThread.h" @@ -750,19 +762,19 @@ void SkScaledImageCache::Unlock(SkScaledImageCache::ID* id) { // get_cache()->dump(); } -size_t SkScaledImageCache::GetBytesUsed() { +size_t SkScaledImageCache::GetTotalBytesUsed() { SkAutoMutexAcquire am(gMutex); - return get_cache()->getBytesUsed(); + return get_cache()->getTotalBytesUsed(); } -size_t SkScaledImageCache::GetByteLimit() { +size_t SkScaledImageCache::GetTotalByteLimit() { SkAutoMutexAcquire am(gMutex); - return get_cache()->getByteLimit(); + return get_cache()->getTotalByteLimit(); } -size_t SkScaledImageCache::SetByteLimit(size_t newLimit) { +size_t SkScaledImageCache::SetTotalByteLimit(size_t newLimit) { SkAutoMutexAcquire am(gMutex); - return get_cache()->setByteLimit(newLimit); + return get_cache()->setTotalByteLimit(newLimit); } SkBitmap::Allocator* SkScaledImageCache::GetAllocator() { @@ -775,18 +787,37 @@ void SkScaledImageCache::Dump() { get_cache()->dump(); } +size_t SkScaledImageCache::SetSingleAllocationByteLimit(size_t size) { + SkAutoMutexAcquire am(gMutex); + return get_cache()->setSingleAllocationByteLimit(size); +} + +size_t SkScaledImageCache::GetSingleAllocationByteLimit() { + SkAutoMutexAcquire am(gMutex); + return get_cache()->getSingleAllocationByteLimit(); +} + /////////////////////////////////////////////////////////////////////////////// #include "SkGraphics.h" -size_t SkGraphics::GetImageCacheBytesUsed() { - return SkScaledImageCache::GetBytesUsed(); +size_t SkGraphics::GetImageCacheTotalBytesUsed() { + return SkScaledImageCache::GetTotalBytesUsed(); +} + +size_t SkGraphics::GetImageCacheTotalByteLimit() { + return SkScaledImageCache::GetTotalByteLimit(); } -size_t SkGraphics::GetImageCacheByteLimit() { - return SkScaledImageCache::GetByteLimit(); +size_t SkGraphics::SetImageCacheTotalByteLimit(size_t newLimit) { + return SkScaledImageCache::SetTotalByteLimit(newLimit); } -size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { - return SkScaledImageCache::SetByteLimit(newLimit); +size_t SkGraphics::GetImageCacheSingleAllocationByteLimit() { + return SkScaledImageCache::GetSingleAllocationByteLimit(); } + +size_t SkGraphics::SetImageCacheSingleAllocationByteLimit(size_t newLimit) { + return SkScaledImageCache::SetSingleAllocationByteLimit(newLimit); +} + diff --git a/src/core/SkScaledImageCache.h b/src/core/SkScaledImageCache.h index fe072306d3..817147e3b8 100644 --- a/src/core/SkScaledImageCache.h +++ b/src/core/SkScaledImageCache.h @@ -60,9 +60,12 @@ public: static void Unlock(ID*); - static size_t GetBytesUsed(); - static size_t GetByteLimit(); - static size_t SetByteLimit(size_t newLimit); + static size_t GetTotalBytesUsed(); + static size_t GetTotalByteLimit(); + static size_t SetTotalByteLimit(size_t newLimit); + + static size_t SetSingleAllocationByteLimit(size_t); + static size_t GetSingleAllocationByteLimit(); static SkBitmap::Allocator* GetAllocator(); @@ -76,9 +79,9 @@ public: /** * Construct the cache to call DiscardableFactory when it * allocates memory for the pixels. In this mode, the cache has - * not explicit budget, and so methods like getBytesUsed() and - * getByteLimit() will return 0, and setByteLimit will ignore its argument - * and return 0. + * not explicit budget, and so methods like getTotalBytesUsed() + * and getTotalByteLimit() will return 0, and setTotalByteLimit + * will ignore its argument and return 0. */ SkScaledImageCache(DiscardableFactory); @@ -86,7 +89,7 @@ public: * Construct the cache, allocating memory with malloc, and respect the * byteLimit, purging automatically when a new image is added to the cache * that pushes the total bytesUsed over the limit. Note: The limit can be - * changed at runtime with setByteLimit. + * changed at runtime with setTotalByteLimit. */ SkScaledImageCache(size_t byteLimit); @@ -144,15 +147,22 @@ public: */ void unlock(ID*); - size_t getBytesUsed() const { return fBytesUsed; } - size_t getByteLimit() const { return fByteLimit; } + size_t getTotalBytesUsed() const { return fTotalBytesUsed; } + size_t getTotalByteLimit() const { return fTotalByteLimit; } /** + * This is respected by SkBitmapProcState::possiblyScaleImage. + * 0 is no maximum at all; this is the default. + * setSingleAllocationByteLimit() returns the previous value. + */ + size_t setSingleAllocationByteLimit(size_t maximumAllocationSize); + size_t getSingleAllocationByteLimit() const; + /** * Set the maximum number of bytes available to this cache. If the current * cache exceeds this new value, it will be purged to try to fit within * this new limit. */ - size_t setByteLimit(size_t newLimit); + size_t setTotalByteLimit(size_t newLimit); SkBitmap::Allocator* allocator() const { return fAllocator; }; @@ -175,8 +185,9 @@ private: // the allocator is NULL or one that matches discardables SkBitmap::Allocator* fAllocator; - size_t fBytesUsed; - size_t fByteLimit; + size_t fTotalBytesUsed; + size_t fTotalByteLimit; + size_t fSingleAllocationByteLimit; int fCount; Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy, diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp index b60fa84b68..bd1df79d14 100644 --- a/src/effects/SkColorMatrixFilter.cpp +++ b/src/effects/SkColorMatrixFilter.cpp @@ -450,6 +450,8 @@ public: private: GrGLUniformManager::UniformHandle fMatrixHandle; GrGLUniformManager::UniformHandle fVectorHandle; + + typedef GrGLEffect INHERITED; }; private: @@ -462,7 +464,7 @@ private: SkColorMatrix fMatrix; - typedef GrGLEffect INHERITED; + typedef GrEffect INHERITED; }; GR_DEFINE_EFFECT_TEST(ColorMatrixEffect); diff --git a/src/ports/SkScalerContext_win_dw.cpp b/src/ports/SkScalerContext_win_dw.cpp index f9f4392b75..2abd8667cb 100644 --- a/src/ports/SkScalerContext_win_dw.cpp +++ b/src/ports/SkScalerContext_win_dw.cpp @@ -26,6 +26,7 @@ #include "SkTypeface_win_dw.h" #include <dwrite.h> +#include <dwrite_1.h> static bool isLCD(const SkScalerContext::Rec& rec) { return SkMask::kLCD16_Format == rec.fMaskFormat || @@ -489,10 +490,8 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx, } if (my) { - my->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; - my->fAscent = my->fTop; + my->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; my->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; - my->fBottom = my->fDescent; my->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; my->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; my->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; @@ -500,6 +499,33 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx, my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; + + if (NULL != fTypeface->fDWriteFontFace1.get()) { + DWRITE_FONT_METRICS1 dwfm1; + fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1); + my->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; + my->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; + my->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; + my->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem; + + my->fMaxCharWidth = my->fXMax - my->fXMin; + } else { + AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get()); + if (head.fExists && + head.fSize >= sizeof(SkOTTableHead) && + head->version == SkOTTableHead::version1) + { + my->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem; + my->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem; + my->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem; + my->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem; + + my->fMaxCharWidth = my->fXMax - my->fXMin; + } else { + my->fTop = my->fAscent; + my->fBottom = my->fDescent; + } + } } } diff --git a/src/ports/SkTypeface_win_dw.h b/src/ports/SkTypeface_win_dw.h index b064ce5770..465db3446b 100644 --- a/src/ports/SkTypeface_win_dw.h +++ b/src/ports/SkTypeface_win_dw.h @@ -17,6 +17,7 @@ #include "SkTypes.h" #include <dwrite.h> +#include <dwrite_1.h> class SkFontDescriptor; struct SkScalerContextRec; @@ -50,7 +51,13 @@ private: , fDWriteFontFamily(SkRefComPtr(fontFamily)) , fDWriteFont(SkRefComPtr(font)) , fDWriteFontFace(SkRefComPtr(fontFace)) - { } + { + if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace1))) { + // IUnknown::QueryInterface states that if it fails, punk will be set to NULL. + // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx + SK_ALWAYSBREAK(NULL == fDWriteFontFace1.get()); + } + } public: SkTScopedComPtr<IDWriteFactory> fFactory; @@ -59,6 +66,7 @@ public: SkTScopedComPtr<IDWriteFontFamily> fDWriteFontFamily; SkTScopedComPtr<IDWriteFont> fDWriteFont; SkTScopedComPtr<IDWriteFontFace> fDWriteFontFace; + SkTScopedComPtr<IDWriteFontFace1> fDWriteFontFace1; static DWriteFontTypeface* Create(IDWriteFactory* factory, IDWriteFontFace* fontFace, diff --git a/tests/Android.mk b/tests/Android.mk index fa43c43eda..ad6eb6d96d 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -183,6 +183,7 @@ LOCAL_SRC_FILES := \ RuntimeConfigTest.cpp \ SHA1Test.cpp \ ScalarTest.cpp \ + ScaledImageCache.cpp \ SerializationTest.cpp \ ShaderImageFilterTest.cpp \ ShaderOpacityTest.cpp \ diff --git a/tests/ImageCacheTest.cpp b/tests/ImageCacheTest.cpp index 92d0b519d0..00f6c77aa3 100644 --- a/tests/ImageCacheTest.cpp +++ b/tests/ImageCacheTest.cpp @@ -74,7 +74,7 @@ static void test_cache(skiatest::Reporter* reporter, SkScaledImageCache& cache, } } - cache.setByteLimit(0); + cache.setTotalByteLimit(0); } #include "SkDiscardableMemoryPool.h" diff --git a/tests/ScaledImageCache.cpp b/tests/ScaledImageCache.cpp new file mode 100644 index 0000000000..2040afea27 --- /dev/null +++ b/tests/ScaledImageCache.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Test.h" +#include "SkGraphics.h" +#include "SkCanvas.h" + +static const int kCanvasSize = 1; +static const int kBitmapSize = 16; +static const int kScale = 8; + +static size_t test_scaled_image_cache_useage() { + SkAutoTUnref<SkCanvas> canvas( + SkCanvas::NewRasterN32(kCanvasSize, kCanvasSize)); + SkBitmap bitmap; + SkAssertResult(bitmap.allocN32Pixels(kBitmapSize, kBitmapSize)); + SkScalar scaledSize = SkIntToScalar(kScale * kBitmapSize); + canvas->clipRect(SkRect::MakeLTRB(0, 0, scaledSize, scaledSize)); + SkPaint paint; + paint.setFilterLevel(SkPaint::kHigh_FilterLevel); + size_t bytesUsed = SkGraphics::GetImageCacheBytesUsed(); + canvas->drawBitmapRect(bitmap, + SkRect::MakeLTRB(0, 0, scaledSize, scaledSize), + &paint); + return SkGraphics::GetImageCacheBytesUsed() - bytesUsed; +} + +// http://crbug.com/389439 +DEF_TEST(ScaledImageCache_SingleAllocationByteLimit, reporter) { + size_t originalByteLimit = SkGraphics::GetImageCacheByteLimit(); + size_t originalAllocationLimit = + SkGraphics::GetImageCacheSingleAllocationByteLimit(); + + size_t size = kBitmapSize * kScale * kBitmapSize * kScale + * SkColorTypeBytesPerPixel(kN32_SkColorType); + + SkGraphics::SetImageCacheByteLimit(0); // clear cache + SkGraphics::SetImageCacheByteLimit(2 * size); + SkGraphics::SetImageCacheSingleAllocationByteLimit(0); + + REPORTER_ASSERT(reporter, size == test_scaled_image_cache_useage()); + + SkGraphics::SetImageCacheByteLimit(0); // clear cache + SkGraphics::SetImageCacheByteLimit(2 * size); + SkGraphics::SetImageCacheSingleAllocationByteLimit(size * 2); + + REPORTER_ASSERT(reporter, size == test_scaled_image_cache_useage()); + + SkGraphics::SetImageCacheByteLimit(0); // clear cache + SkGraphics::SetImageCacheByteLimit(2 * size); + SkGraphics::SetImageCacheSingleAllocationByteLimit(size / 2); + + REPORTER_ASSERT(reporter, 0 == test_scaled_image_cache_useage()); + + SkGraphics::SetImageCacheSingleAllocationByteLimit(originalAllocationLimit); + SkGraphics::SetImageCacheByteLimit(originalByteLimit); +} |