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/border_image_painter.h"
17 
18 namespace {
19 constexpr double EXTRA_OFFSET = 1.0;
20 } // namespace
21 
22 namespace OHOS::Ace::NG {
BorderImagePainter(BorderImageProperty bdImageProps,const std::unique_ptr<BorderWidthProperty> & widthProp,const SizeF & paintSize,const RSImage & image,const DisplayScaleInfo & dipscaleInfo)23 BorderImagePainter::BorderImagePainter(BorderImageProperty bdImageProps,
24     const std::unique_ptr<BorderWidthProperty>& widthProp, const SizeF& paintSize, const RSImage& image,
25     const DisplayScaleInfo& dipscaleInfo)
26     : hasWidthProp_(widthProp != nullptr), borderImageProperty_(std::move(bdImageProps)), paintSize_(paintSize),
27       image_(image)
28 {
29     dipScale_ = dipscaleInfo.vpScale;
30     lpxScale_ = dipscaleInfo.lpxScale;
31     if (hasWidthProp_) {
32         widthProp_ = *widthProp;
33     }
34     imageWidth_ = image_.GetWidth();
35     imageHeight_ = image_.GetHeight();
36     InitPainter();
37 }
38 
InitPainter()39 void BorderImagePainter::InitPainter()
40 {
41     CHECK_NULL_VOID(borderImageProperty_.GetBorderImage());
42     InitBorderImageSlice();
43     InitBorderImageWidth();
44     InitBorderImageOutset();
45     imageCenterWidth_ = std::ceil(imageWidth_ - leftSlice_ - rightSlice_);
46     imageCenterHeight_ = std::ceil(imageHeight_ - topSlice_ - bottomSlice_);
47     borderCenterWidth_ = std::ceil(paintSize_.Width() - leftWidth_ - rightWidth_ + leftOutset_ + rightOutset_);
48     borderCenterHeight_ = std::ceil(paintSize_.Height() - topWidth_ - bottomWidth_ + topOutset_ + bottomOutset_);
49     srcRectLeft_ = RSRect(0, topSlice_, leftSlice_, topSlice_ + imageCenterHeight_);
50     srcRectTop_ = RSRect(leftSlice_, 0, leftSlice_ + imageCenterWidth_, topSlice_);
51     srcRectRight_ = RSRect(imageWidth_ - rightSlice_, topSlice_, imageWidth_, topSlice_ + imageCenterHeight_);
52     srcRectBottom_ = RSRect(leftSlice_, imageHeight_ - bottomSlice_, leftSlice_ + imageCenterWidth_, imageHeight_);
53 }
54 
InitBorderImageSlice()55 void BorderImagePainter::InitBorderImageSlice()
56 {
57     auto borderImage = borderImageProperty_.GetBorderImageValue();
58     BorderImageEdge imageLeft = borderImage->GetBorderImageEdge(BorderImageDirection::LEFT);
59     BorderImageEdge imageTop = borderImage->GetBorderImageEdge(BorderImageDirection::TOP);
60     BorderImageEdge imageRight = borderImage->GetBorderImageEdge(BorderImageDirection::RIGHT);
61     BorderImageEdge imageBottom = borderImage->GetBorderImageEdge(BorderImageDirection::BOTTOM);
62     if (!borderImageProperty_.GetHasBorderImageSlice()) {
63         leftSlice_ = imageWidth_;
64         topSlice_ = imageHeight_;
65         rightSlice_ = imageWidth_;
66         bottomSlice_ = imageHeight_;
67         paintCornersOnly_ = true;
68         return;
69     }
70 
71     if (GreatNotEqual(imageLeft.GetBorderImageSlice().Value(), 0.0)) {
72         imageLeft.GetBorderImageSlice().NormalizeToPx(dipScale_, 0.0, lpxScale_, imageWidth_, leftSlice_);
73     }
74     if (GreatNotEqual(imageRight.GetBorderImageSlice().Value(), 0.0)) {
75         imageRight.GetBorderImageSlice().NormalizeToPx(dipScale_, 0.0, lpxScale_, imageWidth_, rightSlice_);
76     }
77     if (GreatNotEqual(imageTop.GetBorderImageSlice().Value(), 0.0)) {
78         imageTop.GetBorderImageSlice().NormalizeToPx(dipScale_, 0.0, lpxScale_, imageHeight_, topSlice_);
79     }
80     if (GreatNotEqual(imageBottom.GetBorderImageSlice().Value(), 0.0)) {
81         imageBottom.GetBorderImageSlice().NormalizeToPx(dipScale_, 0.0, lpxScale_, imageHeight_, bottomSlice_);
82     }
83     if (GreatNotEqual(leftSlice_, imageWidth_)) {
84         leftSlice_ = imageWidth_;
85     }
86     if (GreatNotEqual(rightSlice_, imageWidth_)) {
87         rightSlice_ = imageWidth_;
88     }
89     if (GreatNotEqual(topSlice_, imageHeight_)) {
90         topSlice_ = imageHeight_;
91     }
92     if (GreatNotEqual(bottomSlice_, imageHeight_)) {
93         bottomSlice_ = imageHeight_;
94     }
95 
96     ParseNegativeNumberToZeroOrCeil(leftSlice_);
97     ParseNegativeNumberToZeroOrCeil(rightSlice_);
98     ParseNegativeNumberToZeroOrCeil(topSlice_);
99     ParseNegativeNumberToZeroOrCeil(bottomSlice_);
100 }
101 
InitBorderImageWidth()102 void BorderImagePainter::InitBorderImageWidth()
103 {
104     if (!borderImageProperty_.GetHasBorderImageWidth() && !hasWidthProp_) {
105         return;
106     }
107     auto borderImage = borderImageProperty_.GetBorderImageValue();
108     BorderImageEdge imageLeft = borderImage->GetBorderImageEdge(BorderImageDirection::LEFT);
109     BorderImageEdge imageTop = borderImage->GetBorderImageEdge(BorderImageDirection::TOP);
110     BorderImageEdge imageRight = borderImage->GetBorderImageEdge(BorderImageDirection::RIGHT);
111     BorderImageEdge imageBottom = borderImage->GetBorderImageEdge(BorderImageDirection::BOTTOM);
112 
113     if (GreatNotEqual(imageLeft.GetBorderImageWidth().Value(), 0.0)) {
114         imageLeft.GetBorderImageWidth().NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Width(), leftWidth_);
115     } else if (hasWidthProp_) {
116         widthProp_.leftDimen->NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Width(), leftWidth_);
117     }
118     if (GreatNotEqual(imageRight.GetBorderImageWidth().Value(), 0.0)) {
119         imageRight.GetBorderImageWidth().NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Width(), rightWidth_);
120     } else if (hasWidthProp_) {
121         widthProp_.rightDimen->NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Width(), rightWidth_);
122     }
123     if (GreatNotEqual(imageTop.GetBorderImageWidth().Value(), 0.0)) {
124         imageTop.GetBorderImageWidth().NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Height(), topWidth_);
125     } else if (hasWidthProp_) {
126         widthProp_.topDimen->NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Height(), topWidth_);
127     }
128     if (GreatNotEqual(imageBottom.GetBorderImageWidth().Value(), 0.0)) {
129         imageBottom.GetBorderImageWidth().NormalizeToPx(
130             dipScale_, 0.0, lpxScale_, paintSize_.Height(), bottomWidth_);
131     } else if (hasWidthProp_) {
132         widthProp_.bottomDimen->NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Height(), bottomWidth_);
133     }
134 
135     ParseNegativeNumberToZeroOrCeil(leftWidth_);
136     ParseNegativeNumberToZeroOrCeil(rightWidth_);
137     ParseNegativeNumberToZeroOrCeil(topWidth_);
138     ParseNegativeNumberToZeroOrCeil(bottomWidth_);
139 }
140 
GetDrawRect(const OffsetF & offset)141 RectF BorderImagePainter::GetDrawRect(const OffsetF& offset)
142 {
143     const float offsetLeftX = std::ceil(offset.GetX() - leftOutset_);
144     const float offsetRightX = std::ceil(offset.GetX() + paintSize_.Width() + rightOutset_);
145     const float offsetTopY = std::ceil(offset.GetY() - topOutset_);
146     const float offsetBottomY = std::ceil(offset.GetY() + paintSize_.Height() + bottomOutset_);
147 
148     // desRectLeftTop:
149     // [offsetLeftX, offsetTopY, offsetLeftX + leftWidth_ + EXTRA_OFFSET, offsetTopY + topWidth_ + EXTRA_OFFSET]
150     // desRectRightBottom:
151     // [offsetRightX - rightWidth_ - EXTRA_OFFSET, offsetBottomY - bottomWidth_ - EXTRA_OFFSET, offsetRightX,
152     // offsetBottomY]
153     float rbX = offsetRightX - rightWidth_ - EXTRA_OFFSET + offsetRightX;
154     float rbY = offsetBottomY - bottomWidth_ - EXTRA_OFFSET + offsetBottomY;
155 
156     return { offsetLeftX, offsetTopY, rbX - offsetLeftX, rbY - offsetTopY };
157 }
158 
InitBorderImageOutset()159 void BorderImagePainter::InitBorderImageOutset()
160 {
161     if (!borderImageProperty_.GetHasBorderImageOutset() && !hasWidthProp_) {
162         return;
163     }
164     auto borderImage = borderImageProperty_.GetBorderImageValue();
165     BorderImageEdge imageLeft = borderImage->GetBorderImageEdge(BorderImageDirection::LEFT);
166     BorderImageEdge imageTop = borderImage->GetBorderImageEdge(BorderImageDirection::TOP);
167     BorderImageEdge imageRight = borderImage->GetBorderImageEdge(BorderImageDirection::RIGHT);
168     BorderImageEdge imageBottom = borderImage->GetBorderImageEdge(BorderImageDirection::BOTTOM);
169 
170     if (GreatNotEqual(imageLeft.GetBorderImageOutset().Value(), 0.0)) {
171         imageLeft.GetBorderImageOutset().NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Width(), leftOutset_);
172     } else if (hasWidthProp_) {
173         widthProp_.leftDimen->NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Width(), leftOutset_);
174     }
175     if (GreatNotEqual(imageRight.GetBorderImageOutset().Value(), 0.0)) {
176         imageRight.GetBorderImageOutset().NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Width(), rightOutset_);
177     } else if (hasWidthProp_) {
178         widthProp_.rightDimen->NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Width(), rightOutset_);
179     }
180     if (GreatNotEqual(imageTop.GetBorderImageOutset().Value(), 0.0)) {
181         imageTop.GetBorderImageOutset().NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Height(), topOutset_);
182     } else if (hasWidthProp_) {
183         widthProp_.topDimen->NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Height(), topOutset_);
184     }
185     if (GreatNotEqual(imageBottom.GetBorderImageOutset().Value(), 0.0)) {
186         imageBottom.GetBorderImageOutset().NormalizeToPx(
187             dipScale_, 0.0, lpxScale_, paintSize_.Height(), bottomOutset_);
188     } else if (hasWidthProp_) {
189         widthProp_.bottomDimen->NormalizeToPx(dipScale_, 0.0, lpxScale_, paintSize_.Height(), bottomOutset_);
190     }
191 
192     ParseNegativeNumberToZeroOrCeil(leftOutset_);
193     ParseNegativeNumberToZeroOrCeil(rightOutset_);
194     ParseNegativeNumberToZeroOrCeil(topOutset_);
195     ParseNegativeNumberToZeroOrCeil(bottomOutset_);
196 }
197 
PaintBorderImage(const OffsetF & offset,RSCanvas & canvas) const198 void BorderImagePainter::PaintBorderImage(const OffsetF& offset, RSCanvas& canvas) const
199 {
200     CHECK_NULL_VOID(borderImageProperty_.GetBorderImage());
201     OffsetF ceiledOffset(std::ceil(offset.GetX()), std::ceil(offset.GetY()));
202     RSPen pen;
203     pen.SetAntiAlias(true);
204     canvas.AttachPen(pen);
205     canvas.Save();
206     PaintBorderImageCorners(ceiledOffset, canvas);
207     if (paintCornersOnly_) {
208         return;
209     }
210     switch (borderImageProperty_.GetBorderImageValue()->GetRepeatMode()) {
211         case BorderImageRepeat::STRETCH:
212             PaintBorderImageStretch(ceiledOffset, canvas);
213             break;
214         case BorderImageRepeat::SPACE:
215             PaintBorderImageSpace(ceiledOffset, canvas);
216             break;
217         case BorderImageRepeat::ROUND:
218             PaintBorderImageRound(ceiledOffset, canvas);
219             break;
220         case BorderImageRepeat::REPEAT:
221             PaintBorderImageRepeat(ceiledOffset, canvas);
222             break;
223         default:
224             LOGE("Unsupported Border Image repeat mode");
225     }
226     if (borderImageProperty_.GetBorderImageValue()->GetNeedFillCenter()) {
227         FillBorderImageCenter(ceiledOffset, canvas);
228     }
229     canvas.Restore();
230     canvas.DetachPen();
231 }
232 
FillBorderImageCenter(const OffsetF & offset,RSCanvas & canvas) const233 void BorderImagePainter::FillBorderImageCenter(const OffsetF& offset, RSCanvas& canvas) const
234 {
235     RSSamplingOptions options;
236     double destLeftOffset = offset.GetX() - leftOutset_ + leftWidth_ - EXTRA_OFFSET;
237     double destTopOffset = offset.GetY() - topOutset_ + topWidth_ - EXTRA_OFFSET;
238     RSRect srcRectCenter =
239         RSRect(leftSlice_, topSlice_, leftSlice_ + imageCenterWidth_, topSlice_ + imageCenterHeight_);
240     RSRect desRectCenter = RSRect(destLeftOffset, destTopOffset, destLeftOffset + borderCenterWidth_ + EXTRA_OFFSET * 2,
241         destTopOffset + borderCenterHeight_ + EXTRA_OFFSET * 2);
242     canvas.DrawImageRect(image_, srcRectCenter, desRectCenter, options);
243 }
244 
PaintBorderImageCorners(const OffsetF & offset,RSCanvas & canvas) const245 void BorderImagePainter::PaintBorderImageCorners(const OffsetF& offset, RSCanvas& canvas) const
246 {
247     RSSamplingOptions options;
248     double offsetLeftX = std::ceil(offset.GetX() - leftOutset_);
249     double offsetRightX = std::ceil(offset.GetX() + paintSize_.Width() + rightOutset_);
250     double offsetTopY = std::ceil(offset.GetY() - topOutset_);
251     double offsetBottomY = std::ceil(offset.GetY() + paintSize_.Height() + bottomOutset_);
252 
253     // top left corner
254     RSRect srcRectLeftTop = RSRect(0, 0, leftSlice_, topSlice_);
255     // top right corner
256     RSRect srcRectRightTop = RSRect(imageWidth_ - rightSlice_, 0, imageWidth_, topSlice_);
257     // left bottom corner
258     RSRect srcRectLeftBottom = RSRect(0, imageHeight_ - bottomSlice_, leftSlice_, imageHeight_);
259     // right bottom corner
260     RSRect srcRectRightBottom =
261         RSRect(imageWidth_ - rightSlice_, imageHeight_ - bottomSlice_, imageWidth_, imageHeight_);
262 
263     // Draw the four corners of the picture to the four corners of the border
264     // left top
265     RSRect desRectLeftTop =
266         RSRect(offsetLeftX, offsetTopY, offsetLeftX + leftWidth_ + EXTRA_OFFSET, offsetTopY + topWidth_ + EXTRA_OFFSET);
267     canvas.DrawImageRect(image_, srcRectLeftTop, desRectLeftTop, options);
268 
269     // right top
270     RSRect desRectRightTop = RSRect(
271         offsetRightX - rightWidth_ - EXTRA_OFFSET, offsetTopY, offsetRightX, offsetTopY + topWidth_ + EXTRA_OFFSET);
272     canvas.DrawImageRect(image_, srcRectRightTop, desRectRightTop, options);
273 
274     // left bottom
275     RSRect desRectLeftBottom = RSRect(offsetLeftX, offsetBottomY - bottomWidth_ - EXTRA_OFFSET,
276         offsetLeftX + leftWidth_ + EXTRA_OFFSET, offsetBottomY);
277     canvas.DrawImageRect(image_, srcRectLeftBottom, desRectLeftBottom, options);
278 
279     // right bottom
280     RSRect desRectRightBottom = RSRect(offsetRightX - rightWidth_ - EXTRA_OFFSET,
281         offsetBottomY - bottomWidth_ - EXTRA_OFFSET, offsetRightX, offsetBottomY);
282     canvas.DrawImageRect(image_, srcRectRightBottom, desRectRightBottom, options);
283 }
284 
PaintBorderImageStretch(const OffsetF & offset,RSCanvas & canvas) const285 void BorderImagePainter::PaintBorderImageStretch(const OffsetF& offset, RSCanvas& canvas) const
286 {
287     RSSamplingOptions options;
288     double offsetLeftX = std::ceil(offset.GetX() - leftOutset_);
289     double offsetRightX = std::ceil(offset.GetX() + paintSize_.Width() + rightOutset_);
290     double offsetTopY = std::ceil(offset.GetY() - topOutset_);
291     double offsetBottomY = std::ceil(offset.GetY() + paintSize_.Height() + bottomOutset_);
292 
293     RSRect desRectLeft = RSRect(
294         offsetLeftX, offsetTopY + topWidth_, offsetLeftX + leftWidth_, offsetTopY + topWidth_ + borderCenterHeight_);
295     canvas.DrawImageRect(image_, srcRectLeft_, desRectLeft, options);
296 
297     RSRect desRectRight = RSRect(
298         offsetRightX - rightWidth_, offsetTopY + topWidth_, offsetRightX, offsetTopY + topWidth_ + borderCenterHeight_);
299     canvas.DrawImageRect(image_, srcRectRight_, desRectRight, options);
300 
301     RSRect desRectTop = RSRect(offsetLeftX + leftWidth_, offsetTopY,
302         offsetLeftX + paintSize_.Width() - rightWidth_ + leftOutset_ + rightOutset_, offsetTopY + topWidth_);
303     canvas.DrawImageRect(image_, srcRectTop_, desRectTop, options);
304 
305     RSRect desRectBottom = RSRect(offsetLeftX + leftWidth_, offsetBottomY - bottomWidth_,
306         offsetLeftX + paintSize_.Width() - rightWidth_ + leftOutset_ + rightOutset_, offsetBottomY);
307     canvas.DrawImageRect(image_, srcRectBottom_, desRectBottom, options);
308 }
309 
PaintBorderImageRound(const OffsetF & offset,RSCanvas & canvas) const310 void BorderImagePainter::PaintBorderImageRound(const OffsetF& offset, RSCanvas& canvas) const
311 {
312     RSSamplingOptions options;
313     double offsetLeftX = std::ceil(offset.GetX() - leftOutset_);
314     double offsetRightX = std::ceil(offset.GetX() + paintSize_.Width() + rightOutset_);
315     double offsetTopY = std::ceil(offset.GetY() - topOutset_);
316     double offsetBottomY = std::ceil(offset.GetY() + paintSize_.Height() + bottomOutset_);
317 
318     auto roundHorizontalCount = static_cast<int32_t>(borderCenterWidth_ / imageCenterWidth_);
319     auto roundVerticalCount = static_cast<int32_t>(borderCenterHeight_ / imageCenterHeight_);
320 
321     // Surplus
322     if (fmod(borderCenterWidth_, imageCenterWidth_) != 0) {
323         roundHorizontalCount += 1;
324     }
325 
326     if (fmod(borderCenterHeight_, imageCenterHeight_) != 0) {
327         roundVerticalCount += 1;
328     }
329 
330     double roundImageWidth = borderCenterWidth_ / roundHorizontalCount;
331     double roundImageHeight = borderCenterHeight_ / roundVerticalCount;
332 
333     double roundStartHorizontal = offsetLeftX + leftWidth_;
334 
335     // draw shrinked border images on top and bottom edge
336     for (int32_t i = 0; i < roundHorizontalCount; i++) {
337         // top
338         RSRect desRectTopRound =
339             RSRect(roundStartHorizontal, offsetTopY, roundStartHorizontal + roundImageWidth, offsetTopY + topWidth_);
340         canvas.DrawImageRect(image_, srcRectTop_, desRectTopRound, options);
341         // bottom
342         RSRect desRectBottomRound = RSRect(
343             roundStartHorizontal, offsetBottomY - bottomWidth_, roundStartHorizontal + roundImageWidth, offsetBottomY);
344         canvas.DrawImageRect(image_, srcRectBottom_, desRectBottomRound, options);
345         roundStartHorizontal += roundImageWidth;
346     }
347     double roundStartVertical = offsetTopY + topWidth_;
348     // draw shrinked border images on left and right edge
349     for (int32_t i = 0; i < roundVerticalCount; i++) {
350         // left
351         RSRect desRectLeftRound =
352             RSRect(offsetLeftX, roundStartVertical, offsetLeftX + leftWidth_, roundStartVertical + roundImageHeight);
353         canvas.DrawImageRect(image_, srcRectLeft_, desRectLeftRound, options);
354         // right
355         RSRect desRectRightRound =
356             RSRect(offsetRightX - rightWidth_, roundStartVertical, offsetRightX, roundStartVertical + roundImageHeight);
357         canvas.DrawImageRect(image_, srcRectRight_, desRectRightRound, options);
358         roundStartVertical += roundImageHeight;
359     }
360 }
361 
PaintBorderImageSpace(const OffsetF & offset,RSCanvas & canvas) const362 void BorderImagePainter::PaintBorderImageSpace(const OffsetF& offset, RSCanvas& canvas) const
363 {
364     RSSamplingOptions options;
365     double offsetLeftX = std::ceil(offset.GetX() - leftOutset_);
366     double offsetRightX = std::ceil(offset.GetX() + paintSize_.Width() + rightOutset_);
367     double offsetTopY = std::ceil(offset.GetY() - topOutset_);
368     double offsetBottomY = std::ceil(offset.GetY() + paintSize_.Height() + bottomOutset_);
369 
370     if (NearZero(imageCenterWidth_) || NearZero(imageCenterHeight_)) {
371         LOGW("Image center width or height is zero.");
372         return;
373     }
374 
375     // calculate maximum count of image pieces can fit in border
376     auto roundHorizontalCount = static_cast<int32_t>(borderCenterWidth_ / imageCenterWidth_);
377     auto roundVerticalCount = static_cast<int32_t>(borderCenterHeight_ / imageCenterHeight_);
378     if (roundHorizontalCount == 0.0) {
379         LOGW("Border image center width exceeds horizontal border center length, left and right side will not paint");
380     }
381     if (roundVerticalCount == 0.0) {
382         LOGW("Border image center height exceeds vertical border center length, top and bottom side will not paint");
383     }
384     // fmod(borderCenterWidth_, imageCenterWidth_) will return total blank length,
385     // and there are roundHorizontalCount + 1 blanks
386     double blankHorizontalSize = fmod(borderCenterWidth_, imageCenterWidth_) / (roundHorizontalCount + 1);
387     double blankVerticalSize = fmod(borderCenterHeight_, imageCenterHeight_) / (roundVerticalCount + 1);
388 
389     double roundStartHorizontal = offsetLeftX + leftWidth_ + blankHorizontalSize;
390     for (int32_t i = 0; i < roundHorizontalCount; i++) {
391         // top
392         RSRect desRectTopRound =
393             RSRect(roundStartHorizontal, offsetTopY, roundStartHorizontal + imageCenterWidth_, offsetTopY + topWidth_);
394         canvas.DrawImageRect(image_, srcRectTop_, desRectTopRound, options);
395         // bottom
396         RSRect desRectBottomRound = RSRect(roundStartHorizontal, offsetBottomY - bottomWidth_,
397             roundStartHorizontal + imageCenterWidth_, offsetBottomY);
398         canvas.DrawImageRect(image_, srcRectBottom_, desRectBottomRound, options);
399 
400         roundStartHorizontal += imageCenterWidth_ + blankHorizontalSize;
401     }
402 
403     double roundStartVertical = offsetTopY + topWidth_ + blankVerticalSize;
404     for (int32_t i = 0; i < roundVerticalCount; i++) {
405         // left
406         RSRect desRectLeftRound =
407             RSRect(offsetLeftX, roundStartVertical, offsetLeftX + leftWidth_, roundStartVertical + imageCenterHeight_);
408         canvas.DrawImageRect(image_, srcRectLeft_, desRectLeftRound, options);
409         // right
410         RSRect desRectRightRound = RSRect(
411             offsetRightX - rightWidth_, roundStartVertical, offsetRightX, roundStartVertical + imageCenterHeight_);
412         canvas.DrawImageRect(image_, srcRectRight_, desRectRightRound, options);
413         roundStartVertical += imageCenterHeight_ + blankVerticalSize;
414     }
415 }
416 
PaintBorderImageRepeat(const OffsetF & offset,RSCanvas & canvas) const417 void BorderImagePainter::PaintBorderImageRepeat(const OffsetF& offset, RSCanvas& canvas) const
418 {
419     RSSamplingOptions options;
420     double offsetLeftX = std::ceil(offset.GetX() - leftOutset_);
421     double offsetRightX = std::ceil(offset.GetX() + paintSize_.Width() + rightOutset_);
422     double offsetTopY = std::ceil(offset.GetY() - topOutset_);
423     double offsetBottomY = std::ceil(offset.GetY() + paintSize_.Height() + bottomOutset_);
424 
425     double widthFactor = 0.0;
426     if (GreatNotEqual(imageCenterWidth_, 0.0)) {
427         widthFactor = borderCenterWidth_ / imageCenterWidth_;
428         if (GreatNotEqual(widthFactor, 0.0) && LessOrEqual(widthFactor, 1.0)) {
429             double halfSurplusImageCenterWidth = (imageCenterWidth_ - borderCenterWidth_) / 2;
430             RSRect srcRectTop = RSRect(halfSurplusImageCenterWidth + leftSlice_, 0,
431                 halfSurplusImageCenterWidth + leftSlice_ + borderCenterWidth_, topSlice_);
432             RSRect desRectTop = RSRect(offsetLeftX + leftWidth_, offsetTopY,
433                 offsetLeftX + leftWidth_ + borderCenterWidth_, offsetTopY + topWidth_);
434             canvas.DrawImageRect(image_, srcRectTop, desRectTop, options);
435 
436             RSRect srcRectBottom = RSRect(halfSurplusImageCenterWidth + leftSlice_, imageHeight_ - bottomSlice_,
437                 halfSurplusImageCenterWidth + leftSlice_ + borderCenterWidth_, imageHeight_);
438             RSRect desRectBottom =
439                 RSRect(offsetLeftX + leftWidth_, offset.GetY() + paintSize_.Height() - bottomWidth_ + bottomOutset_,
440                     offsetLeftX + leftWidth_ + borderCenterWidth_, offset.GetY() + paintSize_.Height() + bottomOutset_);
441             canvas.DrawImageRect(image_, srcRectBottom, desRectBottom, options);
442         } else if (GreatNotEqual(widthFactor, 1.0)) {
443             double halfSurplusHorizontalLength = 0;
444             halfSurplusHorizontalLength = (borderCenterWidth_ - (int)(widthFactor)*imageCenterWidth_) / 2;
445             RSRect srcRectTopLeft = RSRect(
446                 imageWidth_ - rightSlice_ - halfSurplusHorizontalLength, 0, imageWidth_ - rightSlice_, topSlice_);
447             RSRect desRectTopLeftEnd = RSRect(offsetLeftX + leftWidth_, offsetTopY,
448                 offsetLeftX + leftWidth_ + halfSurplusHorizontalLength, offsetTopY + topWidth_);
449             canvas.DrawImageRect(image_, srcRectTopLeft, desRectTopLeftEnd, options);
450 
451             RSRect srcRectTopRight = RSRect(leftSlice_, 0, leftSlice_ + halfSurplusHorizontalLength, topSlice_);
452             RSRect desRectTopRightEnd =
453                 RSRect(offsetLeftX + leftWidth_ + borderCenterWidth_ - halfSurplusHorizontalLength, offsetTopY,
454                     offsetLeftX + leftWidth_ + borderCenterWidth_, offsetTopY + topWidth_);
455             canvas.DrawImageRect(image_, srcRectTopRight, desRectTopRightEnd, options);
456 
457             RSRect srcRectBottomLeft = RSRect(imageWidth_ - rightSlice_ - halfSurplusHorizontalLength,
458                 imageHeight_ - bottomSlice_, imageWidth_ - rightSlice_, imageHeight_);
459             RSRect desRectBottomLeftEnd = RSRect(offsetLeftX + leftWidth_, offsetBottomY - bottomWidth_,
460                 offsetLeftX + leftWidth_ + halfSurplusHorizontalLength, offsetBottomY);
461             canvas.DrawImageRect(image_, srcRectBottomLeft, desRectBottomLeftEnd, options);
462 
463             RSRect srcRectBottomRight =
464                 RSRect(leftSlice_, imageHeight_ - bottomSlice_, leftSlice_ + halfSurplusHorizontalLength, imageHeight_);
465             RSRect desRectBottomRightEnd =
466                 RSRect(offsetLeftX + leftWidth_ + borderCenterWidth_ - halfSurplusHorizontalLength,
467                     offsetBottomY - bottomWidth_, offsetLeftX + leftWidth_ + borderCenterWidth_, offsetBottomY);
468             canvas.DrawImageRect(image_, srcRectBottomRight, desRectBottomRightEnd, options);
469 
470             double repeatHorizontalStart = offsetLeftX + leftWidth_ + halfSurplusHorizontalLength;
471             for (int32_t i = 0; i < static_cast<int32_t>(widthFactor); i++) {
472                 // top
473                 RSRect desRectTopRepeat = RSRect(repeatHorizontalStart, offsetTopY,
474                     repeatHorizontalStart + imageCenterWidth_, offsetTopY + topWidth_);
475                 canvas.DrawImageRect(image_, srcRectTop_, desRectTopRepeat, options);
476 
477                 // bottom
478                 RSRect desRectBottomRepeat = RSRect(repeatHorizontalStart, offsetBottomY - bottomWidth_,
479                     repeatHorizontalStart + imageCenterWidth_, offsetBottomY);
480                 canvas.DrawImageRect(image_, srcRectBottom_, desRectBottomRepeat, options);
481 
482                 repeatHorizontalStart += imageCenterWidth_;
483             }
484         }
485     }
486 
487     double heightFactor = 0.0;
488     double destTopOffsetY = offsetTopY + topWidth_;
489     if (GreatNotEqual(imageCenterHeight_, 0.0)) {
490         heightFactor = borderCenterHeight_ / imageCenterHeight_;
491         if (GreatNotEqual(heightFactor, 0.0) && LessOrEqual(heightFactor, 1.0)) {
492             double halfSurplusImageCenterHeight = (imageCenterHeight_ - borderCenterHeight_) / 2;
493             RSRect srcRectLeft = RSRect(0, topSlice_ + halfSurplusImageCenterHeight, leftSlice_,
494                 topSlice_ + halfSurplusImageCenterHeight + borderCenterHeight_);
495             RSRect desRectLeft =
496                 RSRect(offsetLeftX, destTopOffsetY, offsetLeftX + leftWidth_, destTopOffsetY + borderCenterHeight_);
497             canvas.DrawImageRect(image_, srcRectLeft, desRectLeft, options);
498 
499             RSRect srcRectRight = RSRect(imageWidth_ - rightSlice_, topSlice_ + halfSurplusImageCenterHeight,
500                 imageWidth_, topSlice_ + halfSurplusImageCenterHeight + borderCenterHeight_);
501             RSRect desRectRight =
502                 RSRect(offset.GetX() + paintSize_.Width() - rightWidth_ + rightOutset_, destTopOffsetY,
503                     offset.GetX() + paintSize_.Width() + rightOutset_, destTopOffsetY + borderCenterHeight_);
504             canvas.DrawImageRect(image_, srcRectRight, desRectRight, options);
505         } else if (GreatNotEqual(heightFactor, 1.0)) {
506             double halfSurplusVerticalLength = 0;
507             halfSurplusVerticalLength = (borderCenterHeight_ - (int)(heightFactor)*imageCenterHeight_) / 2;
508             RSRect srcRectLeftTop = RSRect(
509                 0, imageHeight_ - bottomSlice_ - halfSurplusVerticalLength, leftSlice_, imageHeight_ - bottomSlice_);
510             RSRect desRectLeftTopStart = RSRect(
511                 offsetLeftX, destTopOffsetY, offsetLeftX + leftWidth_, destTopOffsetY + halfSurplusVerticalLength);
512             canvas.DrawImageRect(image_, srcRectLeftTop, desRectLeftTopStart, options);
513 
514             RSRect srcRectRightTop = RSRect(imageWidth_ - rightSlice_,
515                 imageHeight_ - bottomSlice_ - halfSurplusVerticalLength, imageWidth_, imageHeight_ - bottomSlice_);
516             RSRect desRectRightTopStart = RSRect(
517                 offsetRightX - rightWidth_, destTopOffsetY, offsetRightX, destTopOffsetY + halfSurplusVerticalLength);
518             canvas.DrawImageRect(image_, srcRectRightTop, desRectRightTopStart, options);
519 
520             RSRect srcRectLeftBottom = RSRect(0, topSlice_, leftSlice_, topSlice_ + halfSurplusVerticalLength);
521             RSRect desRectLeftBottomEnd = RSRect(offsetLeftX, offsetBottomY - bottomWidth_ - halfSurplusVerticalLength,
522                 offsetLeftX + leftWidth_, offsetBottomY - bottomWidth_);
523             canvas.DrawImageRect(image_, srcRectLeftBottom, desRectLeftBottomEnd, options);
524 
525             RSRect srcRectRightBottom =
526                 RSRect(imageWidth_ - rightSlice_, topSlice_, imageWidth_, topSlice_ + halfSurplusVerticalLength);
527             RSRect desRectRightBottomEnd = RSRect(offsetRightX - rightWidth_,
528                 offsetBottomY - bottomWidth_ - halfSurplusVerticalLength, offsetRightX, offsetBottomY - bottomWidth_);
529             canvas.DrawImageRect(image_, srcRectRightBottom, desRectRightBottomEnd, options);
530 
531             double repeatVerticalStart = destTopOffsetY + halfSurplusVerticalLength;
532             for (int32_t i = 0; i < static_cast<int32_t>(heightFactor); i++) {
533                 // left
534                 RSRect desRectLeftRepeat = RSRect(offsetLeftX, repeatVerticalStart, offsetLeftX + leftWidth_,
535                     repeatVerticalStart + imageCenterHeight_);
536                 canvas.DrawImageRect(image_, srcRectLeft_, desRectLeftRepeat, options);
537 
538                 // right
539                 RSRect desRectRightRepeat = RSRect(offsetRightX - rightWidth_, repeatVerticalStart, offsetRightX,
540                     repeatVerticalStart + imageCenterHeight_);
541                 canvas.DrawImageRect(image_, srcRectRight_, desRectRightRepeat, options);
542 
543                 repeatVerticalStart += imageCenterHeight_;
544             }
545         }
546     }
547 }
548 
ParseNegativeNumberToZeroOrCeil(double & value)549 void BorderImagePainter::ParseNegativeNumberToZeroOrCeil(double& value)
550 {
551     if (LessNotEqual(value, 0.0)) {
552         value = 0.0;
553     }
554     value = std::ceil(value);
555 }
556 } // namespace OHOS::Ace::NG
557