• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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/components_ng/image_provider/image_provider.h"
17 
18 #include "base/log/log_wrapper.h"
19 #include "base/network/download_manager.h"
20 #include "base/subwindow/subwindow_manager.h"
21 #include "core/components_ng/image_provider/image_decoder.h"
22 #include "core/components_ng/image_provider/drawing_image_data.h"
23 #include "core/components_ng/image_provider/animated_image_object.h"
24 #include "core/components_ng/image_provider/image_loading_context.h"
25 #include "core/components_ng/image_provider/image_object.h"
26 #include "core/components_ng/image_provider/image_utils.h"
27 #include "core/components_ng/image_provider/pixel_map_image_object.h"
28 #include "core/components_ng/image_provider/static_image_object.h"
29 #include "core/components_ng/image_provider/svg_image_object.h"
30 #include "core/components_ng/pattern/image/image_dfx.h"
31 #include "core/components_ng/render/adapter/drawing_image.h"
32 #include "core/image/image_loader.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34 
35 namespace OHOS::Ace::NG {
36 namespace {
37 constexpr uint64_t MAX_WAITING_TIME_FOR_TASKS = 1000; // 1000ms
38 }
CacheImageObject(const RefPtr<ImageObject> & obj)39 void ImageProvider::CacheImageObject(const RefPtr<ImageObject>& obj)
40 {
41     CHECK_NULL_VOID(obj);
42     auto pipelineCtx = PipelineContext::GetCurrentContext();
43     CHECK_NULL_VOID(pipelineCtx);
44     auto cache = pipelineCtx->GetImageCache();
45     CHECK_NULL_VOID(cache);
46     if (cache && obj->IsSupportCache()) {
47         cache->CacheImgObjNG(obj->GetSourceInfo().GetKey(), obj);
48     }
49 }
50 
51 std::timed_mutex ImageProvider::taskMtx_;
52 std::unordered_map<std::string, ImageProvider::Task> ImageProvider::tasks_;
53 
PrepareImageData(const RefPtr<ImageObject> & imageObj)54 bool ImageProvider::PrepareImageData(const RefPtr<ImageObject>& imageObj)
55 {
56     CHECK_NULL_RETURN(imageObj, false);
57     auto&& dfxConfig = imageObj->GetImageDfxConfig();
58     // Attempt to acquire a timed lock (maximum wait time: 1000ms)
59     auto lock = imageObj->GetPrepareImageDataLock();
60     if (!lock.owns_lock()) {
61         TAG_LOGW(AceLogTag::ACE_IMAGE, "Lock timeout. %{private}s-%{public}s.",
62             dfxConfig.GetImageSrc().c_str(), dfxConfig.ToStringWithoutSrc().c_str());
63         return false;
64     }
65     // data already loaded
66     if (imageObj->GetData()) {
67         return true;
68     }
69 
70     auto container = Container::Current();
71     if (container && container->IsSubContainer()) {
72         TAG_LOGW(AceLogTag::ACE_IMAGE, "%{private}s-%{public}s. subContainer's dataProviderManager is null.",
73             dfxConfig.GetImageSrc().c_str(), dfxConfig.ToStringWithoutSrc().c_str());
74         auto currentId = SubwindowManager::GetInstance()->GetParentContainerId(Container::CurrentId());
75         container = Container::GetContainer(currentId);
76     }
77     CHECK_NULL_RETURN(container, false);
78     auto pipeline = container->GetPipelineContext();
79     CHECK_NULL_RETURN(pipeline, false);
80     // if image object has no skData, reload data.
81     auto imageLoader = ImageLoader::CreateImageLoader(imageObj->GetSourceInfo());
82     if (!imageLoader) {
83         TAG_LOGW(AceLogTag::ACE_IMAGE, "Loader create fail. %{public}s-[%{private}s]",
84             dfxConfig.ToStringWithoutSrc().c_str(), dfxConfig.GetImageSrc().c_str());
85         return false;
86     }
87     NG::ImageLoadResultInfo loadResultInfo;
88     auto newLoadedData =
89         imageLoader->GetImageData(imageObj->GetSourceInfo(), loadResultInfo, WeakClaim(RawPtr(pipeline)));
90     CHECK_NULL_RETURN(newLoadedData, false);
91     // load data success
92     imageObj->SetData(newLoadedData);
93     return true;
94 }
95 
QueryThumbnailCache(const ImageSourceInfo & src)96 RefPtr<ImageObject> ImageProvider::QueryThumbnailCache(const ImageSourceInfo& src)
97 {
98     // query thumbnail from cache
99     auto pipeline = PipelineContext::GetCurrentContext();
100     CHECK_NULL_RETURN(pipeline, nullptr);
101     auto cache = pipeline->GetImageCache();
102     CHECK_NULL_RETURN(cache, nullptr);
103     auto data = DynamicCast<PixmapData>(cache->GetCacheImageData(src.GetKey()));
104     if (data) {
105         return PixelMapImageObject::Create(src, data);
106     }
107     return nullptr;
108 }
109 
QueryImageObjectFromCache(const ImageSourceInfo & src)110 RefPtr<ImageObject> ImageProvider::QueryImageObjectFromCache(const ImageSourceInfo& src)
111 {
112     if (src.GetSrcType() == SrcType::DATA_ABILITY_DECODED) {
113         return QueryThumbnailCache(src);
114     }
115     if (!src.SupportObjCache()) {
116         return nullptr;
117     }
118     auto pipelineCtx = PipelineContext::GetCurrentContext();
119     CHECK_NULL_RETURN(pipelineCtx, nullptr);
120     auto imageCache = pipelineCtx->GetImageCache();
121     CHECK_NULL_RETURN(imageCache, nullptr);
122     RefPtr<ImageObject> imageObj = imageCache->GetCacheImgObjNG(src.GetKey());
123     return imageObj;
124 }
125 
FailCallback(const std::string & key,const std::string & errorMsg,const ImageErrorInfo & errorInfo,bool sync,int32_t containerId)126 void ImageProvider::FailCallback(const std::string& key, const std::string& errorMsg, const ImageErrorInfo& errorInfo,
127     bool sync, int32_t containerId)
128 {
129     auto ctxs = EndTask(key);
130     auto notifyLoadFailTask = [ctxs, errorMsg, errorInfo] {
131         for (auto&& it : ctxs) {
132             auto ctx = it.Upgrade();
133             if (!ctx) {
134                 continue;
135             }
136             ctx->FailCallback(errorMsg, errorInfo);
137         }
138     };
139 
140     if (sync) {
141         notifyLoadFailTask();
142     } else {
143         ImageUtils::PostToUI(std::move(notifyLoadFailTask), "ArkUIImageProviderFail", containerId);
144     }
145 }
146 
SuccessCallback(const RefPtr<CanvasImage> & canvasImage,const std::string & key,bool sync,int32_t containerId)147 void ImageProvider::SuccessCallback(
148     const RefPtr<CanvasImage>& canvasImage, const std::string& key, bool sync, int32_t containerId)
149 {
150     canvasImage->Cache(key);
151     auto ctxs = EndTask(key);
152     // when upload success, pass back canvasImage to LoadingContext
153     auto notifyLoadSuccess = [ctxs, canvasImage] {
154         for (auto&& it : ctxs) {
155             auto ctx = it.Upgrade();
156             if (!ctx) {
157                 continue;
158             }
159             ctx->SuccessCallback(canvasImage->Clone());
160         }
161     };
162 
163     if (sync) {
164         notifyLoadSuccess();
165     } else {
166         ImageUtils::PostToUI(std::move(notifyLoadSuccess), "ArkUIImageProviderSuccess", containerId);
167     }
168 }
169 
CreateImageObjHelper(const ImageSourceInfo & src,bool sync,bool isSceneBoardWindow)170 void ImageProvider::CreateImageObjHelper(const ImageSourceInfo& src, bool sync, bool isSceneBoardWindow)
171 {
172     const ImageDfxConfig& imageDfxConfig = src.GetImageDfxConfig();
173     ACE_SCOPED_TRACE("CreateImageObj %s", imageDfxConfig.ToStringWithSrc().c_str());
174     // load image data
175     auto imageLoader = ImageLoader::CreateImageLoader(src);
176     if (!imageLoader) {
177         FailCallback(src.GetTaskKey(), "Failed to create image loader.",
178             { ImageErrorCode::CREATE_IMAGE_UNKNOWN_SOURCE_TYPE, "unknown source type." }, sync, src.GetContainerId());
179         return;
180     }
181     ImageLoadResultInfo loadResultInfo;
182     auto pipeline = PipelineContext::GetCurrentContext();
183     RefPtr<ImageData> data = imageLoader->GetImageData(src, loadResultInfo, WeakClaim(RawPtr(pipeline)));
184     if (!data) {
185         FailCallback(
186             src.GetTaskKey(), "Failed to load image data", loadResultInfo.errorInfo, sync, src.GetContainerId());
187         return;
188     }
189 
190     // build ImageObject
191     RefPtr<ImageObject> imageObj = ImageProvider::BuildImageObject(src, loadResultInfo.errorInfo, data);
192     if (!imageObj) {
193         FailCallback(
194             src.GetTaskKey(), "Failed to build image object", loadResultInfo.errorInfo, sync, src.GetContainerId());
195         return;
196     }
197 
198     imageObj->SetImageFileSize(loadResultInfo.fileSize);
199 
200     auto cloneImageObj = imageObj->Clone();
201 
202     // ImageObject cache is only for saving image size info, clear data to save memory
203     cloneImageObj->ClearData();
204 
205     // Only skip caching when the image is SVG and it's SceneBorder
206     if (!src.IsSvg() || !isSceneBoardWindow) {
207         CacheImageObject(cloneImageObj);
208     }
209 
210     auto ctxs = EndTask(src.GetTaskKey());
211 
212     // callback to LoadingContext
213     auto notifyDataReadyTask = [ctxs, imageObj, src] {
214         for (auto&& it : ctxs) {
215             auto ctx = it.Upgrade();
216             if (!ctx) {
217                 continue;
218             }
219             ctx->DataReadyCallback(imageObj);
220         }
221     };
222 
223     if (sync) {
224         notifyDataReadyTask();
225     } else {
226         ImageUtils::PostToUI(std::move(notifyDataReadyTask), "ArkUIImageProviderDataReady", src.GetContainerId());
227     }
228 }
229 
RegisterTask(const std::string & key,const WeakPtr<ImageLoadingContext> & ctx)230 bool ImageProvider::RegisterTask(const std::string& key, const WeakPtr<ImageLoadingContext>& ctx)
231 {
232     if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
233         TAG_LOGW(AceLogTag::ACE_IMAGE, "Lock timeout in registerTask.");
234         return false;
235     }
236     // Adopt the already acquired lock
237     std::scoped_lock lock(std::adopt_lock, taskMtx_);
238     // key exists -> task is running
239     auto it = tasks_.find(key);
240     if (it != tasks_.end()) {
241         it->second.ctxs_.insert(ctx);
242         return false;
243     }
244     tasks_[key].ctxs_.insert(ctx);
245     return true;
246 }
247 
EndTask(const std::string & key,bool isErase)248 std::set<WeakPtr<ImageLoadingContext>> ImageProvider::EndTask(const std::string& key, bool isErase)
249 {
250     if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
251         TAG_LOGW(AceLogTag::ACE_IMAGE, "Lock timeout in endTask.");
252         return {};
253     }
254     // Adopt the already acquired lock
255     std::scoped_lock lock(std::adopt_lock, taskMtx_);
256     auto it = tasks_.find(key);
257     if (it == tasks_.end()) {
258         TAG_LOGW(AceLogTag::ACE_IMAGE, "Task InvalidKey %{private}s", key.c_str());
259         return {};
260     }
261     auto ctxs = it->second.ctxs_;
262     if (isErase) {
263         tasks_.erase(it);
264     }
265     return ctxs;
266 }
267 
CancelTask(const std::string & key,const WeakPtr<ImageLoadingContext> & ctx)268 bool ImageProvider::CancelTask(const std::string& key, const WeakPtr<ImageLoadingContext>& ctx)
269 {
270     if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
271         TAG_LOGW(AceLogTag::ACE_IMAGE, "Lock timeout in cancelTask.");
272         return false;
273     }
274     // Adopt the already acquired lock
275     std::scoped_lock lock(std::adopt_lock, taskMtx_);
276     auto it = tasks_.find(key);
277     CHECK_NULL_RETURN(it != tasks_.end(), false);
278     CHECK_NULL_RETURN(it->second.ctxs_.find(ctx) != it->second.ctxs_.end(), false);
279     // only one LoadingContext waiting for this task, can just cancel
280     if (it->second.ctxs_.size() == 1) {
281         // task should be deleted regardless of whether the cancellation is successful or not
282         it->second.bgTask_.Cancel();
283         tasks_.erase(it);
284         return true;
285     }
286     // other LoadingContext still waiting for this task, remove ctx from set
287     it->second.ctxs_.erase(ctx);
288     return false;
289 }
290 
DownLoadSuccessCallback(const RefPtr<ImageObject> & imageObj,const std::string & key,bool sync,int32_t containerId)291 void ImageProvider::DownLoadSuccessCallback(
292     const RefPtr<ImageObject>& imageObj, const std::string& key, bool sync, int32_t containerId)
293 {
294     ImageProvider::CacheImageObject(imageObj);
295     auto ctxs = EndTask(key);
296     auto notifyDownLoadSuccess = [ctxs, imageObj] {
297         for (auto&& it : ctxs) {
298             auto ctx = it.Upgrade();
299             if (!ctx) {
300                 continue;
301             }
302             ctx->DataReadyCallback(imageObj);
303         }
304     };
305 
306     if (sync) {
307         notifyDownLoadSuccess();
308     } else {
309         ImageUtils::PostToUI(std::move(notifyDownLoadSuccess), "ArkUIImageProviderDownLoadSuccess", containerId);
310     }
311 }
312 
DownLoadOnProgressCallback(const std::string & key,bool sync,const uint32_t & dlNow,const uint32_t & dlTotal,int32_t containerId)313 void ImageProvider::DownLoadOnProgressCallback(
314     const std::string& key, bool sync, const uint32_t& dlNow, const uint32_t& dlTotal, int32_t containerId)
315 {
316     auto ctxs = EndTask(key, false);
317     auto notifyDownLoadOnProgressCallback = [ctxs, dlNow, dlTotal] {
318         for (auto&& it : ctxs) {
319             auto ctx = it.Upgrade();
320             if (!ctx) {
321                 continue;
322             }
323             ctx->DownloadOnProgress(dlNow, dlTotal);
324         }
325     };
326 
327     if (sync) {
328         notifyDownLoadOnProgressCallback();
329     } else {
330         ImageUtils::PostToUI(
331             std::move(notifyDownLoadOnProgressCallback), "ArkUIImageDownloadOnProcessCallback", containerId);
332     }
333 }
334 
QueryDataFromCache(const ImageSourceInfo & src)335 RefPtr<ImageData> ImageProvider::QueryDataFromCache(const ImageSourceInfo& src)
336 {
337     ACE_FUNCTION_TRACE();
338     std::string result;
339     if (DownloadManager::GetInstance()->fetchCachedResult(src.GetSrc(), result)) {
340         auto data = ImageData::MakeFromDataWithCopy(result.data(), result.size());
341         return data;
342     }
343     return nullptr;
344 }
345 
DownLoadImage(const UriDownLoadConfig & downLoadConfig)346 void ImageProvider::DownLoadImage(const UriDownLoadConfig& downLoadConfig)
347 {
348     ACE_SCOPED_TRACE("PerformDownload %s", downLoadConfig.imageDfxConfig.ToStringWithSrc().c_str());
349     auto queryData = QueryDataFromCache(downLoadConfig.src);
350     if (queryData) {
351         ImageErrorInfo errorInfo;
352         RefPtr<ImageObject> imageObj = ImageProvider::BuildImageObject(downLoadConfig.src, errorInfo, queryData);
353         if (imageObj) {
354             ACE_SCOPED_TRACE("Hit network image cache %s", downLoadConfig.imageDfxConfig.ToStringWithSrc().c_str());
355             ImageProvider::DownLoadSuccessCallback(
356                 imageObj, downLoadConfig.taskKey, downLoadConfig.sync, downLoadConfig.src.GetContainerId());
357             return;
358         }
359     }
360     DownloadCallback downloadCallback;
361     downloadCallback.successCallback = [downLoadConfig, containerId = downLoadConfig.src.GetContainerId()](
362                                            const std::string&& imageData, bool async, int32_t instanceId) {
363         ContainerScope scope(instanceId);
364         ACE_SCOPED_TRACE("DownloadImageSuccess %s, [%zu]", downLoadConfig.imageDfxConfig.ToStringWithSrc().c_str(),
365             imageData.size());
366         ImageErrorInfo errorInfo;
367         if (!GreatNotEqual(imageData.size(), 0)) {
368             ImageProvider::FailCallback(downLoadConfig.taskKey, "The length of imageData from netStack is not positive",
369                 errorInfo, downLoadConfig.sync, containerId);
370             return;
371         }
372         auto data = ImageData::MakeFromDataWithCopy(imageData.data(), imageData.size());
373         RefPtr<ImageObject> imageObj = ImageProvider::BuildImageObject(downLoadConfig.src, errorInfo, data);
374         if (!imageObj) {
375             ImageProvider::FailCallback(downLoadConfig.taskKey, "After download successful, imageObject Create fail",
376                 errorInfo, downLoadConfig.sync, containerId);
377             return;
378         }
379         ImageProvider::DownLoadSuccessCallback(imageObj, downLoadConfig.taskKey, downLoadConfig.sync, containerId);
380     };
381     downloadCallback.failCallback = [taskKey = downLoadConfig.taskKey, sync = downLoadConfig.sync,
382                                         containerId = downLoadConfig.src.GetContainerId()](std::string errorMessage,
383                                         ImageErrorInfo errorInfo, bool async, int32_t instanceId) {
384         ContainerScope scope(instanceId);
385         ImageProvider::FailCallback(taskKey, errorMessage, errorInfo, sync, containerId);
386     };
387     downloadCallback.cancelCallback = downloadCallback.failCallback;
388     if (downLoadConfig.hasProgressCallback) {
389         downloadCallback.onProgressCallback = [taskKey = downLoadConfig.taskKey, sync = downLoadConfig.sync,
390                                                   containerId = downLoadConfig.src.GetContainerId()](
391                                                   uint32_t dlTotal, uint32_t dlNow, bool async, int32_t instanceId) {
392             ContainerScope scope(instanceId);
393             ImageProvider::DownLoadOnProgressCallback(taskKey, sync, dlNow, dlTotal, containerId);
394         };
395     }
396     NetworkImageLoader::DownloadImage(std::move(downloadCallback), downLoadConfig.src.GetSrc(), downLoadConfig.sync);
397 }
398 
CreateImageObject(const ImageSourceInfo & src,const WeakPtr<ImageLoadingContext> & ctxWp,bool sync,bool isSceneBoardWindow)399 void ImageProvider::CreateImageObject(
400     const ImageSourceInfo& src, const WeakPtr<ImageLoadingContext>& ctxWp, bool sync, bool isSceneBoardWindow)
401 {
402     if (src.GetSrcType() == SrcType::NETWORK && SystemProperties::GetDownloadByNetworkEnabled()) {
403         auto ctx = ctxWp.Upgrade();
404         CHECK_NULL_VOID(ctx);
405         const std::string taskKey = src.GetTaskKey() + (ctx->GetOnProgressCallback() ? "1" : "0");
406         if (!RegisterTask(taskKey, ctxWp)) {
407             // task is already running, only register callbacks
408             return;
409         }
410         UriDownLoadConfig downloadConfig = {
411             .src = src,
412             .imageDfxConfig = ctx->GetImageDfxConfig(),
413             .taskKey = taskKey,
414             .sync = sync,
415             .hasProgressCallback = static_cast<bool>(ctx->GetOnProgressCallback())
416         };
417         if (sync) {
418             DownLoadImage(downloadConfig);
419         } else {
420             auto downloadConfigPtr = std::make_shared<UriDownLoadConfig>(std::move(downloadConfig));
421             auto downloadImageTask = [downloadConfigPtr]() {
422                 DownLoadImage(*downloadConfigPtr);
423             };
424             ImageUtils::PostToBg(downloadImageTask, "ArkUIImageDownload", src.GetContainerId());
425         }
426         return;
427     }
428     if (!RegisterTask(src.GetTaskKey(), ctxWp)) {
429         // task is already running, only register callbacks
430         return;
431     }
432     if (sync) {
433         CreateImageObjHelper(src, true, isSceneBoardWindow);
434     } else {
435         if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
436             TAG_LOGW(AceLogTag::ACE_IMAGE, "Lock timeout in createObj.");
437             return;
438         }
439         // Adopt the already acquired lock
440         std::scoped_lock lock(std::adopt_lock, taskMtx_);
441         // wrap with [CancelableCallback] and record in [tasks_] map
442         CancelableCallback<void()> task;
443         task.Reset(
444             [src, isSceneBoardWindow] { ImageProvider::CreateImageObjHelper(src, false, isSceneBoardWindow); });
445         tasks_[src.GetTaskKey()].bgTask_ = task;
446         auto ctx = ctxWp.Upgrade();
447         CHECK_NULL_VOID(ctx);
448         ImageUtils::PostToBg(task, "ArkUIImageProviderCreateImageObject", ctx->GetContainerId());
449     }
450 }
451 
BuildImageObject(const ImageSourceInfo & src,ImageErrorInfo & errorInfo,const RefPtr<ImageData> & data)452 RefPtr<ImageObject> ImageProvider::BuildImageObject(
453     const ImageSourceInfo& src, ImageErrorInfo& errorInfo, const RefPtr<ImageData>& data)
454 {
455     auto imageDfxConfig = src.GetImageDfxConfig();
456     if (!data) {
457         TAG_LOGW(AceLogTag::ACE_IMAGE, "data is null when build obj, [%{private}s]-%{public}s.",
458             imageDfxConfig.GetImageSrc().c_str(), imageDfxConfig.ToStringWithoutSrc().c_str());
459         return nullptr;
460     }
461     if (src.IsSvg()) {
462         // SVG object needs to make SVG dom during creation
463         return SvgImageObject::Create(src, errorInfo, data);
464     }
465     if (src.IsPixmap()) {
466         return PixelMapImageObject::Create(src, data);
467     }
468 
469     auto rosenImageData = DynamicCast<DrawingImageData>(data);
470     if (!rosenImageData) {
471         TAG_LOGW(AceLogTag::ACE_IMAGE, "rosenImageData null, [%{private}s]-%{public}s.",
472             imageDfxConfig.GetImageSrc().c_str(), imageDfxConfig.ToStringWithoutSrc().c_str());
473         return nullptr;
474     }
475     rosenImageData->SetDfxConfig(imageDfxConfig.GetNodeId(), imageDfxConfig.GetAccessibilityId());
476     auto codec = rosenImageData->Parse();
477     if (!codec.imageSize.IsPositive()) {
478         TAG_LOGW(AceLogTag::ACE_IMAGE,
479             "%{private}s - %{public}s dataSize is invalid : %{public}d-%{public}s-%{public}d.", src.ToString().c_str(),
480             imageDfxConfig.ToStringWithoutSrc().c_str(), static_cast<int32_t>(data->GetSize()),
481             codec.imageSize.ToString().c_str(), codec.frameCount);
482         if (errorInfo.errorCode == ImageErrorCode::DEFAULT) {
483             errorInfo = { ImageErrorCode::BUILD_IMAGE_DATA_SIZE_INVALID, "image data size is invalid." };
484         }
485         return nullptr;
486     }
487     RefPtr<ImageObject> imageObject;
488     if (codec.frameCount > 1) {
489         auto imageObject = MakeRefPtr<AnimatedImageObject>(src, codec.imageSize, data);
490         imageObject->SetFrameCount(codec.frameCount);
491         return imageObject;
492     }
493     imageObject = MakeRefPtr<StaticImageObject>(src, codec.imageSize, data);
494     imageObject->SetOrientation(codec.orientation);
495     return imageObject;
496 }
497 
MakeCanvasImage(const RefPtr<ImageObject> & obj,const WeakPtr<ImageLoadingContext> & ctxWp,const SizeF & size,const ImageDecoderOptions & imageDecoderOptions)498 void ImageProvider::MakeCanvasImage(const RefPtr<ImageObject>& obj, const WeakPtr<ImageLoadingContext>& ctxWp,
499     const SizeF& size, const ImageDecoderOptions& imageDecoderOptions)
500 {
501     auto key = ImageUtils::GenerateImageKey(obj->GetSourceInfo(), size);
502     // check if same task is already executing
503     if (!RegisterTask(key, ctxWp)) {
504         return;
505     }
506     if (imageDecoderOptions.sync) {
507         MakeCanvasImageHelper(obj, size, key, imageDecoderOptions);
508     } else {
509         if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
510             TAG_LOGW(AceLogTag::ACE_IMAGE, "Lock timeout in makeCanvasImage.");
511             return;
512         }
513         // Adopt the already acquired lock
514         std::scoped_lock lock(std::adopt_lock, taskMtx_);
515         // wrap with [CancelableCallback] and record in [tasks_] map
516         CancelableCallback<void()> task;
517         task.Reset(
518             [key, obj, size, imageDecoderOptions] { MakeCanvasImageHelper(obj, size, key, imageDecoderOptions); });
519         tasks_[key].bgTask_ = task;
520         auto ctx = ctxWp.Upgrade();
521         CHECK_NULL_VOID(ctx);
522         ImageUtils::PostToBg(task, "ArkUIImageProviderMakeCanvasImage", ctx->GetContainerId());
523     }
524 }
525 
MakeCanvasImageHelper(const RefPtr<ImageObject> & obj,const SizeF & size,const std::string & key,const ImageDecoderOptions & imageDecoderOptions)526 void ImageProvider::MakeCanvasImageHelper(const RefPtr<ImageObject>& obj, const SizeF& size, const std::string& key,
527     const ImageDecoderOptions& imageDecoderOptions)
528 {
529     RefPtr<CanvasImage> image = nullptr;
530     ImageDecoderConfig imageDecoderConfig = {
531         .desiredSize_ = size,
532         .forceResize_ = imageDecoderOptions.forceResize,
533         .imageQuality_ = imageDecoderOptions.imageQuality,
534         .isHdrDecoderNeed_ = imageDecoderOptions.isHdrDecoderNeed,
535         .photoDecodeFormat_ = imageDecoderOptions.photoDecodeFormat,
536     };
537     ImageErrorInfo errorInfo;
538     // preview and ohos platform
539     if (SystemProperties::GetImageFrameworkEnabled()) {
540         image = ImageDecoder::MakePixmapImage(obj, imageDecoderConfig, errorInfo);
541     } else {
542         image = ImageDecoder::MakeDrawingImage(obj, imageDecoderConfig);
543     }
544 
545     if (image) {
546         SuccessCallback(image, key, imageDecoderOptions.sync, obj->GetSourceInfo().GetContainerId());
547     } else {
548         FailCallback(
549             key, "Failed to decode image", errorInfo, imageDecoderOptions.sync, obj->GetSourceInfo().GetContainerId());
550     }
551 }
552 } // namespace OHOS::Ace::NG
553