| /* | |
| * 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 "include/core/SkBlurTypes.h" | |
| #include "include/core/SkRRect.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkScalar.h" | |
| #include "src/core/SkCachedData.h" | |
| #include "src/core/SkMask.h" | |
| #include "src/core/SkMaskCache.h" | |
| #include "src/core/SkResourceCache.h" | |
| #include "src/core/SkTLazy.h" | |
| #include "tests/Test.h" | |
| #include <cstring> | |
| enum LockedState { | |
| kUnlocked, | |
| kLocked, | |
| }; | |
| enum CachedState { | |
| kNotInCache, | |
| kInCache, | |
| }; | |
| static void check_data(skiatest::Reporter* reporter, SkCachedData* data, | |
| int refcnt, CachedState cacheState, LockedState lockedState) { | |
| REPORTER_ASSERT(reporter, data->testing_only_getRefCnt() == refcnt); | |
| REPORTER_ASSERT(reporter, data->testing_only_isInCache() == (kInCache == cacheState)); | |
| bool isLocked = (data->data() != nullptr); | |
| REPORTER_ASSERT(reporter, isLocked == (lockedState == kLocked)); | |
| } | |
| DEF_TEST(RRectMaskCache, reporter) { | |
| SkResourceCache cache(1024); | |
| SkScalar sigma = 0.8f; | |
| SkRect rect = SkRect::MakeWH(100, 100); | |
| SkRRect rrect; | |
| rrect.setRectXY(rect, 30, 30); | |
| SkBlurStyle style = kNormal_SkBlurStyle; | |
| SkTLazy<SkMask> lazyMask; | |
| sk_sp<SkCachedData> data = SkMaskCache::Find(sigma, style, rrect, &lazyMask, &cache); | |
| REPORTER_ASSERT(reporter, nullptr == data); | |
| REPORTER_ASSERT(reporter, !lazyMask.isValid()); | |
| size_t size = 256; | |
| SkCachedData* rawData = nullptr; | |
| { | |
| sk_sp<SkCachedData> originalData = cache.newCachedData(size); | |
| memset(originalData->writable_data(), 0xff, size); | |
| SkMask mask(nullptr, SkIRect::MakeXYWH(0, 0, 100, 100), 100, SkMask::kBW_Format); | |
| SkMaskCache::Add(sigma, style, rrect, mask, originalData, &cache); | |
| check_data(reporter, originalData.get(), 2, kInCache, kLocked); | |
| // Retain a raw observer pointer to inspect the cached object after originalData is dropped. | |
| // This is safe (not a UAF) because SkResourceCache still retains a ref to it (refcnt = 1). | |
| rawData = originalData.get(); | |
| } | |
| check_data(reporter, rawData, 1, kInCache, kUnlocked); | |
| lazyMask.reset(); | |
| sk_sp<SkCachedData> foundData = SkMaskCache::Find(sigma, style, rrect, &lazyMask, &cache); | |
| REPORTER_ASSERT(reporter, foundData); | |
| REPORTER_ASSERT(reporter, foundData->size() == size); | |
| REPORTER_ASSERT(reporter, lazyMask->fBounds.top() == 0 && lazyMask->fBounds.bottom() == 100); | |
| REPORTER_ASSERT(reporter, foundData->data() == static_cast<const void*>(lazyMask->fImage)); | |
| check_data(reporter, foundData.get(), 2, kInCache, kLocked); | |
| cache.purgeAll(); | |
| check_data(reporter, foundData.get(), 1, kNotInCache, kLocked); | |
| } | |
| DEF_TEST(RectsMaskCache, reporter) { | |
| SkResourceCache cache(1024); | |
| SkScalar sigma = 0.8f; | |
| SkRect rect = SkRect::MakeWH(100, 100); | |
| SkRect rects[2] = {rect}; | |
| SkBlurStyle style = kNormal_SkBlurStyle; | |
| SkTLazy<SkMask> lazyMask; | |
| sk_sp<SkCachedData> data = SkMaskCache::Find(sigma, style, SkSpan(rects, 1), &lazyMask, &cache); | |
| REPORTER_ASSERT(reporter, nullptr == data); | |
| REPORTER_ASSERT(reporter, !lazyMask.isValid()); | |
| size_t size = 256; | |
| SkCachedData* rawData = nullptr; | |
| { | |
| sk_sp<SkCachedData> originalData = cache.newCachedData(size); | |
| memset(originalData->writable_data(), 0xff, size); | |
| SkMask mask(nullptr, SkIRect::MakeXYWH(0, 0, 100, 100), 100, SkMask::kBW_Format); | |
| SkMaskCache::Add(sigma, style, SkSpan(rects, 1), mask, originalData, &cache); | |
| check_data(reporter, originalData.get(), 2, kInCache, kLocked); | |
| // Retain a raw observer pointer to inspect the cached object after originalData is dropped. | |
| // This is safe (not a UAF) because SkResourceCache still retains a ref to it (refcnt = 1). | |
| rawData = originalData.get(); | |
| } | |
| check_data(reporter, rawData, 1, kInCache, kUnlocked); | |
| lazyMask.reset(); | |
| sk_sp<SkCachedData> foundData = | |
| SkMaskCache::Find(sigma, style, SkSpan(rects, 1), &lazyMask, &cache); | |
| REPORTER_ASSERT(reporter, foundData); | |
| REPORTER_ASSERT(reporter, foundData->size() == size); | |
| REPORTER_ASSERT(reporter, lazyMask->fBounds.top() == 0 && lazyMask->fBounds.bottom() == 100); | |
| REPORTER_ASSERT(reporter, foundData->data() == static_cast<const void*>(lazyMask->fImage)); | |
| check_data(reporter, foundData.get(), 2, kInCache, kLocked); | |
| cache.purgeAll(); | |
| check_data(reporter, foundData.get(), 1, kNotInCache, kLocked); | |
| } |