/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "draw/draw_canvas.h" #include "common/typed_text.h" #include "draw/clip_utils.h" #include "gfx_utils/diagram/depiction/depict_curve.h" #include "gfx_utils/diagram/spancolorfill/fill_gradient.h" #include "gfx_utils/diagram/spancolorfill/fill_interpolator.h" namespace OHOS { /** * Renders monochrome polygon paths and fills */ void RenderSolid(const Paint& paint, RasterizerScanlineAntialias& rasterizer, RenderBase& renBase, const bool& isStroke) { GeometryScanline scanline; Rgba8T color; DrawCanvas::RenderBlendSolid(paint, color, isStroke); RenderScanlinesAntiAliasSolid(rasterizer, scanline, renBase, color); } #if defined(ENABLE_CANVAS_EXTEND) && ENABLE_CANVAS_EXTEND void DrawCanvas::DoRender(BufferInfo& gfxDstBuffer, void* param, const Paint& paint, const Rect& rect, const Rect& invalidatedArea, const Style& style, const bool& isStroke) { if (param == nullptr) { return; } #if defined(GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG) && GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG if (paint.HaveShadow()) { DrawCanvas::DoDrawShadow(gfxDstBuffer, param, paint, rect, invalidatedArea, style, isStroke); } #endif TransAffine transform; RenderBuffer renderBuffer; InitRenderAndTransform(gfxDstBuffer, renderBuffer, rect, transform, style, paint); RasterizerScanlineAntialias rasterizer; GeometryScanline scanline; PathParam* pathParam = static_cast(param); rasterizer.ClipBox(0, 0, gfxDstBuffer.width, gfxDstBuffer.height); SetRasterizer(*pathParam->vertices, paint, rasterizer, transform, isStroke); RenderPixfmtRgbaBlend pixFormat(renderBuffer); RenderBase renBase(pixFormat); FillBase allocator; renBase.ResetClipping(true); renBase.ClipBox(invalidatedArea.GetLeft(), invalidatedArea.GetTop(), invalidatedArea.GetRight(), invalidatedArea.GetBottom()); if (paint.GetStyle() == Paint::STROKE_STYLE || paint.GetStyle() == Paint::FILL_STYLE || paint.GetStyle() == Paint::STROKE_FILL_STYLE) { RenderSolid(paint, rasterizer, renBase, isStroke); } #if defined(GRAPHIC_ENABLE_GRADIENT_FILL_FLAG) && GRAPHIC_ENABLE_GRADIENT_FILL_FLAG if (paint.GetStyle() == Paint::GRADIENT) { RenderGradient(paint, rasterizer, transform, renBase, renderBuffer, allocator, invalidatedArea); } #endif #if defined(GRAPHIC_ENABLE_PATTERN_FILL_FLAG) && GRAPHIC_ENABLE_PATTERN_FILL_FLAG if (paint.GetStyle() == Paint::PATTERN) { RenderPattern(paint, pathParam->imageParam, rasterizer, renBase, allocator, rect); } #endif } #if defined(GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG) && GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG void DrawCanvas::DoDrawShadow(BufferInfo& gfxDstBuffer, void* param, const Paint& paint, const Rect& rect, const Rect& invalidatedArea, const Style& style, const bool& isStroke) { if (param == nullptr) { return; } TransAffine transform; RenderBuffer renderBuffer; DrawCanvas::InitRenderAndTransform(gfxDstBuffer, renderBuffer, rect, transform, style, paint); transform.Translate(paint.GetShadowOffsetX(), paint.GetShadowOffsetY()); RasterizerScanlineAntialias rasterizer; GeometryScanline scanline; PathParam* pathParam = static_cast(param); rasterizer.ClipBox(0, 0, gfxDstBuffer.width, gfxDstBuffer.height); DrawCanvas::SetRasterizer(*pathParam->vertices, paint, rasterizer, transform, isStroke); Rect bbox(rasterizer.GetMinX(), rasterizer.GetMinY(), rasterizer.GetMaxX(), rasterizer.GetMaxY()); RenderPixfmtRgbaBlend pixFormat(renderBuffer); RenderBase renBase(pixFormat); FillBase allocator; renBase.ResetClipping(true); renBase.ClipBox(invalidatedArea.GetLeft(), invalidatedArea.GetTop(), invalidatedArea.GetRight(), invalidatedArea.GetBottom()); Rgba8T shadowColor; DrawCanvas::ChangeColor(shadowColor, paint.GetShadowColor(), paint.GetShadowColor().alpha * paint.GetGlobalAlpha()); RenderScanlinesAntiAliasSolid(rasterizer, scanline, renBase, shadowColor); #if GRAPHIC_ENABLE_BLUR_EFFECT_FLAG bbox.SetLeft(bbox.GetLeft() - paint.GetShadowBlur()); bbox.SetTop(bbox.GetTop() - paint.GetShadowBlur()); bbox.SetRight(bbox.GetRight() + paint.GetShadowBlur()); bbox.SetBottom(bbox.GetBottom() + paint.GetShadowBlur()); RenderBuffer shadowBuffer; RenderPixfmtRgbaBlend pixf2(shadowBuffer); Rect shadowRect = {int16_t(bbox.GetLeft()), int16_t(bbox.GetTop()), int16_t(bbox.GetRight()), int16_t(bbox.GetBottom())}; shadowRect.Intersect(shadowRect, invalidatedArea); pixf2.Attach(pixFormat, shadowRect.GetLeft(), shadowRect.GetTop(), shadowRect.GetRight(), shadowRect.GetBottom()); uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(gfxDstBuffer.mode) >> 3; // 3: Shift right 3 bits paint.GetDrawBoxBlur().BoxBlur(pixf2, MATH_UROUND(paint.GetShadowBlur()), pixelByteSize, gfxDstBuffer.stride); #endif // GRAPHIC_ENABLE_BLUR_EFFECT_FLAG } #endif // GRAPHIC_ENABLE_SHADOW_EFFECT_FLAG #endif // ENABLE_CANVAS_EXTEND void DrawCanvas::InitRenderAndTransform(BufferInfo& gfxDstBuffer, RenderBuffer& renderBuffer, const Rect& rect, TransAffine& transform, const Style& style, const Paint& paint) { int16_t realLeft = rect.GetLeft() + style.paddingLeft_ + style.borderWidth_; int16_t realTop = rect.GetTop() + style.paddingTop_ + style.borderWidth_; transform.Reset(); transform *= paint.GetTransAffine(); transform.Translate(realLeft, realTop); renderBuffer.Attach(static_cast(gfxDstBuffer.virAddr), gfxDstBuffer.width, gfxDstBuffer.height, gfxDstBuffer.stride); } void DrawCanvas::SetRasterizer(UICanvasVertices& vertices, const Paint& paint, RasterizerScanlineAntialias& rasterizer, TransAffine& transform, const bool& isStroke) { DepictCurve canvasPath(vertices); if (isStroke) { #if defined(GRAPHIC_ENABLE_DASH_GENERATE_FLAG) && GRAPHIC_ENABLE_DASH_GENERATE_FLAG if (paint.IsLineDash()) { using DashStyle = DepictDash; using StrokeDashStyle = DepictStroke; using StrokeDashTransform = DepictTransform; DashStyle dashStyle(canvasPath); LineDashStyleCalc(dashStyle, paint); StrokeDashStyle strokeDashStyle(dashStyle); LineStyleCalc(strokeDashStyle, paint); StrokeDashTransform strokeDashTransform(strokeDashStyle, transform); rasterizer.Reset(); rasterizer.AddPath(strokeDashTransform); return; } #endif using StrokeLineStyle = DepictStroke; StrokeLineStyle strokeLineStyle(canvasPath); LineStyleCalc(strokeLineStyle, paint); DepictTransform strokeTransform(strokeLineStyle, transform); rasterizer.Reset(); rasterizer.AddPath(strokeTransform); } else { DepictTransform pathTransform(canvasPath, transform); rasterizer.Reset(); rasterizer.AddPath(pathTransform); } } #if defined(GRAPHIC_ENABLE_GRADIENT_FILL_FLAG) && GRAPHIC_ENABLE_GRADIENT_FILL_FLAG void DrawCanvas::RenderGradient(const Paint& paint, RasterizerScanlineAntialias& rasterizer, TransAffine& transform, RenderBase& renBase, RenderBuffer& renderBuffer, FillBase& allocator, const Rect& invalidatedArea) { GeometryScanline scanline; RenderPixfmtRgbaBlend pixFormatComp(renderBuffer); RenderBase m_renBaseComp(pixFormatComp); m_renBaseComp.ResetClipping(true); m_renBaseComp.ClipBox(invalidatedArea.GetLeft(), invalidatedArea.GetTop(), invalidatedArea.GetRight(), invalidatedArea.GetBottom()); TransAffine gradientMatrix; FillInterpolator interpolatorType(gradientMatrix); FillGradientLut gradientColorMode; BuildGradientColor(paint, gradientColorMode); if (paint.GetGradient() == Paint::Linear) { float distance = 0; BuildLineGradientMatrix(paint, gradientMatrix, transform, distance); GradientLinearCalculate gradientLinearCalculate; FillGradient span(interpolatorType, gradientLinearCalculate, gradientColorMode, 0, distance); RenderScanlinesAntiAlias(rasterizer, scanline, renBase, allocator, span); } if (paint.GetGradient() == Paint::Radial) { Paint::RadialGradientPoint radialPoint = paint.GetRadialGradientPoint(); float startRadius = 0; float endRadius = 0; BuildRadialGradientMatrix(paint, gradientMatrix, transform, startRadius, endRadius); GradientRadialCalculate gradientRadialCalculate(radialPoint.r1, radialPoint.x0 - radialPoint.x1, radialPoint.y0 - radialPoint.y1); FillGradient span(interpolatorType, gradientRadialCalculate, gradientColorMode, startRadius, endRadius); RenderScanlinesAntiAlias(rasterizer, scanline, renBase, allocator, span); } } void DrawCanvas::BuildGradientColor(const Paint& paint, FillGradientLut& gradientColorMode) { gradientColorMode.RemoveAll(); ListNode* iter = paint.getStopAndColor().Begin(); uint16_t count = 0; for (; count < paint.getStopAndColor().Size(); count++) { ColorType stopColor = iter->data_.color; Rgba8T sRgba8; ChangeColor(sRgba8, stopColor, stopColor.alpha * paint.GetGlobalAlpha()); gradientColorMode.AddColor(iter->data_.stop, sRgba8); iter = iter->next_; } gradientColorMode.BuildLut(); } void DrawCanvas::BuildRadialGradientMatrix(const Paint& paint, TransAffine& gradientMatrix, TransAffine& transform, float& startRadius, float& endRadius) { Paint::RadialGradientPoint radialPoint = paint.GetRadialGradientPoint(); gradientMatrix.Reset(); gradientMatrix *= TransAffine::TransAffineTranslation(radialPoint.x1, radialPoint.y1); gradientMatrix *= transform; gradientMatrix.Invert(); startRadius = radialPoint.r0; endRadius = radialPoint.r1; } #endif // GRAPHIC_ENABLE_GRADIENT_FILL_FLAG #if defined(GRAPHIC_ENABLE_PATTERN_FILL_FLAG) && GRAPHIC_ENABLE_PATTERN_FILL_FLAG #if defined(ENABLE_CANVAS_EXTEND) && ENABLE_CANVAS_EXTEND void DrawCanvas::RenderPattern(const Paint& paint, void* param, RasterizerScanlineAntialias& rasterizer, RenderBase& renBase, FillBase& allocator, const Rect& rect) { if (param == nullptr) { return; } ImageParam* imageParam = static_cast(param); if (imageParam->image == nullptr) { return; } GeometryScanline scanline; FillPatternRgba spanPattern(imageParam->image->GetImageInfo(), paint.GetPatternRepeatMode(), rect.GetLeft(), rect.GetTop()); RenderScanlinesAntiAlias(rasterizer, scanline, renBase, allocator, spanPattern); } #endif #endif // GRAPHIC_ENABLE_PATTERN_FILL_FLAG } // namespace OHOS