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