• 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/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     // calculate maximum count of image pieces can fit in border
371     auto roundHorizontalCount = static_cast<int32_t>(borderCenterWidth_ / imageCenterWidth_);
372     auto roundVerticalCount = static_cast<int32_t>(borderCenterHeight_ / imageCenterHeight_);
373     if (roundHorizontalCount == 0.0) {
374         LOGW("Border image center width exceeds horizontal border center length, left and right side will not paint");
375     }
376     if (roundVerticalCount == 0.0) {
377         LOGW("Border image center height exceeds vertical border center length, top and bottom side will not paint");
378     }
379     // fmod(borderCenterWidth_, imageCenterWidth_) will return total blank length,
380     // and there are roundHorizontalCount + 1 blanks
381     double blankHorizontalSize = fmod(borderCenterWidth_, imageCenterWidth_) / (roundHorizontalCount + 1);
382     double blankVerticalSize = fmod(borderCenterHeight_, imageCenterHeight_) / (roundVerticalCount + 1);
383 
384     double roundStartHorizontal = offsetLeftX + leftWidth_ + blankHorizontalSize;
385     for (int32_t i = 0; i < roundHorizontalCount; i++) {
386         // top
387         RSRect desRectTopRound =
388             RSRect(roundStartHorizontal, offsetTopY, roundStartHorizontal + imageCenterWidth_, offsetTopY + topWidth_);
389         canvas.DrawImageRect(image_, srcRectTop_, desRectTopRound, options);
390         // bottom
391         RSRect desRectBottomRound = RSRect(roundStartHorizontal, offsetBottomY - bottomWidth_,
392             roundStartHorizontal + imageCenterWidth_, offsetBottomY);
393         canvas.DrawImageRect(image_, srcRectBottom_, desRectBottomRound, options);
394 
395         roundStartHorizontal += imageCenterWidth_ + blankHorizontalSize;
396     }
397 
398     double roundStartVertical = offsetTopY + topWidth_ + blankVerticalSize;
399     for (int32_t i = 0; i < roundVerticalCount; i++) {
400         // left
401         RSRect desRectLeftRound =
402             RSRect(offsetLeftX, roundStartVertical, offsetLeftX + leftWidth_, roundStartVertical + imageCenterHeight_);
403         canvas.DrawImageRect(image_, srcRectLeft_, desRectLeftRound, options);
404         // right
405         RSRect desRectRightRound = RSRect(
406             offsetRightX - rightWidth_, roundStartVertical, offsetRightX, roundStartVertical + imageCenterHeight_);
407         canvas.DrawImageRect(image_, srcRectRight_, desRectRightRound, options);
408         roundStartVertical += imageCenterHeight_ + blankVerticalSize;
409     }
410 }
411 
PaintBorderImageRepeat(const OffsetF & offset,RSCanvas & canvas) const412 void BorderImagePainter::PaintBorderImageRepeat(const OffsetF& offset, RSCanvas& canvas) const
413 {
414     RSSamplingOptions options;
415     double offsetLeftX = std::ceil(offset.GetX() - leftOutset_);
416     double offsetRightX = std::ceil(offset.GetX() + paintSize_.Width() + rightOutset_);
417     double offsetTopY = std::ceil(offset.GetY() - topOutset_);
418     double offsetBottomY = std::ceil(offset.GetY() + paintSize_.Height() + bottomOutset_);
419 
420     double widthFactor = 0.0;
421     if (GreatNotEqual(imageCenterWidth_, 0.0)) {
422         widthFactor = borderCenterWidth_ / imageCenterWidth_;
423         if (GreatNotEqual(widthFactor, 0.0) && LessOrEqual(widthFactor, 1.0)) {
424             double halfSurplusImageCenterWidth = (imageCenterWidth_ - borderCenterWidth_) / 2;
425             RSRect srcRectTop = RSRect(halfSurplusImageCenterWidth + leftSlice_, 0,
426                 halfSurplusImageCenterWidth + leftSlice_ + borderCenterWidth_, topSlice_);
427             RSRect desRectTop = RSRect(offsetLeftX + leftWidth_, offsetTopY,
428                 offsetLeftX + leftWidth_ + borderCenterWidth_, offsetTopY + topWidth_);
429             canvas.DrawImageRect(image_, srcRectTop, desRectTop, options);
430 
431             RSRect srcRectBottom = RSRect(halfSurplusImageCenterWidth + leftSlice_, imageHeight_ - bottomSlice_,
432                 halfSurplusImageCenterWidth + leftSlice_ + borderCenterWidth_, imageHeight_);
433             RSRect desRectBottom =
434                 RSRect(offsetLeftX + leftWidth_, offset.GetY() + paintSize_.Height() - bottomWidth_ + bottomOutset_,
435                     offsetLeftX + leftWidth_ + borderCenterWidth_, offset.GetY() + paintSize_.Height() + bottomOutset_);
436             canvas.DrawImageRect(image_, srcRectBottom, desRectBottom, options);
437         } else if (GreatNotEqual(widthFactor, 1.0)) {
438             double halfSurplusHorizontalLength = 0;
439             halfSurplusHorizontalLength = (borderCenterWidth_ - (int)(widthFactor)*imageCenterWidth_) / 2;
440             RSRect srcRectTopLeft = RSRect(
441                 imageWidth_ - rightSlice_ - halfSurplusHorizontalLength, 0, imageWidth_ - rightSlice_, topSlice_);
442             RSRect desRectTopLeftEnd = RSRect(offsetLeftX + leftWidth_, offsetTopY,
443                 offsetLeftX + leftWidth_ + halfSurplusHorizontalLength, offsetTopY + topWidth_);
444             canvas.DrawImageRect(image_, srcRectTopLeft, desRectTopLeftEnd, options);
445 
446             RSRect srcRectTopRight = RSRect(leftSlice_, 0, leftSlice_ + halfSurplusHorizontalLength, topSlice_);
447             RSRect desRectTopRightEnd =
448                 RSRect(offsetLeftX + leftWidth_ + borderCenterWidth_ - halfSurplusHorizontalLength, offsetTopY,
449                     offsetLeftX + leftWidth_ + borderCenterWidth_, offsetTopY + topWidth_);
450             canvas.DrawImageRect(image_, srcRectTopRight, desRectTopRightEnd, options);
451 
452             RSRect srcRectBottomLeft = RSRect(imageWidth_ - rightSlice_ - halfSurplusHorizontalLength,
453                 imageHeight_ - bottomSlice_, imageWidth_ - rightSlice_, imageHeight_);
454             RSRect desRectBottomLeftEnd = RSRect(offsetLeftX + leftWidth_, offsetBottomY - bottomWidth_,
455                 offsetLeftX + leftWidth_ + halfSurplusHorizontalLength, offsetBottomY);
456             canvas.DrawImageRect(image_, srcRectBottomLeft, desRectBottomLeftEnd, options);
457 
458             RSRect srcRectBottomRight =
459                 RSRect(leftSlice_, imageHeight_ - bottomSlice_, leftSlice_ + halfSurplusHorizontalLength, imageHeight_);
460             RSRect desRectBottomRightEnd =
461                 RSRect(offsetLeftX + leftWidth_ + borderCenterWidth_ - halfSurplusHorizontalLength,
462                     offsetBottomY - bottomWidth_, offsetLeftX + leftWidth_ + borderCenterWidth_, offsetBottomY);
463             canvas.DrawImageRect(image_, srcRectBottomRight, desRectBottomRightEnd, options);
464 
465             double repeatHorizontalStart = offsetLeftX + leftWidth_ + halfSurplusHorizontalLength;
466             for (int32_t i = 0; i < static_cast<int32_t>(widthFactor); i++) {
467                 // top
468                 RSRect desRectTopRepeat = RSRect(repeatHorizontalStart, offsetTopY,
469                     repeatHorizontalStart + imageCenterWidth_, offsetTopY + topWidth_);
470                 canvas.DrawImageRect(image_, srcRectTop_, desRectTopRepeat, options);
471 
472                 // bottom
473                 RSRect desRectBottomRepeat = RSRect(repeatHorizontalStart, offsetBottomY - bottomWidth_,
474                     repeatHorizontalStart + imageCenterWidth_, offsetBottomY);
475                 canvas.DrawImageRect(image_, srcRectBottom_, desRectBottomRepeat, options);
476 
477                 repeatHorizontalStart += imageCenterWidth_;
478             }
479         }
480     }
481 
482     double heightFactor = 0.0;
483     double destTopOffsetY = offsetTopY + topWidth_;
484     if (GreatNotEqual(imageCenterHeight_, 0.0)) {
485         heightFactor = borderCenterHeight_ / imageCenterHeight_;
486         if (GreatNotEqual(heightFactor, 0.0) && LessOrEqual(heightFactor, 1.0)) {
487             double halfSurplusImageCenterHeight = (imageCenterHeight_ - borderCenterHeight_) / 2;
488             RSRect srcRectLeft = RSRect(0, topSlice_ + halfSurplusImageCenterHeight, leftSlice_,
489                 topSlice_ + halfSurplusImageCenterHeight + borderCenterHeight_);
490             RSRect desRectLeft =
491                 RSRect(offsetLeftX, destTopOffsetY, offsetLeftX + leftWidth_, destTopOffsetY + borderCenterHeight_);
492             canvas.DrawImageRect(image_, srcRectLeft, desRectLeft, options);
493 
494             RSRect srcRectRight = RSRect(imageWidth_ - rightSlice_, topSlice_ + halfSurplusImageCenterHeight,
495                 imageWidth_, topSlice_ + halfSurplusImageCenterHeight + borderCenterHeight_);
496             RSRect desRectRight =
497                 RSRect(offset.GetX() + paintSize_.Width() - rightWidth_ + rightOutset_, destTopOffsetY,
498                     offset.GetX() + paintSize_.Width() + rightOutset_, destTopOffsetY + borderCenterHeight_);
499             canvas.DrawImageRect(image_, srcRectRight, desRectRight, options);
500         } else if (GreatNotEqual(heightFactor, 1.0)) {
501             double halfSurplusVerticalLength = 0;
502             halfSurplusVerticalLength = (borderCenterHeight_ - (int)(heightFactor)*imageCenterHeight_) / 2;
503             RSRect srcRectLeftTop = RSRect(
504                 0, imageHeight_ - bottomSlice_ - halfSurplusVerticalLength, leftSlice_, imageHeight_ - bottomSlice_);
505             RSRect desRectLeftTopStart = RSRect(
506                 offsetLeftX, destTopOffsetY, offsetLeftX + leftWidth_, destTopOffsetY + halfSurplusVerticalLength);
507             canvas.DrawImageRect(image_, srcRectLeftTop, desRectLeftTopStart, options);
508 
509             RSRect srcRectRightTop = RSRect(imageWidth_ - rightSlice_,
510                 imageHeight_ - bottomSlice_ - halfSurplusVerticalLength, imageWidth_, imageHeight_ - bottomSlice_);
511             RSRect desRectRightTopStart = RSRect(
512                 offsetRightX - rightWidth_, destTopOffsetY, offsetRightX, destTopOffsetY + halfSurplusVerticalLength);
513             canvas.DrawImageRect(image_, srcRectRightTop, desRectRightTopStart, options);
514 
515             RSRect srcRectLeftBottom = RSRect(0, topSlice_, leftSlice_, topSlice_ + halfSurplusVerticalLength);
516             RSRect desRectLeftBottomEnd = RSRect(offsetLeftX, offsetBottomY - bottomWidth_ - halfSurplusVerticalLength,
517                 offsetLeftX + leftWidth_, offsetBottomY - bottomWidth_);
518             canvas.DrawImageRect(image_, srcRectLeftBottom, desRectLeftBottomEnd, options);
519 
520             RSRect srcRectRightBottom =
521                 RSRect(imageWidth_ - rightSlice_, topSlice_, imageWidth_, topSlice_ + halfSurplusVerticalLength);
522             RSRect desRectRightBottomEnd = RSRect(offsetRightX - rightWidth_,
523                 offsetBottomY - bottomWidth_ - halfSurplusVerticalLength, offsetRightX, offsetBottomY - bottomWidth_);
524             canvas.DrawImageRect(image_, srcRectRightBottom, desRectRightBottomEnd, options);
525 
526             double repeatVerticalStart = destTopOffsetY + halfSurplusVerticalLength;
527             for (int32_t i = 0; i < static_cast<int32_t>(heightFactor); i++) {
528                 // left
529                 RSRect desRectLeftRepeat = RSRect(offsetLeftX, repeatVerticalStart, offsetLeftX + leftWidth_,
530                     repeatVerticalStart + imageCenterHeight_);
531                 canvas.DrawImageRect(image_, srcRectLeft_, desRectLeftRepeat, options);
532 
533                 // right
534                 RSRect desRectRightRepeat = RSRect(offsetRightX - rightWidth_, repeatVerticalStart, offsetRightX,
535                     repeatVerticalStart + imageCenterHeight_);
536                 canvas.DrawImageRect(image_, srcRectRight_, desRectRightRepeat, options);
537 
538                 repeatVerticalStart += imageCenterHeight_;
539             }
540         }
541     }
542 }
543 
ParseNegativeNumberToZeroOrCeil(double & value)544 void BorderImagePainter::ParseNegativeNumberToZeroOrCeil(double& value)
545 {
546     if (LessNotEqual(value, 0.0)) {
547         value = 0.0;
548     }
549     value = std::ceil(value);
550 }
551 } // namespace OHOS::Ace::NG
552