/*
 * Copyright (c) 2020-2021 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_rect.h"
#include "draw/draw_utils.h"
#include "engines/gfx/gfx_engine_manager.h"
#include "gfx_utils/graphic_log.h"
#include "gfx_utils/graphic_math.h"
#include "gfx_utils/style.h"

namespace OHOS {
void DrawRect::Draw(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                    const Style& style, OpacityType opaScale)
{
    if ((rect.GetWidth() <= 0) || (rect.GetHeight() <= 0)) {
        GRAPHIC_LOGD("DrawRect::Draw width or height is zero\n");
        return;
    }

    /**
     * no border
     *      radius = 0 (1/4)
     *      radius > 0 (2/4)
     *          rect width > rect height
     *              radius >= rect height / 2
     *              radius < rect height / 2
     *          rect width <= rect height
     *              radius >= rect width / 2
     *              radius < rect width / 2
     * have border
     *      radius = 0 (3/4)
     *      radius > 0 (4/4)
     *          radius < border width (4.1/4)
     *          radius = border width (4.2/4)
     *          radius > border width (4.3/4)
     *             rect width <= rect height
     *                  radius >= border width + rect height / 2
     *                  radius < border width + rect height / 2
     *             rect width > rect height
     *                  radius >= border width + rect height / 2
     *                  radius < border width + rect height / 2
     */
    if (style.borderWidth_ == 0) {
        if (style.borderRadius_ == 0) {
            /* no border no radius (1/4) */
            OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
            DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, rect, dirtyRect, style.bgColor_, opa);
            return;
        } else {
            /* [2/4] no border with radius (2/4) */
            DrawRectRadiusWithoutBorder(gfxDstBuffer, rect, dirtyRect, style, opaScale);
        }
    } else {
        if (style.borderRadius_ == 0) {
            /* [3/4] border without radius (3/4) */
            DrawRectBorderWithoutRadius(gfxDstBuffer, rect, dirtyRect, style, opaScale);
        } else if (style.borderRadius_ < style.borderWidth_) {
            /* [4.1/4] radius < border width */
            DrawRectRadiusSmallThanBorder(gfxDstBuffer, rect, dirtyRect, style, opaScale);
        } else if (style.borderRadius_ == style.borderWidth_) {
            /* [4.2/4] radius = border width */
            DrawRectRadiusEqualBorder(gfxDstBuffer, rect, dirtyRect, style, opaScale);
        } else {
            /* [4.3/4] radius >= border width + rect height_or_width / 2 */
            DrawRectRadiusBiggerThanBorder(gfxDstBuffer, rect, dirtyRect, style, opaScale);
        }
    }
}

void DrawRect::DrawRectRadiusWithoutBorder(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                           const Style& style, OpacityType opaScale)
{
    // 2 : half
    if ((rect.GetWidth() > rect.GetHeight()) && (style.borderRadius_ >= rect.GetHeight() / 2)) {
        DrawRectRadiusWithoutBorderCon1(gfxDstBuffer, rect, dirtyRect, style, opaScale);
    } else if ((rect.GetWidth() < rect.GetHeight()) && (style.borderRadius_ >= rect.GetWidth() / 2)) {
        DrawRectRadiusWithoutBorderCon2(gfxDstBuffer, rect, dirtyRect, style, opaScale);
    } else if ((rect.GetWidth() == rect.GetHeight()) && (style.borderRadius_ >= rect.GetWidth() / 2)) {
        DrawRectRadiusWithoutBorderCon3(gfxDstBuffer, rect, dirtyRect, style, opaScale);
    } else {
        DrawRectRadiusWithoutBorderCon4(gfxDstBuffer, rect, dirtyRect, style, opaScale);
    }
}

