• 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/adapter/image_decoder.h"
22 #include "core/components_ng/image_provider/adapter/rosen/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/rosen/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, "Failed to acquire lock within timeout. %{private}s-%{public}s.",
62             dfxConfig.imageSrc_.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 pipeline's dataProviderManager is null.",
73             dfxConfig.imageSrc_.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, "Failed to create loader in prepareImageData. %{public}s-[%{private}s]",
84             dfxConfig.ToStringWithoutSrc().c_str(), dfxConfig.imageSrc_.c_str());
85         return false;
86     }
87     auto newLoadedData = imageLoader->GetImageData(imageObj->GetSourceInfo(), WeakClaim(RawPtr(pipeline)));
88     CHECK_NULL_RETURN(newLoadedData, false);
89     // load data success
90     imageObj->SetData(newLoadedData);
91     return true;
92 }
93 
QueryThumbnailCache(const ImageSourceInfo & src)94 RefPtr<ImageObject> ImageProvider::QueryThumbnailCache(const ImageSourceInfo& src)
95 {
96     // query thumbnail from cache
97     auto pipeline = PipelineContext::GetCurrentContext();
98     CHECK_NULL_RETURN(pipeline, nullptr);
99     auto cache = pipeline->GetImageCache();
100     CHECK_NULL_RETURN(cache, nullptr);
101     auto data = DynamicCast<PixmapData>(cache->GetCacheImageData(src.GetKey()));
102     if (data) {
103         return PixelMapImageObject::Create(src, data);
104     }
105     return nullptr;
106 }
107 
QueryImageObjectFromCache(const ImageSourceInfo & src)108 RefPtr<ImageObject> ImageProvider::QueryImageObjectFromCache(const ImageSourceInfo& src)
109 {
110     if (src.GetSrcType() == SrcType::DATA_ABILITY_DECODED) {
111         return QueryThumbnailCache(src);
112     }
113     if (!src.SupportObjCache()) {
114         return nullptr;
115     }
116     auto pipelineCtx = PipelineContext::GetCurrentContext();
117     CHECK_NULL_RETURN(pipelineCtx, nullptr);
118     auto imageCache = pipelineCtx->GetImageCache();
119     CHECK_NULL_RETURN(imageCache, nullptr);
120     RefPtr<ImageObject> imageObj = imageCache->GetCacheImgObjNG(src.GetKey());
121     return imageObj;
122 }
123 
FailCallback(const std::string & key,const std::string & errorMsg,bool sync,int32_t containerId)124 void ImageProvider::FailCallback(
125     const std::string& key, const std::string& errorMsg, bool sync, int32_t containerId)
126 {
127     auto ctxs = EndTask(key);
128 
129     auto notifyLoadFailTask = [ctxs, errorMsg] {
130         for (auto&& it : ctxs) {
131             auto ctx = it.Upgrade();
132             CHECK_NULL_VOID(ctx);
133             ctx->FailCallback(errorMsg);
134         }
135     };
136 
137     if (sync) {
138         notifyLoadFailTask();
139     } else {
140         ImageUtils::PostToUI(std::move(notifyLoadFailTask), "ArkUIImageProviderFail", containerId);
141     }
142 }
143 
SuccessCallback(const RefPtr<CanvasImage> & canvasImage,const std::string & key,bool sync,int32_t containerId)144 void ImageProvider::SuccessCallback(
145     const RefPtr<CanvasImage>& canvasImage, const std::string& key, bool sync, int32_t containerId)
146 {
147     canvasImage->Cache(key);
148     auto ctxs = EndTask(key);
149     // when upload success, pass back canvasImage to LoadingContext
150     auto notifyLoadSuccess = [ctxs, canvasImage] {
151         for (auto&& it : ctxs) {
152             auto ctx = it.Upgrade();
153             CHECK_NULL_VOID(ctx);
154             ctx->SuccessCallback(canvasImage->Clone());
155         }
156     };
157 
158     if (sync) {
159         notifyLoadSuccess();
160     } else {
161         ImageUtils::PostToUI(std::move(notifyLoadSuccess), "ArkUIImageProviderSuccess", containerId);
162     }
163 }
164 
CreateImageObjHelper(const ImageSourceInfo & src,bool sync)165 void ImageProvider::CreateImageObjHelper(const ImageSourceInfo& src, bool sync)
166 {
167     const ImageDfxConfig& imageDfxConfig = src.GetImageDfxConfig();
168     ACE_SCOPED_TRACE("CreateImageObj %s", imageDfxConfig.ToStringWithSrc().c_str());
169     // load image data
170     auto imageLoader = ImageLoader::CreateImageLoader(src);
171     if (!imageLoader) {
172         FailCallback(src.GetTaskKey(), "Failed to create image loader.", sync, src.GetContainerId());
173         return;
174     }
175     auto pipeline = PipelineContext::GetCurrentContext();
176     RefPtr<ImageData> data = imageLoader->GetImageData(src, WeakClaim(RawPtr(pipeline)));
177     if (!data) {
178         FailCallback(src.GetTaskKey(), "Failed to load image data", sync, src.GetContainerId());
179         return;
180     }
181 
182     // build ImageObject
183     RefPtr<ImageObject> imageObj = ImageProvider::BuildImageObject(src, data);
184     if (!imageObj) {
185         FailCallback(src.GetTaskKey(), "Failed to build image object", sync, src.GetContainerId());
186         return;
187     }
188 
189     auto cloneImageObj = imageObj->Clone();
190 
191     // ImageObject cache is only for saving image size info, clear data to save memory
192     cloneImageObj->ClearData();
193 
194     CacheImageObject(cloneImageObj);
195 
196     auto ctxs = EndTask(src.GetTaskKey());
197 
198     // callback to LoadingContext
199     auto notifyDataReadyTask = [ctxs, imageObj, src] {
200         for (auto&& it : ctxs) {
201             auto ctx = it.Upgrade();
202             CHECK_NULL_VOID(ctx);
203             ctx->DataReadyCallback(imageObj);
204         }
205     };
206 
207     if (sync) {
208         notifyDataReadyTask();
209     } else {
210         ImageUtils::PostToUI(std::move(notifyDataReadyTask), "ArkUIImageProviderDataReady", src.GetContainerId());
211     }
212 }
213 
RegisterTask(const std::string & key,const WeakPtr<ImageLoadingContext> & ctx)214 bool ImageProvider::RegisterTask(const std::string& key, const WeakPtr<ImageLoadingContext>& ctx)
215 {
216     if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
217         TAG_LOGW(AceLogTag::ACE_IMAGE,
218             "Failed to acquire mutex within %{public}" PRIu64 "milliseconds, proceeding without registerTask access.",
219             MAX_WAITING_TIME_FOR_TASKS);
220         return false;
221     }
222     // Adopt the already acquired lock
223     std::scoped_lock lock(std::adopt_lock, taskMtx_);
224     // key exists -> task is running
225     auto it = tasks_.find(key);
226     if (it != tasks_.end()) {
227         it->second.ctxs_.insert(ctx);
228         return false;
229     }
230     tasks_[key].ctxs_.insert(ctx);
231     return true;
232 }
233 
EndTask(const std::string & key,bool isErase)234 std::set<WeakPtr<ImageLoadingContext>> ImageProvider::EndTask(const std::string& key, bool isErase)
235 {
236     if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
237         TAG_LOGW(AceLogTag::ACE_IMAGE,
238             "Failed to acquire mutex within %{public}" PRIu64 "milliseconds, proceeding without endTask access.",
239             MAX_WAITING_TIME_FOR_TASKS);
240         return {};
241     }
242     // Adopt the already acquired lock
243     std::scoped_lock lock(std::adopt_lock, taskMtx_);
244     auto it = tasks_.find(key);
245     if (it == tasks_.end()) {
246         TAG_LOGW(AceLogTag::ACE_IMAGE, "task not found in map %{private}s", key.c_str());
247         return {};
248     }
249     auto ctxs = it->second.ctxs_;
250     if (ctxs.empty()) {
251         TAG_LOGW(AceLogTag::ACE_IMAGE, "registered task has empty context %{private}s", key.c_str());
252     }
253     if (isErase) {
254         tasks_.erase(it);
255     }
256     return ctxs;
257 }
258 
CancelTask(const std::string & key,const WeakPtr<ImageLoadingContext> & ctx)259 void ImageProvider::CancelTask(const std::string& key, const WeakPtr<ImageLoadingContext>& ctx)
260 {
261     if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
262         TAG_LOGW(AceLogTag::ACE_IMAGE,
263             "Failed to acquire mutex within %{public}" PRIu64 "milliseconds, proceeding without cancelTask access.",
264             MAX_WAITING_TIME_FOR_TASKS);
265         return;
266     }
267     // Adopt the already acquired lock
268     std::scoped_lock lock(std::adopt_lock, taskMtx_);
269     auto it = tasks_.find(key);
270     CHECK_NULL_VOID(it != tasks_.end());
271     CHECK_NULL_VOID(it->second.ctxs_.find(ctx) != it->second.ctxs_.end());
272     // only one LoadingContext waiting for this task, can just cancel
273     if (it->second.ctxs_.size() == 1) {
274         // task should be deleted regardless of whether the cancellation is successful or not
275         it->second.bgTask_.Cancel();
276         tasks_.erase(it);
277         return;
278     }
279     // other LoadingContext still waiting for this task, remove ctx from set
280     it->second.ctxs_.erase(ctx);
281 }
282 
DownLoadSuccessCallback(const RefPtr<ImageObject> & imageObj,const std::string & key,bool sync,int32_t containerId)283 void ImageProvider::DownLoadSuccessCallback(
284     const RefPtr<ImageObject>& imageObj, const std::string& key, bool sync, int32_t containerId)
285 {
286     ImageProvider::CacheImageObject(imageObj);
287     auto ctxs = EndTask(key);
288     auto notifyDownLoadSuccess = [ctxs, imageObj] {
289         for (auto&& it : ctxs) {
290             auto ctx = it.Upgrade();
291             CHECK_NULL_VOID(ctx);
292             ctx->DataReadyCallback(imageObj);
293         }
294     };
295 
296     if (sync) {
297         notifyDownLoadSuccess();
298     } else {
299         ImageUtils::PostToUI(std::move(notifyDownLoadSuccess), "ArkUIImageProviderDownLoadSuccess", containerId);
300     }
301 }
302 
DownLoadOnProgressCallback(const std::string & key,bool sync,const uint32_t & dlNow,const uint32_t & dlTotal,int32_t containerId)303 void ImageProvider::DownLoadOnProgressCallback(
304     const std::string& key, bool sync, const uint32_t& dlNow, const uint32_t& dlTotal, int32_t containerId)
305 {
306     auto ctxs = EndTask(key, false);
307     auto notifyDownLoadOnProgressCallback = [ctxs, dlNow, dlTotal] {
308         for (auto&& it : ctxs) {
309             auto ctx = it.Upgrade();
310             CHECK_NULL_VOID(ctx);
311             ctx->DownloadOnProgress(dlNow, dlTotal);
312         }
313     };
314 
315     if (sync) {
316         notifyDownLoadOnProgressCallback();
317     } else {
318         ImageUtils::PostToUI(
319             std::move(notifyDownLoadOnProgressCallback), "ArkUIImageDownloadOnProcessCallback", containerId);
320     }
321 }
322 
QueryDataFromCache(const ImageSourceInfo & src)323 RefPtr<ImageData> ImageProvider::QueryDataFromCache(const ImageSourceInfo& src)
324 {
325     ACE_FUNCTION_TRACE();
326     std::string result;
327     if (DownloadManager::GetInstance()->fetchCachedResult(src.GetSrc(), result)) {
328         auto data = ImageData::MakeFromDataWithCopy(result.data(), result.size());
329         return data;
330     }
331     return nullptr;
332 }
333 
DownLoadImage(const ImageSourceInfo & src,const WeakPtr<ImageLoadingContext> & ctxWp,bool sync)334 void ImageProvider::DownLoadImage(const ImageSourceInfo& src, const WeakPtr<ImageLoadingContext>& ctxWp, bool sync)
335 {
336     auto ctx = ctxWp.Upgrade();
337     CHECK_NULL_VOID(ctx);
338     const std::string taskKey = src.GetTaskKey() + (ctx->GetOnProgressCallback() ? "1" : "0");
339     if (!RegisterTask(taskKey, ctxWp)) {
340         // task is already running, only register callbacks
341         return;
342     }
343     auto queryData = QueryDataFromCache(src);
344     if (queryData) {
345         RefPtr<ImageObject> imageObj = ImageProvider::BuildImageObject(src, queryData);
346         if (imageObj) {
347             ImageProvider::DownLoadSuccessCallback(imageObj, taskKey, sync, src.GetContainerId());
348             return;
349         }
350     }
351     DownloadCallback downloadCallback;
352     downloadCallback.successCallback = [ctxWp, sync, taskKey, containerId = src.GetContainerId()](
353                                            const std::string&& imageData, bool async, int32_t instanceId) {
354         ContainerScope scope(instanceId);
355         auto ctx = ctxWp.Upgrade();
356         CHECK_NULL_VOID(ctx);
357         ACE_SCOPED_TRACE(
358             "DownloadImageSuccess %s, [%zu]", ctx->GetImageDfxConfig().ToStringWithSrc().c_str(), imageData.size());
359         if (!GreatNotEqual(imageData.size(), 0)) {
360             ImageProvider::FailCallback(
361                 taskKey, "The length of imageData from netStack is not positive", sync, containerId);
362             return;
363         }
364         auto data = ImageData::MakeFromDataWithCopy(imageData.data(), imageData.size());
365         RefPtr<ImageObject> imageObj = ImageProvider::BuildImageObject(ctx->GetSourceInfo(), data);
366         if (!imageObj) {
367             ImageProvider::FailCallback(
368                 taskKey, "After download successful, imageObject Create fail", sync, containerId);
369             return;
370         }
371         ImageProvider::DownLoadSuccessCallback(imageObj, taskKey, sync, containerId);
372     };
373     downloadCallback.failCallback = [ctxWp, taskKey, sync, containerId = src.GetContainerId()](
374                                         std::string errorMessage, bool async, int32_t instanceId) {
375         ContainerScope scope(instanceId);
376         ImageProvider::FailCallback(taskKey, errorMessage, sync, containerId);
377     };
378     downloadCallback.cancelCallback = downloadCallback.failCallback;
379     if (ctx->GetOnProgressCallback()) {
380         downloadCallback.onProgressCallback = [ctxWp, taskKey, sync, containerId = src.GetContainerId()](
381                                                   uint32_t dlTotal, uint32_t dlNow, bool async, int32_t instanceId) {
382             ContainerScope scope(instanceId);
383             ImageProvider::DownLoadOnProgressCallback(taskKey, sync, dlNow, dlTotal, containerId);
384         };
385     }
386     NetworkImageLoader::DownloadImage(std::move(downloadCallback), src.GetSrc(), sync, src.GetImageDfxConfig().nodeId_);
387 }
388 
CreateImageObject(const ImageSourceInfo & src,const WeakPtr<ImageLoadingContext> & ctxWp,bool sync)389 void ImageProvider::CreateImageObject(const ImageSourceInfo& src, const WeakPtr<ImageLoadingContext>& ctxWp, bool sync)
390 {
391     if (src.GetSrcType() == SrcType::NETWORK && SystemProperties::GetDownloadByNetworkEnabled()) {
392         if (sync) {
393             DownLoadImage(src, ctxWp, sync);
394         } else {
395             auto downLoadImageTask = [&src, ctxWp, sync]() {
396                 DownLoadImage(src, ctxWp, sync);
397             };
398             ImageUtils::PostToBg(downLoadImageTask, "ArkUIImageDownload", src.GetContainerId());
399         }
400         return;
401     }
402     if (!RegisterTask(src.GetTaskKey(), ctxWp)) {
403         // task is already running, only register callbacks
404         return;
405     }
406     if (sync) {
407         CreateImageObjHelper(src, true);
408     } else {
409         if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
410             TAG_LOGW(AceLogTag::ACE_IMAGE,
411                 "Failed to acquire mutex within %{public}" PRIu64
412                 "milliseconds, proceeding without createImageObject access.",
413                 MAX_WAITING_TIME_FOR_TASKS);
414             return;
415         }
416         // Adopt the already acquired lock
417         std::scoped_lock lock(std::adopt_lock, taskMtx_);
418         // wrap with [CancelableCallback] and record in [tasks_] map
419         CancelableCallback<void()> task;
420         task.Reset([src] { ImageProvider::CreateImageObjHelper(src); });
421         tasks_[src.GetKey()].bgTask_ = task;
422         auto ctx = ctxWp.Upgrade();
423         CHECK_NULL_VOID(ctx);
424         ImageUtils::PostToBg(task, "ArkUIImageProviderCreateImageObject", ctx->GetContainerId());
425     }
426 }
427 
BuildImageObject(const ImageSourceInfo & src,const RefPtr<ImageData> & data)428 RefPtr<ImageObject> ImageProvider::BuildImageObject(const ImageSourceInfo& src, const RefPtr<ImageData>& data)
429 {
430     auto imageDfxConfig = src.GetImageDfxConfig();
431     if (!data) {
432         TAG_LOGW(AceLogTag::ACE_IMAGE, "data is null when try ParseImageObjectType, [%{private}s]-%{public}s.",
433             imageDfxConfig.imageSrc_.c_str(), imageDfxConfig.ToStringWithoutSrc().c_str());
434         return nullptr;
435     }
436     if (src.IsSvg()) {
437         // SVG object needs to make SVG dom during creation
438         return SvgImageObject::Create(src, data);
439     }
440     if (src.IsPixmap()) {
441         return PixelMapImageObject::Create(src, data);
442     }
443 
444     auto rosenImageData = DynamicCast<DrawingImageData>(data);
445     if (!rosenImageData) {
446         TAG_LOGW(AceLogTag::ACE_IMAGE, "rosenImageData null, [%{private}s]-%{public}s.",
447             imageDfxConfig.imageSrc_.c_str(), imageDfxConfig.ToStringWithoutSrc().c_str());
448         return nullptr;
449     }
450     rosenImageData->SetDfxConfig(imageDfxConfig.nodeId_, imageDfxConfig.accessibilityId_);
451     auto codec = rosenImageData->Parse();
452     if (!codec.imageSize.IsPositive()) {
453         TAG_LOGW(AceLogTag::ACE_IMAGE,
454             "Image of src: %{private}s, imageData's size = %{public}d is invalid, and the parsed size is invalid "
455             "%{private}s, frameCount is %{public}d, nodeId = %{public}s.",
456             src.ToString().c_str(), static_cast<int32_t>(data->GetSize()), codec.imageSize.ToString().c_str(),
457             codec.frameCount, imageDfxConfig.ToStringWithoutSrc().c_str());
458         return nullptr;
459     }
460     RefPtr<ImageObject> imageObject;
461     if (codec.frameCount > 1) {
462         auto imageObject = MakeRefPtr<AnimatedImageObject>(src, codec.imageSize, data);
463         imageObject->SetFrameCount(codec.frameCount);
464         return imageObject;
465     }
466     imageObject = MakeRefPtr<StaticImageObject>(src, codec.imageSize, data);
467     imageObject->SetOrientation(codec.orientation);
468     return imageObject;
469 }
470 
MakeCanvasImage(const RefPtr<ImageObject> & obj,const WeakPtr<ImageLoadingContext> & ctxWp,const SizeF & size,const ImageDecoderOptions & imageDecoderOptions)471 void ImageProvider::MakeCanvasImage(const RefPtr<ImageObject>& obj, const WeakPtr<ImageLoadingContext>& ctxWp,
472     const SizeF& size, const ImageDecoderOptions& imageDecoderOptions)
473 {
474     auto key = ImageUtils::GenerateImageKey(obj->GetSourceInfo(), size);
475     // check if same task is already executing
476     if (!RegisterTask(key, ctxWp)) {
477         return;
478     }
479     if (imageDecoderOptions.sync) {
480         MakeCanvasImageHelper(obj, size, key, imageDecoderOptions);
481     } else {
482         if (!taskMtx_.try_lock_for(std::chrono::milliseconds(MAX_WAITING_TIME_FOR_TASKS))) {
483             TAG_LOGW(AceLogTag::ACE_IMAGE,
484                 "Failed to acquire mutex within %{public}" PRIu64
485                 "milliseconds, proceeding without makeCanvasImage access.",
486                 MAX_WAITING_TIME_FOR_TASKS);
487             return;
488         }
489         // Adopt the already acquired lock
490         std::scoped_lock lock(std::adopt_lock, taskMtx_);
491         // wrap with [CancelableCallback] and record in [tasks_] map
492         CancelableCallback<void()> task;
493         task.Reset(
494             [key, obj, size, imageDecoderOptions] { MakeCanvasImageHelper(obj, size, key, imageDecoderOptions); });
495         tasks_[key].bgTask_ = task;
496         auto ctx = ctxWp.Upgrade();
497         CHECK_NULL_VOID(ctx);
498         ImageUtils::PostToBg(task, "ArkUIImageProviderMakeCanvasImage", ctx->GetContainerId());
499     }
500 }
501 
MakeCanvasImageHelper(const RefPtr<ImageObject> & obj,const SizeF & size,const std::string & key,const ImageDecoderOptions & imageDecoderOptions)502 void ImageProvider::MakeCanvasImageHelper(const RefPtr<ImageObject>& obj, const SizeF& size, const std::string& key,
503     const ImageDecoderOptions& imageDecoderOptions)
504 {
505     ImageDecoder decoder(obj, size, imageDecoderOptions.forceResize);
506     RefPtr<CanvasImage> image;
507     // preview and ohos platform
508     if (SystemProperties::GetImageFrameworkEnabled()) {
509         image = decoder.MakePixmapImage(imageDecoderOptions.imageQuality, imageDecoderOptions.isHdrDecoderNeed,
510             imageDecoderOptions.photoDecodeFormat);
511     } else {
512         image = decoder.MakeDrawingImage();
513     }
514 
515     if (image) {
516         SuccessCallback(image, key, imageDecoderOptions.sync, obj->GetSourceInfo().GetContainerId());
517     } else {
518         FailCallback(key, "Failed to decode image", obj->GetSourceInfo().GetContainerId());
519     }
520 }
521 } // namespace OHOS::Ace::NG
522