• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/image_provider/image_loading_context.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/common/container.h"
20 #include "core/components/common/layout/constants.h"
21 #include "core/components_ng/image_provider/drawing_image_data.h"
22 #include "core/components_ng/image_provider/image_utils.h"
23 #include "core/components_ng/image_provider/pixel_map_image_object.h"
24 #include "core/components_ng/image_provider/static_image_object.h"
25 #include "core/components_ng/pattern/image/image_dfx.h"
26 #include "core/components_ng/render/image_painter.h"
27 #include "core/image/image_file_cache.h"
28 #include "core/image/image_loader.h"
29 #include "core/pipeline_ng/pipeline_context.h"
30 
31 namespace OHOS::Ace::NG {
32 
ImageLoadingContext(const ImageSourceInfo & src,LoadNotifier && loadNotifier,bool syncLoad,bool isSceneBoardWindow,const ImageDfxConfig & imageDfxConfig)33 ImageLoadingContext::ImageLoadingContext(const ImageSourceInfo& src, LoadNotifier&& loadNotifier, bool syncLoad,
34     bool isSceneBoardWindow, const ImageDfxConfig& imageDfxConfig)
35     : src_(src), notifiers_(std::move(loadNotifier)), containerId_(Container::CurrentId()), syncLoad_(syncLoad),
36       isSceneBoardWindow_(isSceneBoardWindow), imageDfxConfig_(imageDfxConfig)
37 {
38     stateManager_ = MakeRefPtr<ImageStateManager>(WeakClaim(this));
39     src_.SetImageDfxConfig(imageDfxConfig_);
40 
41     if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE) &&
42         src_.GetSrcType() == SrcType::PIXMAP) {
43         syncLoad_ = true;
44     }
45 }
46 
~ImageLoadingContext()47 ImageLoadingContext::~ImageLoadingContext()
48 {
49     if (!syncLoad_) {
50         auto state = stateManager_->GetCurrentState();
51         if (state == ImageLoadingState::DATA_LOADING) {
52             // cancel CreateImgObj task
53             if (!Downloadable()) {
54                 ImageProvider::CancelTask(src_.GetTaskKey(), WeakClaim(this));
55                 return;
56             }
57             std::string taskKey = src_.GetTaskKey() + (GetOnProgressCallback() ? "1" : "0");
58             if (ImageProvider::CancelTask(taskKey, WeakClaim(this))) {
59                 DownloadManager::GetInstance()->RemoveDownloadTaskWithPreload(src_.GetSrc());
60             }
61         } else if (state == ImageLoadingState::MAKE_CANVAS_IMAGE && InstanceOf<StaticImageObject>(imageObj_)) {
62             // cancel MakeCanvasImage task
63             ImageProvider::CancelTask(canvasKey_, WeakClaim(this));
64         }
65     }
66 }
67 
CalculateTargetSize(const SizeF & srcSize,const SizeF & dstSize,const SizeF & rawImageSize)68 SizeF ImageLoadingContext::CalculateTargetSize(const SizeF& srcSize, const SizeF& dstSize, const SizeF& rawImageSize)
69 {
70     if (!srcSize.IsPositive()) {
71         return rawImageSize;
72     }
73 
74     SizeF targetSize = rawImageSize;
75     auto context = PipelineContext::GetCurrentContext();
76     auto viewScale = context ? context->GetViewScale() : 1.0;
77     double widthScale = dstSize.Width() / srcSize.Width() * viewScale;
78     double heightScale = dstSize.Height() / srcSize.Height() * viewScale;
79     if (widthScale < 1.0 && heightScale < 1.0) {
80         targetSize = SizeF(targetSize.Width() * widthScale, targetSize.Height() * heightScale);
81     }
82     return targetSize;
83 }
84 
OnUnloaded()85 void ImageLoadingContext::OnUnloaded()
86 {
87     imageObj_ = nullptr;
88     canvasImage_ = nullptr;
89     srcRect_ = RectF();
90     dstRect_ = RectF();
91     dstSize_ = SizeF();
92 }
93 
OnLoadSuccess()94 void ImageLoadingContext::OnLoadSuccess()
95 {
96     if (DynamicCast<StaticImageObject>(imageObj_)) {
97         imageObj_->ClearData();
98     }
99     if (notifiers_.onLoadSuccess_) {
100         notifiers_.onLoadSuccess_(src_);
101     }
102     ImageUtils::PostToUI(std::move(pendingMakeCanvasImageTask_), "ArkUIImageMakeCanvasImage");
103 }
104 
OnLoadFail()105 void ImageLoadingContext::OnLoadFail()
106 {
107     if (notifiers_.onLoadFail_) {
108         notifiers_.onLoadFail_(src_, errorMsg_, errorInfo_);
109     }
110 }
111 
OnDataReady()112 void ImageLoadingContext::OnDataReady()
113 {
114     if (notifiers_.onDataReady_) {
115         notifiers_.onDataReady_(src_);
116     }
117 }
118 
OnDataReadyOnCompleteCallBack()119 void ImageLoadingContext::OnDataReadyOnCompleteCallBack()
120 {
121     if (notifiers_.onDataReadyComplete_) {
122         notifiers_.onDataReadyComplete_(src_);
123     }
124 }
125 
SetOnProgressCallback(std::function<void (const uint32_t & dlNow,const uint32_t & dlTotal)> && onProgress)126 void ImageLoadingContext::SetOnProgressCallback(
127     std::function<void(const uint32_t& dlNow, const uint32_t& dlTotal)>&& onProgress)
128 {
129     onProgressCallback_ = onProgress;
130 }
131 
OnDataLoading()132 void ImageLoadingContext::OnDataLoading()
133 {
134     auto obj = ImageProvider::QueryImageObjectFromCache(src_);
135     if (obj) {
136         TAG_LOGD(AceLogTag::ACE_IMAGE, "%{private}s obj hit cache", src_.GetSrc().c_str());
137         DataReadyCallback(obj);
138         return;
139     }
140     src_.SetContainerId(containerId_);
141     src_.SetImageDfxConfig(GetImageDfxConfig());
142     ImageProvider::CreateImageObject(src_, WeakClaim(this), syncLoad_, isSceneBoardWindow_);
143 }
144 
Downloadable()145 bool ImageLoadingContext::Downloadable()
146 {
147     return src_.GetSrcType() == SrcType::NETWORK && SystemProperties::GetDownloadByNetworkEnabled();
148 }
149 
DownloadOnProgress(const uint32_t & dlNow,const uint32_t & dlTotal)150 void ImageLoadingContext::DownloadOnProgress(const uint32_t& dlNow, const uint32_t& dlTotal)
151 {
152     if (onProgressCallback_) {
153         onProgressCallback_(dlNow, dlTotal);
154     }
155 }
156 
OnMakeCanvasImage()157 void ImageLoadingContext::OnMakeCanvasImage()
158 {
159     CHECK_NULL_VOID(imageObj_);
160 
161     // only update params when entered MakeCanvasImage state successfully
162     if (updateParamsCallback_) {
163         updateParamsCallback_();
164         updateParamsCallback_ = nullptr;
165     }
166     auto userDefinedSize = GetSourceSize();
167     SizeF targetSize;
168     if (userDefinedSize) {
169         ImagePainter::ApplyImageFit(imageFit_, *userDefinedSize, dstSize_, srcRect_, dstRect_);
170         targetSize = *userDefinedSize;
171     } else {
172         auto imageSize = GetImageSize();
173         // calculate the srcRect based on original image size
174         ImagePainter::ApplyImageFit(imageFit_, imageSize, dstSize_, srcRect_, dstRect_);
175 
176         bool isPixelMapResource = (SrcType::DATA_ABILITY_DECODED == GetSourceInfo().GetSrcType());
177         if (autoResize_ && !isPixelMapResource) {
178             targetSize = CalculateTargetSize(srcRect_.GetSize(), dstRect_.GetSize(), imageSize);
179             // calculate real srcRect used for paint based on resized image size
180             ImagePainter::ApplyImageFit(imageFit_, targetSize, dstSize_, srcRect_, dstRect_);
181         }
182 
183         // upscale targetSize if size level is mapped
184         if (targetSize.IsPositive() && sizeLevel_ > targetSize.Width()) {
185             targetSize.ApplyScale(sizeLevel_ / targetSize.Width());
186         }
187     }
188 
189     // step4: [MakeCanvasImage] according to [targetSize]
190     src_.SetImageHdr(GetIsHdrDecoderNeed());
191     canvasKey_ = ImageUtils::GenerateImageKey(src_, targetSize);
192     imageObj_->SetImageSourceInfoHdr(GetIsHdrDecoderNeed());
193     imageObj_->SetImageDfxConfig(imageDfxConfig_);
194     imageObj_->MakeCanvasImage(WeakClaim(this), targetSize, userDefinedSize.has_value(), syncLoad_);
195 }
196 
ResizableCalcDstSize()197 void ImageLoadingContext::ResizableCalcDstSize()
198 {
199     auto userDefinedSize = GetSourceSize();
200     if (userDefinedSize) {
201         ImagePainter::ApplyImageFit(imageFit_, *userDefinedSize, dstSize_, srcRect_, dstRect_);
202         return;
203     }
204     auto imageSize = GetImageSize();
205     // calculate the srcRect based on original image size
206     ImagePainter::ApplyImageFit(imageFit_, imageSize, dstSize_, srcRect_, dstRect_);
207 
208     bool isPixelMapResource = (SrcType::DATA_ABILITY_DECODED == GetSourceInfo().GetSrcType());
209     if (autoResize_ && !isPixelMapResource) {
210         SizeF targetSize = CalculateTargetSize(srcRect_.GetSize(), dstRect_.GetSize(), imageSize);
211         // calculate real srcRect used for paint based on resized image size
212         ImagePainter::ApplyImageFit(imageFit_, targetSize, dstSize_, srcRect_, dstRect_);
213     }
214 }
215 
DataReadyCallback(const RefPtr<ImageObject> & imageObj)216 void ImageLoadingContext::DataReadyCallback(const RefPtr<ImageObject>& imageObj)
217 {
218     CHECK_NULL_VOID(imageObj);
219     imageObj_ = imageObj->Clone();
220     if (measureFinish_) {
221         OnDataReadyOnCompleteCallBack();
222     } else {
223         needDataReadyCallBack_ = true;
224     }
225     stateManager_->HandleCommand(ImageLoadingCommand::LOAD_DATA_SUCCESS);
226 }
227 
SuccessCallback(const RefPtr<CanvasImage> & canvasImage)228 void ImageLoadingContext::SuccessCallback(const RefPtr<CanvasImage>& canvasImage)
229 {
230     canvasImage_ = canvasImage;
231     stateManager_->HandleCommand(ImageLoadingCommand::MAKE_CANVAS_IMAGE_SUCCESS);
232 }
233 
FailCallback(const std::string & errorMsg,const ImageErrorInfo & errorInfo)234 void ImageLoadingContext::FailCallback(const std::string& errorMsg, const ImageErrorInfo& errorInfo)
235 {
236     errorInfo_ = errorInfo;
237     errorMsg_ = errorMsg;
238     needErrorCallBack_ = true;
239     TAG_LOGD(AceLogTag::ACE_IMAGE, "fail-%{private}s-%{public}s-%{public}s", src_.ToString().c_str(),
240         errorMsg.c_str(), imageDfxConfig_.ToStringWithoutSrc().c_str());
241     CHECK_NULL_VOID(measureFinish_);
242     stateManager_->HandleCommand(ImageLoadingCommand::LOAD_FAIL);
243     needErrorCallBack_ = false;
244 }
245 
CallbackAfterMeasureIfNeed()246 void ImageLoadingContext::CallbackAfterMeasureIfNeed()
247 {
248     if (needErrorCallBack_) {
249         stateManager_->HandleCommand(ImageLoadingCommand::LOAD_FAIL);
250         needErrorCallBack_ = false;
251     }
252     if (needDataReadyCallBack_) {
253         OnDataReadyOnCompleteCallBack();
254         needDataReadyCallBack_ = false;
255     }
256 }
257 
GetDstRect() const258 const RectF& ImageLoadingContext::GetDstRect() const
259 {
260     return dstRect_;
261 }
262 
GetSrcRect() const263 const RectF& ImageLoadingContext::GetSrcRect() const
264 {
265     return srcRect_;
266 }
267 
MoveCanvasImage()268 RefPtr<CanvasImage> ImageLoadingContext::MoveCanvasImage()
269 {
270     return std::move(canvasImage_);
271 }
272 
MoveImageObject()273 RefPtr<ImageObject> ImageLoadingContext::MoveImageObject()
274 {
275     return std::move(imageObj_);
276 }
277 
LoadImageData()278 void ImageLoadingContext::LoadImageData()
279 {
280     stateManager_->HandleCommand(ImageLoadingCommand::LOAD_DATA);
281 }
282 
RoundUp(int32_t value)283 int32_t ImageLoadingContext::RoundUp(int32_t value)
284 {
285     CHECK_NULL_RETURN(imageObj_, -1);
286     auto res = imageObj_->GetImageSize().Width();
287     CHECK_NULL_RETURN(value > 0 && res > 0, -1);
288     while (res / 2 >= value) {
289         res /= 2;
290     }
291     return res;
292 }
293 
MakeCanvasImageIfNeed(const SizeF & dstSize,bool autoResize,ImageFit imageFit,const std::optional<SizeF> & sourceSize,bool hasValidSlice)294 bool ImageLoadingContext::MakeCanvasImageIfNeed(const SizeF& dstSize, bool autoResize, ImageFit imageFit,
295     const std::optional<SizeF>& sourceSize, bool hasValidSlice)
296 {
297     bool res = autoResize != autoResize_ || imageFit != imageFit_ || sourceSize != GetSourceSize() || firstLoadImage_;
298 
299     /* When function is called with a changed dstSize, assume the image will be resized frequently. To minimize
300      * MakeCanvasImage operations, map dstSize to size levels in log_2. Only Remake when the size level changes.
301      */
302     if (SizeChanging(dstSize)) {
303         res |= RoundUp(dstSize.Width()) != sizeLevel_;
304     } else if (dstSize_ == SizeF()) {
305         res |= dstSize.IsPositive();
306     }
307     if (!res && hasValidSlice) {
308         dstSize_ = dstSize;
309     }
310     CHECK_NULL_RETURN(res, res);
311     if (stateManager_->GetCurrentState() == ImageLoadingState::MAKE_CANVAS_IMAGE) {
312         pendingMakeCanvasImageTask_ = [weak = AceType::WeakClaim(this), dstSize, autoResize, imageFit, sourceSize]() {
313             auto ctx = weak.Upgrade();
314             CHECK_NULL_VOID(ctx);
315             CHECK_NULL_VOID(ctx->SizeChanging(dstSize));
316             ctx->MakeCanvasImage(dstSize, autoResize, imageFit, sourceSize);
317         };
318     } else {
319         MakeCanvasImage(dstSize, autoResize, imageFit, sourceSize);
320     }
321     return res;
322 }
323 
MakeCanvasImage(const SizeF & dstSize,bool autoResize,ImageFit imageFit,const std::optional<SizeF> & sourceSize)324 void ImageLoadingContext::MakeCanvasImage(
325     const SizeF& dstSize, bool autoResize, ImageFit imageFit, const std::optional<SizeF>& sourceSize)
326 {
327     // Because calling of this interface does not guarantee the execution of [MakeCanvasImage], so in order to avoid
328     // updating params before they are not actually used, capture the params in a function. This function will only run
329     // when it actually do [MakeCanvasImage], i.e. doing the update in [OnMakeCanvasImageTask]
330     updateParamsCallback_ = [wp = WeakClaim(this), dstSize, autoResize, imageFit, sourceSize]() {
331         auto ctx = wp.Upgrade();
332         CHECK_NULL_VOID(ctx);
333         if (ctx->SizeChanging(dstSize) || ctx->firstLoadImage_) {
334             ctx->sizeLevel_ = ctx->RoundUp(dstSize.Width());
335         }
336         ctx->firstLoadImage_ = false;
337         ctx->dstSize_ = dstSize;
338         ctx->imageFit_ = imageFit;
339         ctx->autoResize_ = autoResize;
340         ctx->SetSourceSize(sourceSize);
341     };
342     // send command to [StateManager] and waiting the callback from it to determine next step
343     stateManager_->HandleCommand(ImageLoadingCommand::MAKE_CANVAS_IMAGE);
344 }
345 
GetImageSize() const346 SizeF ImageLoadingContext::GetImageSize() const
347 {
348     CHECK_NULL_RETURN(imageObj_, SizeF(-1.0, -1.0));
349     auto imageSize = imageObj_->GetImageSize();
350     auto orientation = imageObj_->GetOrientation();
351     if (orientation == ImageRotateOrientation::LEFT || orientation == ImageRotateOrientation::RIGHT ||
352         orientation == ImageRotateOrientation::LEFT_MIRRORED || orientation == ImageRotateOrientation::RIGHT_MIRRORED) {
353         return { imageSize.Height(), imageSize.Width() };
354     }
355     return imageSize;
356 }
357 
GetOriginImageSize() const358 SizeF ImageLoadingContext::GetOriginImageSize() const
359 {
360     return imageObj_ ? imageObj_->GetImageSize() : SizeF(-1, -1);
361 }
362 
GetImageFit() const363 ImageFit ImageLoadingContext::GetImageFit() const
364 {
365     return imageFit_;
366 }
367 
SetImageFit(ImageFit imageFit)368 void ImageLoadingContext::SetImageFit(ImageFit imageFit)
369 {
370     imageFit_ = imageFit;
371 }
372 
GetSourceInfo() const373 const ImageSourceInfo& ImageLoadingContext::GetSourceInfo() const
374 {
375     return src_;
376 }
377 
SetAutoResize(bool autoResize)378 void ImageLoadingContext::SetAutoResize(bool autoResize)
379 {
380     autoResize_ = autoResize;
381 }
382 
GetDstSize() const383 const SizeF& ImageLoadingContext::GetDstSize() const
384 {
385     return dstSize_;
386 }
387 
GetAutoResize() const388 bool ImageLoadingContext::GetAutoResize() const
389 {
390     return autoResize_;
391 }
392 
SetSourceSize(const std::optional<SizeF> & sourceSize)393 void ImageLoadingContext::SetSourceSize(const std::optional<SizeF>& sourceSize)
394 {
395     if (sourceSize.has_value()) {
396         sourceSizePtr_ = std::make_unique<SizeF>(sourceSize.value());
397     }
398 }
399 
GetSourceSize() const400 std::optional<SizeF> ImageLoadingContext::GetSourceSize() const
401 {
402     CHECK_NULL_RETURN(sourceSizePtr_, std::nullopt);
403     if (sourceSizePtr_->Width() <= 0.0 || sourceSizePtr_->Height() <= 0.0) {
404         TAG_LOGW(AceLogTag::ACE_IMAGE, "Invalid SourceSize, using image size.");
405         return std::nullopt;
406     }
407     return { *sourceSizePtr_ };
408 }
409 
NeedAlt() const410 bool ImageLoadingContext::NeedAlt() const
411 {
412     auto state = stateManager_->GetCurrentState();
413     return state != ImageLoadingState::LOAD_SUCCESS;
414 }
415 
ResetLoading()416 void ImageLoadingContext::ResetLoading()
417 {
418     stateManager_->HandleCommand(ImageLoadingCommand::RESET_STATE);
419 }
420 
ResumeLoading()421 void ImageLoadingContext::ResumeLoading()
422 {
423     stateManager_->HandleCommand(ImageLoadingCommand::LOAD_DATA);
424 }
425 
GetCurrentLoadingState()426 const std::string ImageLoadingContext::GetCurrentLoadingState()
427 {
428     ImageLoadingState state = ImageLoadingState::UNLOADED;
429     if (stateManager_) {
430         state = stateManager_->GetCurrentState();
431     }
432     switch (state) {
433         case ImageLoadingState::DATA_LOADING:
434             return "DATA_LOADING";
435         case ImageLoadingState::DATA_READY:
436             return "DATA_READY";
437         case ImageLoadingState::MAKE_CANVAS_IMAGE:
438             return "MAKE_CANVAS_IMAGE";
439         case ImageLoadingState::LOAD_SUCCESS:
440             return "LOAD_SUCCESS";
441         case ImageLoadingState::LOAD_FAIL:
442             return "LOAD_FAIL";
443 
444         default:
445             return "UNLOADED";
446     }
447 }
448 
GetFrameCount() const449 int32_t ImageLoadingContext::GetFrameCount() const
450 {
451     return imageObj_ ? imageObj_->GetFrameCount() : 0;
452 }
453 
GetImageSizeInfo() const454 std::string ImageLoadingContext::GetImageSizeInfo() const
455 {
456     if (!imageObj_) {
457         return "[imageObj=null]";
458     }
459 
460     std::ostringstream oss;
461     oss << "[fileSize=" << imageObj_->GetImageFileSize()
462         << ", dataSize=" << imageObj_->GetImageDataSize() << "]";
463     return oss.str();
464 }
465 } // namespace OHOS::Ace::NG
466