void DrawRect::DrawRectRadiusWithoutBorderCon1(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                               const Style& style, OpacityType opaScale)
{
    int16_t radius = rect.GetHeight() / 2;
    int16_t col2X = rect.GetLeft() + radius - 1;
    int16_t col3X = rect.GetRight() - radius + 1;

    int16_t row1Y = rect.GetTop();
    int16_t row2Y = rect.GetTop() + radius - 1;
    int16_t row3Y = rect.GetBottom();

    Style arcStyle = style;
    arcStyle.lineWidth_ = radius;
    arcStyle.lineColor_ = style.bgColor_;
    arcStyle.lineOpa_ = style.bgOpa_;
    // draw left sector
    ArcInfo arcInfo;
    arcInfo.center = {col2X, row2Y};
    arcInfo.radius = radius;
    arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw right sector
    arcInfo.center = {col3X, row2Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw top rectangle
    DrawUtils* drawUtils = DrawUtils::GetInstance();
    Rect topRect(col2X, row1Y, col3X - 1, row2Y - 1);
    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    drawUtils->DrawColorArea(gfxDstBuffer, topRect, dirtyRect, style.bgColor_, opa);

    // draw bottom rectangle
    Rect bottomRect(col2X + 1, row2Y, col3X - 1, row3Y);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomRect, dirtyRect, style.bgColor_, opa);
}

void DrawRect::DrawRectRadiusWithoutBorderCon2(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                               const Style& style, OpacityType opaScale)
{
    int16_t radius = rect.GetWidth() / 2;
    int16_t col1X = rect.GetLeft();
    int16_t col2X = rect.GetLeft() + radius - 1;
    int16_t col3X = rect.GetRight();

    int16_t row2Y = rect.GetTop() + radius - 1;
    int16_t row3Y = rect.GetBottom() - radius + 1;

    Style arcStyle = style;
    arcStyle.lineWidth_ = radius;
    arcStyle.lineColor_ = style.bgColor_;
    arcStyle.lineOpa_ = style.bgOpa_;
    // draw top sector
    ArcInfo arcInfo;
    arcInfo.center = {col2X, row2Y};
    arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
    arcInfo.endAngle = QUARTER_IN_DEGREE;
    arcInfo.radius = radius;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw bottom sector
    arcInfo.center = {col2X, row3Y};
    arcInfo.startAngle = QUARTER_IN_DEGREE;
    arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw middle rectangle
    Rect middleRect(col1X, row2Y + 1, col3X, row3Y - 1);
    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, middleRect, dirtyRect, style.bgColor_, opa);
}

