1/*
2 * Copyright (c) 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 "draw/draw_canvas.h"
17#include "common/typed_text.h"
18#include "draw/clip_utils.h"
19#include "gfx_utils/diagram/depiction/depict_curve.h"
20#include "gfx_utils/diagram/spancolorfill/fill_gradient.h"
21#include "gfx_utils/diagram/spancolorfill/fill_interpolator.h"
22
23namespace OHOS {
24/**
25 * Renders monochrome polygon paths and fills
26 */
27void RenderSolid(const Paint& paint, RasterizerScanlineAntialias& rasterizer, RenderBase& renBase, const bool& isStroke)
28{
29    GeometryScanline scanline;
30    Rgba8T color;
31    DrawCanvas::RenderBlendSolid(paint, color, isStroke);
32    RenderScanlinesAntiAliasSolid(rasterizer, scanline, renBase, color);
33}
34
35#if defined(ENABLE_CANVAS_EXTEND) && ENABLE_CANVAS_EXTEND
36void DrawCanvas::DoRender(BufferInfo& gfxDstBuffer,
37                          void* param,
38                          const Paint& paint,
39                          const Rect& rect,
40                          const Rect& invalidatedArea,
41                          const Style& style,
42                          const bool& isStroke)
43{
44    if (param == nullptr) {
45        return;
46    }
47#if defined(GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG) && GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG
48    if (paint.HaveShadow()) {
49        DrawCanvas::DoDrawShadow(gfxDstBuffer, param, paint, rect, invalidatedArea, style, isStroke);
50    }
51#endif
52    TransAffine transform;
53    RenderBuffer renderBuffer;
54    InitRenderAndTransform(gfxDstBuffer, renderBuffer, rect, transform, style, paint);
55
56    RasterizerScanlineAntialias rasterizer;
57    GeometryScanline scanline;
58
59    PathParam* pathParam = static_cast<PathParam*>(param);
60    rasterizer.ClipBox(0, 0, gfxDstBuffer.width, gfxDstBuffer.height);
61    SetRasterizer(*pathParam->vertices, paint, rasterizer, transform, isStroke);
62
63    RenderPixfmtRgbaBlend pixFormat(renderBuffer);
64    RenderBase renBase(pixFormat);
65    FillBase allocator;
66
67    renBase.ResetClipping(true);
68    renBase.ClipBox(invalidatedArea.GetLeft(), invalidatedArea.GetTop(), invalidatedArea.GetRight(),
69                    invalidatedArea.GetBottom());
70
71    if (paint.GetStyle() == Paint::STROKE_STYLE || paint.GetStyle() == Paint::FILL_STYLE ||
72        paint.GetStyle() == Paint::STROKE_FILL_STYLE) {
73        RenderSolid(paint, rasterizer, renBase, isStroke);
74    }
75
76#if defined(GRAPHIC_ENABLE_GRADIENT_FILL_FLAG) && GRAPHIC_ENABLE_GRADIENT_FILL_FLAG
77    if (paint.GetStyle() == Paint::GRADIENT) {
78        RenderGradient(paint, rasterizer, transform, renBase, renderBuffer, allocator, invalidatedArea);
79    }
80#endif
81#if defined(GRAPHIC_ENABLE_PATTERN_FILL_FLAG) && GRAPHIC_ENABLE_PATTERN_FILL_FLAG
82    if (paint.GetStyle() == Paint::PATTERN) {
83        RenderPattern(paint, pathParam->imageParam, rasterizer, renBase, allocator, rect);
84    }
85#endif
86}
87
88#if defined(GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG) && GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG
89void DrawCanvas::DoDrawShadow(BufferInfo& gfxDstBuffer,
90                              void* param,
91                              const Paint& paint,
92                              const Rect& rect,
93                              const Rect& invalidatedArea,
94                              const Style& style,
95                              const bool& isStroke)
96{
97    if (param == nullptr) {
98        return;
99    }
100
101    TransAffine transform;
102    RenderBuffer renderBuffer;
103    DrawCanvas::InitRenderAndTransform(gfxDstBuffer, renderBuffer, rect, transform, style, paint);
104
105    transform.Translate(paint.GetShadowOffsetX(), paint.GetShadowOffsetY());
106
107    RasterizerScanlineAntialias rasterizer;
108    GeometryScanline scanline;
109    PathParam* pathParam = static_cast<PathParam*>(param);
110    rasterizer.ClipBox(0, 0, gfxDstBuffer.width, gfxDstBuffer.height);
111    DrawCanvas::SetRasterizer(*pathParam->vertices, paint, rasterizer, transform, isStroke);
112    Rect bbox(rasterizer.GetMinX(), rasterizer.GetMinY(), rasterizer.GetMaxX(), rasterizer.GetMaxY());
113
114    RenderPixfmtRgbaBlend pixFormat(renderBuffer);
115    RenderBase renBase(pixFormat);
116    FillBase allocator;
117
118    renBase.ResetClipping(true);
119    renBase.ClipBox(invalidatedArea.GetLeft(), invalidatedArea.GetTop(), invalidatedArea.GetRight(),
120                    invalidatedArea.GetBottom());
121
122    Rgba8T shadowColor;
123    DrawCanvas::ChangeColor(shadowColor, paint.GetShadowColor(), paint.GetShadowColor().alpha * paint.GetGlobalAlpha());
124
125    RenderScanlinesAntiAliasSolid(rasterizer, scanline, renBase, shadowColor);
126#if GRAPHIC_ENABLE_BLUR_EFFECT_FLAG
127    bbox.SetLeft(bbox.GetLeft() - paint.GetShadowBlur());
128    bbox.SetTop(bbox.GetTop() - paint.GetShadowBlur());
129    bbox.SetRight(bbox.GetRight() + paint.GetShadowBlur());
130    bbox.SetBottom(bbox.GetBottom() + paint.GetShadowBlur());
131    RenderBuffer shadowBuffer;
132    RenderPixfmtRgbaBlend pixf2(shadowBuffer);
133    Rect shadowRect = {int16_t(bbox.GetLeft()), int16_t(bbox.GetTop()), int16_t(bbox.GetRight()),
134                       int16_t(bbox.GetBottom())};
135    shadowRect.Intersect(shadowRect, invalidatedArea);
136    pixf2.Attach(pixFormat, shadowRect.GetLeft(), shadowRect.GetTop(), shadowRect.GetRight(), shadowRect.GetBottom());
137    uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(gfxDstBuffer.mode) >> 3; // 3: Shift right 3 bits
138
139    paint.GetDrawBoxBlur().BoxBlur(pixf2, MATH_UROUND(paint.GetShadowBlur()), pixelByteSize, gfxDstBuffer.stride);
140
141#endif // GRAPHIC_ENABLE_BLUR_EFFECT_FLAG
142}
143#endif // GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG
144#endif // ENABLE_CANVAS_EXTEND
145
146void DrawCanvas::InitRenderAndTransform(BufferInfo& gfxDstBuffer,
147                                        RenderBuffer& renderBuffer,
148                                        const Rect& rect,
149                                        TransAffine& transform,
150                                        const Style& style,
151                                        const Paint& paint)
152{
153    int16_t realLeft = rect.GetLeft() + style.paddingLeft_ + style.borderWidth_;
154    int16_t realTop = rect.GetTop() + style.paddingTop_ + style.borderWidth_;
155    transform.Reset();
156    transform *= paint.GetTransAffine();
157    transform.Translate(realLeft, realTop);
158    renderBuffer.Attach(static_cast<uint8_t*>(gfxDstBuffer.virAddr), gfxDstBuffer.width, gfxDstBuffer.height,
159                        gfxDstBuffer.stride);
160}
161
162void DrawCanvas::SetRasterizer(UICanvasVertices& vertices,
163                               const Paint& paint,
164                               RasterizerScanlineAntialias& rasterizer,
165                               TransAffine& transform,
166                               const bool& isStroke)
167{
168    DepictCurve canvasPath(vertices);
169    if (isStroke) {
170#if defined(GRAPHIC_ENABLE_DASH_GENERATE_FLAG) && GRAPHIC_ENABLE_DASH_GENERATE_FLAG
171        if (paint.IsLineDash()) {
172            using DashStyle = DepictDash;
173            using StrokeDashStyle = DepictStroke<DashStyle>;
174            using StrokeDashTransform = DepictTransform<StrokeDashStyle>;
175            DashStyle dashStyle(canvasPath);
176            LineDashStyleCalc(dashStyle, paint);
177            StrokeDashStyle strokeDashStyle(dashStyle);
178            LineStyleCalc(strokeDashStyle, paint);
179            StrokeDashTransform strokeDashTransform(strokeDashStyle, transform);
180            rasterizer.Reset();
181            rasterizer.AddPath(strokeDashTransform);
182            return;
183        }
184#endif
185        using StrokeLineStyle = DepictStroke<DepictCurve>;
186        StrokeLineStyle strokeLineStyle(canvasPath);
187        LineStyleCalc(strokeLineStyle, paint);
188
189        DepictTransform<StrokeLineStyle> strokeTransform(strokeLineStyle, transform);
190        rasterizer.Reset();
191        rasterizer.AddPath(strokeTransform);
192    } else {
193        DepictTransform<DepictCurve> pathTransform(canvasPath, transform);
194        rasterizer.Reset();
195        rasterizer.AddPath(pathTransform);
196    }
197}
198
199#if defined(GRAPHIC_ENABLE_GRADIENT_FILL_FLAG) && GRAPHIC_ENABLE_GRADIENT_FILL_FLAG
200void DrawCanvas::RenderGradient(const Paint& paint,
201                                RasterizerScanlineAntialias& rasterizer,
202                                TransAffine& transform,
203                                RenderBase& renBase,
204                                RenderBuffer& renderBuffer,
205                                FillBase& allocator,
206                                const Rect& invalidatedArea)
207{
208    GeometryScanline scanline;
209
210    RenderPixfmtRgbaBlend pixFormatComp(renderBuffer);
211    RenderBase m_renBaseComp(pixFormatComp);
212
213    m_renBaseComp.ResetClipping(true);
214    m_renBaseComp.ClipBox(invalidatedArea.GetLeft(), invalidatedArea.GetTop(), invalidatedArea.GetRight(),
215                          invalidatedArea.GetBottom());
216    TransAffine gradientMatrix;
217    FillInterpolator interpolatorType(gradientMatrix);
218    FillGradientLut gradientColorMode;
219    BuildGradientColor(paint, gradientColorMode);
220    if (paint.GetGradient() == Paint::Linear) {
221        float distance = 0;
222        BuildLineGradientMatrix(paint, gradientMatrix, transform, distance);
223        GradientLinearCalculate gradientLinearCalculate;
224        FillGradient span(interpolatorType, gradientLinearCalculate, gradientColorMode, 0, distance);
225        RenderScanlinesAntiAlias(rasterizer, scanline, renBase, allocator, span);
226    }
227
228    if (paint.GetGradient() == Paint::Radial) {
229        Paint::RadialGradientPoint radialPoint = paint.GetRadialGradientPoint();
230        float startRadius = 0;
231        float endRadius = 0;
232        BuildRadialGradientMatrix(paint, gradientMatrix, transform, startRadius, endRadius);
233        GradientRadialCalculate gradientRadialCalculate(radialPoint.r1, radialPoint.x0 - radialPoint.x1,
234                                                        radialPoint.y0 - radialPoint.y1);
235        FillGradient span(interpolatorType, gradientRadialCalculate, gradientColorMode, startRadius, endRadius);
236        RenderScanlinesAntiAlias(rasterizer, scanline, renBase, allocator, span);
237    }
238}
239
240void DrawCanvas::BuildGradientColor(const Paint& paint, FillGradientLut& gradientColorMode)
241{
242    gradientColorMode.RemoveAll();
243    ListNode<Paint::StopAndColor>* iter = paint.getStopAndColor().Begin();
244    uint16_t count = 0;
245    for (; count < paint.getStopAndColor().Size(); count++) {
246        ColorType stopColor = iter->data_.color;
247        Rgba8T sRgba8;
248        ChangeColor(sRgba8, stopColor, stopColor.alpha * paint.GetGlobalAlpha());
249        gradientColorMode.AddColor(iter->data_.stop, sRgba8);
250        iter = iter->next_;
251    }
252    gradientColorMode.BuildLut();
253}
254
255void DrawCanvas::BuildRadialGradientMatrix(const Paint& paint,
256                                           TransAffine& gradientMatrix,
257                                           TransAffine& transform,
258                                           float& startRadius,
259                                           float& endRadius)
260{
261    Paint::RadialGradientPoint radialPoint = paint.GetRadialGradientPoint();
262    gradientMatrix.Reset();
263    gradientMatrix *= TransAffine::TransAffineTranslation(radialPoint.x1, radialPoint.y1);
264    gradientMatrix *= transform;
265    gradientMatrix.Invert();
266    startRadius = radialPoint.r0;
267    endRadius = radialPoint.r1;
268}
269#endif // GRAPHIC_ENABLE_GRADIENT_FILL_FLAG
270
271#if defined(GRAPHIC_ENABLE_PATTERN_FILL_FLAG) && GRAPHIC_ENABLE_PATTERN_FILL_FLAG
272#if defined(ENABLE_CANVAS_EXTEND) && ENABLE_CANVAS_EXTEND
273void DrawCanvas::RenderPattern(const Paint& paint,
274                               void* param,
275                               RasterizerScanlineAntialias& rasterizer,
276                               RenderBase& renBase,
277                               FillBase& allocator,
278                               const Rect& rect)
279{
280    if (param == nullptr) {
281        return;
282    }
283    ImageParam* imageParam = static_cast<ImageParam*>(param);
284    if (imageParam->image == nullptr) {
285        return;
286    }
287    GeometryScanline scanline;
288    FillPatternRgba spanPattern(imageParam->image->GetImageInfo(), paint.GetPatternRepeatMode(), rect.GetLeft(),
289                                rect.GetTop());
290    RenderScanlinesAntiAlias(rasterizer, scanline, renBase, allocator, spanPattern);
291}
292#endif
293#endif // GRAPHIC_ENABLE_PATTERN_FILL_FLAG
294
295} // namespace OHOS
296