1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License.
5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at
6a3e0fd82Sopenharmony_ci *
7a3e0fd82Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8a3e0fd82Sopenharmony_ci *
9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and
13a3e0fd82Sopenharmony_ci * limitations under the License.
14a3e0fd82Sopenharmony_ci */
15a3e0fd82Sopenharmony_ci
16a3e0fd82Sopenharmony_ci#include "draw/draw_arc.h"
17a3e0fd82Sopenharmony_ci#include "common/image.h"
18a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_math.h"
19a3e0fd82Sopenharmony_ci
20a3e0fd82Sopenharmony_cinamespace OHOS {
21a3e0fd82Sopenharmony_ci#define IS_IN_DEGREERANE(d, s, e) ((s) <= (e)) ? (((d) >= (s)) && ((d) <= (e))) : (((d) >= (s)) || ((d) <= (e)))
22a3e0fd82Sopenharmony_ciDrawArc* DrawArc::GetInstance()
23a3e0fd82Sopenharmony_ci{
24a3e0fd82Sopenharmony_ci    static DrawArc drawArc;
25a3e0fd82Sopenharmony_ci    return &drawArc;
26a3e0fd82Sopenharmony_ci}
27a3e0fd82Sopenharmony_ci
28a3e0fd82Sopenharmony_civoid DrawArc::DrawImg(BufferInfo& gfxDstBuffer,
29a3e0fd82Sopenharmony_ci                      const Point& imgPos,
30a3e0fd82Sopenharmony_ci                      Rect& area,
31a3e0fd82Sopenharmony_ci                      const Rect& invalidatedArea,
32a3e0fd82Sopenharmony_ci                      const Style& style,
33a3e0fd82Sopenharmony_ci                      uint8_t opaScale,
34a3e0fd82Sopenharmony_ci                      const Image* image)
35a3e0fd82Sopenharmony_ci{
36a3e0fd82Sopenharmony_ci    if (image == nullptr) {
37a3e0fd82Sopenharmony_ci        return;
38a3e0fd82Sopenharmony_ci    }
39a3e0fd82Sopenharmony_ci    ImageHeader header = {0};
40a3e0fd82Sopenharmony_ci    image->GetHeader(header);
41a3e0fd82Sopenharmony_ci
42a3e0fd82Sopenharmony_ci    Rect cordsTmp;
43a3e0fd82Sopenharmony_ci    cordsTmp.SetPosition(imgPos.x, imgPos.y);
44a3e0fd82Sopenharmony_ci    cordsTmp.SetHeight(header.height);
45a3e0fd82Sopenharmony_ci    cordsTmp.SetWidth(header.width);
46a3e0fd82Sopenharmony_ci    if (area.Intersect(area, invalidatedArea)) {
47a3e0fd82Sopenharmony_ci        image->DrawImage(gfxDstBuffer, cordsTmp, area, style, opaScale);
48a3e0fd82Sopenharmony_ci    }
49a3e0fd82Sopenharmony_ci}
50a3e0fd82Sopenharmony_ci
51a3e0fd82Sopenharmony_civoid DrawArc::DrawVerLine(BufferInfo& gfxDstBuffer,
52a3e0fd82Sopenharmony_ci                          const Point& begin,
53a3e0fd82Sopenharmony_ci                          const Point& imgPos,
54a3e0fd82Sopenharmony_ci                          const Rect& mask,
55a3e0fd82Sopenharmony_ci                          int16_t len,
56a3e0fd82Sopenharmony_ci                          const Style& style,
57a3e0fd82Sopenharmony_ci                          uint8_t opaScale,
58a3e0fd82Sopenharmony_ci                          const Image* image)
59a3e0fd82Sopenharmony_ci{
60a3e0fd82Sopenharmony_ci    Rect rect(begin.x, begin.y, begin.x, begin.y + len);
61a3e0fd82Sopenharmony_ci    if ((image != nullptr) && (image->GetSrcType() != IMG_SRC_UNKNOWN)) {
62a3e0fd82Sopenharmony_ci        DrawImg(gfxDstBuffer, imgPos, rect, mask, style, opaScale, image);
63a3e0fd82Sopenharmony_ci    } else {
64a3e0fd82Sopenharmony_ci        DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, rect, mask, style.lineColor_, opaScale);
65a3e0fd82Sopenharmony_ci    }
66a3e0fd82Sopenharmony_ci}
67a3e0fd82Sopenharmony_ci
68a3e0fd82Sopenharmony_civoid DrawArc::DrawHorLine(BufferInfo& gfxDstBuffer,
69a3e0fd82Sopenharmony_ci                          const Point& begin,
70a3e0fd82Sopenharmony_ci                          const Point& imgPos,
71a3e0fd82Sopenharmony_ci                          const Rect& mask,
72a3e0fd82Sopenharmony_ci                          int16_t len,
73a3e0fd82Sopenharmony_ci                          const Style& style,
74a3e0fd82Sopenharmony_ci                          uint8_t opaScale,
75a3e0fd82Sopenharmony_ci                          const Image* image)
76a3e0fd82Sopenharmony_ci{
77a3e0fd82Sopenharmony_ci    if ((image != nullptr) && (image->GetSrcType() != IMG_SRC_UNKNOWN)) {
78a3e0fd82Sopenharmony_ci        Rect rect(begin.x, begin.y, begin.x + len, begin.y);
79a3e0fd82Sopenharmony_ci        DrawImg(gfxDstBuffer, imgPos, rect, mask, style, opaScale, image);
80a3e0fd82Sopenharmony_ci    } else {
81a3e0fd82Sopenharmony_ci        if (len == 0) {
82a3e0fd82Sopenharmony_ci            DrawUtils::GetInstance()->DrawPixel(gfxDstBuffer, begin.x, begin.y, mask, style.lineColor_, opaScale);
83a3e0fd82Sopenharmony_ci        } else {
84a3e0fd82Sopenharmony_ci            Rect rect(begin.x, begin.y, begin.x + len, begin.y);
85a3e0fd82Sopenharmony_ci            DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, rect, mask, style.lineColor_, opaScale);
86a3e0fd82Sopenharmony_ci        }
87a3e0fd82Sopenharmony_ci    }
88a3e0fd82Sopenharmony_ci}
89a3e0fd82Sopenharmony_ci
90a3e0fd82Sopenharmony_ciint16_t DrawArc::GetDrawAngle(int16_t angle)
91a3e0fd82Sopenharmony_ci{
92a3e0fd82Sopenharmony_ci    if (angle < 0) {
93a3e0fd82Sopenharmony_ci        angle = (angle % CIRCLE_IN_DEGREE) + CIRCLE_IN_DEGREE;
94a3e0fd82Sopenharmony_ci    } else if (angle > CIRCLE_IN_DEGREE) {
95a3e0fd82Sopenharmony_ci        angle = angle % CIRCLE_IN_DEGREE;
96a3e0fd82Sopenharmony_ci    }
97a3e0fd82Sopenharmony_ci    return angle;
98a3e0fd82Sopenharmony_ci}
99a3e0fd82Sopenharmony_ci
100a3e0fd82Sopenharmony_civoid DrawArc::GetDrawRange(int16_t& start, int16_t& end)
101a3e0fd82Sopenharmony_ci{
102a3e0fd82Sopenharmony_ci    int16_t tempAngle = GetDrawAngle(start);
103a3e0fd82Sopenharmony_ci    if (start == end) {
104a3e0fd82Sopenharmony_ci        start = tempAngle;
105a3e0fd82Sopenharmony_ci        end = tempAngle;
106a3e0fd82Sopenharmony_ci    } else if (end - start >= CIRCLE_IN_DEGREE) {
107a3e0fd82Sopenharmony_ci        // draw circle
108a3e0fd82Sopenharmony_ci        start = 0;
109a3e0fd82Sopenharmony_ci        end = CIRCLE_IN_DEGREE;
110a3e0fd82Sopenharmony_ci    } else {
111a3e0fd82Sopenharmony_ci        start = tempAngle;
112a3e0fd82Sopenharmony_ci        end = GetDrawAngle(end);
113a3e0fd82Sopenharmony_ci    }
114a3e0fd82Sopenharmony_ci}
115a3e0fd82Sopenharmony_ci
116a3e0fd82Sopenharmony_ciuint16_t DrawArc::CalculateTanDegree(uint16_t x, uint16_t y)
117a3e0fd82Sopenharmony_ci{
118a3e0fd82Sopenharmony_ci    uint16_t degree = FastAtan2(x, y);
119a3e0fd82Sopenharmony_ci    if ((degree == QUARTER_IN_DEGREE) && (y != 0)) {
120a3e0fd82Sopenharmony_ci        degree--;
121a3e0fd82Sopenharmony_ci    }
122a3e0fd82Sopenharmony_ci    if ((degree == 0) && (x != 0)) {
123a3e0fd82Sopenharmony_ci        degree++;
124a3e0fd82Sopenharmony_ci    }
125a3e0fd82Sopenharmony_ci    return degree;
126a3e0fd82Sopenharmony_ci}
127a3e0fd82Sopenharmony_ci
128a3e0fd82Sopenharmony_civoid DrawArc::DrawCircleNoEndpoint(BufferInfo& gfxDstBuffer,
129a3e0fd82Sopenharmony_ci                                   ArcInfo& arcInfo,
130a3e0fd82Sopenharmony_ci                                   const Rect& mask,
131a3e0fd82Sopenharmony_ci                                   const Style& style,
132a3e0fd82Sopenharmony_ci                                   uint8_t opa,
133a3e0fd82Sopenharmony_ci                                   bool anti)
134a3e0fd82Sopenharmony_ci{
135a3e0fd82Sopenharmony_ci    DrawAxisLine(gfxDstBuffer, arcInfo, mask, style, opa);
136a3e0fd82Sopenharmony_ci
137a3e0fd82Sopenharmony_ci    int16_t yStart = mask.GetTop() - arcInfo.center.y;
138a3e0fd82Sopenharmony_ci    int16_t yEnd = mask.GetBottom() - arcInfo.center.y;
139a3e0fd82Sopenharmony_ci    CalculatedYStartAndYEnd(yStart, yEnd);
140a3e0fd82Sopenharmony_ci
141a3e0fd82Sopenharmony_ci    int16_t xLineStart = -outRadius_;
142a3e0fd82Sopenharmony_ci    int16_t xLineStart2 = xLineStart - 1;
143a3e0fd82Sopenharmony_ci    int16_t xLineStart3 = COORD_MIN;
144a3e0fd82Sopenharmony_ci
145a3e0fd82Sopenharmony_ci    for (y_ = yEnd; y_ > yStart; y_--) {
146a3e0fd82Sopenharmony_ci        ySqr_ = static_cast<int32_t>(y_) * y_;
147a3e0fd82Sopenharmony_ci        bool isSetStartPot = false;
148a3e0fd82Sopenharmony_ci        for (int16_t xi = xLineStart2; xi < 0; xi++) {
149a3e0fd82Sopenharmony_ci            uint32_t currentSqr = static_cast<int32_t>(xi) * xi + ySqr_;
150a3e0fd82Sopenharmony_ci            if (currentSqr > outRadiusSqr_) {
151a3e0fd82Sopenharmony_ci                continue;
152a3e0fd82Sopenharmony_ci            }
153a3e0fd82Sopenharmony_ci            if (!isSetStartPot) {
154a3e0fd82Sopenharmony_ci                xLineStart2 = xi;
155a3e0fd82Sopenharmony_ci                lineStart_ = xi;
156a3e0fd82Sopenharmony_ci                if (xLineStart3 != COORD_MIN) {
157a3e0fd82Sopenharmony_ci                    xi = xLineStart3;
158a3e0fd82Sopenharmony_ci                }
159a3e0fd82Sopenharmony_ci                isSetStartPot = true;
160a3e0fd82Sopenharmony_ci            }
161a3e0fd82Sopenharmony_ci            if (y_ <= -inRadius_) {
162a3e0fd82Sopenharmony_ci                lineEnd_ = -1;
163a3e0fd82Sopenharmony_ci                break;
164a3e0fd82Sopenharmony_ci            }
165a3e0fd82Sopenharmony_ci            if (currentSqr < inRadiusSqr_) {
166a3e0fd82Sopenharmony_ci                xLineStart3 = xi - 1;
167a3e0fd82Sopenharmony_ci                lineEnd_ = xi - 1;
168a3e0fd82Sopenharmony_ci                break;
169a3e0fd82Sopenharmony_ci            }
170a3e0fd82Sopenharmony_ci        }
171a3e0fd82Sopenharmony_ci        if (!isSetStartPot) {
172a3e0fd82Sopenharmony_ci            continue;
173a3e0fd82Sopenharmony_ci        }
174a3e0fd82Sopenharmony_ci#if defined(ENABLE_ANTIALIAS) && ENABLE_ANTIALIAS
175a3e0fd82Sopenharmony_ci        if (anti) {
176a3e0fd82Sopenharmony_ci            DrawLineAnti(gfxDstBuffer, arcInfo, mask, style, opa);
177a3e0fd82Sopenharmony_ci        }
178a3e0fd82Sopenharmony_ci#endif
179a3e0fd82Sopenharmony_ci        DrawLineWithDegree(gfxDstBuffer, arcInfo, -lineEnd_, -lineStart_, y_, mask, style, opa, ARC_QUADRANT_ONE);
180a3e0fd82Sopenharmony_ci
181a3e0fd82Sopenharmony_ci        DrawLineWithDegree(gfxDstBuffer, arcInfo, -lineEnd_, -lineStart_, -y_, mask, style, opa, ARC_QUADRANT_TWO);
182a3e0fd82Sopenharmony_ci
183a3e0fd82Sopenharmony_ci        DrawLineWithDegree(gfxDstBuffer, arcInfo, lineStart_, lineEnd_, -y_, mask, style, opa, ARC_QUADRANT_THREE);
184a3e0fd82Sopenharmony_ci
185a3e0fd82Sopenharmony_ci        DrawLineWithDegree(gfxDstBuffer, arcInfo, lineStart_, lineEnd_, y_, mask, style, opa, ARC_QUADRANT_FOUR);
186a3e0fd82Sopenharmony_ci    }
187a3e0fd82Sopenharmony_ci}
188a3e0fd82Sopenharmony_ci
189a3e0fd82Sopenharmony_civoid DrawArc::CalculatedYStartAndYEnd(int16_t& yStart, int16_t& yEnd)
190a3e0fd82Sopenharmony_ci{
191a3e0fd82Sopenharmony_ci    if ((yStart >= 0) && (yEnd >= 0)) {
192a3e0fd82Sopenharmony_ci        int16_t tmp = yStart;
193a3e0fd82Sopenharmony_ci        yStart = -yEnd;
194a3e0fd82Sopenharmony_ci        yEnd = -tmp;
195a3e0fd82Sopenharmony_ci    } else if ((yStart < 0) && (yEnd > 0)) {
196a3e0fd82Sopenharmony_ci        yStart = MATH_MIN(yStart, -yEnd);
197a3e0fd82Sopenharmony_ci        yEnd = -1;
198a3e0fd82Sopenharmony_ci    }
199a3e0fd82Sopenharmony_ci    yStart = MATH_MAX(yStart, -outRadius_) - 1;
200a3e0fd82Sopenharmony_ci    yEnd = MATH_MIN(yEnd, -1);
201a3e0fd82Sopenharmony_ci}
202a3e0fd82Sopenharmony_ci
203a3e0fd82Sopenharmony_civoid DrawArc::DrawAxisLine(BufferInfo& gfxDstBuffer,
204a3e0fd82Sopenharmony_ci                           ArcInfo& arcInfo,
205a3e0fd82Sopenharmony_ci                           const Rect& mask,
206a3e0fd82Sopenharmony_ci                           const Style& style,
207a3e0fd82Sopenharmony_ci                           uint8_t opa)
208a3e0fd82Sopenharmony_ci{
209a3e0fd82Sopenharmony_ci    int16_t lineWidth = 0;
210a3e0fd82Sopenharmony_ci    int16_t outRadius = outRadius_ - 1;
211a3e0fd82Sopenharmony_ci    int16_t inRadius = inRadius_;
212a3e0fd82Sopenharmony_ci    if (inRadius <= 0) {
213a3e0fd82Sopenharmony_ci        inRadius = 1;
214a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer, arcInfo.center, arcInfo.imgPos, mask, 0, style, opa, arcInfo.imgSrc);
215a3e0fd82Sopenharmony_ci    }
216a3e0fd82Sopenharmony_ci    lineWidth = outRadius - inRadius;
217a3e0fd82Sopenharmony_ci
218a3e0fd82Sopenharmony_ci    if (isCircle_ || (IS_IN_DEGREERANE(THREE_QUARTER_IN_DEGREE, arcInfo.startAngle, arcInfo.endAngle))) {
219a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer, Point { static_cast<int16_t>(arcInfo.center.x - outRadius), arcInfo.center.y },
220a3e0fd82Sopenharmony_ci                    arcInfo.imgPos, mask, lineWidth, style, opa, arcInfo.imgSrc);
221a3e0fd82Sopenharmony_ci    }
222a3e0fd82Sopenharmony_ci
223a3e0fd82Sopenharmony_ci    if (isCircle_ || (IS_IN_DEGREERANE(QUARTER_IN_DEGREE, arcInfo.startAngle, arcInfo.endAngle))) {
224a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer, Point { static_cast<int16_t>(arcInfo.center.x + inRadius), arcInfo.center.y },
225a3e0fd82Sopenharmony_ci                    arcInfo.imgPos, mask, lineWidth, style, opa, arcInfo.imgSrc);
226a3e0fd82Sopenharmony_ci    }
227a3e0fd82Sopenharmony_ci
228a3e0fd82Sopenharmony_ci    if (isCircle_ || (IS_IN_DEGREERANE(0, arcInfo.startAngle, arcInfo.endAngle))) {
229a3e0fd82Sopenharmony_ci        DrawVerLine(gfxDstBuffer, Point { arcInfo.center.x, static_cast<int16_t>(arcInfo.center.y - outRadius) },
230a3e0fd82Sopenharmony_ci                    arcInfo.imgPos, mask, lineWidth, style, opa, arcInfo.imgSrc);
231a3e0fd82Sopenharmony_ci    }
232a3e0fd82Sopenharmony_ci
233a3e0fd82Sopenharmony_ci    if (isCircle_ || (IS_IN_DEGREERANE(SEMICIRCLE_IN_DEGREE, arcInfo.startAngle, arcInfo.endAngle))) {
234a3e0fd82Sopenharmony_ci        DrawVerLine(gfxDstBuffer, Point { arcInfo.center.x, static_cast<int16_t>(arcInfo.center.y + inRadius) },
235a3e0fd82Sopenharmony_ci                    arcInfo.imgPos, mask, lineWidth, style, opa, arcInfo.imgSrc);
236a3e0fd82Sopenharmony_ci    }
237a3e0fd82Sopenharmony_ci}
238a3e0fd82Sopenharmony_ci
239a3e0fd82Sopenharmony_civoid DrawArc::DrawLineWithDegree(BufferInfo& gfxDstBuffer,
240a3e0fd82Sopenharmony_ci                                 ArcInfo& arcInfo,
241a3e0fd82Sopenharmony_ci                                 int16_t start,
242a3e0fd82Sopenharmony_ci                                 int16_t end,
243a3e0fd82Sopenharmony_ci                                 int16_t y,
244a3e0fd82Sopenharmony_ci                                 const Rect& mask,
245a3e0fd82Sopenharmony_ci                                 const Style& style,
246a3e0fd82Sopenharmony_ci                                 uint8_t opaScale,
247a3e0fd82Sopenharmony_ci                                 uint8_t quadrant)
248a3e0fd82Sopenharmony_ci{
249a3e0fd82Sopenharmony_ci    if (isCircle_) {
250a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer,
251a3e0fd82Sopenharmony_ci                    Point {static_cast<int16_t>(arcInfo.center.x + start), static_cast<int16_t>(arcInfo.center.y + y)},
252a3e0fd82Sopenharmony_ci                    arcInfo.imgPos, mask, end - start, style, opaScale, arcInfo.imgSrc);
253a3e0fd82Sopenharmony_ci        return;
254a3e0fd82Sopenharmony_ci    }
255a3e0fd82Sopenharmony_ci    uint16_t degreeStart = GetDegreeInQuadrant(CalculateTanDegree(MATH_ABS(start), MATH_ABS(y)), quadrant);
256a3e0fd82Sopenharmony_ci    uint16_t degreeEnd = GetDegreeInQuadrant(CalculateTanDegree(MATH_ABS(end), MATH_ABS(y)), quadrant);
257a3e0fd82Sopenharmony_ci    if (degreeStart > degreeEnd) {
258a3e0fd82Sopenharmony_ci        uint16_t tmp = degreeStart;
259a3e0fd82Sopenharmony_ci        degreeStart = degreeEnd;
260a3e0fd82Sopenharmony_ci        degreeEnd = tmp;
261a3e0fd82Sopenharmony_ci    }
262a3e0fd82Sopenharmony_ci
263a3e0fd82Sopenharmony_ci    int16_t lineDegreeRet = GetDegreeRangeIntersectState(degreeStart, degreeEnd, arcInfo.startAngle, arcInfo.endAngle);
264a3e0fd82Sopenharmony_ci    int16_t drawEnd = 0;
265a3e0fd82Sopenharmony_ci    switch (lineDegreeRet) {
266a3e0fd82Sopenharmony_ci        case OUT_DEGREE_RANG:
267a3e0fd82Sopenharmony_ci            return;
268a3e0fd82Sopenharmony_ci        case IN_DEGREE_RANG:
269a3e0fd82Sopenharmony_ci            DrawHorLine(gfxDstBuffer,
270a3e0fd82Sopenharmony_ci                Point { static_cast<int16_t>(arcInfo.center.x + start), static_cast<int16_t>(arcInfo.center.y + y) },
271a3e0fd82Sopenharmony_ci                arcInfo.imgPos, mask, end - start, style, opaScale, arcInfo.imgSrc);
272a3e0fd82Sopenharmony_ci            return;
273a3e0fd82Sopenharmony_ci        case INTERSECT:
274a3e0fd82Sopenharmony_ci            DrawLineWithDegreeInner(gfxDstBuffer, arcInfo, start, end, y, mask, style, opaScale, quadrant);
275a3e0fd82Sopenharmony_ci            return;
276a3e0fd82Sopenharmony_ci        case DOUBLE_INTERSECT:
277a3e0fd82Sopenharmony_ci            drawEnd = DrawLineWithDegreeInner(gfxDstBuffer, arcInfo, start, end, y, mask, style, opaScale, quadrant);
278a3e0fd82Sopenharmony_ci            DrawLineWithDegreeInner(gfxDstBuffer, arcInfo, drawEnd + 1, end, y, mask, style, opaScale, quadrant);
279a3e0fd82Sopenharmony_ci            return;
280a3e0fd82Sopenharmony_ci        default:
281a3e0fd82Sopenharmony_ci            return;
282a3e0fd82Sopenharmony_ci    }
283a3e0fd82Sopenharmony_ci}
284a3e0fd82Sopenharmony_ci
285a3e0fd82Sopenharmony_ciint16_t DrawArc::DrawLineWithDegreeInner(BufferInfo& gfxDstBuffer,
286a3e0fd82Sopenharmony_ci                                         ArcInfo& arcInfo,
287a3e0fd82Sopenharmony_ci                                         int16_t start,
288a3e0fd82Sopenharmony_ci                                         int16_t end,
289a3e0fd82Sopenharmony_ci                                         int16_t y,
290a3e0fd82Sopenharmony_ci                                         const Rect& mask,
291a3e0fd82Sopenharmony_ci                                         const Style& style,
292a3e0fd82Sopenharmony_ci                                         uint8_t opaScale,
293a3e0fd82Sopenharmony_ci                                         uint8_t quadrant)
294a3e0fd82Sopenharmony_ci{
295a3e0fd82Sopenharmony_ci    int16_t drawStart = COORD_MIN;
296a3e0fd82Sopenharmony_ci    int16_t drawEnd = COORD_MIN;
297a3e0fd82Sopenharmony_ci    for (int16_t xi = start; xi <= end; xi++) {
298a3e0fd82Sopenharmony_ci        uint16_t degreeBase = CalculateTanDegree(MATH_ABS(xi), MATH_ABS(y));
299a3e0fd82Sopenharmony_ci        uint16_t degree = GetDegreeInQuadrant(degreeBase, quadrant);
300a3e0fd82Sopenharmony_ci        if (IS_IN_DEGREERANE(degree, arcInfo.startAngle, arcInfo.endAngle)) {
301a3e0fd82Sopenharmony_ci            if (drawStart == COORD_MIN) {
302a3e0fd82Sopenharmony_ci                drawStart = xi;
303a3e0fd82Sopenharmony_ci            }
304a3e0fd82Sopenharmony_ci        } else {
305a3e0fd82Sopenharmony_ci            if ((drawStart != COORD_MIN) && (drawEnd == COORD_MIN)) {
306a3e0fd82Sopenharmony_ci                drawEnd = xi - 1;
307a3e0fd82Sopenharmony_ci                break;
308a3e0fd82Sopenharmony_ci            }
309a3e0fd82Sopenharmony_ci        }
310a3e0fd82Sopenharmony_ci    }
311a3e0fd82Sopenharmony_ci    if (drawEnd == COORD_MIN) {
312a3e0fd82Sopenharmony_ci        drawEnd = end;
313a3e0fd82Sopenharmony_ci    }
314a3e0fd82Sopenharmony_ci    if ((drawStart != COORD_MIN) && (drawEnd != COORD_MIN)) {
315a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer,
316a3e0fd82Sopenharmony_ci            Point { static_cast<int16_t>(arcInfo.center.x + drawStart), static_cast<int16_t>(arcInfo.center.y + y) },
317a3e0fd82Sopenharmony_ci            arcInfo.imgPos, mask, drawEnd - drawStart, style, opaScale, arcInfo.imgSrc);
318a3e0fd82Sopenharmony_ci    }
319a3e0fd82Sopenharmony_ci    return drawEnd;
320a3e0fd82Sopenharmony_ci}
321a3e0fd82Sopenharmony_ci
322a3e0fd82Sopenharmony_ci#if ENABLE_ANTIALIAS
323a3e0fd82Sopenharmony_civoid DrawArc::DrawLineAnti(BufferInfo& gfxDstBuffer, ArcInfo& arcInfo, const Rect& mask,
324a3e0fd82Sopenharmony_ci                           const Style& style, uint8_t opa)
325a3e0fd82Sopenharmony_ci{
326a3e0fd82Sopenharmony_ci    outAntiStart_ = lineStart_;
327a3e0fd82Sopenharmony_ci    outAntiEnd_ = lineStart_;
328a3e0fd82Sopenharmony_ci    inAntiStart_ = lineEnd_ + 1;
329a3e0fd82Sopenharmony_ci    inAntiEnd_ = COORD_MIN;
330a3e0fd82Sopenharmony_ci
331a3e0fd82Sopenharmony_ci    for (int16_t xAnti = lineStart_; xAnti <= lineEnd_; xAnti++) {
332a3e0fd82Sopenharmony_ci        uint32_t currentSqr = static_cast<int32_t>(xAnti) * xAnti + ySqr_;
333a3e0fd82Sopenharmony_ci        if ((currentSqr <= antiOutRadiusSqr_) || (xAnti == lineEnd_)) {
334a3e0fd82Sopenharmony_ci            lineStart_ = xAnti;
335a3e0fd82Sopenharmony_ci            outAntiEnd_ = xAnti - 1;
336a3e0fd82Sopenharmony_ci            break;
337a3e0fd82Sopenharmony_ci        }
338a3e0fd82Sopenharmony_ci    }
339a3e0fd82Sopenharmony_ci
340a3e0fd82Sopenharmony_ci    for (int16_t xAnti = lineEnd_ + 1; xAnti <= -1; xAnti++) {
341a3e0fd82Sopenharmony_ci        uint32_t currentSqr = static_cast<int32_t>(xAnti) * xAnti + ySqr_;
342a3e0fd82Sopenharmony_ci        if ((currentSqr <= antiInRadiusSqr_) || (xAnti == -1)) {
343a3e0fd82Sopenharmony_ci            inAntiEnd_ = xAnti;
344a3e0fd82Sopenharmony_ci            break;
345a3e0fd82Sopenharmony_ci        }
346a3e0fd82Sopenharmony_ci    }
347a3e0fd82Sopenharmony_ci
348a3e0fd82Sopenharmony_ci    for (int16_t xAnti = outAntiStart_; xAnti <= outAntiEnd_; xAnti++) {
349a3e0fd82Sopenharmony_ci        uint32_t currentSqr = static_cast<int32_t>(xAnti) * xAnti + ySqr_;
350a3e0fd82Sopenharmony_ci        uint8_t antiOpa =
351a3e0fd82Sopenharmony_ci            (((static_cast<uint64_t>(outRadius_) << 1) - 1 - (currentSqr - antiOutRadiusSqr_)) * OPA_OPAQUE) /
352a3e0fd82Sopenharmony_ci            ((outRadius_ << 1) - 1);
353a3e0fd82Sopenharmony_ci        antiOpa = (opa == OPA_OPAQUE) ? antiOpa : (static_cast<uint16_t>(antiOpa) * opa) >> SHIFT_8;
354a3e0fd82Sopenharmony_ci        DrawPointAnti(gfxDstBuffer, arcInfo, xAnti, mask, style, antiOpa);
355a3e0fd82Sopenharmony_ci    }
356a3e0fd82Sopenharmony_ci
357a3e0fd82Sopenharmony_ci    for (int16_t xAnti = inAntiStart_; xAnti <= inAntiEnd_; xAnti++) {
358a3e0fd82Sopenharmony_ci        uint32_t currentSqr = static_cast<int32_t>(xAnti) * xAnti + ySqr_;
359a3e0fd82Sopenharmony_ci        if (currentSqr <= antiInRadiusSqr_) {
360a3e0fd82Sopenharmony_ci            break;
361a3e0fd82Sopenharmony_ci        }
362a3e0fd82Sopenharmony_ci        uint8_t antiOpa = (static_cast<uint64_t>(currentSqr - antiInRadiusSqr_) * OPA_OPAQUE) / ((inRadius_ << 1) - 1);
363a3e0fd82Sopenharmony_ci        antiOpa = (opa == OPA_OPAQUE) ? antiOpa : (static_cast<uint16_t>(antiOpa) * opa) >> SHIFT_8;
364a3e0fd82Sopenharmony_ci        DrawPointAnti(gfxDstBuffer, arcInfo, xAnti, mask, style, antiOpa);
365a3e0fd82Sopenharmony_ci    }
366a3e0fd82Sopenharmony_ci}
367a3e0fd82Sopenharmony_ci
368a3e0fd82Sopenharmony_civoid DrawArc::DrawPointAnti(BufferInfo& gfxDstBuffer, ArcInfo& arcInfo, int16_t x, const Rect& mask,
369a3e0fd82Sopenharmony_ci                            const Style& style, uint8_t antiOpa)
370a3e0fd82Sopenharmony_ci{
371a3e0fd82Sopenharmony_ci    int16_t startX;
372a3e0fd82Sopenharmony_ci    int16_t starty;
373a3e0fd82Sopenharmony_ci    uint16_t degreeBase = CalculateTanDegree(MATH_ABS(x), MATH_ABS(y_));
374a3e0fd82Sopenharmony_ci    if (isCircle_ || (IS_IN_DEGREERANE(CIRCLE_IN_DEGREE - degreeBase, arcInfo.startAngle, arcInfo.endAngle))) {
375a3e0fd82Sopenharmony_ci        startX = arcInfo.center.x + x;
376a3e0fd82Sopenharmony_ci        starty = arcInfo.center.y + y_;
377a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer, Point { startX, starty }, arcInfo.imgPos, mask, 0, style, antiOpa, arcInfo.imgSrc);
378a3e0fd82Sopenharmony_ci    }
379a3e0fd82Sopenharmony_ci    if (isCircle_ || (IS_IN_DEGREERANE(SEMICIRCLE_IN_DEGREE + degreeBase, arcInfo.startAngle, arcInfo.endAngle))) {
380a3e0fd82Sopenharmony_ci        startX = arcInfo.center.x + x;
381a3e0fd82Sopenharmony_ci        starty = arcInfo.center.y - y_;
382a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer, Point { startX, starty }, arcInfo.imgPos, mask, 0, style, antiOpa, arcInfo.imgSrc);
383a3e0fd82Sopenharmony_ci    }
384a3e0fd82Sopenharmony_ci    if (isCircle_ || (IS_IN_DEGREERANE(degreeBase, arcInfo.startAngle, arcInfo.endAngle))) {
385a3e0fd82Sopenharmony_ci        startX = arcInfo.center.x - x;
386a3e0fd82Sopenharmony_ci        starty = arcInfo.center.y + y_;
387a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer, Point { startX, starty }, arcInfo.imgPos, mask, 0, style, antiOpa, arcInfo.imgSrc);
388a3e0fd82Sopenharmony_ci    }
389a3e0fd82Sopenharmony_ci    if (isCircle_ || (IS_IN_DEGREERANE(SEMICIRCLE_IN_DEGREE - degreeBase, arcInfo.startAngle, arcInfo.endAngle))) {
390a3e0fd82Sopenharmony_ci        startX = arcInfo.center.x - x;
391a3e0fd82Sopenharmony_ci        starty = arcInfo.center.y - y_;
392a3e0fd82Sopenharmony_ci        DrawHorLine(gfxDstBuffer, Point { startX, starty }, arcInfo.imgPos, mask, 0, style, antiOpa, arcInfo.imgSrc);
393a3e0fd82Sopenharmony_ci    }
394a3e0fd82Sopenharmony_ci}
395a3e0fd82Sopenharmony_ci#endif
396a3e0fd82Sopenharmony_ci
397a3e0fd82Sopenharmony_ciuint16_t DrawArc::GetDegreeInQuadrant(uint16_t degree, uint8_t quadrant)
398a3e0fd82Sopenharmony_ci{
399a3e0fd82Sopenharmony_ci    switch (quadrant) {
400a3e0fd82Sopenharmony_ci        case ARC_QUADRANT_ONE:
401a3e0fd82Sopenharmony_ci            return degree;
402a3e0fd82Sopenharmony_ci        case ARC_QUADRANT_TWO:
403a3e0fd82Sopenharmony_ci            return SEMICIRCLE_IN_DEGREE - degree;
404a3e0fd82Sopenharmony_ci        case ARC_QUADRANT_THREE:
405a3e0fd82Sopenharmony_ci            return SEMICIRCLE_IN_DEGREE + degree;
406a3e0fd82Sopenharmony_ci        case ARC_QUADRANT_FOUR:
407a3e0fd82Sopenharmony_ci            return CIRCLE_IN_DEGREE - degree;
408a3e0fd82Sopenharmony_ci        default:
409a3e0fd82Sopenharmony_ci            return degree;
410a3e0fd82Sopenharmony_ci    }
411a3e0fd82Sopenharmony_ci}
412a3e0fd82Sopenharmony_ci
413a3e0fd82Sopenharmony_civoid DrawArc::Draw(BufferInfo& gfxDstBuffer, ArcInfo& arcInfo, const Rect& mask,
414a3e0fd82Sopenharmony_ci                   const Style& style, uint8_t opaScale, uint8_t cap)
415a3e0fd82Sopenharmony_ci{
416a3e0fd82Sopenharmony_ci    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.lineOpa_);
417a3e0fd82Sopenharmony_ci    if ((opa == OPA_TRANSPARENT) || (style.lineWidth_ < 1)) {
418a3e0fd82Sopenharmony_ci        return;
419a3e0fd82Sopenharmony_ci    }
420a3e0fd82Sopenharmony_ci
421a3e0fd82Sopenharmony_ci    SetArcInfo(arcInfo, style);
422a3e0fd82Sopenharmony_ci    if (arcInfo.startAngle != arcInfo.endAngle) {
423a3e0fd82Sopenharmony_ci        if ((arcInfo.imgSrc != nullptr) && (arcInfo.imgSrc->GetSrcType() != IMG_SRC_UNKNOWN)) {
424a3e0fd82Sopenharmony_ci            DrawCircleNoEndpoint(gfxDstBuffer, arcInfo, mask, style, opa, false);
425a3e0fd82Sopenharmony_ci        } else {
426a3e0fd82Sopenharmony_ci            DrawCircleNoEndpoint(gfxDstBuffer, arcInfo, mask, style, opa, true);
427a3e0fd82Sopenharmony_ci        }
428a3e0fd82Sopenharmony_ci    }
429a3e0fd82Sopenharmony_ci
430a3e0fd82Sopenharmony_ci    if (!isCircle_ && (cap != CapType::CAP_NONE)) {
431a3e0fd82Sopenharmony_ci        int16_t lineWidth = style.lineWidth_;
432a3e0fd82Sopenharmony_ci        if (lineWidth > arcInfo.radius) {
433a3e0fd82Sopenharmony_ci            lineWidth = arcInfo.radius;
434a3e0fd82Sopenharmony_ci        }
435a3e0fd82Sopenharmony_ci
436a3e0fd82Sopenharmony_ci        ArcInfo endArcInfo = arcInfo;
437a3e0fd82Sopenharmony_ci        endArcInfo.startAngle = 0;
438a3e0fd82Sopenharmony_ci        endArcInfo.endAngle = CIRCLE_IN_DEGREE;
439a3e0fd82Sopenharmony_ci
440a3e0fd82Sopenharmony_ci        int16_t outRadius = arcInfo.radius - 1;
441a3e0fd82Sopenharmony_ci        lineWidth--;
442a3e0fd82Sopenharmony_ci        /* the arc radius of the round cap should be half the line width */
443a3e0fd82Sopenharmony_ci        endArcInfo.radius = (static_cast<uint16_t>(lineWidth + 1) >> 1) + 1;
444a3e0fd82Sopenharmony_ci
445a3e0fd82Sopenharmony_ci        /* 0.5: round up */
446a3e0fd82Sopenharmony_ci        float temp = (outRadius - endArcInfo.radius + 1) * Sin(arcInfo.startAngle);
447a3e0fd82Sopenharmony_ci        int16_t startCapX = static_cast<int16_t>((temp > 0) ? (temp + 0.5f) : (temp - 0.5f));
448a3e0fd82Sopenharmony_ci
449a3e0fd82Sopenharmony_ci        temp = (outRadius - endArcInfo.radius + 1) * Sin(QUARTER_IN_DEGREE - arcInfo.startAngle);
450a3e0fd82Sopenharmony_ci        int16_t startCapY = static_cast<int16_t>((temp > 0) ? (temp + 0.5f) : (temp - 0.5f));
451a3e0fd82Sopenharmony_ci
452a3e0fd82Sopenharmony_ci        endArcInfo.center.x += startCapX;
453a3e0fd82Sopenharmony_ci        endArcInfo.center.y -= startCapY;
454a3e0fd82Sopenharmony_ci        SetArcInfo(endArcInfo, style);
455a3e0fd82Sopenharmony_ci
456a3e0fd82Sopenharmony_ci        temp = (outRadius - endArcInfo.radius + 1) * Sin(arcInfo.endAngle);
457a3e0fd82Sopenharmony_ci        int16_t endCapX = static_cast<int16_t>((temp > 0) ? (temp + 0.5f) : (temp - 0.5f));
458a3e0fd82Sopenharmony_ci
459a3e0fd82Sopenharmony_ci        temp = (outRadius - endArcInfo.radius + 1) * Sin(QUARTER_IN_DEGREE - arcInfo.endAngle);
460a3e0fd82Sopenharmony_ci        int16_t endCapY = static_cast<int16_t>((temp > 0) ? (temp + 0.5f) : (temp - 0.5f));
461a3e0fd82Sopenharmony_ci
462a3e0fd82Sopenharmony_ci        if ((endCapX == startCapX) && (endCapY == startCapY)) {
463a3e0fd82Sopenharmony_ci            if (cap != CapType::CAP_ROUND_UNSHOW) {
464a3e0fd82Sopenharmony_ci                DrawCircleNoEndpoint(gfxDstBuffer, endArcInfo, mask, style, opa, true);
465a3e0fd82Sopenharmony_ci            }
466a3e0fd82Sopenharmony_ci        } else {
467a3e0fd82Sopenharmony_ci            DrawCircleNoEndpoint(gfxDstBuffer, endArcInfo, mask, style, opa, true);
468a3e0fd82Sopenharmony_ci        }
469a3e0fd82Sopenharmony_ci
470a3e0fd82Sopenharmony_ci        endArcInfo.center = arcInfo.center;
471a3e0fd82Sopenharmony_ci        endArcInfo.center.x += endCapX;
472a3e0fd82Sopenharmony_ci        endArcInfo.center.y -= endCapY;
473a3e0fd82Sopenharmony_ci        SetArcInfo(endArcInfo, style);
474a3e0fd82Sopenharmony_ci        if (endCapX != 0) {
475a3e0fd82Sopenharmony_ci            DrawCircleNoEndpoint(gfxDstBuffer, endArcInfo, mask, style, opa, true);
476a3e0fd82Sopenharmony_ci        } else {
477a3e0fd82Sopenharmony_ci            if (cap != CapType::CAP_ROUND_UNSHOW) {
478a3e0fd82Sopenharmony_ci                DrawCircleNoEndpoint(gfxDstBuffer, endArcInfo, mask, style, opa, true);
479a3e0fd82Sopenharmony_ci            }
480a3e0fd82Sopenharmony_ci        }
481a3e0fd82Sopenharmony_ci    }
482a3e0fd82Sopenharmony_ci}
483a3e0fd82Sopenharmony_ci
484a3e0fd82Sopenharmony_ciint16_t DrawArc::GetDegreeRangeIntersectState(uint16_t degreeStart, uint16_t degreeEnd, uint16_t start, uint16_t end)
485a3e0fd82Sopenharmony_ci{
486a3e0fd82Sopenharmony_ci    if (start <= end) {
487a3e0fd82Sopenharmony_ci        if ((degreeStart >= start) && (degreeStart <= end) && (degreeEnd >= start) && (degreeEnd <= end)) {
488a3e0fd82Sopenharmony_ci            return IN_DEGREE_RANG;
489a3e0fd82Sopenharmony_ci        } else if ((degreeEnd < start) || (degreeStart > end)) {
490a3e0fd82Sopenharmony_ci            return OUT_DEGREE_RANG;
491a3e0fd82Sopenharmony_ci        } else {
492a3e0fd82Sopenharmony_ci            return INTERSECT;
493a3e0fd82Sopenharmony_ci        }
494a3e0fd82Sopenharmony_ci    } else {
495a3e0fd82Sopenharmony_ci        if (((degreeStart >= start) && (degreeEnd >= start)) || ((degreeStart <= end) && (degreeEnd <= end))) {
496a3e0fd82Sopenharmony_ci            return IN_DEGREE_RANG;
497a3e0fd82Sopenharmony_ci        } else if ((degreeStart > end) && (degreeEnd < start)) {
498a3e0fd82Sopenharmony_ci            return OUT_DEGREE_RANG;
499a3e0fd82Sopenharmony_ci        } else if ((degreeStart <= end) && (degreeEnd >= start)) {
500a3e0fd82Sopenharmony_ci            return DOUBLE_INTERSECT;
501a3e0fd82Sopenharmony_ci        } else {
502a3e0fd82Sopenharmony_ci            return INTERSECT;
503a3e0fd82Sopenharmony_ci        }
504a3e0fd82Sopenharmony_ci    }
505a3e0fd82Sopenharmony_ci}
506a3e0fd82Sopenharmony_ci
507a3e0fd82Sopenharmony_civoid DrawArc::SetArcInfo(ArcInfo& arcInfo, const Style& style)
508a3e0fd82Sopenharmony_ci{
509a3e0fd82Sopenharmony_ci    outRadius_ = arcInfo.radius;
510a3e0fd82Sopenharmony_ci    inRadius_ = outRadius_ - style.lineWidth_;
511a3e0fd82Sopenharmony_ci    if (inRadius_ < 0) {
512a3e0fd82Sopenharmony_ci        inRadius_ = 0;
513a3e0fd82Sopenharmony_ci    }
514a3e0fd82Sopenharmony_ci    outRadiusSqr_ = outRadius_ * outRadius_;
515a3e0fd82Sopenharmony_ci    inRadiusSqr_ = inRadius_ * inRadius_;
516a3e0fd82Sopenharmony_ci
517a3e0fd82Sopenharmony_ci    if ((arcInfo.startAngle == 0) && (arcInfo.endAngle == CIRCLE_IN_DEGREE)) {
518a3e0fd82Sopenharmony_ci        isCircle_ = true;
519a3e0fd82Sopenharmony_ci    } else {
520a3e0fd82Sopenharmony_ci        isCircle_ = false;
521a3e0fd82Sopenharmony_ci    }
522a3e0fd82Sopenharmony_ci
523a3e0fd82Sopenharmony_ci#if ENABLE_ANTIALIAS
524a3e0fd82Sopenharmony_ci    antiOutRadiusSqr_ = (outRadius_ - 1) * (outRadius_ - 1);
525a3e0fd82Sopenharmony_ci    if (inRadius_ == 0) {
526a3e0fd82Sopenharmony_ci        antiInRadiusSqr_ = 0;
527a3e0fd82Sopenharmony_ci    } else {
528a3e0fd82Sopenharmony_ci        antiInRadiusSqr_ = (inRadius_ - 1) * (inRadius_ - 1);
529a3e0fd82Sopenharmony_ci    }
530a3e0fd82Sopenharmony_ci#endif
531a3e0fd82Sopenharmony_ci}
532a3e0fd82Sopenharmony_ci} // namespace OHOS
533