void DrawRect::DrawRectRadiusWithoutBorderCon3(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                               const Style& style, OpacityType opaScale)
{
    int16_t radius = rect.GetWidth() / 2;
    int16_t col1X = rect.GetLeft() + radius - 1;
    int16_t row1Y = rect.GetTop() + radius - 1;

    Style arcStyle = style;
    arcStyle.lineWidth_ = radius;
    arcStyle.lineColor_ = style.bgColor_;
    arcStyle.lineOpa_ = style.bgOpa_;
    // draw circle
    ArcInfo arcInfo;
    arcInfo.center = {col1X, row1Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = radius;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine::GetInstance()->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
}

void DrawRect::DrawRectRadiusWithoutBorderCon4(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                               const Style& style, OpacityType opaScale)
{
    int16_t radius = style.borderRadius_;
    int16_t col1X = rect.GetLeft();
    int16_t col2X = rect.GetLeft() + radius - 1;
    int16_t col3X = rect.GetRight() - radius + 1;
    int16_t col4X = rect.GetRight();

    int16_t row1Y = rect.GetTop();
    int16_t row2Y = rect.GetTop() + radius - 1;
    int16_t row3Y = rect.GetBottom() - radius + 1;
    int16_t row4Y = rect.GetBottom();

    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    // draw top rectangle
    Rect topRect(col2X, row1Y, col3X - 1, row2Y);
    DrawUtils* drawUtils = DrawUtils::GetInstance();
    drawUtils->DrawColorArea(gfxDstBuffer, topRect, dirtyRect, style.bgColor_, opa);

    // draw middle rectangle
    Rect middleRect(col1X, row2Y + 1, col4X, row3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, middleRect, dirtyRect, style.bgColor_, opa);

    // draw bottom rectangle
    Rect bottomRect(col2X + 1, row3Y, col3X - 1, row4Y);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomRect, dirtyRect, style.bgColor_, opa);

    Style arcStyle = style;
    arcStyle.lineWidth_ = radius;
    arcStyle.lineColor_ = style.bgColor_;
    arcStyle.lineOpa_ = style.bgOpa_;
    // top left sector
    ArcInfo arcInfo;
    arcInfo.center = {col2X, row2Y};
    arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = radius;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // top right sector
    arcInfo.center = {col3X, row2Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // bottom left sector
    arcInfo.center = {col2X, row3Y};
    arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
    arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // bottom right sector
    arcInfo.center = {col3X, row3Y};
    arcInfo.startAngle = QUARTER_IN_DEGREE;
    arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
}

void DrawRect::DrawRectBorderWithoutRadius(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                           const Style& style, OpacityType opaScale)
{
    int16_t col1X = rect.GetLeft();
    int16_t col2X = rect.GetLeft() + style.borderWidth_ - 1;
    int16_t col3X = rect.GetRight() - style.borderWidth_ + 1;
    int16_t col4X = rect.GetRight();

    int16_t row1Y = rect.GetTop();
    int16_t row2Y = rect.GetTop() + style.borderWidth_ - 1;
    int16_t row3Y = rect.GetBottom() - style.borderWidth_ + 1;
    int16_t row4Y = rect.GetBottom();

    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.borderOpa_);
    // draw top border
    Rect topRect(col1X, row1Y, col4X, row2Y);
    DrawUtils* drawUtils = DrawUtils::GetInstance();
    drawUtils->DrawColorArea(gfxDstBuffer, topRect, dirtyRect, style.borderColor_, opa);

    // draw left border
    Rect leftRect(col1X, row2Y + 1, col2X, row3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, leftRect, dirtyRect, style.borderColor_, opa);

    OpacityType opaBg = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    // draw middle rectangle
    Rect middleRect(col2X + 1, row2Y + 1, col3X - 1, row3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, middleRect, dirtyRect, style.bgColor_, opaBg);

    // draw right border
    Rect rightRect(col3X, row2Y + 1, col4X, row3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, rightRect, dirtyRect, style.borderColor_, opa);

    // draw bottom border
    Rect bottomRect(col1X, row3Y, col4X, row4Y);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomRect, dirtyRect, style.borderColor_, opa);
}

void DrawRect::DrawRectRadiusEqualBorder(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                         const Style& style, OpacityType opaScale)
{
    int16_t col1X = rect.GetLeft();
    int16_t col2X = rect.GetLeft() + style.borderRadius_ - 1;
    int16_t col3X = rect.GetRight() - style.borderRadius_ + 1;
    int16_t col4X = rect.GetRight();

    int16_t row1Y = rect.GetTop();
    int16_t row2Y = rect.GetTop() + style.borderRadius_ - 1;
    int16_t row3Y = rect.GetBottom() - style.borderRadius_ + 1;
    int16_t row4Y = rect.GetBottom();

    Style arcStyle = style;
    arcStyle.lineWidth_ = style.borderWidth_;
    arcStyle.lineColor_ = style.borderColor_;
    arcStyle.lineOpa_ = style.borderOpa_;
    // draw top left sector in border
    ArcInfo arcInfo;
    arcInfo.center = {col2X, row2Y};
    arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = style.borderRadius_;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw top right sector in border
    arcInfo.center = {col3X, row2Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw bottom left sector in border
    arcInfo.center = {col2X, row3Y};
    arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
    arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw bottom right sector in border
    arcInfo.center = {col3X, row3Y};
    arcInfo.startAngle = QUARTER_IN_DEGREE;
    arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.borderOpa_);
    // draw top rectangle in border
    Rect topRect(col2X, row1Y, col3X - 1, row2Y);
    DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, topRect, dirtyRect, style.borderColor_, opa);

    // draw left rectangle in border
    Rect leftRect(col1X, row2Y + 1, col2X, row3Y - 1);
    DrawUtils* drawUtils = DrawUtils::GetInstance();
    drawUtils->DrawColorArea(gfxDstBuffer, leftRect, dirtyRect, style.borderColor_, opa);

    OpacityType opaBg = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    // draw middle rectangle
    Rect middleRect(col2X + 1, row2Y + 1, col3X - 1, row3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, middleRect, dirtyRect, style.bgColor_, opaBg);

    // draw right rectangle in border
    Rect rightRect(col3X, row2Y + 1, col4X, row3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, rightRect, dirtyRect, style.borderColor_, opa);

    // draw bottom rectangle in border
    Rect bottomRect(col2X + 1, row3Y, col3X - 1, row4Y);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomRect, dirtyRect, style.borderColor_, opa);
}

