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