1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/image/image_cache.h"
17
18 #include <string>
19
20 #include "base/log/dump_log.h"
21 #include "core/components_ng/image_provider/image_object.h"
22 #include "core/image/image_object.h"
23
24 namespace OHOS::Ace {
Create()25 RefPtr<ImageCache> ImageCache::Create()
26 {
27 return MakeRefPtr<ImageCache>();
28 }
29
30 // TODO: Create a real ImageCache later
31 #ifdef FLUTTER_2_5
32 class MockImageCache : public ImageCache {
Clear()33 void Clear() override {};
GetDataFromCacheFile(const std::string & filePath)34 RefPtr<NG::ImageData> GetDataFromCacheFile(const std::string& filePath) override
35 {
36 return nullptr;
37 }
38 };
39
Create()40 RefPtr<ImageCache> ImageCache::Create()
41 {
42 return AceType::MakeRefPtr<MockImageCache>();
43 }
44
Purge()45 void ImageCache::Purge() {}
46 #endif
47
CacheImage(const std::string & key,const std::shared_ptr<CachedImage> & image)48 void ImageCache::CacheImage(const std::string& key, const std::shared_ptr<CachedImage>& image)
49 {
50 if (key.empty() || capacity_ == 0) {
51 return;
52 }
53 std::scoped_lock lock(imageCacheMutex_);
54 CountLimitLRU::CacheWithCountLimitLRU<std::shared_ptr<CachedImage>>(key, image, cacheList_, imageCache_, capacity_);
55 }
56
GetCacheImage(const std::string & key)57 std::shared_ptr<CachedImage> ImageCache::GetCacheImage(const std::string& key)
58 {
59 std::scoped_lock lock(imageCacheMutex_);
60 return CountLimitLRU::GetCacheObjWithCountLimitLRU<std::shared_ptr<CachedImage>>(key, cacheList_, imageCache_);
61 }
62
CacheImgObjNG(const std::string & key,const RefPtr<NG::ImageObject> & imgObj)63 void ImageCache::CacheImgObjNG(const std::string& key, const RefPtr<NG::ImageObject>& imgObj)
64 {
65 if (key.empty() || imgObjCapacity_ == 0) {
66 return;
67 }
68 std::scoped_lock lock(imgObjMutex_);
69 CountLimitLRU::CacheWithCountLimitLRU<RefPtr<NG::ImageObject>>(
70 key, imgObj, cacheImgObjListNG_, imgObjCacheNG_, imgObjCapacity_);
71 }
72
GetCacheImgObjNG(const std::string & key)73 RefPtr<NG::ImageObject> ImageCache::GetCacheImgObjNG(const std::string& key)
74 {
75 std::scoped_lock lock(imgObjMutex_);
76 return CountLimitLRU::GetCacheObjWithCountLimitLRU<RefPtr<NG::ImageObject>>(
77 key, cacheImgObjListNG_, imgObjCacheNG_);
78 }
79
CacheImgObj(const std::string & key,const RefPtr<ImageObject> & imgObj)80 void ImageCache::CacheImgObj(const std::string& key, const RefPtr<ImageObject>& imgObj)
81 {
82 if (key.empty() || imgObjCapacity_ == 0) {
83 return;
84 }
85 std::scoped_lock lock(imgObjMutex_);
86 CountLimitLRU::CacheWithCountLimitLRU<RefPtr<ImageObject>>(
87 key, imgObj, cacheImgObjList_, imgObjCache_, imgObjCapacity_);
88 }
89
GetCacheImgObj(const std::string & key)90 RefPtr<ImageObject> ImageCache::GetCacheImgObj(const std::string& key)
91 {
92 std::scoped_lock lock(imgObjMutex_);
93 return CountLimitLRU::GetCacheObjWithCountLimitLRU<RefPtr<ImageObject>>(key, cacheImgObjList_, imgObjCache_);
94 }
95
CacheImageData(const std::string & key,const RefPtr<NG::ImageData> & imageData)96 void ImageCache::CacheImageData(const std::string& key, const RefPtr<NG::ImageData>& imageData)
97 {
98 if (key.empty() || !imageData || dataSizeLimit_ == 0) {
99 return;
100 }
101 std::scoped_lock lock(dataCacheMutex_);
102 auto dataSize = imageData->GetSize();
103 if (dataSize > (dataSizeLimit_ >> 1)) { // if data is longer than half limit, do not cache it.
104 TAG_LOGW(AceLogTag::ACE_IMAGE, "data is %{public}d, bigger than half limit %{public}d, do not cache it",
105 static_cast<int32_t>(dataSize), static_cast<int32_t>(dataSizeLimit_ >> 1));
106 return;
107 }
108 auto iter = imageDataCache_.find(key);
109 if (iter == imageDataCache_.end()) {
110 if (!ProcessImageDataCacheInner(dataSize)) {
111 return;
112 }
113 dataCacheList_.emplace_front(key, imageData);
114 imageDataCache_.emplace(key, dataCacheList_.begin());
115 } else {
116 auto oldSize = iter->second->cacheObj->GetSize();
117 if (oldSize != dataSize) {
118 curDataSize_ -= oldSize;
119 if (!ProcessImageDataCacheInner(dataSize)) {
120 return;
121 }
122 }
123 iter->second->cacheObj = imageData;
124 dataCacheList_.splice(dataCacheList_.begin(), dataCacheList_, iter->second);
125 iter->second = dataCacheList_.begin();
126 }
127 }
128
ProcessImageDataCacheInner(size_t dataSize)129 bool ImageCache::ProcessImageDataCacheInner(size_t dataSize)
130 {
131 while (dataSize + curDataSize_ > dataSizeLimit_ && !dataCacheList_.empty()) {
132 curDataSize_ -= dataCacheList_.back().cacheObj->GetSize();
133 imageDataCache_.erase(dataCacheList_.back().cacheKey);
134 dataCacheList_.pop_back();
135 }
136 if (dataSize + curDataSize_ > dataSizeLimit_) {
137 return false;
138 }
139 curDataSize_ += dataSize;
140 return true;
141 }
142
GetCacheImageData(const std::string & key)143 RefPtr<NG::ImageData> ImageCache::GetCacheImageData(const std::string& key)
144 {
145 std::scoped_lock lock(dataCacheMutex_);
146 auto iter = imageDataCache_.find(key);
147 if (iter != imageDataCache_.end()) {
148 dataCacheList_.splice(dataCacheList_.begin(), dataCacheList_, iter->second);
149 iter->second = dataCacheList_.begin();
150 return iter->second->cacheObj;
151 }
152 return nullptr;
153 }
154
ClearCacheImage(const std::string & key)155 void ImageCache::ClearCacheImage(const std::string& key)
156 {
157 {
158 std::scoped_lock lock(imageCacheMutex_);
159 auto iter = imageCache_.find(key);
160 if (iter != imageCache_.end()) {
161 cacheList_.erase(iter->second);
162 imageCache_.erase(iter);
163 }
164 }
165
166 {
167 std::scoped_lock lock(dataCacheMutex_);
168 auto iter = imageDataCache_.find(key);
169 if (iter != imageDataCache_.end()) {
170 dataCacheList_.erase(iter->second);
171 imageDataCache_.erase(iter);
172 }
173 }
174 }
175
Clear()176 void ImageCache::Clear()
177 {
178 {
179 std::scoped_lock lock(imageCacheMutex_);
180 cacheList_.clear();
181 imageCache_.clear();
182 }
183 {
184 std::scoped_lock lock(dataCacheMutex_);
185 dataCacheList_.clear();
186 imageDataCache_.clear();
187 }
188 {
189 std::scoped_lock lock(imgObjMutex_);
190 cacheImgObjListNG_.clear();
191 imgObjCacheNG_.clear();
192 cacheImgObjList_.clear();
193 imgObjCache_.clear();
194 }
195 }
196
DumpCacheInfo()197 void ImageCache::DumpCacheInfo()
198 {
199 auto cacheSize = dataCacheList_.size();
200 auto capacity = static_cast<int32_t>(capacity_);
201 auto dataSizeLimit = static_cast<int32_t>(dataSizeLimit_);
202 DumpLog::GetInstance().Print("------------ImageCacheInfo------------");
203 DumpLog::GetInstance().Print("User set ImageRawDataCacheSize : " + std::to_string(dataSizeLimit) + "(B)" +
204 ", ImageCacheCount :" + std::to_string(capacity) + "(number)");
205 DumpLog::GetInstance().Print("Cache count: " + std::to_string(cacheSize));
206 if (cacheSize == 0) {
207 return;
208 }
209 auto totalCount = 0;
210 for (const auto& item : dataCacheList_) {
211 auto imageObj = item.cacheObj;
212 auto key = item.cacheKey;
213 std::string srcStr = "NA";
214 for (const auto& cacheImageObj : cacheImgObjListNG_) {
215 if (cacheImageObj.cacheKey == key) {
216 srcStr = cacheImageObj.cacheObj->GetSourceInfo().ToString();
217 break;
218 }
219 }
220 totalCount += imageObj->GetSize();
221 DumpLog::GetInstance().Print("Cache Obj of key: " + key + ", src:" + srcStr + "," + imageObj->ToString());
222 }
223 DumpLog::GetInstance().Print("Cache total size: " + std::to_string(totalCount));
224 }
225 } // namespace OHOS::Ace
226