1 /*
2 * Copyright (c) 2021 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/image/render_image.h"
17
18 #include "base/log/dump_log.h"
19 #include "base/log/log.h"
20 #include "base/utils/utils.h"
21 #include "core/components/image/image_component.h"
22 #include "core/components/image/image_event.h"
23 #include "core/event/ace_event_helper.h"
24
25 namespace OHOS::Ace {
26 namespace {
27
28 constexpr double RESIZE_AGAIN_THRESHOLD = 1.2;
29
30 } // namespace
31
Update(const RefPtr<Component> & component)32 void RenderImage::Update(const RefPtr<Component>& component)
33 {
34 const RefPtr<ImageComponent> image = AceType::DynamicCast<ImageComponent>(component);
35 if (!image) {
36 LOGE("image component is null!");
37 return;
38 }
39 currentSrcRect_ = srcRect_;
40 currentDstRect_ = dstRect_;
41 currentDstRectList_ = rectList_;
42
43 width_ = image->GetWidth();
44 syncMode_ = image->GetSyncMode();
45 height_ = image->GetHeight();
46 alignment_ = image->GetAlignment();
47 imageObjectPosition_ = image->GetImageObjectPosition();
48 fitMaxSize_ = image->GetFitMaxSize();
49 hasObjectPosition_ = image->GetHasObjectPosition();
50 color_ = image->GetColor();
51 previousLayoutSize_ = Size();
52 SetTextDirection(image->GetTextDirection());
53 matchTextDirection_ = image->IsMatchTextDirection();
54 SetRadius(image->GetBorder());
55 auto context = context_.Upgrade();
56 if (context && context->GetIsDeclarative()) {
57 loadImgSuccessEvent_ = AceAsyncEvent<void(const std::shared_ptr<BaseEventInfo>&)>::Create(
58 image->GetLoadSuccessEvent(), context_);
59 loadImgFailEvent_ = AceAsyncEvent<void(const std::shared_ptr<BaseEventInfo>&)>::Create(
60 image->GetLoadFailEvent(), context_);
61 } else {
62 loadSuccessEvent_ =
63 AceAsyncEvent<void(const std::string&)>::Create(image->GetLoadSuccessEvent(), context_);
64 loadFailEvent_ = AceAsyncEvent<void(const std::string&)>::Create(image->GetLoadFailEvent(), context_);
65 }
66 svgAnimatorFinishEvent_ = image->GetSvgAnimatorFinishEvent();
67 imageFit_ = image->GetImageFit();
68 imageInterpolation_ = image->GetImageInterpolation();
69 imageRenderMode_ = image->GetImageRenderMode();
70 imageRepeat_ = image->GetImageRepeat();
71
72 useSkiaSvg_ = image->GetUseSkiaSvg();
73 autoResize_ = image->GetAutoResize();
74 imageAlt_ = image->GetAlt();
75 auto inComingSrc = image->GetSrc();
76 ImageSourceInfo inComingSource(
77 inComingSrc,
78 image->GetImageSourceSize().first,
79 image->GetImageSourceSize().second,
80 inComingSrc.empty() ? image->GetResourceId() : InternalResource::ResourceId::NO_ID,
81 image->GetPixmap());
82 auto fillColor = image->GetImageFill();
83 if (fillColor.has_value()) {
84 inComingSource.SetFillColor(fillColor.value());
85 }
86 border_ = image->GetBorder();
87 // this value is used for update frequency with same image source info.
88 LOGD("sourceInfo %{public}s", sourceInfo_.ToString().c_str());
89 LOGD("inComingSource %{public}s", inComingSource.ToString().c_str());
90 LOGD("imageLoadingStatus_: %{public}d", static_cast<int32_t>(imageLoadingStatus_));
91 proceedPreviousLoading_ = sourceInfo_.IsValid() && sourceInfo_ == inComingSource;
92 sourceInfo_ = inComingSource;
93 MarkNeedLayout(sourceInfo_.IsSvg());
94 }
95
PerformLayout()96 void RenderImage::PerformLayout()
97 {
98 if (background_) {
99 PerformLayoutBgImage();
100 if (imageRenderFunc_) {
101 imageRenderFunc_();
102 }
103 return;
104 }
105
106 auto context = context_.Upgrade();
107 if (!context) {
108 return;
109 }
110 scale_ = context->GetViewScale();
111 if (LessOrEqual(scale_, 0)) {
112 scale_ = 1.0;
113 }
114 if (width_.IsValid() && height_.IsValid()) {
115 imageComponentSize_ = Size(NormalizeToPx(width_), NormalizeToPx(height_));
116 isImageSizeSet_ = true;
117 }
118 // Divided by the true pixel ratio to apply image fit.
119 Size pictureSize = Measure() * (1.0 / scale_);
120 auto maxSize = GetLayoutParam().GetMaxSize();
121 if (fitMaxSize_ && (!imageComponentSize_.IsValid() || (!isImageSizeSet_ && maxSize != formerMaxSize_))) {
122 imageComponentSize_ = maxSize;
123 formerMaxSize_ = imageComponentSize_;
124 }
125 SetLayoutSize(GetLayoutParam().Constrain(imageComponentSize_.IsValid() && !imageComponentSize_.IsInfinite() ?
126 imageComponentSize_ : CalculateBackupImageSize(pictureSize)));
127 if (rawImageSizeUpdated_) {
128 previousLayoutSize_ = GetLayoutSize();
129 }
130 srcRect_.SetRect(Offset(), pictureSize);
131 dstRect_.SetRect(Offset(), GetLayoutSize());
132 ApplyImageFit(srcRect_, dstRect_);
133 // Restore image size.
134 srcRect_.ApplyScale(scale_);
135 if (!imageComponentSize_.IsValid()) {
136 SetLayoutSize(dstRect_.GetSize());
137 }
138 decltype(imageLayoutCallbacks_) imageLayoutCallbacks(std::move(imageLayoutCallbacks_));
139 std::for_each(
140 imageLayoutCallbacks.begin(), imageLayoutCallbacks.end(), [](std::function<void()> callback) { callback(); });
141 LayoutImageObject();
142 if (renderAltImage_) {
143 LayoutParam altLayoutParam;
144 altLayoutParam.SetFixedSize(GetLayoutSize());
145 renderAltImage_->Layout(altLayoutParam);
146 }
147
148 CalculateResizeTarget();
149 if (hasObjectPosition_) {
150 ApplyObjectPosition();
151 }
152 }
153
CalculateBackupImageSize(const Size & pictureSize)154 Size RenderImage::CalculateBackupImageSize(const Size& pictureSize)
155 {
156 // Since the return value of this function is used to determine the layout size of Image Component, it is essential
157 // to guarantee that there is no infinite edge to avoid thread stuck that may occur.
158 //
159 // Generally speaking, the size of the picture will not be infinite, but the size of the svg picture is equal to the
160 // maximum value of the layout parameters, so there is the possibility of infinity.
161 //
162 // Note that [pictureSize] has been scaled by [scale_], so we need to obtain the original picture size via
163 // [Measure()] to verify whether or not it has infinite edge.
164 auto rawPicSize = Measure();
165 if (!rawPicSize.IsValid() || rawPicSize.IsInfinite()) {
166 return Size();
167 }
168 uint8_t infiniteStatus = (static_cast<uint8_t>(imageComponentSize_.IsWidthInfinite()) << 1) |
169 static_cast<uint8_t>(imageComponentSize_.IsHeightInfinite());
170 double pictureSizeRatio = pictureSize.Width() / pictureSize.Height();
171 Size backupImageSize = imageComponentSize_;
172 switch (infiniteStatus) {
173 case 0b00: // both width and height are infinite
174 backupImageSize = pictureSize;
175 break;
176 case 0b01: // only height is infinite
177 backupImageSize.SetHeight(imageComponentSize_.Width() / pictureSizeRatio);
178 break;
179 case 0b10: // only width is infinite
180 backupImageSize.SetWidth(imageComponentSize_.Height() * pictureSizeRatio);
181 break;
182 default:
183 backupImageSize = imageComponentSize_;
184 break;
185 }
186 return backupImageSize;
187 }
188
NeedResize() const189 bool RenderImage::NeedResize() const
190 {
191 if (!resizeTarget_.IsValid()) {
192 return false;
193 }
194 if (!previousResizeTarget_.IsValid()) {
195 return true;
196 }
197 if (resizeTarget_ < previousResizeTarget_) {
198 return false;
199 }
200 double widthEnlargedBy = resizeTarget_.Width() / previousResizeTarget_.Width();
201 double heightEnlargedBy = resizeTarget_.Height() / previousResizeTarget_.Height();
202 if (widthEnlargedBy > RESIZE_AGAIN_THRESHOLD || heightEnlargedBy > RESIZE_AGAIN_THRESHOLD) {
203 return true;
204 }
205 return false;
206 }
207
CalculateResizeTarget()208 void RenderImage::CalculateResizeTarget()
209 {
210 if (!srcRect_.IsValid()) {
211 return;
212 }
213 if (!autoResize_) {
214 resizeTarget_ = rawImageSize_;
215 resizeScale_ = Size(1.0, 1.0);
216 return;
217 }
218 double widthScale = dstRect_.Width() / srcRect_.Width() * scale_;
219 double heightScale = dstRect_.Height() / srcRect_.Height() * scale_;
220 if (widthScale < 1.0 && heightScale < 1.0) {
221 resizeScale_ = Size(widthScale, heightScale);
222 } else {
223 resizeScale_ = Size(1.0, 1.0);
224 }
225 resizeTarget_ = Size(rawImageSize_.Width() * resizeScale_.Width(), rawImageSize_.Height() * resizeScale_.Height());
226 }
227
ApplyImageFit(Rect & srcRect,Rect & dstRect)228 void RenderImage::ApplyImageFit(Rect& srcRect, Rect& dstRect)
229 {
230 Size rawPicSize = srcRect.GetSize();
231 Size layoutSize = GetLayoutSize();
232 switch (imageFit_) {
233 case ImageFit::FILL:
234 break;
235 case ImageFit::NONE:
236 ApplyNone(srcRect, dstRect, rawPicSize, layoutSize);
237 break;
238 case ImageFit::COVER:
239 ApplyCover(srcRect, dstRect, rawPicSize, layoutSize);
240 break;
241 case ImageFit::FITWIDTH:
242 ApplyFitWidth(srcRect, dstRect, rawPicSize, layoutSize);
243 break;
244 case ImageFit::FITHEIGHT:
245 ApplyFitHeight(srcRect, dstRect, rawPicSize, layoutSize);
246 break;
247 case ImageFit::SCALEDOWN:
248 if (srcRect.GetSize() < dstRect.GetSize()) {
249 ApplyNone(srcRect, dstRect, rawPicSize, layoutSize);
250 } else {
251 ApplyContain(srcRect, dstRect, rawPicSize, layoutSize);
252 }
253 break;
254 case ImageFit::CONTAIN:
255 ApplyContain(srcRect, dstRect, rawPicSize, layoutSize);
256 break;
257 default:
258 ApplyContain(srcRect, dstRect, rawPicSize, layoutSize);
259 break;
260 }
261 }
262
ApplyContain(Rect & srcRect,Rect & dstRect,const Size & rawPicSize,const Size & layoutSize)263 void RenderImage::ApplyContain(Rect& srcRect, Rect& dstRect, const Size& rawPicSize, const Size& layoutSize)
264 {
265 if (!rawPicSize.IsValid()) {
266 return;
267 }
268 if (Size::CalcRatio(srcRect) > Size::CalcRatio(dstRect)) {
269 dstRect.SetSize(rawPicSize * (layoutSize.Width() / rawPicSize.Width()));
270 } else {
271 dstRect.SetSize(rawPicSize * (layoutSize.Height() / rawPicSize.Height()));
272 }
273 dstRect.SetOffset(Alignment::GetAlignPosition(layoutSize, dstRect.GetSize(), alignment_));
274 }
275
ApplyCover(Rect & srcRect,Rect & dstRect,const Size & rawPicSize,const Size & layoutSize)276 void RenderImage::ApplyCover(Rect& srcRect, Rect& dstRect, const Size& rawPicSize, const Size& layoutSize)
277 {
278 if (Size::CalcRatio(srcRect) > Size::CalcRatio(dstRect)) {
279 srcRect.SetSize(layoutSize * (rawPicSize.Height() / layoutSize.Height()));
280 } else {
281 srcRect.SetSize(layoutSize * (rawPicSize.Width() / layoutSize.Width()));
282 }
283 srcRect.SetOffset(Alignment::GetAlignPosition(rawPicSize, srcRect.GetSize(), alignment_));
284 }
285
ApplyFitWidth(Rect & srcRect,Rect & dstRect,const Size & rawPicSize,const Size & layoutSize)286 void RenderImage::ApplyFitWidth(Rect& srcRect, Rect& dstRect, const Size& rawPicSize, const Size& layoutSize)
287 {
288 if (Size::CalcRatio(srcRect) > Size::CalcRatio(dstRect)) {
289 dstRect.SetSize(rawPicSize * (layoutSize.Width() / rawPicSize.Width()));
290 dstRect.SetOffset(Alignment::GetAlignPosition(layoutSize, dstRect.GetSize(), alignment_));
291 } else {
292 srcRect.SetSize(layoutSize * (rawPicSize.Width() / layoutSize.Width()));
293 srcRect.SetOffset(Alignment::GetAlignPosition(rawPicSize, srcRect.GetSize(), alignment_));
294 }
295 }
296
ApplyFitHeight(Rect & srcRect,Rect & dstRect,const Size & rawPicSize,const Size & layoutSize)297 void RenderImage::ApplyFitHeight(Rect& srcRect, Rect& dstRect, const Size& rawPicSize, const Size& layoutSize)
298 {
299 if (Size::CalcRatio(srcRect) > Size::CalcRatio(dstRect)) {
300 srcRect.SetSize(layoutSize * (rawPicSize.Height() / layoutSize.Height()));
301 srcRect.SetOffset(Alignment::GetAlignPosition(rawPicSize, srcRect.GetSize(), alignment_));
302 } else {
303 dstRect.SetSize(rawPicSize * (layoutSize.Height() / rawPicSize.Height()));
304 dstRect.SetOffset(Alignment::GetAlignPosition(layoutSize, dstRect.GetSize(), alignment_));
305 }
306 }
307
ApplyNone(Rect & srcRect,Rect & dstRect,const Size & rawPicSize,const Size & layoutSize)308 void RenderImage::ApplyNone(Rect& srcRect, Rect& dstRect, const Size& rawPicSize, const Size& layoutSize)
309 {
310 Size srcSize =
311 Size(std::min(layoutSize.Width(), rawPicSize.Width()), std::min(layoutSize.Height(), rawPicSize.Height()));
312 dstRect.SetRect(Alignment::GetAlignPosition(layoutSize, srcSize, alignment_), srcSize);
313 srcRect.SetRect(Alignment::GetAlignPosition(rawPicSize, srcSize, alignment_), srcSize);
314 }
315
FireLoadEvent(const Size & picSize) const316 void RenderImage::FireLoadEvent(const Size& picSize) const
317 {
318 auto context = context_.Upgrade();
319 if (context && context->GetIsDeclarative()) {
320 if (loadImgSuccessEvent_ && (imageLoadingStatus_ == ImageLoadingStatus::LOAD_SUCCESS)) {
321 // here the last param of [loadImgSuccessEvent_] is [1],
322 // which means the callback is triggered by [OnLoadSuccess]
323 loadImgSuccessEvent_(std::make_shared<LoadImageSuccessEvent>(picSize.Width(), picSize.Height(),
324 GetLayoutSize().Width(), GetLayoutSize().Height(), 1));
325 }
326 if (loadImgFailEvent_ && (imageLoadingStatus_ == ImageLoadingStatus::LOAD_FAIL)) {
327 loadImgFailEvent_(std::make_shared<LoadImageFailEvent>(GetLayoutSize().Width(), GetLayoutSize().Height()));
328 }
329 return;
330 }
331 std::string param;
332 if (loadSuccessEvent_ && (imageLoadingStatus_ == ImageLoadingStatus::LOAD_SUCCESS)) {
333 param = std::string("\"complete\",{\"width\":")
334 .append(std::to_string(picSize.Width()))
335 .append(",\"height\":")
336 .append(std::to_string(picSize.Height()))
337 .append("}");
338 loadSuccessEvent_(param);
339 }
340 if (loadFailEvent_ && (imageLoadingStatus_ == ImageLoadingStatus::LOAD_FAIL)) {
341 param = std::string("\"error\",{\"width\":")
342 .append(std::to_string(picSize.Width()))
343 .append(",\"height\":")
344 .append(std::to_string(picSize.Height()))
345 .append("}");
346 loadFailEvent_(param);
347 }
348 if (loadFailCallback_ && (imageLoadingStatus_ == ImageLoadingStatus::LOAD_FAIL)) {
349 loadFailCallback_();
350 loadFailCallback_ = nullptr;
351 }
352 }
353
SetRadius(const Border & border)354 void RenderImage::SetRadius(const Border& border)
355 {
356 auto leftEdgeWidth = border.Left().GetWidth();
357 auto topEdgeWidth = border.Top().GetWidth();
358 auto rightEdgeWidth = border.Right().GetWidth();
359 auto bottomEdgeWidth = border.Bottom().GetWidth();
360 topLeftRadius_ = Radius(border.TopLeftRadius() - Radius(topEdgeWidth, leftEdgeWidth));
361 topRightRadius_ = Radius(border.TopRightRadius() - Radius(topEdgeWidth, rightEdgeWidth));
362 bottomLeftRadius_ = Radius(border.BottomLeftRadius() - Radius(bottomEdgeWidth, leftEdgeWidth));
363 bottomRightRadius_ = Radius(border.BottomRightRadius() - Radius(bottomEdgeWidth, rightEdgeWidth));
364 }
365
IsSVG(const std::string & src,InternalResource::ResourceId resourceId)366 bool RenderImage::IsSVG(const std::string& src, InternalResource::ResourceId resourceId)
367 {
368 return ImageComponent::IsSvgSuffix(src) ||
369 (src.empty() && resourceId > InternalResource::ResourceId::SVG_START &&
370 resourceId < InternalResource::ResourceId::SVG_END);
371 }
372
PerformLayoutBgImage()373 void RenderImage::PerformLayoutBgImage()
374 {
375 if (!background_) {
376 return;
377 }
378 if (!rawImageSize_.IsValid()) {
379 return;
380 }
381
382 GenerateImageRects(rawImageSize_, imageSize_, imageRepeat_, imagePosition_);
383 srcRect_.SetOffset(Offset());
384 srcRect_.SetSize(rawImageSize_);
385 dstRect_.SetOffset(Offset());
386 dstRect_.SetSize(imageRenderSize_);
387 }
388
389 // objectPosition
ApplyObjectPosition()390 void RenderImage::ApplyObjectPosition()
391 {
392 Size layoutSize = GetLayoutSize();
393 Offset offset;
394 if (imageObjectPosition_.GetSizeTypeX() == BackgroundImagePositionType::PX) {
395 offset.SetX((layoutSize.Width() - dstRect_.Width()) / 2 - imageObjectPosition_.GetSizeValueX());
396 } else {
397 offset.SetX(
398 (layoutSize.Width() - dstRect_.Width()) / 2 - imageObjectPosition_.GetSizeValueX() *
399 (layoutSize.Width() - dstRect_.Width()) / PERCENT_TRANSLATE);
400 }
401
402 if (imageObjectPosition_.GetSizeTypeY() == BackgroundImagePositionType::PX) {
403 offset.SetY((layoutSize.Height() - dstRect_.Height()) / 2 - imageObjectPosition_.GetSizeValueY());
404 } else {
405 offset.SetY(
406 (layoutSize.Height() - dstRect_.Height()) / 2 - imageObjectPosition_.GetSizeValueY() *
407 (layoutSize.Height() - dstRect_.Height()) / PERCENT_TRANSLATE);
408 }
409 imageRenderPosition_ = offset;
410 }
411
GenerateImageRects(const Size & srcSize,const BackgroundImageSize & imageSize,ImageRepeat imageRepeat,const BackgroundImagePosition & imagePosition)412 void RenderImage::GenerateImageRects(const Size& srcSize, const BackgroundImageSize& imageSize, ImageRepeat imageRepeat,
413 const BackgroundImagePosition& imagePosition)
414 {
415 rectList_.clear();
416 if (NearEqual(boxPaintSize_.Width(), Size::INFINITE_SIZE) ||
417 NearEqual(boxPaintSize_.Height(), Size::INFINITE_SIZE)) {
418 boxPaintSize_ = viewPort_;
419 }
420
421 // Different with Image Repeat
422 imageRenderSize_ = CalculateImageRenderSize(srcSize, imageSize);
423 if (NearZero(imageRenderSize_.Width()) || NearZero(imageRenderSize_.Height())) {
424 return;
425 }
426 // Ceil render size
427 imageRenderSize_ = Size(ceil(imageRenderSize_.Width()), ceil(imageRenderSize_.Height()));
428
429 CalculateImageRenderPosition(imagePosition);
430
431 int32_t minX = 0;
432 int32_t minY = 0;
433 int32_t maxX = 0;
434 int32_t maxY = 0;
435 if (imageRepeat == ImageRepeat::REPEAT || imageRepeat == ImageRepeat::REPEATX) {
436 if (LessOrEqual(imageRenderPosition_.GetX(), 0.0)) {
437 minX = 0;
438 maxX = std::ceil((boxPaintSize_.Width() - imageRenderPosition_.GetX()) / imageRenderSize_.Width());
439 } else {
440 minX = std::floor((-imageRenderPosition_.GetX()) / imageRenderSize_.Width());
441 maxX = std::ceil((boxPaintSize_.Width() - imageRenderPosition_.GetX()) / imageRenderSize_.Width());
442 }
443 }
444
445 if (imageRepeat == ImageRepeat::REPEAT || imageRepeat == ImageRepeat::REPEATY) {
446 if (LessOrEqual(imageRenderPosition_.GetY(), 0.0)) {
447 minY = 0;
448 maxY = std::ceil((boxPaintSize_.Height() - imageRenderPosition_.GetY()) / imageRenderSize_.Height());
449 } else {
450 minY = std::floor((-imageRenderPosition_.GetY()) / imageRenderSize_.Height());
451 maxY = std::ceil((boxPaintSize_.Height() - imageRenderPosition_.GetY()) / imageRenderSize_.Height());
452 }
453 }
454
455 Rect imageCell = Rect(imageRenderPosition_, Size(imageRenderSize_.Width(), imageRenderSize_.Height()));
456 for (int32_t i = minY; i <= maxY; ++i) {
457 for (int32_t j = minX; j <= maxX; ++j) {
458 rectList_.emplace_back(imageCell + Offset(j * imageRenderSize_.Width(), i * imageRenderSize_.Height()));
459 }
460 }
461
462 if (imageLoadingStatus_ == ImageLoadingStatus::LOAD_SUCCESS) {
463 currentDstRectList_ = rectList_;
464 }
465 LOGD("[BOX][Dep:%{public}d][%{public}p][IMAGE] Result: X:%{public}d-%{public}d, Y:%{public}d-%{public}d",
466 GetDepth(), this, minX, maxX, minY, maxY);
467 }
468
CalculateImageRenderSize(const Size & srcSize,const BackgroundImageSize & imageSize) const469 Size RenderImage::CalculateImageRenderSize(const Size& srcSize, const BackgroundImageSize& imageSize) const
470 {
471 Size renderSize;
472 if (NearZero(srcSize.Width()) || NearZero(srcSize.Height()) || NearZero(boxPaintSize_.Width()) ||
473 NearZero(boxPaintSize_.Height())) {
474 return renderSize;
475 }
476
477 if (!imageSize.IsValid()) {
478 return renderSize;
479 }
480
481 if (imageSize.GetSizeTypeX() == BackgroundImageSizeType::CONTAIN ||
482 imageSize.GetSizeTypeX() == BackgroundImageSizeType::COVER) {
483 renderSize = CalculateImageRenderSizeWithSingleParam(srcSize, imageSize);
484 } else {
485 renderSize = CalculateImageRenderSizeWithDoubleParam(srcSize, imageSize);
486 }
487
488 return renderSize;
489 }
490
CalculateImageRenderSizeWithSingleParam(const Size & srcSize,const BackgroundImageSize & imageSize) const491 Size RenderImage::CalculateImageRenderSizeWithSingleParam(
492 const Size& srcSize, const BackgroundImageSize& imageSize) const
493 {
494 Size sizeRet;
495 if (NearZero(srcSize.Width()) || NearZero(srcSize.Height()) || NearZero(boxPaintSize_.Width()) ||
496 NearZero(boxPaintSize_.Height())) {
497 return sizeRet;
498 }
499 double renderSizeX = 0.0;
500 double renderSizeY = 0.0;
501 if (imageSize.GetSizeTypeX() == BackgroundImageSizeType::CONTAIN) {
502 double srcAspectRatio = srcSize.Width() / srcSize.Height();
503 double paintAspectRatio = boxPaintSize_.Width() / boxPaintSize_.Height();
504 renderSizeX = paintAspectRatio >= srcAspectRatio ? srcSize.Width() * (boxPaintSize_.Height() / srcSize.Height())
505 : boxPaintSize_.Width();
506 renderSizeY = paintAspectRatio >= srcAspectRatio ? boxPaintSize_.Height()
507 : srcSize.Height() * (boxPaintSize_.Width() / srcSize.Width());
508 } else if (imageSize.GetSizeTypeX() == BackgroundImageSizeType::COVER) {
509 double srcAspectRatio = srcSize.Width() / srcSize.Height();
510 double paintAspectRatio = boxPaintSize_.Width() / boxPaintSize_.Height();
511 renderSizeX = paintAspectRatio >= srcAspectRatio
512 ? boxPaintSize_.Width()
513 : srcSize.Width() * (boxPaintSize_.Height() / srcSize.Height());
514 renderSizeY = paintAspectRatio >= srcAspectRatio ? srcSize.Height() * (boxPaintSize_.Width() / srcSize.Width())
515 : boxPaintSize_.Height();
516 }
517
518 sizeRet.SetWidth(renderSizeX);
519 sizeRet.SetHeight(renderSizeY);
520 return sizeRet;
521 }
522
CalculateImageRenderSizeWithDoubleParam(const Size & srcSize,const BackgroundImageSize & imageSize) const523 Size RenderImage::CalculateImageRenderSizeWithDoubleParam(
524 const Size& srcSize, const BackgroundImageSize& imageSize) const
525 {
526 Size sizeRet;
527 if (NearZero(srcSize.Width()) || NearZero(srcSize.Height()) || NearZero(boxPaintSize_.Width()) ||
528 NearZero(boxPaintSize_.Height())) {
529 return sizeRet;
530 }
531
532 double renderSizeX = 0.0;
533 double renderSizeY = 0.0;
534 if (imageSize.GetSizeTypeX() == BackgroundImageSizeType::LENGTH) {
535 renderSizeX = imageSize.GetSizeValueX();
536 } else if (imageSize.GetSizeTypeX() == BackgroundImageSizeType::PERCENT) {
537 renderSizeX = boxPaintSize_.Width() * imageSize.GetSizeValueX() / PERCENT_TRANSLATE;
538 }
539
540 if (imageSize.GetSizeTypeY() == BackgroundImageSizeType::LENGTH) {
541 renderSizeY = imageSize.GetSizeValueY();
542 } else if (imageSize.GetSizeTypeY() == BackgroundImageSizeType::PERCENT) {
543 renderSizeY = boxPaintSize_.Height() * imageSize.GetSizeValueY() / PERCENT_TRANSLATE;
544 }
545
546 if (imageSize.GetSizeTypeX() == BackgroundImageSizeType::AUTO &&
547 imageSize.GetSizeTypeY() == BackgroundImageSizeType::AUTO) {
548 renderSizeX = srcSize.Width();
549 renderSizeY = srcSize.Height();
550 } else if (imageSize.GetSizeTypeX() == BackgroundImageSizeType::AUTO) {
551 renderSizeX = srcSize.Width() * (renderSizeY / srcSize.Height());
552 } else if (imageSize.GetSizeTypeY() == BackgroundImageSizeType::AUTO) {
553 renderSizeY = srcSize.Height() * (renderSizeX / srcSize.Width());
554 }
555
556 sizeRet.SetWidth(renderSizeX);
557 sizeRet.SetHeight(renderSizeY);
558 if (!sizeRet.IsValid()) {
559 sizeRet = Size();
560 }
561 return sizeRet;
562 }
563
CalculateImageRenderPosition(const BackgroundImagePosition & imagePosition)564 void RenderImage::CalculateImageRenderPosition(const BackgroundImagePosition& imagePosition)
565 {
566 Offset offset;
567
568 if (imagePosition.GetSizeTypeX() == BackgroundImagePositionType::PX) {
569 offset.SetX(imagePosition.GetSizeValueX());
570 } else {
571 offset.SetX(
572 imagePosition.GetSizeValueX() * (boxPaintSize_.Width() - imageRenderSize_.Width()) / PERCENT_TRANSLATE);
573 }
574
575 if (imagePosition.GetSizeTypeY() == BackgroundImagePositionType::PX) {
576 offset.SetY(imagePosition.GetSizeValueY());
577 } else {
578 offset.SetY(
579 imagePosition.GetSizeValueY() * (boxPaintSize_.Height() - imageRenderSize_.Height()) / PERCENT_TRANSLATE);
580 }
581
582 imageRenderPosition_ = offset;
583 }
584
ClearRenderObject()585 void RenderImage::ClearRenderObject()
586 {
587 RenderNode::ClearRenderObject();
588
589 isImageSizeSet_ = false;
590 rawImageSizeUpdated_ = false;
591 matchTextDirection_ = false;
592 imageComponentSize_ = Size();
593 formerMaxSize_ = Size();
594 alignment_ = Alignment::CENTER;
595 imageLoadingStatus_ = ImageLoadingStatus::UNLOADED;
596
597 imageFit_ = ImageFit::COVER;
598 imageRepeat_ = ImageRepeat::NOREPEAT;
599 rectList_.clear();
600 color_.reset();
601 sourceInfo_.Reset();
602 singleWidth_ = 0.0;
603 displaySrcWidth_ = 0.0;
604 scale_ = 1.0;
605 horizontalRepeatNum_ = 1.0;
606 rotate_ = 0.0;
607 keepOffsetZero_ = false;
608 resizeCallLoadImage_ = false;
609 frameCount_ = 0;
610 topLeftRadius_ = Radius(0.0);
611 topRightRadius_ = Radius(0.0);
612 bottomLeftRadius_ = Radius(0.0);
613 bottomRightRadius_ = Radius(0.0);
614 resizeScale_ = Size();
615 resizeTarget_ = Size();
616 previousResizeTarget_ = Size();
617 currentResizeScale_ = Size();
618 width_ = Dimension();
619 height_ = Dimension();
620 rawImageSize_ = Size();
621 renderAltImage_ = nullptr;
622 proceedPreviousLoading_ = false;
623 imageUpdateFunc_ = nullptr;
624 imageRenderFunc_ = nullptr;
625 background_ = false;
626 boxPaintSize_ = Size();
627 boxMarginOffset_ = Offset();
628 imageSize_ = BackgroundImageSize();
629 imagePosition_ = BackgroundImagePosition();
630 imageObjectPosition_ = ImageObjectPosition();
631 imageRenderSize_ = Size();
632 imageRenderPosition_ = Offset();
633 forceResize_ = false;
634 forceReload_ = false;
635 imageSizeForEvent_ = { 0.0, 0.0 };
636 retryCnt_ = 0;
637 }
638
PrintImageLog(const Size & srcSize,const BackgroundImageSize & imageSize,ImageRepeat imageRepeat,const BackgroundImagePosition & imagePosition) const639 void RenderImage::PrintImageLog(const Size& srcSize, const BackgroundImageSize& imageSize, ImageRepeat imageRepeat,
640 const BackgroundImagePosition& imagePosition) const
641 {
642 LOGD("[BOX][IMAGE][Dep:%{public}d] Param:Src W:%{public}.1lf, H:%{public}.1lf, Size:%{public}.1lf|%{public}d, "
643 "%{public}.1lf|%{public}d, Rep:%{public}u, Pos X:%{public}.1lf|%{public}d, Y:%{public}.1lf|%{public}d, "
644 "BoxPaint:%{public}.1lf * %{public}.1lf, MarginOffset: %{public}.1lf * %{public}.1lf",
645 GetDepth(), srcSize.Width(), srcSize.Height(), imageSize.GetSizeValueX(), imageSize.GetSizeTypeX(),
646 imageSize.GetSizeValueY(), imageSize.GetSizeTypeY(), imageRepeat, imagePosition.GetSizeValueX(),
647 imagePosition.GetSizeTypeX(), imagePosition.GetSizeValueY(), imagePosition.GetSizeTypeY(),
648 boxPaintSize_.Width(), boxPaintSize_.Height(), boxMarginOffset_.GetX(), boxMarginOffset_.GetY());
649 LOGD("[BOX][IMAGE][Dep:%{public}d] Result: Size:(%{public}.1lf*%{public}.1lf), Pos(%{public}.1lf,%{public}.1lf), "
650 "rect:%{public}s",
651 GetDepth(), imageRenderSize_.Width(), imageRenderSize_.Height(), imageRenderPosition_.GetX(),
652 imageRenderPosition_.GetY(), rectList_.front().ToString().c_str());
653 }
654
Dump()655 void RenderImage::Dump()
656 {
657 DumpLog::GetInstance().AddDesc(std::string("UsingWideGamut: ").append(IsSourceWideGamut() ? "true" : "false"));
658 }
659
660 } // namespace OHOS::Ace
661