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/render/image_painter.h"
17
18 #include "core/components_ng/render/drawing_prop_convertor.h"
19 #include "core/pipeline_ng/pipeline_context.h"
20
21 namespace OHOS::Ace::NG {
22
23 namespace {
24
25 constexpr Color COLOR_PRIVATE_MODE = Color(0x66d7d7d7);
26 constexpr Dimension RECT_BORDER_RADIUS = 2.0_vp;
27 constexpr uint32_t RADIUS_POINT_COUNT = 4;
28
ApplyContain(const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect)29 void ApplyContain(const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect)
30 {
31 if (rawPicSize.IsNonPositive()) {
32 return;
33 }
34 if (Size::CalcRatio(srcRect) > Size::CalcRatio(dstRect)) {
35 dstRect.SetSize(rawPicSize * (dstSize.Width() / rawPicSize.Width()));
36 } else {
37 dstRect.SetSize(rawPicSize * (dstSize.Height() / rawPicSize.Height()));
38 }
39 dstRect.SetOffset(Alignment::GetAlignPosition(dstSize, dstRect.GetSize(), Alignment::CENTER));
40 }
41
ApplyCover(const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect)42 void ApplyCover(const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect)
43 {
44 if (Size::CalcRatio(srcRect) > Size::CalcRatio(dstRect)) {
45 srcRect.SetSize(dstSize * (rawPicSize.Height() / dstSize.Height()));
46 } else {
47 srcRect.SetSize(dstSize * (rawPicSize.Width() / dstSize.Width()));
48 }
49 srcRect.SetOffset(Alignment::GetAlignPosition(rawPicSize, srcRect.GetSize(), Alignment::CENTER));
50 }
51
ApplyCoverTopLeft(const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect)52 void ApplyCoverTopLeft(const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect)
53 {
54 ApplyCover(rawPicSize, dstSize, srcRect, dstRect);
55 }
56
ApplyFitWidth(const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect)57 void ApplyFitWidth(const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect)
58 {
59 if (Size::CalcRatio(srcRect) > Size::CalcRatio(dstRect)) {
60 dstRect.SetSize(rawPicSize * (dstSize.Width() / rawPicSize.Width()));
61 dstRect.SetOffset(Alignment::GetAlignPosition(dstSize, dstRect.GetSize(), Alignment::CENTER));
62 } else {
63 srcRect.SetSize(dstSize * (rawPicSize.Width() / dstSize.Width()));
64 srcRect.SetOffset(Alignment::GetAlignPosition(rawPicSize, srcRect.GetSize(), Alignment::CENTER));
65 }
66 }
67
ApplyFitHeight(const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect)68 void ApplyFitHeight(const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect)
69 {
70 if (Size::CalcRatio(srcRect) > Size::CalcRatio(dstRect)) {
71 srcRect.SetSize(dstSize * (rawPicSize.Height() / dstSize.Height()));
72 srcRect.SetOffset(Alignment::GetAlignPosition(rawPicSize, srcRect.GetSize(), Alignment::CENTER));
73 } else {
74 dstRect.SetSize(rawPicSize * (dstSize.Height() / rawPicSize.Height()));
75 dstRect.SetOffset(Alignment::GetAlignPosition(dstSize, dstRect.GetSize(), Alignment::CENTER));
76 }
77 }
78
ApplyNone(const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect)79 void ApplyNone(const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect)
80 {
81 SizeF srcSize(std::min(dstSize.Width(), rawPicSize.Width()), std::min(dstSize.Height(), rawPicSize.Height()));
82 dstRect.SetRect(Alignment::GetAlignPosition(dstSize, srcSize, Alignment::CENTER), srcSize);
83 srcRect.SetRect(Alignment::GetAlignPosition(rawPicSize, srcSize, Alignment::CENTER), srcSize);
84 }
85
ApplyAlignment(const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect,const Alignment & alignMent)86 void ApplyAlignment(
87 const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect, const Alignment& alignMent)
88 {
89 SizeF srcSize(std::min(dstSize.Width(), rawPicSize.Width()), std::min(dstSize.Height(), rawPicSize.Height()));
90 dstRect.SetRect(Alignment::GetAlignPosition(dstSize, srcSize, alignMent), srcSize);
91 srcRect.SetRect(Alignment::GetAlignPosition(rawPicSize, srcSize, alignMent), srcSize);
92 }
93 } // namespace
94
95 const std::unordered_map<ImageFit, std::function<Alignment(bool)>> ImagePainter::ALIMENT_OPERATIONS = {
96 { ImageFit::TOP_LEFT,
__anon1ef437450202() 97 [](bool isRightToLeft) { return isRightToLeft ? Alignment::TOP_RIGHT : Alignment::TOP_LEFT; } },
__anon1ef437450302() 98 { ImageFit::TOP, [](bool) { return Alignment::TOP_CENTER; } },
99 { ImageFit::TOP_END,
__anon1ef437450402() 100 [](bool isRightToLeft) { return isRightToLeft ? Alignment::TOP_LEFT : Alignment::TOP_RIGHT; } },
101 { ImageFit::START,
__anon1ef437450502() 102 [](bool isRightToLeft) { return isRightToLeft ? Alignment::CENTER_RIGHT : Alignment::CENTER_LEFT; } },
__anon1ef437450602() 103 { ImageFit::CENTER, [](bool) { return Alignment::CENTER; } },
104 { ImageFit::END,
__anon1ef437450702() 105 [](bool isRightToLeft) { return isRightToLeft ? Alignment::CENTER_LEFT : Alignment::CENTER_RIGHT; } },
106 { ImageFit::BOTTOM_START,
__anon1ef437450802() 107 [](bool isRightToLeft) { return isRightToLeft ? Alignment::BOTTOM_RIGHT : Alignment::BOTTOM_LEFT; } },
__anon1ef437450902() 108 { ImageFit::BOTTOM, [](bool) { return Alignment::BOTTOM_CENTER; } },
109 { ImageFit::BOTTOM_END,
__anon1ef437450a02() 110 [](bool isRightToLeft) { return isRightToLeft ? Alignment::BOTTOM_LEFT : Alignment::BOTTOM_RIGHT; } }
111 };
112
DrawObscuration(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const113 void ImagePainter::DrawObscuration(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
114 {
115 CHECK_NULL_VOID(canvasImage_);
116 const auto config = canvasImage_->GetPaintConfig();
117 RSBrush brush;
118 Color fillColor = COLOR_PRIVATE_MODE;
119 RSColor rSColor(fillColor.GetRed(), fillColor.GetGreen(), fillColor.GetBlue(), fillColor.GetAlpha());
120 brush.SetColor(rSColor);
121 std::vector<RSPoint> radiusXY(RADIUS_POINT_COUNT);
122 if (config.borderRadiusXY_) {
123 for (auto index = 0U; index < radiusXY.size(); index++) {
124 radiusXY[index].SetX(static_cast<float>((*config.borderRadiusXY_)[index].GetX()));
125 radiusXY[index].SetY(static_cast<float>((*config.borderRadiusXY_)[index].GetY()));
126 }
127 } else if (config.isSvg_) {
128 // obscured SVGs need a default corner radius
129 for (auto& radius : radiusXY) {
130 radius.SetX(static_cast<float>(RECT_BORDER_RADIUS.ConvertToPx()));
131 radius.SetY(static_cast<float>(RECT_BORDER_RADIUS.ConvertToPx()));
132 }
133 }
134 canvas.AttachBrush(brush);
135 RSRoundRect rsRoundRect(
136 RSRect(offset.GetX(), offset.GetY(), contentSize.Width() + offset.GetX(), contentSize.Height() + offset.GetY()),
137 radiusXY);
138 canvas.DrawRoundRect(rsRoundRect);
139 canvas.DetachBrush();
140 }
141
DrawImage(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const142 void ImagePainter::DrawImage(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
143 {
144 CHECK_NULL_VOID(canvasImage_);
145 const auto config = canvasImage_->GetPaintConfig();
146 bool drawObscuration = std::any_of(config.obscuredReasons_.begin(), config.obscuredReasons_.end(),
147 [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
148 if (drawObscuration) {
149 DrawObscuration(canvas, offset, contentSize);
150 } else if (config.isSvg_) {
151 DrawSVGImage(canvas, offset, contentSize);
152 } else {
153 DrawStaticImage(canvas, offset, contentSize);
154 }
155 }
156
DrawSVGImage(RSCanvas & canvas,const OffsetF & offset,const SizeF & svgContainerSize) const157 void ImagePainter::DrawSVGImage(RSCanvas& canvas, const OffsetF& offset, const SizeF& svgContainerSize) const
158 {
159 CHECK_NULL_VOID(canvasImage_);
160 canvas.Save();
161 canvas.Translate(offset.GetX(), offset.GetY());
162 const auto config = canvasImage_->GetPaintConfig();
163 if (config.flipHorizontally_) {
164 ImagePainter::FlipHorizontal(canvas, svgContainerSize);
165 }
166
167 RectF srcRect;
168 srcRect.SetSize(svgContainerSize);
169 canvasImage_->DrawToRSCanvas(canvas, ToRSRect(srcRect), ToRSRect(config.dstRect_),
170 config.borderRadiusXY_ ? *config.borderRadiusXY_ : BorderRadiusArray());
171 canvas.Restore();
172 }
173
DrawStaticImage(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const174 void ImagePainter::DrawStaticImage(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
175 {
176 CHECK_NULL_VOID(canvasImage_);
177 const auto config = canvasImage_->GetPaintConfig();
178 canvas.Save();
179 canvas.Translate(offset.GetX(), offset.GetY());
180
181 if (config.flipHorizontally_) {
182 ImagePainter::FlipHorizontal(canvas, contentSize);
183 }
184
185 canvasImage_->DrawToRSCanvas(canvas, ToRSRect(config.srcRect_), ToRSRect(config.dstRect_),
186 config.borderRadiusXY_ ? *config.borderRadiusXY_ : BorderRadiusArray());
187 canvas.Restore();
188 }
189
FlipHorizontal(RSCanvas & canvas,const SizeF & contentSize)190 void ImagePainter::FlipHorizontal(RSCanvas& canvas, const SizeF& contentSize)
191 {
192 canvas.Translate(contentSize.Width() / 2, contentSize.Height() / 2);
193 canvas.Scale(-1.0, 1.0);
194 canvas.Translate(-contentSize.Width() / 2, -contentSize.Height() / 2);
195 }
196
DrawImageWithRepeat(RSCanvas & canvas,const RectF & contentRect) const197 void ImagePainter::DrawImageWithRepeat(RSCanvas& canvas, const RectF& contentRect) const
198 {
199 auto config = canvasImage_->GetPaintConfig();
200 if (config.imageRepeat_ == ImageRepeat::NO_REPEAT) {
201 return;
202 }
203 auto offset = contentRect.GetOffset();
204 float contentWidth = contentRect.Width();
205 float contentHeight = contentRect.Height();
206 float singleImageWidth = config.dstRect_.Width();
207 float singleImageHeight = config.dstRect_.Height();
208 if (NearZero(singleImageWidth) || NearZero(singleImageHeight)) {
209 return;
210 }
211
212 bool imageRepeatX = config.imageRepeat_ == ImageRepeat::REPEAT || config.imageRepeat_ == ImageRepeat::REPEAT_X;
213 bool imageRepeatY = config.imageRepeat_ == ImageRepeat::REPEAT || config.imageRepeat_ == ImageRepeat::REPEAT_Y;
214 std::vector<uint32_t> dirRepeatNum = { static_cast<uint32_t>(ceil(config.dstRect_.GetY() / singleImageHeight)),
215 static_cast<uint32_t>((ceil((contentHeight - config.dstRect_.GetY()) / singleImageHeight))) - 1,
216 static_cast<uint32_t>(ceil(config.dstRect_.GetX() / singleImageWidth)),
217 imageRepeatX ? static_cast<uint32_t>(ceil((contentWidth - config.dstRect_.GetX()) / singleImageWidth)) : 1 };
218
219 canvas.Save();
220 auto clipRect = RSRect(offset.GetX(), offset.GetY(), static_cast<float>(offset.GetX() + contentWidth),
221 static_cast<float>(offset.GetY() + contentHeight));
222 canvas.ClipRect(clipRect, RSClipOp::INTERSECT);
223 uint32_t up = 0;
224 uint32_t down = 1;
225 uint32_t left = 2;
226 uint32_t right = 3;
227 auto drawRepeatYTask = [this, &canvas, &config, &dirRepeatNum, &singleImageHeight, &imageRepeatY, &contentRect](
228 OffsetF offsetTempY, uint32_t dir) {
229 float downNum = (dir == 0) ? -1 : 1;
230 for (size_t j = 0; j < dirRepeatNum[dir] && imageRepeatY; j++) {
231 offsetTempY.SetY(static_cast<float>(offsetTempY.GetY() + singleImageHeight * downNum));
232 DrawStaticImage(canvas, offsetTempY, contentRect.GetSize());
233 }
234 };
235 auto offsetTempX = offset;
236 // right
237 for (size_t i = 0; i < dirRepeatNum[right]; i++) {
238 DrawStaticImage(canvas, offsetTempX, contentRect.GetSize());
239 drawRepeatYTask(offsetTempX, up);
240 drawRepeatYTask(offsetTempX, down);
241 offsetTempX.SetX(static_cast<float>(offsetTempX.GetX() + singleImageWidth));
242 }
243 // left
244 offsetTempX = offset;
245 for (size_t i = 0; i < dirRepeatNum[left] && imageRepeatX; i++) {
246 offsetTempX.SetX(static_cast<float>(offsetTempX.GetX() - singleImageWidth));
247 DrawStaticImage(canvas, offsetTempX, contentRect.GetSize());
248 drawRepeatYTask(offsetTempX, up);
249 drawRepeatYTask(offsetTempX, down);
250 }
251 canvas.Restore();
252 }
253
ApplyImageAlignmentFit(ImageFit imageFit,const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect)254 void ImagePainter::ApplyImageAlignmentFit(
255 ImageFit imageFit, const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect)
256 {
257 auto isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
258 auto itImageFit = ALIMENT_OPERATIONS.find(imageFit);
259 if (itImageFit != ALIMENT_OPERATIONS.end()) {
260 Alignment alignment = itImageFit->second(isRightToLeft);
261 ApplyAlignment(rawPicSize, dstSize, srcRect, dstRect, alignment);
262 }
263 }
264
ApplyImageFit(ImageFit imageFit,const SizeF & rawPicSize,const SizeF & dstSize,RectF & srcRect,RectF & dstRect)265 void ImagePainter::ApplyImageFit(
266 ImageFit imageFit, const SizeF& rawPicSize, const SizeF& dstSize, RectF& srcRect, RectF& dstRect)
267 {
268 auto context = PipelineContext::GetCurrentContext();
269 float viewScale = context ? context->GetViewScale() : 1.0;
270 srcRect.SetOffset(OffsetF());
271 srcRect.SetSize(rawPicSize);
272 srcRect.ApplyScale(1.0 / viewScale);
273 dstRect.SetOffset(OffsetF());
274 dstRect.SetSize(dstSize);
275 if (imageFit >= ImageFit::TOP_LEFT && imageFit <= ImageFit::BOTTOM_END) {
276 ApplyImageAlignmentFit(imageFit, rawPicSize, dstSize, srcRect, dstRect);
277 srcRect.ApplyScale(viewScale);
278 return;
279 }
280 switch (imageFit) {
281 case ImageFit::FILL:
282 break;
283 case ImageFit::NONE:
284 ApplyNone(rawPicSize, dstSize, srcRect, dstRect);
285 break;
286 case ImageFit::COVER:
287 ApplyCover(rawPicSize, dstSize, srcRect, dstRect);
288 break;
289 case ImageFit::COVER_TOP_LEFT:
290 ApplyCoverTopLeft(rawPicSize, dstSize, srcRect, dstRect);
291 break;
292 case ImageFit::FITWIDTH:
293 ApplyFitWidth(rawPicSize, dstSize, srcRect, dstRect);
294 break;
295 case ImageFit::FITHEIGHT:
296 ApplyFitHeight(rawPicSize, dstSize, srcRect, dstRect);
297 break;
298 case ImageFit::SCALE_DOWN:
299 if (srcRect.GetSize() < dstRect.GetSize()) {
300 ApplyNone(rawPicSize, dstSize, srcRect, dstRect);
301 } else {
302 ApplyContain(rawPicSize, dstSize, srcRect, dstRect);
303 }
304 break;
305 case ImageFit::CONTAIN:
306 default:
307 ApplyContain(rawPicSize, dstSize, srcRect, dstRect);
308 break;
309 }
310 srcRect.ApplyScale(viewScale);
311 }
312
CalculateBgImagePosition(const SizeF & boxPaintSize_,const SizeF & imageRenderSize_,const std::optional<BackgroundImagePosition> & bgImgPositionOpt)313 OffsetF ImagePainter::CalculateBgImagePosition(const SizeF& boxPaintSize_, const SizeF& imageRenderSize_,
314 const std::optional<BackgroundImagePosition>& bgImgPositionOpt)
315 {
316 OffsetF offset(.0, .0);
317 if (bgImgPositionOpt == std::nullopt) {
318 return offset;
319 }
320 const auto& bgImgPosition = bgImgPositionOpt.value();
321 if (bgImgPosition.GetSizeTypeX() == BackgroundImagePositionType::PX) {
322 offset.SetX(bgImgPosition.GetSizeValueX());
323 } else {
324 offset.SetX(bgImgPosition.GetSizeValueX() * boxPaintSize_.Width());
325 }
326
327 if (bgImgPosition.GetSizeTypeY() == BackgroundImagePositionType::PX) {
328 offset.SetY(bgImgPosition.GetSizeValueY());
329 } else {
330 offset.SetY(bgImgPosition.GetSizeValueY() * boxPaintSize_.Height());
331 }
332
333 if (bgImgPosition.IsAlign()) {
334 offset.SetX(
335 bgImgPosition.GetSizeValueX() * (boxPaintSize_.Width() - imageRenderSize_.Width()) / PERCENT_TRANSLATE);
336 offset.SetY(
337 bgImgPosition.GetSizeValueY() * (boxPaintSize_.Height() - imageRenderSize_.Height()) / PERCENT_TRANSLATE);
338 }
339 return offset;
340 }
341
342 namespace {
CalculateBgWidth(const SizeF & boxPaintSize_,const SizeF & srcSize,const BackgroundImageSize & bgImageSize)343 float CalculateBgWidth(const SizeF& boxPaintSize_, const SizeF& srcSize, const BackgroundImageSize& bgImageSize)
344 {
345 float width = 0.0f;
346 float paintAspectRatio = boxPaintSize_.Width() / boxPaintSize_.Height();
347 float srcAspectRatio = srcSize.Width() / srcSize.Height();
348 auto bgImageSizeTypeX = bgImageSize.GetSizeTypeX();
349 switch (bgImageSizeTypeX) {
350 case BackgroundImageSizeType::COVER:
351 width = paintAspectRatio >= srcAspectRatio ? boxPaintSize_.Width()
352 : srcSize.Width() * (boxPaintSize_.Height() / srcSize.Height());
353 break;
354 case BackgroundImageSizeType::CONTAIN:
355 width = paintAspectRatio >= srcAspectRatio ? srcSize.Width() * (boxPaintSize_.Height() / srcSize.Height())
356 : boxPaintSize_.Width();
357 break;
358 case BackgroundImageSizeType::FILL:
359 width = boxPaintSize_.Width();
360 break;
361 case BackgroundImageSizeType::LENGTH:
362 width = bgImageSize.GetSizeValueX();
363 break;
364 case BackgroundImageSizeType::PERCENT:
365 width = boxPaintSize_.Width() * bgImageSize.GetSizeValueX() / PERCENT_TRANSLATE;
366 break;
367 default:
368 break;
369 }
370 return width;
371 }
372
CalculateBgHeight(const SizeF & boxPaintSize_,const SizeF & srcSize,const BackgroundImageSize & bgImageSize)373 float CalculateBgHeight(const SizeF& boxPaintSize_, const SizeF& srcSize, const BackgroundImageSize& bgImageSize)
374 {
375 float height = 0.0f;
376 float paintAspectRatio = boxPaintSize_.Width() / boxPaintSize_.Height();
377 float srcAspectRatio = srcSize.Width() / srcSize.Height();
378 auto bgImageSizeTypeY = bgImageSize.GetSizeTypeY();
379 switch (bgImageSizeTypeY) {
380 case BackgroundImageSizeType::COVER:
381 height = paintAspectRatio >= srcAspectRatio ? srcSize.Height() * (boxPaintSize_.Width() / srcSize.Width())
382 : boxPaintSize_.Height();
383 break;
384 case BackgroundImageSizeType::CONTAIN:
385 height = paintAspectRatio >= srcAspectRatio ? boxPaintSize_.Height()
386 : srcSize.Height() * (boxPaintSize_.Width() / srcSize.Width());
387 break;
388 case BackgroundImageSizeType::FILL:
389 height = boxPaintSize_.Height();
390 break;
391 case BackgroundImageSizeType::LENGTH:
392 height = bgImageSize.GetSizeValueY();
393 break;
394 case BackgroundImageSizeType::PERCENT:
395 height = boxPaintSize_.Height() * bgImageSize.GetSizeValueY() / PERCENT_TRANSLATE;
396 break;
397 default:
398 break;
399 }
400 return height;
401 }
402 } // namespace
403
CalculateBgImageSize(const SizeF & boxPaintSize_,const SizeF & srcSize,const std::optional<BackgroundImageSize> & bgImageSizeOpt)404 SizeF ImagePainter::CalculateBgImageSize(
405 const SizeF& boxPaintSize_, const SizeF& srcSize, const std::optional<BackgroundImageSize>& bgImageSizeOpt)
406 {
407 SizeF sizeRet(srcSize.Width(), srcSize.Height());
408 if (bgImageSizeOpt == std::nullopt || NearZero(srcSize.Width()) || NearZero(srcSize.Height()) ||
409 NearZero(boxPaintSize_.Width()) || NearZero(boxPaintSize_.Height())) {
410 return sizeRet;
411 }
412 auto bgImageSize = bgImageSizeOpt.value();
413 float renderSizeX = CalculateBgWidth(boxPaintSize_, srcSize, bgImageSize);
414 float renderSizeY = CalculateBgHeight(boxPaintSize_, srcSize, bgImageSize);
415
416 if (bgImageSize.GetSizeTypeX() == BackgroundImageSizeType::AUTO &&
417 bgImageSize.GetSizeTypeY() == BackgroundImageSizeType::AUTO) {
418 renderSizeX = srcSize.Width();
419 renderSizeY = srcSize.Height();
420 } else if (bgImageSize.GetSizeTypeX() == BackgroundImageSizeType::AUTO) {
421 renderSizeX = srcSize.Width() * (renderSizeY / srcSize.Height());
422 } else if (bgImageSize.GetSizeTypeY() == BackgroundImageSizeType::AUTO) {
423 renderSizeY = srcSize.Height() * (renderSizeX / srcSize.Width());
424 }
425 // fit image ratio if width or height is not set
426 float srcRatio = srcSize.Width() / srcSize.Height();
427 CHECK_NULL_RETURN(srcRatio > 0, sizeRet);
428 if (renderSizeX <= 0) {
429 renderSizeX = renderSizeY * srcRatio;
430 } else if (renderSizeY <= 0) {
431 renderSizeY = renderSizeX / srcRatio;
432 }
433 sizeRet.SetWidth(renderSizeX);
434 sizeRet.SetHeight(renderSizeY);
435 return sizeRet;
436 }
437
438 } // namespace OHOS::Ace::NG
439