1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2021-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 "clip_utils.h"
17a3e0fd82Sopenharmony_ci#include "draw_utils.h"
18a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/depiction/depict_curve.h"
19a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/rasterizer/rasterizer_scanline_antialias.h"
20a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/scanline/geometry_scanline.h"
21a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/spancolorfill/fill_base.h"
22a3e0fd82Sopenharmony_ci#include "gfx_utils/diagram/spancolorfill/fill_pattern_rgba.h"
23a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_log.h"
24a3e0fd82Sopenharmony_ci#include "render/render_base.h"
25a3e0fd82Sopenharmony_ci#include "render/render_pixfmt_rgba_blend.h"
26a3e0fd82Sopenharmony_ci
27a3e0fd82Sopenharmony_cinamespace OHOS {
28a3e0fd82Sopenharmony_ciusing UICanvasPath = DepictCurve;
29a3e0fd82Sopenharmony_ciusing PathTransform = DepictTransform<UICanvasPath>;
30a3e0fd82Sopenharmony_ci
31a3e0fd82Sopenharmony_ciClipPath& ClipPath::MoveTo(const PointF& point)
32a3e0fd82Sopenharmony_ci{
33a3e0fd82Sopenharmony_ci    vertices_->MoveTo(point.x, point.y);
34a3e0fd82Sopenharmony_ci    return *this;
35a3e0fd82Sopenharmony_ci}
36a3e0fd82Sopenharmony_ci
37a3e0fd82Sopenharmony_ciClipPath& ClipPath::LineTo(const PointF& point)
38a3e0fd82Sopenharmony_ci{
39a3e0fd82Sopenharmony_ci    if (vertices_->GetTotalVertices() != 0) {
40a3e0fd82Sopenharmony_ci        vertices_->LineTo(point.x, point.y);
41a3e0fd82Sopenharmony_ci    } else {
42a3e0fd82Sopenharmony_ci        vertices_->MoveTo(point.x, point.y);
43a3e0fd82Sopenharmony_ci    }
44a3e0fd82Sopenharmony_ci    return *this;
45a3e0fd82Sopenharmony_ci}
46a3e0fd82Sopenharmony_ci
47a3e0fd82Sopenharmony_ciClipPath& ClipPath::CurveTo(const PointF& control1, const PointF& control2, const PointF& end)
48a3e0fd82Sopenharmony_ci{
49a3e0fd82Sopenharmony_ci    vertices_->CubicBezierCurve(control1.x, control1.y, control2.x, control2.y, end.x, end.y);
50a3e0fd82Sopenharmony_ci    return *this;
51a3e0fd82Sopenharmony_ci}
52a3e0fd82Sopenharmony_ci
53a3e0fd82Sopenharmony_ciClipPath& ClipPath::Arc(const PointF& center, float radius, int16_t startAngle, int16_t endAngle)
54a3e0fd82Sopenharmony_ci{
55a3e0fd82Sopenharmony_ci    if (startAngle == endAngle) {
56a3e0fd82Sopenharmony_ci        return *this;
57a3e0fd82Sopenharmony_ci    }
58a3e0fd82Sopenharmony_ci    float sinma = radius * Sin(startAngle);
59a3e0fd82Sopenharmony_ci    float cosma = radius * Sin(QUARTER_IN_DEGREE - startAngle);
60a3e0fd82Sopenharmony_ci    if (vertices_->GetTotalVertices() != 0) {
61a3e0fd82Sopenharmony_ci        vertices_->LineTo(float(center.x + sinma), float(center.y - cosma));
62a3e0fd82Sopenharmony_ci    } else {
63a3e0fd82Sopenharmony_ci        vertices_->MoveTo(float(center.x + sinma), float(center.y - cosma));
64a3e0fd82Sopenharmony_ci    }
65a3e0fd82Sopenharmony_ci    if (MATH_ABS(startAngle - endAngle) < CIRCLE_IN_DEGREE) {
66a3e0fd82Sopenharmony_ci        sinma = radius * Sin(endAngle);
67a3e0fd82Sopenharmony_ci        cosma = radius * Sin(QUARTER_IN_DEGREE - endAngle);
68a3e0fd82Sopenharmony_ci    } else {
69a3e0fd82Sopenharmony_ci        Circle(center, radius);
70a3e0fd82Sopenharmony_ci        return *this;
71a3e0fd82Sopenharmony_ci    }
72a3e0fd82Sopenharmony_ci
73a3e0fd82Sopenharmony_ci    int16_t angle = endAngle - startAngle;
74a3e0fd82Sopenharmony_ci    bool largeArcFlag = false;
75a3e0fd82Sopenharmony_ci    if (angle > SEMICIRCLE_IN_DEGREE || angle <= 0) {
76a3e0fd82Sopenharmony_ci        largeArcFlag = true;
77a3e0fd82Sopenharmony_ci    }
78a3e0fd82Sopenharmony_ci    vertices_->ArcTo(radius, radius, angle, largeArcFlag, 1, center.x + sinma, center.y - cosma);
79a3e0fd82Sopenharmony_ci    return *this;
80a3e0fd82Sopenharmony_ci}
81a3e0fd82Sopenharmony_ci
82a3e0fd82Sopenharmony_ciClipPath& ClipPath::Circle(const PointF& center, float radius)
83a3e0fd82Sopenharmony_ci{
84a3e0fd82Sopenharmony_ci    if (radius <= 0) {
85a3e0fd82Sopenharmony_ci        return *this;
86a3e0fd82Sopenharmony_ci    }
87a3e0fd82Sopenharmony_ci    vertices_->RemoveAll();
88a3e0fd82Sopenharmony_ci#if defined(GRAPHIC_ENABLE_BEZIER_ARC_FLAG) && GRAPHIC_ENABLE_BEZIER_ARC_FLAG
89a3e0fd82Sopenharmony_ci    BezierArc arc(center.x, center.y, radius, radius, 0, TWO_TIMES * PI);
90a3e0fd82Sopenharmony_ci    vertices_->ConcatPath(arc, 0);
91a3e0fd82Sopenharmony_ci#endif
92a3e0fd82Sopenharmony_ci    return *this;
93a3e0fd82Sopenharmony_ci}
94a3e0fd82Sopenharmony_ci
95a3e0fd82Sopenharmony_ciUICanvasVertices& ClipUtils::CloseVertices(const ClipPath& path)
96a3e0fd82Sopenharmony_ci{
97a3e0fd82Sopenharmony_ci    UICanvasVertices& vertices = path.GetVertices();
98a3e0fd82Sopenharmony_ci    vertices.ClosePolygon();
99a3e0fd82Sopenharmony_ci    return vertices;
100a3e0fd82Sopenharmony_ci}
101a3e0fd82Sopenharmony_ci
102a3e0fd82Sopenharmony_civoid ClipUtils::PerformScan(const ClipPath& path, const ImageInfo* imageInfo)
103a3e0fd82Sopenharmony_ci{
104a3e0fd82Sopenharmony_ci    RasterizerScanlineAntialias rasterizer;
105a3e0fd82Sopenharmony_ci    GeometryScanline scanline;
106a3e0fd82Sopenharmony_ci    TransAffine transform;
107a3e0fd82Sopenharmony_ci    UICanvasVertices& vertices = CloseVertices(path);
108a3e0fd82Sopenharmony_ci    UICanvasPath canvasPath(vertices);
109a3e0fd82Sopenharmony_ci    PathTransform pathTransform(canvasPath, transform);
110a3e0fd82Sopenharmony_ci    rasterizer.Reset();
111a3e0fd82Sopenharmony_ci    rasterizer.AddPath(pathTransform);
112a3e0fd82Sopenharmony_ci    if (!rasterizer.RewindScanlines()) {
113a3e0fd82Sopenharmony_ci        for (int32_t i = 0; i < imageInfo->header.height; i++) {
114a3e0fd82Sopenharmony_ci            DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo);
115a3e0fd82Sopenharmony_ci        }
116a3e0fd82Sopenharmony_ci        return;
117a3e0fd82Sopenharmony_ci    }
118a3e0fd82Sopenharmony_ci    scanline.Reset(rasterizer.GetMinX(), rasterizer.GetMaxX());
119a3e0fd82Sopenharmony_ci
120a3e0fd82Sopenharmony_ci    bool first = true;
121a3e0fd82Sopenharmony_ci    int16_t y = 0;
122a3e0fd82Sopenharmony_ci    while (rasterizer.SweepScanline(scanline)) {
123a3e0fd82Sopenharmony_ci        y = scanline.GetYLevel();
124a3e0fd82Sopenharmony_ci        if (first) {
125a3e0fd82Sopenharmony_ci            for (int32_t i = 0; i < y; i++) {
126a3e0fd82Sopenharmony_ci                DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo);
127a3e0fd82Sopenharmony_ci            }
128a3e0fd82Sopenharmony_ci            first = false;
129a3e0fd82Sopenharmony_ci        }
130a3e0fd82Sopenharmony_ci        uint32_t numSpans = scanline.NumSpans();
131a3e0fd82Sopenharmony_ci        GeometryScanline::ConstIterator span = scanline.Begin();
132a3e0fd82Sopenharmony_ci        int16_t index = 0;
133a3e0fd82Sopenharmony_ci        while (true) {
134a3e0fd82Sopenharmony_ci            int32_t x = span->x;
135a3e0fd82Sopenharmony_ci            int32_t len = span->spanLength;
136a3e0fd82Sopenharmony_ci            const uint8_t* covers = span->covers;
137a3e0fd82Sopenharmony_ci
138a3e0fd82Sopenharmony_ci            if (len < 0) {
139a3e0fd82Sopenharmony_ci                len = -len;
140a3e0fd82Sopenharmony_ci            }
141a3e0fd82Sopenharmony_ci            DrawHorLine(index, y, x - index - 1, OPA_TRANSPARENT, imageInfo);
142a3e0fd82Sopenharmony_ci            for (int16_t i = x; i < x + len; i++, covers++) {
143a3e0fd82Sopenharmony_ci                DrawPixel(i, y, *covers, imageInfo);
144a3e0fd82Sopenharmony_ci            }
145a3e0fd82Sopenharmony_ci            index = x + len;
146a3e0fd82Sopenharmony_ci            if (--numSpans == 0) {
147a3e0fd82Sopenharmony_ci                break;
148a3e0fd82Sopenharmony_ci            }
149a3e0fd82Sopenharmony_ci            ++span;
150a3e0fd82Sopenharmony_ci        }
151a3e0fd82Sopenharmony_ci        DrawHorLine(index, y, imageInfo->header.width - index, OPA_TRANSPARENT, imageInfo);
152a3e0fd82Sopenharmony_ci    }
153a3e0fd82Sopenharmony_ci
154a3e0fd82Sopenharmony_ci    for (int32_t i = y + 1; i < imageInfo->header.height; i++) {
155a3e0fd82Sopenharmony_ci        DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo);
156a3e0fd82Sopenharmony_ci    }
157a3e0fd82Sopenharmony_ci}
158a3e0fd82Sopenharmony_ci
159a3e0fd82Sopenharmony_civoid ClipUtils::DrawPixel(int16_t x, int16_t y, uint8_t opa, const ImageInfo* imageInfo)
160a3e0fd82Sopenharmony_ci{
161a3e0fd82Sopenharmony_ci    if (x < 0 || x > imageInfo->header.width - 1 || y < 0 || y > imageInfo->header.height - 1) {
162a3e0fd82Sopenharmony_ci        return;
163a3e0fd82Sopenharmony_ci    }
164a3e0fd82Sopenharmony_ci
165a3e0fd82Sopenharmony_ci    int32_t offset = imageInfo->header.width * y + x;
166a3e0fd82Sopenharmony_ci    switch (imageInfo->header.colorMode) {
167a3e0fd82Sopenharmony_ci        case ARGB8888: {
168a3e0fd82Sopenharmony_ci            Color32* buffer = reinterpret_cast<Color32*>(const_cast<uint8_t*>(imageInfo->data));
169a3e0fd82Sopenharmony_ci            buffer[offset].alpha = buffer[offset].alpha * opa / OPA_OPAQUE;
170a3e0fd82Sopenharmony_ci            break;
171a3e0fd82Sopenharmony_ci        }
172a3e0fd82Sopenharmony_ci        default: {
173a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("Only images in ARGB8888 format are supported!");
174a3e0fd82Sopenharmony_ci            break;
175a3e0fd82Sopenharmony_ci        }
176a3e0fd82Sopenharmony_ci    }
177a3e0fd82Sopenharmony_ci}
178a3e0fd82Sopenharmony_ci
179a3e0fd82Sopenharmony_civoid ClipUtils::DrawHorLine(int16_t x, int16_t y, int16_t width, uint8_t opa, const ImageInfo* imageInfo)
180a3e0fd82Sopenharmony_ci{
181a3e0fd82Sopenharmony_ci    for (int32_t i = x; i <= x + width; i++) {
182a3e0fd82Sopenharmony_ci        DrawPixel(i, y, opa, imageInfo);
183a3e0fd82Sopenharmony_ci    }
184a3e0fd82Sopenharmony_ci}
185a3e0fd82Sopenharmony_ci};
186