1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "clip_utils.h"
17 #include "draw_utils.h"
18 #include "gfx_utils/diagram/depiction/depict_curve.h"
19 #include "gfx_utils/diagram/rasterizer/rasterizer_scanline_antialias.h"
20 #include "gfx_utils/diagram/scanline/geometry_scanline.h"
21 #include "gfx_utils/diagram/spancolorfill/fill_base.h"
22 #include "gfx_utils/diagram/spancolorfill/fill_pattern_rgba.h"
23 #include "gfx_utils/graphic_log.h"
24 #include "render/render_base.h"
25 #include "render/render_pixfmt_rgba_blend.h"
26 
27 namespace OHOS {
28 using UICanvasPath = DepictCurve;
29 using PathTransform = DepictTransform<UICanvasPath>;
30 
MoveTo(const PointF & point)31 ClipPath& ClipPath::MoveTo(const PointF& point)
32 {
33     vertices_->MoveTo(point.x, point.y);
34     return *this;
35 }
36 
LineTo(const PointF & point)37 ClipPath& ClipPath::LineTo(const PointF& point)
38 {
39     if (vertices_->GetTotalVertices() != 0) {
40         vertices_->LineTo(point.x, point.y);
41     } else {
42         vertices_->MoveTo(point.x, point.y);
43     }
44     return *this;
45 }
46 
CurveTo(const PointF & control1,const PointF & control2,const PointF & end)47 ClipPath& ClipPath::CurveTo(const PointF& control1, const PointF& control2, const PointF& end)
48 {
49     vertices_->CubicBezierCurve(control1.x, control1.y, control2.x, control2.y, end.x, end.y);
50     return *this;
51 }
52 
Arc(const PointF & center,float radius,int16_t startAngle,int16_t endAngle)53 ClipPath& ClipPath::Arc(const PointF& center, float radius, int16_t startAngle, int16_t endAngle)
54 {
55     if (startAngle == endAngle) {
56         return *this;
57     }
58     float sinma = radius * Sin(startAngle);
59     float cosma = radius * Sin(QUARTER_IN_DEGREE - startAngle);
60     if (vertices_->GetTotalVertices() != 0) {
61         vertices_->LineTo(float(center.x + sinma), float(center.y - cosma));
62     } else {
63         vertices_->MoveTo(float(center.x + sinma), float(center.y - cosma));
64     }
65     if (MATH_ABS(startAngle - endAngle) < CIRCLE_IN_DEGREE) {
66         sinma = radius * Sin(endAngle);
67         cosma = radius * Sin(QUARTER_IN_DEGREE - endAngle);
68     } else {
69         Circle(center, radius);
70         return *this;
71     }
72 
73     int16_t angle = endAngle - startAngle;
74     bool largeArcFlag = false;
75     if (angle > SEMICIRCLE_IN_DEGREE || angle <= 0) {
76         largeArcFlag = true;
77     }
78     vertices_->ArcTo(radius, radius, angle, largeArcFlag, 1, center.x + sinma, center.y - cosma);
79     return *this;
80 }
81 
Circle(const PointF & center,float radius)82 ClipPath& ClipPath::Circle(const PointF& center, float radius)
83 {
84     if (radius <= 0) {
85         return *this;
86     }
87     vertices_->RemoveAll();
88 #if defined(GRAPHIC_ENABLE_BEZIER_ARC_FLAG) && GRAPHIC_ENABLE_BEZIER_ARC_FLAG
89     BezierArc arc(center.x, center.y, radius, radius, 0, TWO_TIMES * PI);
90     vertices_->ConcatPath(arc, 0);
91 #endif
92     return *this;
93 }
94 
CloseVertices(const ClipPath & path)95 UICanvasVertices& ClipUtils::CloseVertices(const ClipPath& path)
96 {
97     UICanvasVertices& vertices = path.GetVertices();
98     vertices.ClosePolygon();
99     return vertices;
100 }
101 
PerformScan(const ClipPath & path,const ImageInfo * imageInfo)102 void ClipUtils::PerformScan(const ClipPath& path, const ImageInfo* imageInfo)
103 {
104     RasterizerScanlineAntialias rasterizer;
105     GeometryScanline scanline;
106     TransAffine transform;
107     UICanvasVertices& vertices = CloseVertices(path);
108     UICanvasPath canvasPath(vertices);
109     PathTransform pathTransform(canvasPath, transform);
110     rasterizer.Reset();
111     rasterizer.AddPath(pathTransform);
112     if (!rasterizer.RewindScanlines()) {
113         for (int32_t i = 0; i < imageInfo->header.height; i++) {
114             DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo);
115         }
116         return;
117     }
118     scanline.Reset(rasterizer.GetMinX(), rasterizer.GetMaxX());
119 
120     bool first = true;
121     int16_t y = 0;
122     while (rasterizer.SweepScanline(scanline)) {
123         y = scanline.GetYLevel();
124         if (first) {
125             for (int32_t i = 0; i < y; i++) {
126                 DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo);
127             }
128             first = false;
129         }
130         uint32_t numSpans = scanline.NumSpans();
131         GeometryScanline::ConstIterator span = scanline.Begin();
132         int16_t index = 0;
133         while (true) {
134             int32_t x = span->x;
135             int32_t len = span->spanLength;
136             const uint8_t* covers = span->covers;
137 
138             if (len < 0) {
139                 len = -len;
140             }
141             DrawHorLine(index, y, x - index - 1, OPA_TRANSPARENT, imageInfo);
142             for (int16_t i = x; i < x + len; i++, covers++) {
143                 DrawPixel(i, y, *covers, imageInfo);
144             }
145             index = x + len;
146             if (--numSpans == 0) {
147                 break;
148             }
149             ++span;
150         }
151         DrawHorLine(index, y, imageInfo->header.width - index, OPA_TRANSPARENT, imageInfo);
152     }
153 
154     for (int32_t i = y + 1; i < imageInfo->header.height; i++) {
155         DrawHorLine(0, i, imageInfo->header.width, OPA_TRANSPARENT, imageInfo);
156     }
157 }
158 
DrawPixel(int16_t x,int16_t y,uint8_t opa,const ImageInfo * imageInfo)159 void ClipUtils::DrawPixel(int16_t x, int16_t y, uint8_t opa, const ImageInfo* imageInfo)
160 {
161     if (x < 0 || x > imageInfo->header.width - 1 || y < 0 || y > imageInfo->header.height - 1) {
162         return;
163     }
164 
165     int32_t offset = imageInfo->header.width * y + x;
166     switch (imageInfo->header.colorMode) {
167         case ARGB8888: {
168             Color32* buffer = reinterpret_cast<Color32*>(const_cast<uint8_t*>(imageInfo->data));
169             buffer[offset].alpha = buffer[offset].alpha * opa / OPA_OPAQUE;
170             break;
171         }
172         default: {
173             GRAPHIC_LOGE("Only images in ARGB8888 format are supported!");
174             break;
175         }
176     }
177 }
178 
DrawHorLine(int16_t x,int16_t y,int16_t width,uint8_t opa,const ImageInfo * imageInfo)179 void ClipUtils::DrawHorLine(int16_t x, int16_t y, int16_t width, uint8_t opa, const ImageInfo* imageInfo)
180 {
181     for (int32_t i = x; i <= x + width; i++) {
182         DrawPixel(i, y, opa, imageInfo);
183     }
184 }
185 };
186