* 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<PathParam*>(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<PathParam*>(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;
paint.GetDrawBoxBlur().BoxBlur(pixf2, MATH_UROUND(paint.GetShadowBlur()), pixelByteSize, gfxDstBuffer.stride);
#endif
}
#endif
#endif
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<uint8_t*>(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<DashStyle>;
using StrokeDashTransform = DepictTransform<StrokeDashStyle>;
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<DepictCurve>;
StrokeLineStyle strokeLineStyle(canvasPath);
LineStyleCalc(strokeLineStyle, paint);
DepictTransform<StrokeLineStyle> strokeTransform(strokeLineStyle, transform);
rasterizer.Reset();
rasterizer.AddPath(strokeTransform);
} else {
DepictTransform<DepictCurve> 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<Paint::StopAndColor>* 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
#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<ImageParam*>(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
}