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/adapter/rosen/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,const ImageDfxConfig & imageDfxConfig)33 ImageLoadingContext::ImageLoadingContext(
34 const ImageSourceInfo& src, LoadNotifier&& loadNotifier, bool syncLoad, const ImageDfxConfig& imageDfxConfig)
35 : src_(src), notifiers_(std::move(loadNotifier)), containerId_(Container::CurrentId()), syncLoad_(syncLoad),
36 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 ImageProvider::CancelTask(src_.GetTaskKey(), WeakClaim(this));
54 if (Downloadable()) {
55 DownloadManager::GetInstance()->RemoveDownloadTaskWithPreload(src_.GetSrc(), imageDfxConfig_.nodeId_);
56 }
57 } else if (state == ImageLoadingState::MAKE_CANVAS_IMAGE) {
58 // cancel MakeCanvasImage task
59 if (InstanceOf<StaticImageObject>(imageObj_)) {
60 ImageProvider::CancelTask(canvasKey_, WeakClaim(this));
61 }
62 }
63 }
64 }
65
CalculateTargetSize(const SizeF & srcSize,const SizeF & dstSize,const SizeF & rawImageSize)66 SizeF ImageLoadingContext::CalculateTargetSize(const SizeF& srcSize, const SizeF& dstSize, const SizeF& rawImageSize)
67 {
68 if (!srcSize.IsPositive()) {
69 return rawImageSize;
70 }
71
72 SizeF targetSize = rawImageSize;
73 auto context = PipelineContext::GetCurrentContext();
74 auto viewScale = context ? context->GetViewScale() : 1.0;
75 double widthScale = dstSize.Width() / srcSize.Width() * viewScale;
76 double heightScale = dstSize.Height() / srcSize.Height() * viewScale;
77 if (widthScale < 1.0 && heightScale < 1.0) {
78 targetSize = SizeF(targetSize.Width() * widthScale, targetSize.Height() * heightScale);
79 }
80 return targetSize;
81 }
82
OnUnloaded()83 void ImageLoadingContext::OnUnloaded()
84 {
85 imageObj_ = nullptr;
86 canvasImage_ = nullptr;
87 srcRect_ = RectF();
88 dstRect_ = RectF();
89 dstSize_ = SizeF();
90 }
91
OnLoadSuccess()92 void ImageLoadingContext::OnLoadSuccess()
93 {
94 if (DynamicCast<StaticImageObject>(imageObj_)) {
95 imageObj_->ClearData();
96 }
97 if (notifiers_.onLoadSuccess_) {
98 notifiers_.onLoadSuccess_(src_);
99 }
100 ImageUtils::PostToUI(std::move(pendingMakeCanvasImageTask_), "ArkUIImageMakeCanvasImage");
101 }
102
OnLoadFail()103 void ImageLoadingContext::OnLoadFail()
104 {
105 if (notifiers_.onLoadFail_) {
106 notifiers_.onLoadFail_(src_, errorMsg_);
107 }
108 }
109
OnDataReady()110 void ImageLoadingContext::OnDataReady()
111 {
112 if (notifiers_.onDataReady_) {
113 notifiers_.onDataReady_(src_);
114 }
115 }
116
OnDataReadyOnCompleteCallBack()117 void ImageLoadingContext::OnDataReadyOnCompleteCallBack()
118 {
119 if (notifiers_.onDataReadyComplete_) {
120 notifiers_.onDataReadyComplete_(src_);
121 }
122 }
123
SetOnProgressCallback(std::function<void (const uint32_t & dlNow,const uint32_t & dlTotal)> && onProgress)124 void ImageLoadingContext::SetOnProgressCallback(
125 std::function<void(const uint32_t& dlNow, const uint32_t& dlTotal)>&& onProgress)
126 {
127 onProgressCallback_ = onProgress;
128 }
129
OnDataLoading()130 void ImageLoadingContext::OnDataLoading()
131 {
132 auto obj = ImageProvider::QueryImageObjectFromCache(src_);
133 if (obj) {
134 TAG_LOGD(AceLogTag::ACE_IMAGE, "%{private}s hit cache, not need create object", src_.GetSrc().c_str());
135 DataReadyCallback(obj);
136 return;
137 }
138 src_.SetContainerId(containerId_);
139 src_.SetImageDfxConfig(GetImageDfxConfig());
140 ImageProvider::CreateImageObject(src_, WeakClaim(this), syncLoad_);
141 }
142
Downloadable()143 bool ImageLoadingContext::Downloadable()
144 {
145 return src_.GetSrcType() == SrcType::NETWORK && SystemProperties::GetDownloadByNetworkEnabled();
146 }
147
DownloadOnProgress(const uint32_t & dlNow,const uint32_t & dlTotal)148 void ImageLoadingContext::DownloadOnProgress(const uint32_t& dlNow, const uint32_t& dlTotal)
149 {
150 if (onProgressCallback_) {
151 onProgressCallback_(dlNow, dlTotal);
152 }
153 }
154
OnMakeCanvasImage()155 void ImageLoadingContext::OnMakeCanvasImage()
156 {
157 CHECK_NULL_VOID(imageObj_);
158
159 // only update params when entered MakeCanvasImage state successfully
160 if (updateParamsCallback_) {
161 updateParamsCallback_();
162 updateParamsCallback_ = nullptr;
163 }
164 auto userDefinedSize = GetSourceSize();
165 SizeF targetSize;
166 if (userDefinedSize) {
167 ImagePainter::ApplyImageFit(imageFit_, *userDefinedSize, dstSize_, srcRect_, dstRect_);
168 targetSize = *userDefinedSize;
169 } else {
170 auto imageSize = GetImageSize();
171 // calculate the srcRect based on original image size
172 ImagePainter::ApplyImageFit(imageFit_, imageSize, dstSize_, srcRect_, dstRect_);
173
174 bool isPixelMapResource = (SrcType::DATA_ABILITY_DECODED == GetSourceInfo().GetSrcType());
175 if (autoResize_ && !isPixelMapResource) {
176 targetSize = CalculateTargetSize(srcRect_.GetSize(), dstRect_.GetSize(), imageSize);
177 // calculate real srcRect used for paint based on resized image size
178 ImagePainter::ApplyImageFit(imageFit_, targetSize, dstSize_, srcRect_, dstRect_);
179 }
180
181 // upscale targetSize if size level is mapped
182 if (targetSize.IsPositive() && sizeLevel_ > targetSize.Width()) {
183 targetSize.ApplyScale(sizeLevel_ / targetSize.Width());
184 }
185 }
186
187 // step4: [MakeCanvasImage] according to [targetSize]
188 canvasKey_ = ImageUtils::GenerateImageKey(src_, targetSize);
189 imageObj_->SetImageDfxConfig(imageDfxConfig_);
190 imageObj_->MakeCanvasImage(WeakClaim(this), targetSize, userDefinedSize.has_value(), syncLoad_);
191 }
192
ResizableCalcDstSize()193 void ImageLoadingContext::ResizableCalcDstSize()
194 {
195 auto userDefinedSize = GetSourceSize();
196 if (userDefinedSize) {
197 ImagePainter::ApplyImageFit(imageFit_, *userDefinedSize, dstSize_, srcRect_, dstRect_);
198 return;
199 }
200 auto imageSize = GetImageSize();
201 // calculate the srcRect based on original image size
202 ImagePainter::ApplyImageFit(imageFit_, imageSize, dstSize_, srcRect_, dstRect_);
203
204 bool isPixelMapResource = (SrcType::DATA_ABILITY_DECODED == GetSourceInfo().GetSrcType());
205 if (autoResize_ && !isPixelMapResource) {
206 SizeF targetSize = CalculateTargetSize(srcRect_.GetSize(), dstRect_.GetSize(), imageSize);
207 // calculate real srcRect used for paint based on resized image size
208 ImagePainter::ApplyImageFit(imageFit_, targetSize, dstSize_, srcRect_, dstRect_);
209 }
210 }
211
DataReadyCallback(const RefPtr<ImageObject> & imageObj)212 void ImageLoadingContext::DataReadyCallback(const RefPtr<ImageObject>& imageObj)
213 {
214 CHECK_NULL_VOID(imageObj);
215 imageObj_ = imageObj->Clone();
216 if (measureFinish_) {
217 OnDataReadyOnCompleteCallBack();
218 } else {
219 needDataReadyCallBack_ = true;
220 }
221 stateManager_->HandleCommand(ImageLoadingCommand::LOAD_DATA_SUCCESS);
222 }
223
SuccessCallback(const RefPtr<CanvasImage> & canvasImage)224 void ImageLoadingContext::SuccessCallback(const RefPtr<CanvasImage>& canvasImage)
225 {
226 canvasImage_ = canvasImage;
227 stateManager_->HandleCommand(ImageLoadingCommand::MAKE_CANVAS_IMAGE_SUCCESS);
228 }
229
FailCallback(const std::string & errorMsg)230 void ImageLoadingContext::FailCallback(const std::string& errorMsg)
231 {
232 errorMsg_ = errorMsg;
233 needErrorCallBack_ = true;
234 TAG_LOGW(AceLogTag::ACE_IMAGE, "Image LoadFail, src = %{private}s, reason: %{public}s, %{public}s",
235 src_.ToString().c_str(), errorMsg.c_str(), imageDfxConfig_.ToStringWithoutSrc().c_str());
236 CHECK_NULL_VOID(measureFinish_);
237 stateManager_->HandleCommand(ImageLoadingCommand::LOAD_FAIL);
238 needErrorCallBack_ = false;
239 }
240
CallbackAfterMeasureIfNeed()241 void ImageLoadingContext::CallbackAfterMeasureIfNeed()
242 {
243 if (needErrorCallBack_) {
244 stateManager_->HandleCommand(ImageLoadingCommand::LOAD_FAIL);
245 needErrorCallBack_ = false;
246 }
247 if (needDataReadyCallBack_) {
248 OnDataReadyOnCompleteCallBack();
249 needDataReadyCallBack_ = false;
250 }
251 }
252
GetDstRect() const253 const RectF& ImageLoadingContext::GetDstRect() const
254 {
255 return dstRect_;
256 }
257
GetSrcRect() const258 const RectF& ImageLoadingContext::GetSrcRect() const
259 {
260 return srcRect_;
261 }
262
MoveCanvasImage()263 RefPtr<CanvasImage> ImageLoadingContext::MoveCanvasImage()
264 {
265 return std::move(canvasImage_);
266 }
267
MoveImageObject()268 RefPtr<ImageObject> ImageLoadingContext::MoveImageObject()
269 {
270 return std::move(imageObj_);
271 }
272
LoadImageData()273 void ImageLoadingContext::LoadImageData()
274 {
275 stateManager_->HandleCommand(ImageLoadingCommand::LOAD_DATA);
276 }
277
RoundUp(int32_t value)278 int32_t ImageLoadingContext::RoundUp(int32_t value)
279 {
280 CHECK_NULL_RETURN(imageObj_, -1);
281 auto res = imageObj_->GetImageSize().Width();
282 CHECK_NULL_RETURN(value > 0 && res > 0, -1);
283 while (res / 2 >= value) {
284 res /= 2;
285 }
286 return res;
287 }
288
MakeCanvasImageIfNeed(const SizeF & dstSize,bool autoResize,ImageFit imageFit,const std::optional<SizeF> & sourceSize,bool hasValidSlice)289 bool ImageLoadingContext::MakeCanvasImageIfNeed(const SizeF& dstSize, bool autoResize, ImageFit imageFit,
290 const std::optional<SizeF>& sourceSize, bool hasValidSlice)
291 {
292 bool res = autoResize != autoResize_ || imageFit != imageFit_ || sourceSize != GetSourceSize() || firstLoadImage_;
293
294 /* When function is called with a changed dstSize, assume the image will be resized frequently. To minimize
295 * MakeCanvasImage operations, map dstSize to size levels in log_2. Only Remake when the size level changes.
296 */
297 if (SizeChanging(dstSize)) {
298 res |= RoundUp(dstSize.Width()) != sizeLevel_;
299 } else if (dstSize_ == SizeF()) {
300 res |= dstSize.IsPositive();
301 }
302 if (!res && hasValidSlice) {
303 dstSize_ = dstSize;
304 }
305 CHECK_NULL_RETURN(res, res);
306 if (stateManager_->GetCurrentState() == ImageLoadingState::MAKE_CANVAS_IMAGE) {
307 pendingMakeCanvasImageTask_ = [weak = AceType::WeakClaim(this), dstSize, autoResize, imageFit, sourceSize]() {
308 auto ctx = weak.Upgrade();
309 CHECK_NULL_VOID(ctx);
310 CHECK_NULL_VOID(ctx->SizeChanging(dstSize));
311 ctx->MakeCanvasImage(dstSize, autoResize, imageFit, sourceSize);
312 };
313 } else {
314 MakeCanvasImage(dstSize, autoResize, imageFit, sourceSize);
315 }
316 return res;
317 }
318
MakeCanvasImage(const SizeF & dstSize,bool autoResize,ImageFit imageFit,const std::optional<SizeF> & sourceSize)319 void ImageLoadingContext::MakeCanvasImage(
320 const SizeF& dstSize, bool autoResize, ImageFit imageFit, const std::optional<SizeF>& sourceSize)
321 {
322 // Because calling of this interface does not guarantee the execution of [MakeCanvasImage], so in order to avoid
323 // updating params before they are not actually used, capture the params in a function. This function will only run
324 // when it actually do [MakeCanvasImage], i.e. doing the update in [OnMakeCanvasImageTask]
325 updateParamsCallback_ = [wp = WeakClaim(this), dstSize, autoResize, imageFit, sourceSize]() {
326 auto ctx = wp.Upgrade();
327 CHECK_NULL_VOID(ctx);
328 if (ctx->SizeChanging(dstSize) || ctx->firstLoadImage_) {
329 ctx->sizeLevel_ = ctx->RoundUp(dstSize.Width());
330 }
331 ctx->firstLoadImage_ = false;
332 ctx->dstSize_ = dstSize;
333 ctx->imageFit_ = imageFit;
334 ctx->autoResize_ = autoResize;
335 ctx->SetSourceSize(sourceSize);
336 };
337 // send command to [StateManager] and waiting the callback from it to determine next step
338 stateManager_->HandleCommand(ImageLoadingCommand::MAKE_CANVAS_IMAGE);
339 }
340
GetImageSize() const341 SizeF ImageLoadingContext::GetImageSize() const
342 {
343 CHECK_NULL_RETURN(imageObj_, SizeF(-1.0, -1.0));
344 auto imageSize = imageObj_->GetImageSize();
345 auto orientation = imageObj_->GetOrientation();
346 if (orientation == ImageRotateOrientation::LEFT || orientation == ImageRotateOrientation::RIGHT) {
347 return { imageSize.Height(), imageSize.Width() };
348 }
349 return imageSize;
350 }
351
GetOriginImageSize() const352 SizeF ImageLoadingContext::GetOriginImageSize() const
353 {
354 return imageObj_ ? imageObj_->GetImageSize() : SizeF(-1, -1);
355 }
356
GetImageFit() const357 ImageFit ImageLoadingContext::GetImageFit() const
358 {
359 return imageFit_;
360 }
361
SetImageFit(ImageFit imageFit)362 void ImageLoadingContext::SetImageFit(ImageFit imageFit)
363 {
364 imageFit_ = imageFit;
365 }
366
GetSourceInfo() const367 const ImageSourceInfo& ImageLoadingContext::GetSourceInfo() const
368 {
369 return src_;
370 }
371
SetAutoResize(bool autoResize)372 void ImageLoadingContext::SetAutoResize(bool autoResize)
373 {
374 autoResize_ = autoResize;
375 }
376
GetDstSize() const377 const SizeF& ImageLoadingContext::GetDstSize() const
378 {
379 return dstSize_;
380 }
381
GetAutoResize() const382 bool ImageLoadingContext::GetAutoResize() const
383 {
384 return autoResize_;
385 }
386
SetSourceSize(const std::optional<SizeF> & sourceSize)387 void ImageLoadingContext::SetSourceSize(const std::optional<SizeF>& sourceSize)
388 {
389 if (sourceSize.has_value()) {
390 sourceSizePtr_ = std::make_unique<SizeF>(sourceSize.value());
391 }
392 }
393
GetSourceSize() const394 std::optional<SizeF> ImageLoadingContext::GetSourceSize() const
395 {
396 CHECK_NULL_RETURN(sourceSizePtr_, std::nullopt);
397 if (sourceSizePtr_->Width() <= 0.0 || sourceSizePtr_->Height() <= 0.0) {
398 TAG_LOGW(AceLogTag::ACE_IMAGE,
399 "Property SourceSize is at least One invalid! Use the Image Size to calculate resize target");
400 return std::nullopt;
401 }
402 return { *sourceSizePtr_ };
403 }
404
NeedAlt() const405 bool ImageLoadingContext::NeedAlt() const
406 {
407 auto state = stateManager_->GetCurrentState();
408 return state != ImageLoadingState::LOAD_SUCCESS;
409 }
410
ResetLoading()411 void ImageLoadingContext::ResetLoading()
412 {
413 stateManager_->HandleCommand(ImageLoadingCommand::RESET_STATE);
414 }
415
ResumeLoading()416 void ImageLoadingContext::ResumeLoading()
417 {
418 stateManager_->HandleCommand(ImageLoadingCommand::LOAD_DATA);
419 }
420
GetCurrentLoadingState()421 const std::string ImageLoadingContext::GetCurrentLoadingState()
422 {
423 ImageLoadingState state = ImageLoadingState::UNLOADED;
424 if (stateManager_) {
425 state = stateManager_->GetCurrentState();
426 }
427 switch (state) {
428 case ImageLoadingState::DATA_LOADING:
429 return "DATA_LOADING";
430 case ImageLoadingState::DATA_READY:
431 return "DATA_READY";
432 case ImageLoadingState::MAKE_CANVAS_IMAGE:
433 return "MAKE_CANVAS_IMAGE";
434 case ImageLoadingState::LOAD_SUCCESS:
435 return "LOAD_SUCCESS";
436 case ImageLoadingState::LOAD_FAIL:
437 return "LOAD_FAIL";
438
439 default:
440 return "UNLOADED";
441 }
442 }
443
GetFrameCount() const444 int32_t ImageLoadingContext::GetFrameCount() const
445 {
446 return imageObj_ ? imageObj_->GetFrameCount() : 0;
447 }
448
449 } // namespace OHOS::Ace::NG
450