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