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