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 
23 namespace OHOS {
24 /**
25  * Renders monochrome polygon paths and fills
26  */
RenderSolid(const Paint & paint,RasterizerScanlineAntialias & rasterizer,RenderBase & renBase,const bool & isStroke)27 void 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
DoRender(BufferInfo & gfxDstBuffer,void * param,const Paint & paint,const Rect & rect,const Rect & invalidatedArea,const Style & style,const bool & isStroke)36 void 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
DoDrawShadow(BufferInfo & gfxDstBuffer,void * param,const Paint & paint,const Rect & rect,const Rect & invalidatedArea,const Style & style,const bool & isStroke)89 void 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 
InitRenderAndTransform(BufferInfo & gfxDstBuffer,RenderBuffer & renderBuffer,const Rect & rect,TransAffine & transform,const Style & style,const Paint & paint)146 void 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 
SetRasterizer(UICanvasVertices & vertices,const Paint & paint,RasterizerScanlineAntialias & rasterizer,TransAffine & transform,const bool & isStroke)162 void 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
RenderGradient(const Paint & paint,RasterizerScanlineAntialias & rasterizer,TransAffine & transform,RenderBase & renBase,RenderBuffer & renderBuffer,FillBase & allocator,const Rect & invalidatedArea)200 void 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 
BuildGradientColor(const Paint & paint,FillGradientLut & gradientColorMode)240 void 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 
BuildRadialGradientMatrix(const Paint & paint,TransAffine & gradientMatrix,TransAffine & transform,float & startRadius,float & endRadius)255 void 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
RenderPattern(const Paint & paint,void * param,RasterizerScanlineAntialias & rasterizer,RenderBase & renBase,FillBase & allocator,const Rect & rect)273 void 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