• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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