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