void DrawRect::DrawRectRadiusSmallThanBorder(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                             const Style& style, OpacityType opaScale)
{
    int16_t radiusCol1X = rect.GetLeft();
    int16_t radiusCol2X = rect.GetLeft() + style.borderRadius_ - 1;
    int16_t radiusCol3X = rect.GetRight() - style.borderRadius_ + 1;
    int16_t radiusCol4X = rect.GetRight();

    int16_t radiusRow1Y = rect.GetTop();
    int16_t radiusRow2Y = rect.GetTop() + style.borderRadius_ - 1;
    int16_t radiusRow3Y = rect.GetBottom() - style.borderRadius_ + 1;
    int16_t radiusRow4Y = rect.GetBottom();

    int16_t rectCol1X = radiusCol1X;
    int16_t rectCol2X = rect.GetLeft() + style.borderWidth_ - 1;
    int16_t rectCol3X = rect.GetRight() - style.borderWidth_ + 1;
    int16_t rectCol4X = radiusCol4X;

    int16_t rectRow1Y = radiusRow2Y;
    int16_t rectRow2Y = rect.GetTop() + style.borderWidth_ - 1;
    int16_t rectRow3Y = rect.GetBottom() - style.borderWidth_ + 1;

    Style arcStyle = style;
    arcStyle.lineWidth_ = style.borderWidth_;
    arcStyle.lineColor_ = style.borderColor_;
    arcStyle.lineOpa_ = style.borderOpa_;
    // draw top left sector in border
    ArcInfo arcInfo;
    arcInfo.center = {radiusCol2X, radiusRow2Y};
    arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = style.borderRadius_;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw top right sector in border
    arcInfo.center = {radiusCol3X, radiusRow2Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw bottom left sector in border
    arcInfo.center = {radiusCol2X, radiusRow3Y};
    arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
    arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    // draw bottom right sector in border
    arcInfo.center = {radiusCol3X, radiusRow3Y};
    arcInfo.startAngle = QUARTER_IN_DEGREE;
    arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.borderOpa_);
    // draw top rectangle in border
    Rect topRect(radiusCol2X, radiusRow1Y, radiusCol3X - 1, radiusRow2Y);
    DrawUtils* drawUtils = DrawUtils::GetInstance();
    drawUtils->DrawColorArea(gfxDstBuffer, topRect, dirtyRect, style.borderColor_, opa);
    Rect topRect2(rectCol1X, rectRow1Y + 1, rectCol4X, rectRow2Y);
    drawUtils->DrawColorArea(gfxDstBuffer, topRect2, dirtyRect, style.borderColor_, opa);

    // draw left rectangle in border
    Rect leftRect(rectCol1X, rectRow2Y + 1, rectCol2X, rectRow3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, leftRect, dirtyRect, style.borderColor_, opa);

    OpacityType opaBg = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    // draw middle rectangle
    Rect middleRect(rectCol2X + 1, rectRow2Y + 1, rectCol3X - 1, rectRow3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, middleRect, dirtyRect, style.bgColor_, opaBg);

    // draw right rectangle in border
    Rect rightRect(rectCol3X, rectRow2Y + 1, rectCol4X, rectRow3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, rightRect, dirtyRect, style.borderColor_, opa);

    // draw bottom rectangle in border
    Rect bottomRect(radiusCol2X + 1, radiusRow3Y, radiusCol3X - 1, radiusRow4Y);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomRect, dirtyRect, style.borderColor_, opa);
    Rect bottomRect2(rectCol1X, rectRow3Y, rectCol4X, radiusRow3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomRect2, dirtyRect, style.borderColor_, opa);
}

