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