| /* | 
 |  * 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/SkCanvas.h" | 
 | #include "include/core/SkColor.h" | 
 | #include "include/core/SkImageInfo.h" | 
 | #include "include/core/SkPaint.h" | 
 | #include "include/core/SkPicture.h" | 
 | #include "include/core/SkPictureRecorder.h" | 
 | #include "include/core/SkRefCnt.h" | 
 | #include "include/core/SkSamplingOptions.h" | 
 | #include "include/core/SkSurface.h" | 
 | #include "include/core/SkTileMode.h" | 
 | #include "src/core/SkPicturePriv.h" | 
 | #include "src/core/SkResourceCache.h" | 
 | #include "tests/Test.h" | 
 |  | 
 | #include <cstdint> | 
 | #include <initializer_list> | 
 |  | 
 | // Test that the SkPictureShader cache is purged on shader deletion. | 
 | DEF_TEST(PictureShader_caching, reporter) { | 
 |     auto makePicture = [] () { | 
 |         SkPictureRecorder recorder; | 
 |         recorder.beginRecording(100, 100)->drawColor(SK_ColorGREEN); | 
 |         return recorder.finishRecordingAsPicture(); | 
 |     }; | 
 |  | 
 |     sk_sp<SkPicture> picture = makePicture(); | 
 |     REPORTER_ASSERT(reporter, picture->unique()); | 
 |  | 
 |     sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)); | 
 |  | 
 |     { | 
 |         SkPaint paint; | 
 |         paint.setShader(picture->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, | 
 |                                             SkFilterMode::kNearest)); | 
 |         surface->getCanvas()->drawPaint(paint); | 
 |  | 
 |         // We should have about 3 refs by now: local + shader + shader cache. | 
 |         REPORTER_ASSERT(reporter, !picture->unique()); | 
 |     } | 
 |  | 
 |     // Draw another picture shader to have a chance to purge. | 
 |     { | 
 |         SkPaint paint; | 
 |         paint.setShader(makePicture()->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, | 
 |                                                   SkFilterMode::kNearest)); | 
 |         surface->getCanvas()->drawPaint(paint); | 
 |  | 
 |     } | 
 |  | 
 |     // All but the local ref should be gone now. | 
 |     REPORTER_ASSERT(reporter, picture->unique()); | 
 | } | 
 |  | 
 | /* | 
 |  *  Check caching of picture-shaders | 
 |  *  - we do cache the underlying image (i.e. there is a cache entry) | 
 |  *  - there is only 1 entry, even with differing tile modes | 
 |  *  - after deleting the picture, the cache entry is purged | 
 |  */ | 
 | DEF_TEST(PictureShader_caching2, reporter) { | 
 |     auto picture = []() { | 
 |         SkPictureRecorder recorder; | 
 |         recorder.beginRecording(100, 100)->drawColor(SK_ColorGREEN); | 
 |         return recorder.finishRecordingAsPicture(); | 
 |     }(); | 
 |     REPORTER_ASSERT(reporter, picture->unique()); | 
 |  | 
 |     struct Data { | 
 |         uint64_t sharedID; | 
 |         int counter; | 
 |     } data = { | 
 |         SkPicturePriv::MakeSharedID(picture->uniqueID()), | 
 |         0, | 
 |     }; | 
 |  | 
 |     auto counter = [](const SkResourceCache::Rec& rec, void* dataPtr) { | 
 |         if (rec.getKey().getSharedID() == ((Data*)dataPtr)->sharedID) { | 
 |             ((Data*)dataPtr)->counter += 1; | 
 |         } | 
 |     }; | 
 |  | 
 |     SkResourceCache::VisitAll(counter, &data); | 
 |     REPORTER_ASSERT(reporter, data.counter == 0); | 
 |  | 
 |     // Draw with a view variants of picture-shaders that all use the same picture. | 
 |     // Only expect 1 cache entry for all (since same CTM for all). | 
 |     sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)); | 
 |     for (SkTileMode m : { | 
 |         SkTileMode::kClamp, SkTileMode::kRepeat, SkTileMode::kRepeat, SkTileMode::kDecal | 
 |     }) { | 
 |         SkPaint paint; | 
 |         paint.setShader(picture->makeShader(m, m, SkFilterMode::kNearest)); | 
 |         surface->getCanvas()->drawPaint(paint); | 
 |     } | 
 |  | 
 |     // Don't expect any additional refs on the picture | 
 |     REPORTER_ASSERT(reporter, picture->unique()); | 
 |  | 
 |     // Check that we did cache something, but only 1 thing | 
 |     data.counter = 0; | 
 |     SkResourceCache::VisitAll(counter, &data); | 
 |     REPORTER_ASSERT(reporter, data.counter == 1); | 
 |  | 
 |     // Now delete the picture, and check the we purge the cache entry | 
 |  | 
 |     picture.reset(); | 
 |     SkResourceCache::CheckMessages(); | 
 |  | 
 |     data.counter = 0; | 
 |     SkResourceCache::VisitAll(counter, &data); | 
 |     REPORTER_ASSERT(reporter, data.counter == 0); | 
 | } |