void DrawRect::DrawRectRadiusBiggerThanBorder(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                              const Style& style, OpacityType opaScale)
{
    // 2 : half
    if ((rect.GetWidth() > rect.GetHeight()) && (style.borderRadius_ >= rect.GetHeight() / 2)) {
        DrawRectRadiusBiggerThanBorderCon1(gfxDstBuffer, rect, dirtyRect, style, opaScale);
    } else if ((rect.GetWidth() < rect.GetHeight()) && (style.borderRadius_ >= rect.GetWidth() / 2)) {
        DrawRectRadiusBiggerThanBorderCon2(gfxDstBuffer, rect, dirtyRect, style, opaScale);
    } else if ((rect.GetWidth() == rect.GetHeight()) && (style.borderRadius_ >= rect.GetWidth() / 2)) {
        DrawRectRadiusBiggerThanBorderCon3(gfxDstBuffer, rect, dirtyRect, style, opaScale);
    } else {
        DrawRectRadiusBiggerThanBorderCon4(gfxDstBuffer, rect, dirtyRect, style, opaScale);
    }
}

void DrawRect::DrawRectRadiusBiggerThanBorderCon1(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                                  const Style& style, OpacityType opaScale)
{
    int16_t radius = rect.GetHeight() / 2;
    int16_t borderWidth = style.borderWidth_;
    int16_t col2X = rect.GetLeft() + radius - 1;
    int16_t col3X = rect.GetRight() - radius + 1;

    int16_t row1Y = rect.GetTop();
    int16_t row2Y = rect.GetTop() + borderWidth - 1;
    int16_t row3Y = rect.GetTop() + radius - 1;
    int16_t row4Y = rect.GetBottom() - borderWidth + 1;
    int16_t row5Y = rect.GetBottom();

    Style arcStyle = style;
    arcStyle.lineWidth_ = borderWidth;
    arcStyle.lineColor_ = style.borderColor_;
    arcStyle.lineOpa_ = style.borderOpa_;
    // draw left arc in border
    ArcInfo arcInfo;
    arcInfo.center = {col2X, row3Y};
    arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = radius;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;

    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw right arc in border
    arcInfo.center = {col3X, row3Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    radius = radius - borderWidth;
    arcStyle.lineWidth_ = radius;
    arcStyle.lineColor_ = style.bgColor_;
    arcStyle.lineOpa_ = style.bgOpa_;

    // draw left sector in rectangle
    arcInfo.center = {col2X, row3Y};
    arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = radius;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw right sector in rectangle
    arcInfo.center = {col3X, row3Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.borderOpa_);
    // top rectangle in border
    Rect topBorderRect(col2X, row1Y, col3X - 1, row2Y);
    DrawUtils* drawUtils = DrawUtils::GetInstance();
    drawUtils->DrawColorArea(gfxDstBuffer, topBorderRect, dirtyRect, style.borderColor_, opa);
    OpacityType opaBg = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    // middle rectangle inner
    Rect middleInnerRect(col2X, row2Y + 1, col3X - 1, row3Y);
    drawUtils->DrawColorArea(gfxDstBuffer, middleInnerRect, dirtyRect, style.bgColor_, opaBg);
    Rect middleInnerRect2(col2X + 1, row3Y + 1, col3X - 1, row4Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, middleInnerRect2, dirtyRect, style.bgColor_, opaBg);

    // bottom rectangle in border
    Rect bottomBorderRect(col2X + 1, row4Y, col3X - 1, row5Y);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomBorderRect, dirtyRect, style.borderColor_, opa);
}

