• 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/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