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