skottie_mru_resource_provider_unittest.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "cc/paint/skottie_mru_resource_provider.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/containers/flat_map.h"
  8. #include "base/files/file_path.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/strings/string_piece.h"
  11. #include "cc/paint/paint_image.h"
  12. #include "cc/paint/skottie_resource_metadata.h"
  13. #include "cc/test/lottie_test_data.h"
  14. #include "cc/test/skia_common.h"
  15. #include "testing/gmock/include/gmock/gmock.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. #include "third_party/abseil-cpp/absl/types/optional.h"
  18. #include "third_party/skia/include/core/SkRefCnt.h"
  19. #include "third_party/skia/modules/skresources/include/SkResources.h"
  20. #include "ui/gfx/geometry/size.h"
  21. namespace cc {
  22. namespace {
  23. using ::testing::Contains;
  24. using ::testing::Eq;
  25. using ::testing::FieldsAre;
  26. using ::testing::Key;
  27. using ::testing::Optional;
  28. using ::testing::Pair;
  29. using ::testing::SizeIs;
  30. using ::testing::UnorderedElementsAre;
  31. class FrameDataStub {
  32. public:
  33. using FrameData = skresources::ImageAsset::FrameData;
  34. void SetAssetFrameData(base::StringPiece asset_id,
  35. FrameData current_frame_data) {
  36. asset_to_frame_data_[HashSkottieResourceId(asset_id)] =
  37. std::move(current_frame_data);
  38. asset_to_result_[HashSkottieResourceId(asset_id)] =
  39. SkottieWrapper::FrameDataFetchResult::NEW_DATA_AVAILABLE;
  40. }
  41. void SetAssetResult(base::StringPiece asset_id,
  42. SkottieWrapper::FrameDataFetchResult current_result) {
  43. asset_to_result_[HashSkottieResourceId(asset_id)] = current_result;
  44. }
  45. SkottieWrapper::FrameDataFetchResult GetFrameDataForAsset(
  46. SkottieResourceIdHash asset_id,
  47. float t,
  48. sk_sp<SkImage>& image_out,
  49. SkSamplingOptions& sampling_out) const {
  50. if (asset_to_frame_data_.contains(asset_id)) {
  51. image_out = asset_to_frame_data_.at(asset_id).image;
  52. sampling_out = asset_to_frame_data_.at(asset_id).sampling;
  53. }
  54. return asset_to_result_.contains(asset_id)
  55. ? asset_to_result_.at(asset_id)
  56. : SkottieWrapper::FrameDataFetchResult::NO_UPDATE;
  57. }
  58. private:
  59. base::flat_map<SkottieResourceIdHash, FrameData> asset_to_frame_data_;
  60. base::flat_map<SkottieResourceIdHash, SkottieWrapper::FrameDataFetchResult>
  61. asset_to_result_;
  62. };
  63. class SkottieMRUResourceProviderTest : public ::testing::Test {
  64. protected:
  65. void Init(base::StringPiece animation_json) {
  66. provider_ = sk_make_sp<SkottieMRUResourceProvider>(
  67. base::BindRepeating(&FrameDataStub::GetFrameDataForAsset,
  68. base::Unretained(&frame_data_stub_)),
  69. animation_json);
  70. provider_base_ = provider_.get();
  71. }
  72. FrameDataStub frame_data_stub_;
  73. sk_sp<SkottieMRUResourceProvider> provider_;
  74. raw_ptr<skresources::ResourceProvider> provider_base_;
  75. };
  76. TEST_F(SkottieMRUResourceProviderTest, ProvidesMostRecentFrameDataForAsset) {
  77. Init(R"({
  78. "assets": [
  79. {
  80. "id": "test-resource-id"
  81. }
  82. ]
  83. })");
  84. sk_sp<skresources::ImageAsset> asset = provider_base_->loadImageAsset(
  85. "test-resource-path", "test-resource-name", "test-resource-id");
  86. PaintImage image_1 = CreateBitmapImage(gfx::Size(10, 10));
  87. frame_data_stub_.SetAssetFrameData("test-resource-id",
  88. {.image = image_1.GetSwSkImage()});
  89. EXPECT_THAT(asset->getFrameData(/*t=*/0).image, Eq(image_1.GetSwSkImage()));
  90. // The same image should be re-used for the next timestamp.
  91. frame_data_stub_.SetAssetResult(
  92. "test-resource-id", SkottieWrapper::FrameDataFetchResult::NO_UPDATE);
  93. EXPECT_THAT(asset->getFrameData(/*t=*/0.1).image, Eq(image_1.GetSwSkImage()));
  94. // Now the new image should be used.
  95. PaintImage image_2 = CreateBitmapImage(gfx::Size(20, 20));
  96. frame_data_stub_.SetAssetFrameData("test-resource-id",
  97. {.image = image_2.GetSwSkImage()});
  98. EXPECT_THAT(asset->getFrameData(/*t=*/0.2).image, Eq(image_2.GetSwSkImage()));
  99. }
  100. TEST_F(SkottieMRUResourceProviderTest, ProvidesFrameDataForMultipleAssets) {
  101. Init(R"({
  102. "assets": [
  103. {
  104. "id": "test-resource-id-1"
  105. },
  106. {
  107. "id": "test-resource-id-2"
  108. }
  109. ]
  110. })");
  111. sk_sp<skresources::ImageAsset> asset_1 = provider_base_->loadImageAsset(
  112. "test-resource-path", "test-resource-name", "test-resource-id-1");
  113. sk_sp<skresources::ImageAsset> asset_2 = provider_base_->loadImageAsset(
  114. "test-resource-path", "test-resource-name", "test-resource-id-2");
  115. PaintImage image_1 = CreateBitmapImage(gfx::Size(10, 10));
  116. frame_data_stub_.SetAssetFrameData("test-resource-id-1",
  117. {.image = image_1.GetSwSkImage()});
  118. PaintImage image_2 = CreateBitmapImage(gfx::Size(20, 20));
  119. frame_data_stub_.SetAssetFrameData("test-resource-id-2",
  120. {.image = image_2.GetSwSkImage()});
  121. EXPECT_THAT(asset_1->getFrameData(/*t=*/0).image, Eq(image_1.GetSwSkImage()));
  122. EXPECT_THAT(asset_2->getFrameData(/*t=*/0).image, Eq(image_2.GetSwSkImage()));
  123. }
  124. TEST_F(SkottieMRUResourceProviderTest, ReturnsCorrectImageAssetMetadata) {
  125. Init(R"({
  126. "assets": [
  127. {
  128. "id": "test-resource-id-1",
  129. "w": 100,
  130. "h": 101
  131. },
  132. {
  133. "id": "test-resource-id-2",
  134. "w": 200,
  135. "h": 201
  136. }
  137. ]
  138. })");
  139. sk_sp<skresources::ImageAsset> asset_1 = provider_base_->loadImageAsset(
  140. "test-resource-path-1", "test-resource-name-1", "test-resource-id-1");
  141. sk_sp<skresources::ImageAsset> asset_2 = provider_base_->loadImageAsset(
  142. "test-resource-path-2", "test-resource-name-2", "test-resource-id-2");
  143. EXPECT_THAT(
  144. provider_->GetImageAssetMetadata().asset_storage(),
  145. UnorderedElementsAre(
  146. Pair("test-resource-id-1",
  147. FieldsAre(base::FilePath(
  148. FILE_PATH_LITERAL(
  149. "test-resource-path-1/test-resource-name-1"))
  150. .NormalizePathSeparators(),
  151. Optional(gfx::Size(100, 101)))),
  152. Pair("test-resource-id-2",
  153. FieldsAre(base::FilePath(
  154. FILE_PATH_LITERAL(
  155. "test-resource-path-2/test-resource-name-2"))
  156. .NormalizePathSeparators(),
  157. Optional(gfx::Size(200, 201))))));
  158. }
  159. TEST_F(SkottieMRUResourceProviderTest, HandlesMissingAssetDimensions) {
  160. Init(R"({
  161. "assets": [
  162. {
  163. "id": "test-resource-id"
  164. }
  165. ]
  166. })");
  167. sk_sp<skresources::ImageAsset> asset_1 = provider_base_->loadImageAsset(
  168. "test-resource-path", "test-resource-name", "test-resource-id");
  169. EXPECT_THAT(
  170. provider_->GetImageAssetMetadata().asset_storage(),
  171. UnorderedElementsAre(Pair(
  172. "test-resource-id",
  173. FieldsAre(base::FilePath(FILE_PATH_LITERAL(
  174. "test-resource-path/test-resource-name"))
  175. .NormalizePathSeparators(),
  176. Eq(absl::nullopt)))));
  177. }
  178. TEST_F(SkottieMRUResourceProviderTest, HandlesIncompleteDimensions) {
  179. Init(R"({
  180. "assets": [
  181. {
  182. "id": "test-resource-id",
  183. "w": 100
  184. }
  185. ]
  186. })");
  187. sk_sp<skresources::ImageAsset> asset_1 = provider_base_->loadImageAsset(
  188. "test-resource-path", "test-resource-name", "test-resource-id");
  189. EXPECT_THAT(
  190. provider_->GetImageAssetMetadata().asset_storage(),
  191. UnorderedElementsAre(Pair(
  192. "test-resource-id",
  193. FieldsAre(base::FilePath(FILE_PATH_LITERAL(
  194. "test-resource-path/test-resource-name"))
  195. .NormalizePathSeparators(),
  196. Eq(absl::nullopt)))));
  197. Init(R"({
  198. "assets": [
  199. {
  200. "id": "test-resource-id",
  201. "h": 100
  202. }
  203. ]
  204. })");
  205. asset_1 = provider_base_->loadImageAsset(
  206. "test-resource-path", "test-resource-name", "test-resource-id");
  207. EXPECT_THAT(
  208. provider_->GetImageAssetMetadata().asset_storage(),
  209. UnorderedElementsAre(Pair(
  210. "test-resource-id",
  211. FieldsAre(base::FilePath(FILE_PATH_LITERAL(
  212. "test-resource-path/test-resource-name"))
  213. .NormalizePathSeparators(),
  214. Eq(absl::nullopt)))));
  215. }
  216. TEST_F(SkottieMRUResourceProviderTest, HandlesInvalidDimensions) {
  217. Init(R"({
  218. "assets": [
  219. {
  220. "id": "test-resource-id",
  221. "w": -100
  222. }
  223. ]
  224. })");
  225. sk_sp<skresources::ImageAsset> asset_1 = provider_base_->loadImageAsset(
  226. "test-resource-path", "test-resource-name", "test-resource-id");
  227. EXPECT_THAT(
  228. provider_->GetImageAssetMetadata().asset_storage(),
  229. UnorderedElementsAre(Pair(
  230. "test-resource-id",
  231. FieldsAre(base::FilePath(FILE_PATH_LITERAL(
  232. "test-resource-path/test-resource-name"))
  233. .NormalizePathSeparators(),
  234. Eq(absl::nullopt)))));
  235. Init(R"({
  236. "assets": [
  237. {
  238. "id": "test-resource-id",
  239. "h": -100
  240. }
  241. ]
  242. })");
  243. asset_1 = provider_base_->loadImageAsset(
  244. "test-resource-path", "test-resource-name", "test-resource-id");
  245. EXPECT_THAT(
  246. provider_->GetImageAssetMetadata().asset_storage(),
  247. UnorderedElementsAre(Pair(
  248. "test-resource-id",
  249. FieldsAre(base::FilePath(FILE_PATH_LITERAL(
  250. "test-resource-path/test-resource-name"))
  251. .NormalizePathSeparators(),
  252. Eq(absl::nullopt)))));
  253. }
  254. } // namespace
  255. } // namespace cc