void DrawRect::DrawRectRadiusBiggerThanBorderCon2(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                                  const Style& style, OpacityType opaScale)
{
    int16_t radius = rect.GetWidth() / 2;
    int16_t borderWidth = style.borderWidth_;
    int16_t col1X = rect.GetLeft();
    int16_t col2X = rect.GetLeft() + borderWidth - 1;
    int16_t col3X = rect.GetLeft() + radius - 1;
    int16_t col4X = rect.GetRight() - borderWidth + 1;
    int16_t col5X = rect.GetRight();

    int16_t row2Y = rect.GetTop() + radius - 1;
    int16_t row3Y = rect.GetBottom() - radius + 1;

    Style arcStyle = style;
    arcStyle.lineWidth_ = borderWidth;
    arcStyle.lineColor_ = style.borderColor_;
    arcStyle.lineOpa_ = style.borderOpa_;
    // draw top arc in border
    ArcInfo arcInfo;
    arcInfo.center = {col3X, row2Y};
    arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
    arcInfo.endAngle = QUARTER_IN_DEGREE;
    arcInfo.radius = radius;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw bottom arc in border
    arcInfo.center = {col3X, row3Y};
    arcInfo.startAngle = QUARTER_IN_DEGREE;
    arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    radius = radius - borderWidth;
    arcStyle.lineWidth_ = radius;
    arcStyle.lineColor_ = style.bgColor_;
    arcStyle.lineOpa_ = style.bgOpa_;

    // draw top sector in rectangle
    arcInfo.center = {col3X, row2Y};
    arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
    arcInfo.endAngle = QUARTER_IN_DEGREE;
    arcInfo.radius = radius;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw bottom sector in rectangle
    arcInfo.center = {col3X, row3Y};
    arcInfo.startAngle = QUARTER_IN_DEGREE;
    arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.borderOpa_);
    // left rectangle in border
    Rect topBorderRect(col1X, row2Y + 1, col2X, row3Y - 1);
    DrawUtils* drawUtils = DrawUtils::GetInstance();
    drawUtils->DrawColorArea(gfxDstBuffer, topBorderRect, dirtyRect, style.borderColor_, opa);

    OpacityType opaBg = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    // middle rectangle inner
    Rect middleInnerRect(col2X + 1, row2Y + 1, col4X - 1, row3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, middleInnerRect, dirtyRect, style.bgColor_, opaBg);

    // right rectangle in border
    Rect bottomBorderRect(col4X, row2Y + 1, col5X, row3Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomBorderRect, dirtyRect, style.borderColor_, opa);
}

