1a3e0fd82Sopenharmony_ci/* 2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2022 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_line.h" 17a3e0fd82Sopenharmony_ci#include "draw/draw_utils.h" 18a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_math.h" 19a3e0fd82Sopenharmony_ci 20a3e0fd82Sopenharmony_cinamespace OHOS { 21a3e0fd82Sopenharmony_ci#define INCREASE_ACC(acc, accTemp, adj, step, dir) \ 22a3e0fd82Sopenharmony_ci do { \ 23a3e0fd82Sopenharmony_ci (accTemp) = (acc); \ 24a3e0fd82Sopenharmony_ci (acc) += (adj); \ 25a3e0fd82Sopenharmony_ci if ((acc) <= (accTemp)) { \ 26a3e0fd82Sopenharmony_ci (step) += (dir); \ 27a3e0fd82Sopenharmony_ci } \ 28a3e0fd82Sopenharmony_ci } while (0) 29a3e0fd82Sopenharmony_ci 30a3e0fd82Sopenharmony_ci#define SWAP_START_END(sx, sy, ex, ey, dx, dy, dir) \ 31a3e0fd82Sopenharmony_ci do { \ 32a3e0fd82Sopenharmony_ci if ((dy) >= (dx)) { \ 33a3e0fd82Sopenharmony_ci if ((sy) > (ey)) { \ 34a3e0fd82Sopenharmony_ci SWAP_POINTS((sx), (ex), (sy), (ey)); \ 35a3e0fd82Sopenharmony_ci } \ 36a3e0fd82Sopenharmony_ci if ((ex) < (sx)) { \ 37a3e0fd82Sopenharmony_ci (dir) = -1; \ 38a3e0fd82Sopenharmony_ci } \ 39a3e0fd82Sopenharmony_ci } else { \ 40a3e0fd82Sopenharmony_ci if ((sx) < (ex)) { \ 41a3e0fd82Sopenharmony_ci SWAP_POINTS((sx), (ex), (sy), (ey)); \ 42a3e0fd82Sopenharmony_ci } \ 43a3e0fd82Sopenharmony_ci if ((ey) < (sy)) { \ 44a3e0fd82Sopenharmony_ci (dir) = -1; \ 45a3e0fd82Sopenharmony_ci } \ 46a3e0fd82Sopenharmony_ci } \ 47a3e0fd82Sopenharmony_ci } while (0) 48a3e0fd82Sopenharmony_ci 49a3e0fd82Sopenharmony_ci#define SWAP_IF_Y_LARGER(x1, x2, y1, y2) \ 50a3e0fd82Sopenharmony_ci if ((y1) > (y2)) { \ 51a3e0fd82Sopenharmony_ci SWAP_POINTS((x1), (x2), (y1), (y2)); \ 52a3e0fd82Sopenharmony_ci } 53a3e0fd82Sopenharmony_ci 54a3e0fd82Sopenharmony_ci#define SWAP_IF_X_SMALLER(x1, x2, y1, y2) \ 55a3e0fd82Sopenharmony_ci if ((x1) < (x2)) { \ 56a3e0fd82Sopenharmony_ci SWAP_POINTS((x1), (x2), (y1), (y2)); \ 57a3e0fd82Sopenharmony_ci } 58a3e0fd82Sopenharmony_ci 59a3e0fd82Sopenharmony_civoid DrawLine::Draw(BufferInfo& gfxDstBuffer, 60a3e0fd82Sopenharmony_ci const Point& start, 61a3e0fd82Sopenharmony_ci const Point& end, 62a3e0fd82Sopenharmony_ci const Rect& mask, 63a3e0fd82Sopenharmony_ci int16_t width, 64a3e0fd82Sopenharmony_ci const ColorType& color, 65a3e0fd82Sopenharmony_ci OpacityType opacity) 66a3e0fd82Sopenharmony_ci{ 67a3e0fd82Sopenharmony_ci if ((width == 0) || (opacity == OPA_TRANSPARENT)) { 68a3e0fd82Sopenharmony_ci return; 69a3e0fd82Sopenharmony_ci } 70a3e0fd82Sopenharmony_ci 71a3e0fd82Sopenharmony_ci int16_t yTop; 72a3e0fd82Sopenharmony_ci int16_t yBottom; 73a3e0fd82Sopenharmony_ci 74a3e0fd82Sopenharmony_ci if (start.y < end.y) { 75a3e0fd82Sopenharmony_ci yTop = start.y - width / 2; // 2: half 76a3e0fd82Sopenharmony_ci yBottom = end.y + width / 2; // 2: half 77a3e0fd82Sopenharmony_ci } else { 78a3e0fd82Sopenharmony_ci yTop = end.y - width / 2; // 2: half 79a3e0fd82Sopenharmony_ci yBottom = start.y + width / 2; // 2: half 80a3e0fd82Sopenharmony_ci } 81a3e0fd82Sopenharmony_ci 82a3e0fd82Sopenharmony_ci if ((yBottom < mask.GetTop()) || (yTop > mask.GetBottom())) { 83a3e0fd82Sopenharmony_ci return; 84a3e0fd82Sopenharmony_ci } 85a3e0fd82Sopenharmony_ci 86a3e0fd82Sopenharmony_ci if (start.y == end.y) { 87a3e0fd82Sopenharmony_ci DrawHorizontalLine(gfxDstBuffer, start, end, mask, width, color, opacity); 88a3e0fd82Sopenharmony_ci } else if (start.x == end.x) { 89a3e0fd82Sopenharmony_ci DrawVerticalLine(gfxDstBuffer, start, end, mask, width, color, opacity); 90a3e0fd82Sopenharmony_ci } else { 91a3e0fd82Sopenharmony_ci DrawWuLine(gfxDstBuffer, start, end, mask, width, color, opacity); 92a3e0fd82Sopenharmony_ci } 93a3e0fd82Sopenharmony_ci} 94a3e0fd82Sopenharmony_ci 95a3e0fd82Sopenharmony_civoid DrawLine::DrawVerticalLine(BufferInfo& gfxDstBuffer, 96a3e0fd82Sopenharmony_ci const Point& start, 97a3e0fd82Sopenharmony_ci const Point& end, 98a3e0fd82Sopenharmony_ci const Rect& mask, 99a3e0fd82Sopenharmony_ci int16_t width, 100a3e0fd82Sopenharmony_ci const ColorType& color, 101a3e0fd82Sopenharmony_ci OpacityType opacity) 102a3e0fd82Sopenharmony_ci{ 103a3e0fd82Sopenharmony_ci Rect rect; 104a3e0fd82Sopenharmony_ci 105a3e0fd82Sopenharmony_ci if (start.y < end.y) { 106a3e0fd82Sopenharmony_ci rect.SetX(start.x - width / 2); // 2: half 107a3e0fd82Sopenharmony_ci rect.SetY(start.y); 108a3e0fd82Sopenharmony_ci rect.SetWidth(width); 109a3e0fd82Sopenharmony_ci rect.SetHeight(end.y - start.y + 1); 110a3e0fd82Sopenharmony_ci } else { 111a3e0fd82Sopenharmony_ci rect.SetX(end.x - width / 2); // 2: half 112a3e0fd82Sopenharmony_ci rect.SetY(end.y); 113a3e0fd82Sopenharmony_ci rect.SetWidth(width); 114a3e0fd82Sopenharmony_ci rect.SetHeight(start.y - end.y + 1); 115a3e0fd82Sopenharmony_ci } 116a3e0fd82Sopenharmony_ci 117a3e0fd82Sopenharmony_ci DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, rect, mask, color, opacity); 118a3e0fd82Sopenharmony_ci} 119a3e0fd82Sopenharmony_ci 120a3e0fd82Sopenharmony_civoid DrawLine::DrawHorizontalLine(BufferInfo& gfxDstBuffer, const Point& start, 121a3e0fd82Sopenharmony_ci const Point& end, 122a3e0fd82Sopenharmony_ci const Rect& mask, 123a3e0fd82Sopenharmony_ci int16_t width, 124a3e0fd82Sopenharmony_ci const ColorType& color, 125a3e0fd82Sopenharmony_ci OpacityType opacity) 126a3e0fd82Sopenharmony_ci{ 127a3e0fd82Sopenharmony_ci Rect rect; 128a3e0fd82Sopenharmony_ci 129a3e0fd82Sopenharmony_ci if (start.x < end.x) { 130a3e0fd82Sopenharmony_ci rect.SetX(start.x); 131a3e0fd82Sopenharmony_ci rect.SetY(start.y - width / 2); // 2: half 132a3e0fd82Sopenharmony_ci rect.SetWidth(end.x - start.x + 1); 133a3e0fd82Sopenharmony_ci rect.SetHeight(width); 134a3e0fd82Sopenharmony_ci } else { 135a3e0fd82Sopenharmony_ci rect.SetX(end.x); 136a3e0fd82Sopenharmony_ci rect.SetY(end.y - width / 2); // 2: half 137a3e0fd82Sopenharmony_ci rect.SetWidth(start.x - end.x + 1); 138a3e0fd82Sopenharmony_ci rect.SetHeight(width); 139a3e0fd82Sopenharmony_ci } 140a3e0fd82Sopenharmony_ci 141a3e0fd82Sopenharmony_ci DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, rect, mask, color, opacity); 142a3e0fd82Sopenharmony_ci} 143a3e0fd82Sopenharmony_ci 144a3e0fd82Sopenharmony_civoid DrawLine::DrawWuLine(BufferInfo& gfxDstBuffer, const Point& start, const Point& end, 145a3e0fd82Sopenharmony_ci const Rect& mask, int16_t width, const ColorType& color, OpacityType opacity) 146a3e0fd82Sopenharmony_ci{ 147a3e0fd82Sopenharmony_ci if (width <= 2) { // 2 : thin line width 148a3e0fd82Sopenharmony_ci DrawThinWuLine(gfxDstBuffer, start, end, mask, width, color, opacity); 149a3e0fd82Sopenharmony_ci return; 150a3e0fd82Sopenharmony_ci } 151a3e0fd82Sopenharmony_ci 152a3e0fd82Sopenharmony_ci int16_t sx = start.x; 153a3e0fd82Sopenharmony_ci int16_t sy = start.y; 154a3e0fd82Sopenharmony_ci int16_t ex = end.x; 155a3e0fd82Sopenharmony_ci int16_t ey = end.y; 156a3e0fd82Sopenharmony_ci uint16_t dx = MATH_ABS(ex - sx); 157a3e0fd82Sopenharmony_ci uint16_t dy = MATH_ABS(ey - sy); 158a3e0fd82Sopenharmony_ci int8_t dir = 1; 159a3e0fd82Sopenharmony_ci SWAP_START_END(sx, sy, ex, ey, dx, dy, dir); 160a3e0fd82Sopenharmony_ci 161a3e0fd82Sopenharmony_ci // calculate four vertex ordered according to dy and dx 162a3e0fd82Sopenharmony_ci float plot = -static_cast<float>(ex - sx) / static_cast<float>(ey - sy); 163a3e0fd82Sopenharmony_ci float offset = 1 / (1 + plot * plot); 164a3e0fd82Sopenharmony_ci offset = Sqrt(offset) * width / 2; // 2: half 165a3e0fd82Sopenharmony_ci float x0 = sx + offset; 166a3e0fd82Sopenharmony_ci float y0 = sy + (x0 - sx) * plot; 167a3e0fd82Sopenharmony_ci float x1 = sx - offset; 168a3e0fd82Sopenharmony_ci float y1 = sy + (x1 - sx) * plot; 169a3e0fd82Sopenharmony_ci float x2 = ex + offset; 170a3e0fd82Sopenharmony_ci float y2 = ey + (x2 - ex) * plot; 171a3e0fd82Sopenharmony_ci float x3 = ex - offset; 172a3e0fd82Sopenharmony_ci float y3 = ey + (x3 - ex) * plot; 173a3e0fd82Sopenharmony_ci int16_t x0Int = MATH_ROUND(x0); 174a3e0fd82Sopenharmony_ci int16_t y0Int = MATH_ROUND(y0); 175a3e0fd82Sopenharmony_ci int16_t x1Int = MATH_ROUND(x1); 176a3e0fd82Sopenharmony_ci int16_t y1Int = MATH_ROUND(y1); 177a3e0fd82Sopenharmony_ci int16_t x2Int = MATH_ROUND(x2); 178a3e0fd82Sopenharmony_ci int16_t y2Int = MATH_ROUND(y2); 179a3e0fd82Sopenharmony_ci int16_t x3Int = MATH_ROUND(x3); 180a3e0fd82Sopenharmony_ci int16_t y3Int = MATH_ROUND(y3); 181a3e0fd82Sopenharmony_ci // width is longer than distance between start point and end point, need swap direction of line. 182a3e0fd82Sopenharmony_ci if (dx * dx + dy * dy < width * width) { 183a3e0fd82Sopenharmony_ci if ((dx == 1) && (dy == 1)) { 184a3e0fd82Sopenharmony_ci DrawThinWuLine(gfxDstBuffer, { x0Int, y0Int }, { x3Int, y3Int }, mask, 2, color, opacity); // 2 : line width 185a3e0fd82Sopenharmony_ci return; 186a3e0fd82Sopenharmony_ci } 187a3e0fd82Sopenharmony_ci dx = MATH_ABS(x0Int - x1Int); 188a3e0fd82Sopenharmony_ci dy = MATH_ABS(y0Int - y1Int); 189a3e0fd82Sopenharmony_ci if (dy == dx) { 190a3e0fd82Sopenharmony_ci dir = -dir; 191a3e0fd82Sopenharmony_ci } 192a3e0fd82Sopenharmony_ci } 193a3e0fd82Sopenharmony_ci if (dy >= dx) { 194a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x0Int, x1Int, y0Int, y1Int); 195a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x1Int, x2Int, y1Int, y2Int); 196a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x2Int, x3Int, y2Int, y3Int); 197a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x0Int, x1Int, y0Int, y1Int); 198a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x1Int, x2Int, y1Int, y2Int); 199a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x0Int, x1Int, y0Int, y1Int); 200a3e0fd82Sopenharmony_ci if (dir == -1) { 201a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x1Int, x0Int, y1Int, y0Int); 202a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x3Int, x2Int, y3Int, y2Int); 203a3e0fd82Sopenharmony_ci } else { 204a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x0Int, x1Int, y0Int, y1Int); 205a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x2Int, x3Int, y2Int, y3Int); 206a3e0fd82Sopenharmony_ci } 207a3e0fd82Sopenharmony_ci } else { 208a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x0Int, x1Int, y0Int, y1Int); 209a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x1Int, x2Int, y1Int, y2Int); 210a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x2Int, x3Int, y2Int, y3Int); 211a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x0Int, x1Int, y0Int, y1Int); 212a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x1Int, x2Int, y1Int, y2Int); 213a3e0fd82Sopenharmony_ci SWAP_IF_X_SMALLER(x0Int, x1Int, y0Int, y1Int); 214a3e0fd82Sopenharmony_ci if (dir == 1) { 215a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x1Int, x0Int, y1Int, y0Int); 216a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x3Int, x2Int, y3Int, y2Int); 217a3e0fd82Sopenharmony_ci } else { 218a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x0Int, x1Int, y0Int, y1Int); 219a3e0fd82Sopenharmony_ci SWAP_IF_Y_LARGER(x2Int, x3Int, y2Int, y3Int); 220a3e0fd82Sopenharmony_ci } 221a3e0fd82Sopenharmony_ci } 222a3e0fd82Sopenharmony_ci 223a3e0fd82Sopenharmony_ci uint64_t adj0; 224a3e0fd82Sopenharmony_ci uint16_t accTemp0; 225a3e0fd82Sopenharmony_ci uint16_t acc0 = 0; 226a3e0fd82Sopenharmony_ci uint64_t adj1; 227a3e0fd82Sopenharmony_ci uint16_t accTemp1; 228a3e0fd82Sopenharmony_ci uint16_t acc1 = 0; 229a3e0fd82Sopenharmony_ci uint16_t accTemp2; 230a3e0fd82Sopenharmony_ci uint16_t acc2 = 0; 231a3e0fd82Sopenharmony_ci 232a3e0fd82Sopenharmony_ci int16_t endPoints0[MAX_LINE_WIDTH] = { 0 }; 233a3e0fd82Sopenharmony_ci int16_t endPoints1[MAX_LINE_WIDTH] = { 0 }; 234a3e0fd82Sopenharmony_ci int16_t temp0 = 0; 235a3e0fd82Sopenharmony_ci int16_t temp1 = 0; 236a3e0fd82Sopenharmony_ci int16_t edge0 = 0; 237a3e0fd82Sopenharmony_ci int16_t edge1 = 0; 238a3e0fd82Sopenharmony_ci Rect rect; 239a3e0fd82Sopenharmony_ci DrawUtils* drawUtils = DrawUtils::GetInstance(); 240a3e0fd82Sopenharmony_ci // sort points 241a3e0fd82Sopenharmony_ci if (dy >= dx) { 242a3e0fd82Sopenharmony_ci adj0 = static_cast<uint64_t>(dx << SHIFT_16) / static_cast<uint64_t>(dy); 243a3e0fd82Sopenharmony_ci adj1 = static_cast<uint64_t>(MATH_ABS(y1Int - y0Int) << SHIFT_16) / 244a3e0fd82Sopenharmony_ci static_cast<uint64_t>(MATH_ABS(x1Int - x0Int)); 245a3e0fd82Sopenharmony_ci if (adj1 != 0) { 246a3e0fd82Sopenharmony_ci // draw top line 247a3e0fd82Sopenharmony_ci dx = MATH_ABS(x1Int - x0Int); 248a3e0fd82Sopenharmony_ci sx = x0Int; 249a3e0fd82Sopenharmony_ci sy = y0Int; 250a3e0fd82Sopenharmony_ci drawUtils->DrawPixel(gfxDstBuffer, x0Int, y0Int, mask, color, opacity); 251a3e0fd82Sopenharmony_ci while (--dx) { 252a3e0fd82Sopenharmony_ci accTemp1 = acc1; 253a3e0fd82Sopenharmony_ci acc1 += adj1; 254a3e0fd82Sopenharmony_ci if (acc1 <= accTemp1) { 255a3e0fd82Sopenharmony_ci if (sy - y0Int < MAX_LINE_WIDTH) { 256a3e0fd82Sopenharmony_ci endPoints0[sy - y0Int] = sx; 257a3e0fd82Sopenharmony_ci } 258a3e0fd82Sopenharmony_ci sy++; 259a3e0fd82Sopenharmony_ci } 260a3e0fd82Sopenharmony_ci sx -= dir; 261a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx, sy, mask, color, opacity, 262a3e0fd82Sopenharmony_ci (acc1 >> SHIFT_8) ^ OPA_OPAQUE); 263a3e0fd82Sopenharmony_ci } 264a3e0fd82Sopenharmony_ci if (sy - y0Int < MAX_LINE_WIDTH) { 265a3e0fd82Sopenharmony_ci endPoints0[sy - y0Int] = sx - dir; 266a3e0fd82Sopenharmony_ci } 267a3e0fd82Sopenharmony_ci 268a3e0fd82Sopenharmony_ci // draw botttom line 269a3e0fd82Sopenharmony_ci acc1 = 0; 270a3e0fd82Sopenharmony_ci dx = MATH_ABS(x3Int - x2Int); 271a3e0fd82Sopenharmony_ci sy = y3Int; 272a3e0fd82Sopenharmony_ci sx = x3Int; 273a3e0fd82Sopenharmony_ci drawUtils->DrawPixel(gfxDstBuffer, x3Int, y3Int, mask, color, opacity); 274a3e0fd82Sopenharmony_ci while (--dx) { 275a3e0fd82Sopenharmony_ci accTemp1 = acc1; 276a3e0fd82Sopenharmony_ci acc1 += adj1; 277a3e0fd82Sopenharmony_ci if (acc1 <= accTemp1) { 278a3e0fd82Sopenharmony_ci if (temp1 < MAX_LINE_WIDTH) { 279a3e0fd82Sopenharmony_ci endPoints1[temp1++] = sx; 280a3e0fd82Sopenharmony_ci } 281a3e0fd82Sopenharmony_ci sy--; 282a3e0fd82Sopenharmony_ci } 283a3e0fd82Sopenharmony_ci sx += dir; 284a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx, sy, mask, color, opacity, 285a3e0fd82Sopenharmony_ci (acc1 >> SHIFT_8) ^ OPA_OPAQUE); 286a3e0fd82Sopenharmony_ci } 287a3e0fd82Sopenharmony_ci if (temp1 < MAX_LINE_WIDTH) { 288a3e0fd82Sopenharmony_ci endPoints1[temp1++] = sx + dir; 289a3e0fd82Sopenharmony_ci } 290a3e0fd82Sopenharmony_ci } else { 291a3e0fd82Sopenharmony_ci /* If y0 is equal to y1, draw two horizontal lines as the top line and bottom line. */ 292a3e0fd82Sopenharmony_ci rect.SetRect(MATH_MIN(x0Int, x1Int), y0Int, MATH_MAX(x0Int, x1Int), y1Int); 293a3e0fd82Sopenharmony_ci drawUtils->DrawColorArea(gfxDstBuffer, rect, mask, color, opacity); 294a3e0fd82Sopenharmony_ci rect.SetRect(MATH_MIN(x2Int, x3Int), y3Int, MATH_MAX(x2Int, x3Int), y2Int); 295a3e0fd82Sopenharmony_ci drawUtils->DrawColorArea(gfxDstBuffer, rect, mask, color, opacity); 296a3e0fd82Sopenharmony_ci } 297a3e0fd82Sopenharmony_ci 298a3e0fd82Sopenharmony_ci sx = x0Int; 299a3e0fd82Sopenharmony_ci sy = y0Int + 1; 300a3e0fd82Sopenharmony_ci dy = MATH_ABS(y3Int - y0Int); 301a3e0fd82Sopenharmony_ci if (dy == 0) { 302a3e0fd82Sopenharmony_ci return; 303a3e0fd82Sopenharmony_ci } 304a3e0fd82Sopenharmony_ci int16_t sxTemp = x1Int; 305a3e0fd82Sopenharmony_ci while (--dy) { 306a3e0fd82Sopenharmony_ci if (sy <= y1Int) { 307a3e0fd82Sopenharmony_ci INCREASE_ACC(acc0, accTemp0, adj0, sx, dir); 308a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx + dir, sy, mask, 309a3e0fd82Sopenharmony_ci color, opacity, acc0 >> SHIFT_8); 310a3e0fd82Sopenharmony_ci if (temp0 < MAX_LINE_WIDTH) { 311a3e0fd82Sopenharmony_ci edge0 = endPoints0[temp0++]; 312a3e0fd82Sopenharmony_ci } 313a3e0fd82Sopenharmony_ci edge1 = sx; 314a3e0fd82Sopenharmony_ci } else if (sy < y2Int) { 315a3e0fd82Sopenharmony_ci INCREASE_ACC(acc0, accTemp0, adj0, sx, dir); 316a3e0fd82Sopenharmony_ci INCREASE_ACC(acc2, accTemp2, adj0, sxTemp, dir); 317a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx + dir, sy, mask, 318a3e0fd82Sopenharmony_ci color, opacity, acc0 >> SHIFT_8); 319a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sxTemp, sy, mask, color, opacity, 320a3e0fd82Sopenharmony_ci (acc2 >> SHIFT_8) ^ OPA_OPAQUE); 321a3e0fd82Sopenharmony_ci edge0 = sxTemp + dir; 322a3e0fd82Sopenharmony_ci edge1 = sx; 323a3e0fd82Sopenharmony_ci } else if (sy < y3Int) { 324a3e0fd82Sopenharmony_ci INCREASE_ACC(acc2, accTemp2, adj0, sxTemp, dir); 325a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sxTemp, sy, mask, color, opacity, 326a3e0fd82Sopenharmony_ci (acc2 >> SHIFT_8) ^ OPA_OPAQUE); 327a3e0fd82Sopenharmony_ci edge0 = sxTemp + dir; 328a3e0fd82Sopenharmony_ci if (temp1 > 0) { 329a3e0fd82Sopenharmony_ci edge1 = endPoints1[--temp1]; 330a3e0fd82Sopenharmony_ci } 331a3e0fd82Sopenharmony_ci } 332a3e0fd82Sopenharmony_ci if ((dir < 0) && (edge0 > edge1)) { 333a3e0fd82Sopenharmony_ci SWAP_INT16(edge0, edge1); 334a3e0fd82Sopenharmony_ci } 335a3e0fd82Sopenharmony_ci rect.SetRect(edge0, sy, edge1, sy); 336a3e0fd82Sopenharmony_ci drawUtils->DrawColorArea(gfxDstBuffer, rect, mask, color, opacity); 337a3e0fd82Sopenharmony_ci sy++; 338a3e0fd82Sopenharmony_ci } 339a3e0fd82Sopenharmony_ci } else { 340a3e0fd82Sopenharmony_ci adj0 = static_cast<uint64_t>(dy << SHIFT_16) / static_cast<uint64_t>(dx); 341a3e0fd82Sopenharmony_ci adj1 = static_cast<uint64_t>(MATH_ABS(x1Int - x0Int) << SHIFT_16) / 342a3e0fd82Sopenharmony_ci static_cast<uint64_t>(MATH_ABS(y1Int - y0Int)); 343a3e0fd82Sopenharmony_ci if (adj1 != 0) { 344a3e0fd82Sopenharmony_ci // draw top line 345a3e0fd82Sopenharmony_ci dy = MATH_ABS(y1Int - y0Int); 346a3e0fd82Sopenharmony_ci sx = x0Int; 347a3e0fd82Sopenharmony_ci sy = y0Int; 348a3e0fd82Sopenharmony_ci drawUtils->DrawPixel(gfxDstBuffer, sx, sy, mask, color, opacity); 349a3e0fd82Sopenharmony_ci while (--dy) { 350a3e0fd82Sopenharmony_ci accTemp1 = acc1; 351a3e0fd82Sopenharmony_ci acc1 += adj1; 352a3e0fd82Sopenharmony_ci if (acc1 <= accTemp1) { 353a3e0fd82Sopenharmony_ci if (x0Int - sx < MAX_LINE_WIDTH) { 354a3e0fd82Sopenharmony_ci endPoints0[x0Int - sx] = sy; 355a3e0fd82Sopenharmony_ci } 356a3e0fd82Sopenharmony_ci sx--; 357a3e0fd82Sopenharmony_ci } 358a3e0fd82Sopenharmony_ci sy -= dir; 359a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx, sy, mask, color, opacity, 360a3e0fd82Sopenharmony_ci (acc1 >> SHIFT_8) ^ OPA_OPAQUE); 361a3e0fd82Sopenharmony_ci } 362a3e0fd82Sopenharmony_ci if (x0Int - sx < MAX_LINE_WIDTH) { 363a3e0fd82Sopenharmony_ci endPoints0[x0Int - sx] = sy - dir; 364a3e0fd82Sopenharmony_ci } 365a3e0fd82Sopenharmony_ci 366a3e0fd82Sopenharmony_ci // draw botttom line 367a3e0fd82Sopenharmony_ci acc1 = 0; 368a3e0fd82Sopenharmony_ci dy = MATH_ABS(y3Int - y2Int); 369a3e0fd82Sopenharmony_ci sy = y3Int; 370a3e0fd82Sopenharmony_ci sx = x3Int; 371a3e0fd82Sopenharmony_ci while (--dy) { 372a3e0fd82Sopenharmony_ci accTemp1 = acc1; 373a3e0fd82Sopenharmony_ci acc1 += adj1; 374a3e0fd82Sopenharmony_ci if (acc1 <= accTemp1) { 375a3e0fd82Sopenharmony_ci if (temp1 < MAX_LINE_WIDTH) { 376a3e0fd82Sopenharmony_ci endPoints1[temp1++] = sy; 377a3e0fd82Sopenharmony_ci } 378a3e0fd82Sopenharmony_ci sx++; 379a3e0fd82Sopenharmony_ci } 380a3e0fd82Sopenharmony_ci sy += dir; 381a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx, sy, mask, color, opacity, 382a3e0fd82Sopenharmony_ci (acc1 >> SHIFT_8) ^ OPA_OPAQUE); 383a3e0fd82Sopenharmony_ci } 384a3e0fd82Sopenharmony_ci drawUtils->DrawPixel(gfxDstBuffer, x3Int, y3Int, mask, color, opacity); 385a3e0fd82Sopenharmony_ci if (temp1 < MAX_LINE_WIDTH) { 386a3e0fd82Sopenharmony_ci endPoints1[temp1++] = sy + dir; 387a3e0fd82Sopenharmony_ci } 388a3e0fd82Sopenharmony_ci } else { 389a3e0fd82Sopenharmony_ci /* If x0 is equal to x1, draw two vertical lines as the top line and bottom line. */ 390a3e0fd82Sopenharmony_ci rect.SetRect(x1Int, MATH_MIN(y0Int, y1Int), x0Int, MATH_MAX(y0Int, y1Int)); 391a3e0fd82Sopenharmony_ci drawUtils->DrawColorArea(gfxDstBuffer, rect, mask, color, opacity); 392a3e0fd82Sopenharmony_ci rect.SetRect(x3Int, MATH_MIN(y2Int, y3Int), x2Int, MATH_MAX(y2Int, y3Int)); 393a3e0fd82Sopenharmony_ci drawUtils->DrawColorArea(gfxDstBuffer, rect, mask, color, opacity); 394a3e0fd82Sopenharmony_ci } 395a3e0fd82Sopenharmony_ci 396a3e0fd82Sopenharmony_ci sx = x0Int - 1; 397a3e0fd82Sopenharmony_ci sy = y0Int; 398a3e0fd82Sopenharmony_ci dx = MATH_ABS(x3Int - x0Int); 399a3e0fd82Sopenharmony_ci int16_t syTemp = y1Int; 400a3e0fd82Sopenharmony_ci if (dx == 0) { 401a3e0fd82Sopenharmony_ci return; 402a3e0fd82Sopenharmony_ci } 403a3e0fd82Sopenharmony_ci while (--dx) { 404a3e0fd82Sopenharmony_ci if (sx >= x1Int) { 405a3e0fd82Sopenharmony_ci INCREASE_ACC(acc0, accTemp0, adj0, sy, dir); 406a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx, sy + dir, mask, 407a3e0fd82Sopenharmony_ci color, opacity, acc0 >> SHIFT_8); 408a3e0fd82Sopenharmony_ci if (temp0 < MAX_LINE_WIDTH) { 409a3e0fd82Sopenharmony_ci edge0 = endPoints0[temp0++]; 410a3e0fd82Sopenharmony_ci } 411a3e0fd82Sopenharmony_ci edge1 = sy; 412a3e0fd82Sopenharmony_ci } else if (sx > x2Int) { 413a3e0fd82Sopenharmony_ci INCREASE_ACC(acc0, accTemp0, adj0, sy, dir); 414a3e0fd82Sopenharmony_ci INCREASE_ACC(acc2, accTemp2, adj0, syTemp, dir); 415a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx, sy + dir, mask, 416a3e0fd82Sopenharmony_ci color, opacity, acc0 >> SHIFT_8); 417a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx, syTemp, mask, color, 418a3e0fd82Sopenharmony_ci opacity, (acc2 >> SHIFT_8) ^ OPA_OPAQUE); 419a3e0fd82Sopenharmony_ci edge0 = syTemp + dir; 420a3e0fd82Sopenharmony_ci edge1 = sy; 421a3e0fd82Sopenharmony_ci } else if (sx > x3Int) { 422a3e0fd82Sopenharmony_ci INCREASE_ACC(acc2, accTemp2, adj0, syTemp, dir); 423a3e0fd82Sopenharmony_ci drawUtils->DrawPixelInLine(gfxDstBuffer, sx, syTemp, mask, color, opacity, 424a3e0fd82Sopenharmony_ci (acc2 >> SHIFT_8) ^ OPA_OPAQUE); 425a3e0fd82Sopenharmony_ci edge0 = syTemp + dir; 426a3e0fd82Sopenharmony_ci if (temp1 > 0) { 427a3e0fd82Sopenharmony_ci edge1 = endPoints1[--temp1]; 428a3e0fd82Sopenharmony_ci } 429a3e0fd82Sopenharmony_ci } 430a3e0fd82Sopenharmony_ci if ((dir < 0) && (edge0 > edge1)) { 431a3e0fd82Sopenharmony_ci SWAP_INT16(edge0, edge1); 432a3e0fd82Sopenharmony_ci } 433a3e0fd82Sopenharmony_ci rect.SetRect(sx, edge0, sx, edge1); 434a3e0fd82Sopenharmony_ci drawUtils->DrawColorArea(gfxDstBuffer, rect, mask, color, opacity); 435a3e0fd82Sopenharmony_ci sx--; 436a3e0fd82Sopenharmony_ci } 437a3e0fd82Sopenharmony_ci } 438a3e0fd82Sopenharmony_ci} 439a3e0fd82Sopenharmony_ci 440a3e0fd82Sopenharmony_civoid DrawLine::DrawThinWuLine(BufferInfo& gfxDstBuffer, const Point& start, const Point& end, 441a3e0fd82Sopenharmony_ci const Rect& mask, int16_t width, const ColorType& color, OpacityType opacity) 442a3e0fd82Sopenharmony_ci{ 443a3e0fd82Sopenharmony_ci int16_t sx = start.x; 444a3e0fd82Sopenharmony_ci int16_t sy = start.y; 445a3e0fd82Sopenharmony_ci int16_t ex = end.x; 446a3e0fd82Sopenharmony_ci int16_t ey = end.y; 447a3e0fd82Sopenharmony_ci uint16_t dx = MATH_ABS(ex - sx); 448a3e0fd82Sopenharmony_ci uint16_t dy = MATH_ABS(ey - sy); 449a3e0fd82Sopenharmony_ci uint64_t adj; 450a3e0fd82Sopenharmony_ci uint16_t accTemp; 451a3e0fd82Sopenharmony_ci uint16_t acc = 0; 452a3e0fd82Sopenharmony_ci int8_t dir = 1; 453a3e0fd82Sopenharmony_ci SWAP_START_END(sx, sy, ex, ey, dx, dy, dir); 454a3e0fd82Sopenharmony_ci DrawUtils* drawUtils = DrawUtils::GetInstance(); 455a3e0fd82Sopenharmony_ci if (dy >= dx) { 456a3e0fd82Sopenharmony_ci adj = static_cast<uint64_t>(dx << SHIFT_16) / static_cast<uint64_t>(dy); 457a3e0fd82Sopenharmony_ci while (dy--) { 458a3e0fd82Sopenharmony_ci INCREASE_ACC(acc, accTemp, adj, sx, dir); 459a3e0fd82Sopenharmony_ci sy++; 460a3e0fd82Sopenharmony_ci if (width == 1) { 461a3e0fd82Sopenharmony_ci drawUtils->DrawAdjPixelInLine(gfxDstBuffer, sx, sy, sx + dir, sy, mask, 462a3e0fd82Sopenharmony_ci color, opacity, acc >> SHIFT_8); 463a3e0fd82Sopenharmony_ci } else { 464a3e0fd82Sopenharmony_ci drawUtils->DrawVerPixelInLine(gfxDstBuffer, sx, sy, dir, mask, 465a3e0fd82Sopenharmony_ci color, opacity, acc >> SHIFT_8); 466a3e0fd82Sopenharmony_ci } 467a3e0fd82Sopenharmony_ci } 468a3e0fd82Sopenharmony_ci } else { 469a3e0fd82Sopenharmony_ci adj = static_cast<uint64_t>(dy << SHIFT_16) / static_cast<uint64_t>(dx); 470a3e0fd82Sopenharmony_ci while (dx--) { 471a3e0fd82Sopenharmony_ci INCREASE_ACC(acc, accTemp, adj, sy, dir); 472a3e0fd82Sopenharmony_ci sx--; 473a3e0fd82Sopenharmony_ci if (width == 1) { 474a3e0fd82Sopenharmony_ci drawUtils->DrawAdjPixelInLine(gfxDstBuffer, sx, sy, sx, sy + dir, mask, 475a3e0fd82Sopenharmony_ci color, opacity, acc >> SHIFT_8); 476a3e0fd82Sopenharmony_ci } else { 477a3e0fd82Sopenharmony_ci drawUtils->DrawHorPixelInLine(gfxDstBuffer, sx, sy, dir, mask, 478a3e0fd82Sopenharmony_ci color, opacity, acc >> SHIFT_8); 479a3e0fd82Sopenharmony_ci } 480a3e0fd82Sopenharmony_ci } 481a3e0fd82Sopenharmony_ci } 482a3e0fd82Sopenharmony_ci} 483a3e0fd82Sopenharmony_ci} // namespace OHOS 484