void DrawRect::DrawRectRadiusBiggerThanBorderCon3(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                                  const Style& style, OpacityType opaScale)
{
    int16_t radius = rect.GetWidth() / 2;
    int16_t borderWidth = style.borderWidth_;
    int16_t col2X = rect.GetLeft() + radius - 1;
    int16_t row2Y = rect.GetTop() + radius - 1;

    Style arcStyle = style;
    arcStyle.lineWidth_ = borderWidth;
    arcStyle.lineColor_ = style.borderColor_;
    arcStyle.lineOpa_ = style.borderOpa_;
    // draw circle in border
    ArcInfo arcInfo;
    arcInfo.center = {col2X, row2Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = radius;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    radius = radius - borderWidth;
    arcStyle.lineWidth_ = radius;
    arcStyle.lineColor_ = style.bgColor_;
    arcStyle.lineOpa_ = style.bgOpa_;

    // draw circle in rectangle
    arcInfo.center = {col2X, row2Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = radius;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
}

void DrawRect::DrawRectRadiusBiggerThanBorderCon4(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& dirtyRect,
                                                  const Style& style, OpacityType opaScale)
{
    int16_t radius = style.borderRadius_;
    int16_t borderWidth = style.borderWidth_;
    int16_t col1X = rect.GetLeft();
    int16_t col2X = rect.GetLeft() + borderWidth - 1;
    int16_t col3X = rect.GetLeft() + radius - 1;
    int16_t col4X = rect.GetRight() - radius + 1;
    int16_t col5X = rect.GetRight() - borderWidth + 1;
    int16_t col6X = rect.GetRight();

    int16_t row1Y = rect.GetTop();
    int16_t row2Y = rect.GetTop() + borderWidth - 1;
    int16_t row3Y = rect.GetTop() + radius - 1;
    int16_t row4Y = rect.GetBottom() - radius + 1;
    int16_t row5Y = rect.GetBottom() - borderWidth + 1;
    int16_t row6Y = rect.GetBottom();

    Style arcStyle = style;
    arcStyle.lineWidth_ = borderWidth;
    arcStyle.lineColor_ = style.borderColor_;
    arcStyle.lineOpa_ = style.borderOpa_;

    // draw top left arc in border
    ArcInfo arcInfo;
    arcInfo.center = {col3X, row3Y};
    arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = radius;
    arcInfo.imgPos = {0, 0};
    arcInfo.imgSrc = nullptr;
    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw top right arc in border
    arcInfo.center = {col4X, row3Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw bottom left arc in border
    arcInfo.center = {col3X, row4Y};
    arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
    arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw bottom right arc in border
    arcInfo.center = {col4X, row4Y};
    arcInfo.startAngle = QUARTER_IN_DEGREE;
    arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    radius = radius - borderWidth;
    arcStyle.lineWidth_ = radius;
    arcStyle.lineColor_ = style.bgColor_;
    arcStyle.lineOpa_ = style.bgOpa_;

    // draw top left sector in rectangle
    arcInfo.center = {col3X, row3Y};
    arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
    arcInfo.endAngle = CIRCLE_IN_DEGREE;
    arcInfo.radius = radius;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw top right sector in rectangle
    arcInfo.center = {col4X, row3Y};
    arcInfo.startAngle = 0;
    arcInfo.endAngle = QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw bottom left sector in rectangle
    arcInfo.center = {col3X, row4Y};
    arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
    arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);
    // draw bottom right sector in rectangle
    arcInfo.center = {col4X, row4Y};
    arcInfo.startAngle = QUARTER_IN_DEGREE;
    arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
    baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, dirtyRect, arcStyle, opaScale, CapType::CAP_NONE);

    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.borderOpa_);
    // top rectangle in border
    Rect topBorderRect(col3X, row1Y, col4X - 1, row2Y);
    DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, topBorderRect, dirtyRect, style.borderColor_, opa);

    OpacityType opaBg = DrawUtils::GetMixOpacity(opaScale, style.bgOpa_);
    // top rectangle inner
    Rect topInnerRect(col3X, row2Y + 1, col4X - 1, row3Y);
    DrawUtils* drawUtils = DrawUtils::GetInstance();
    drawUtils->DrawColorArea(gfxDstBuffer, topInnerRect, dirtyRect, style.bgColor_, opaBg);

    // left rectangle in border
    Rect leftBorderRect(col1X, row3Y + 1, col2X, row4Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, leftBorderRect, dirtyRect, style.borderColor_, opa);

    // middle rectangle inner
    Rect middleInnerRect(col2X + 1, row3Y + 1, col5X - 1, row4Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, middleInnerRect, dirtyRect, style.bgColor_, opaBg);

    // right rectangle in border
    Rect rightBorderRect(col5X, row3Y + 1, col6X, row4Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, rightBorderRect, dirtyRect, style.borderColor_, opa);

    // bottom rectangle inner
    Rect bottomInnerRect(col3X + 1, row4Y, col4X - 1, row5Y - 1);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomInnerRect, dirtyRect, style.bgColor_, opaBg);

    // bottom rectangle in border
    Rect bottomBorderRect(col3X + 1, row5Y, col4X - 1, row6Y);
    drawUtils->DrawColorArea(gfxDstBuffer, bottomBorderRect, dirtyRect, style.borderColor_, opa);
}
} // namespace OHOS