/*
 * 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.
 */

/**
* @brief Defines scanline renderer
* @since 1.0
* @version 1.0
*/

#include "render_scanline.h"

namespace OHOS {
void RenderScanlinesAntiAliasSolid(RasterizerScanlineAntialias& raster, GeometryScanline& scanline,
                                   RenderBase& renBase, const Rgba8T& color)
{
    if (!raster.RewindScanlines()) {
        return;
    }
    scanline.Reset(raster.GetMinX(), raster.GetMaxX());
    while (raster.SweepScanline(scanline)) {
        int32_t y = scanline.GetYLevel();
        uint32_t numSpans = scanline.NumSpans();
        GeometryScanline::ConstIterator span = scanline.Begin();
        while (true) {
            int32_t x = span->x;
            if (span->spanLength > 0) {
                renBase.BlendSolidHSpan(x, y, static_cast<uint32_t>(span->spanLength),
                                        color, span->covers);
            } else {
                renBase.BlendHLine(x, y, static_cast<uint32_t>(x - span->spanLength - 1),
                                   color, *(span->covers));
            }
            if (--numSpans == 0) {
                break;
            }
            ++span;
        }
    }
}

void RenderScanlinesAntiAlias(RasterizerScanlineAntialias& raster, GeometryScanline& scanline,
                              RenderBase& renBase, FillBase& alloc, SpanBase& spanGen)
{
    if (!raster.RewindScanlines()) {
        return;
    }
    scanline.Reset(raster.GetMinX(), raster.GetMaxX());
    spanGen.Prepare(); // Segment generator preparation
    alloc.Resize(raster.GetMaxX()-raster.GetMinX());
    while (raster.SweepScanline(scanline)) {
        int32_t y = scanline.GetYLevel();
        uint32_t numSpans = scanline.NumSpans();
        GeometryScanline::ConstIterator span = scanline.Begin();
        while (true) {
            int32_t x = span->x;
            int32_t len = span->spanLength;
            const uint8_t* covers = span->covers;

            if (len < 0) {
                len = -len;
            }

            spanGen.Generate(alloc.GetSpanPtr(), x, y, len);
            renBase.BlendColorHSpan(x, y, len, alloc.GetSpanPtr(),
                                    (span->spanLength < 0) ? 0 : covers, *covers);

            if (--numSpans == 0) {
                break;
            }
            ++span;
        }
    }
}

void BlendScanLine(GlobalCompositeOperation op, RasterizerScanlineAntialias& raster1,
                   RasterizerScanlineAntialias& raster2, GeometryScanline& sl1, GeometryScanline& sl2,
                   RenderBase& renBase, FillBase& alloc, SpanBase& spanGen1, SpanBase& spanGen2)
{
    switch (op) {
        case SOURCE_OVER:
            BlendSourceOver(raster2, raster1, sl2, sl1, renBase, alloc, spanGen2, spanGen1);
            break;
        case SOURCE_ATOP:
            BlendSourceAtop(raster1, raster2, sl1, sl2, renBase, alloc, spanGen1, spanGen2);
            break;
        case SOURCE_IN:
            BlendSourceIn(raster1, raster2, sl1, sl2, renBase, alloc, spanGen1);
            break;
        case SOURCE_OUT:
            BlendSourceOut(raster1, raster2, sl1, sl2, renBase, alloc, spanGen1);
            break;
        case DESTINATION_OVER:
            BlendSourceOver(raster1, raster2, sl1, sl2, renBase, alloc, spanGen1, spanGen2);
            break;
        case DESTINATION_ATOP:
            BlendSourceAtop(raster2, raster1, sl2, sl1, renBase, alloc, spanGen2, spanGen1);
            break;
        case DESTINATION_IN:
            BlendSourceIn(raster2, raster1, sl2, sl1, renBase, alloc, spanGen2);
            break;
        case DESTINATION_OUT:
            BlendSourceOut(raster2, raster1, sl2, sl1, renBase, alloc, spanGen2);
            break;
        case LIGHTER:
            BlendLIGHTER(raster1, raster2, sl1, sl2, renBase, alloc, spanGen1, spanGen2);
            break;
        case COPY:
            RenderScanlinesAntiAlias(raster1, sl1, renBase, alloc, spanGen1);
            break;
        case XOR:
            BlendXOR(raster1, raster2, sl1, sl2, renBase, alloc, spanGen1, spanGen2);
            break;
        default:
            break;
    }
}

void BlendSourceAtop(RasterizerScanlineAntialias& raster1, RasterizerScanlineAntialias& raster2,
                     GeometryScanline& scanline1, GeometryScanline& scanline2, RenderBase& renBase,
                     FillBase& alloc, SpanBase& spanGen1, SpanBase& spanGen2)
{
    if ((!raster1.RewindScanlines()) || (!raster2.RewindScanlines())) {
        return;
    }
    scanline1.Reset(raster1.GetMinX(), raster1.GetMaxX());
    scanline2.Reset(raster2.GetMinX(), raster2.GetMaxX());
    int16_t allocMinx = (raster1.GetMinX() > raster2.GetMinX()) ? raster2.GetMinX() : raster1.GetMinX();
    int16_t allocMaxX = (raster1.GetMaxX() > raster2.GetMaxX()) ? raster1.GetMaxX() : raster2.GetMaxX();
    alloc.Resize(allocMaxX - allocMinx);
    int32_t y1 = 0;
    if (raster1.SweepScanline(scanline1)) {
        y1 = scanline1.GetYLevel();
        spanGen1.Prepare(); // Segment generator preparation
    }
    while (raster2.SweepScanline(scanline2)) {
        spanGen2.Prepare();
        int32_t y2 = scanline2.GetYLevel();
        uint32_t numSpans2 = scanline2.NumSpans();
        GeometryScanline::ConstIterator span2 = scanline2.Begin();
        GeometryScanline::ConstIterator span1 = scanline1.Begin();
        if (y2 > y1) {
            while (raster1.SweepScanline(scanline1)) {
                y1 = scanline1.GetYLevel();
                if (y1 == y2) {
                    span1 = scanline1.Begin();
                    break;
                }
            }
        }
        while (true) {
            int32_t x2 = span2->x;
            if (y1 == y2) {
                int32_t x1 = span1->x;
                if (span2->spanLength > 0) {
                    if (span1->spanLength > 0) {
                        spanGen2.Generate(alloc.GetSpanPtr(), x2, y2, span2->spanLength);
                        renBase.BlendColorHSpan(x2, y2, (uint32_t)span2->spanLength,
                                                alloc.GetSpanPtr(), span2->covers);
                        if ((x1 <= x2) && ((x2 + span2->spanLength) < (x1 + span1->spanLength))) {
                            spanGen1.Generate(alloc.GetSpanPtr(), x2, y2, span2->spanLength);
                            renBase.BlendColorHSpan(x2, y2, (uint32_t)span2->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span2->covers);
                        } else if ((x1 >= x2) && ((x1 + span1->spanLength) <= (x2 + span2->spanLength))) {
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span1->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span1->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span1->covers);
                        } else if ((x1 > x2) && (x1 < (x2 + span2->spanLength)) &&
                                   ((x1 + span1->spanLength) >= (x2 + span2->spanLength))) {
                            GeometryScanline scanline3;
                            CalcinterScanline(scanline3, x1, x2, span1, span2);
                            GeometryScanline::ConstIterator span3 = scanline3.Begin();
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span3->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span3->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span3->covers);
                        } else if ((x1 < x2) && ((x1 + span1->spanLength) > x2) &&
                                   ((x1 + span1->spanLength) <= (x2 + span2->spanLength))) {
                            GeometryScanline scanline3;
                            CalcinterScanline(scanline3, x2, x1, span2, span1);
                            GeometryScanline::ConstIterator span3 = scanline3.Begin();
                            spanGen1.Generate(alloc.GetSpanPtr(), x2, y2, span3->spanLength);
                            renBase.BlendColorHSpan(x2, y2, (uint32_t)span3->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span3->covers);
                        }
                    }
                }
                ++span1;
                } else {
                    if (span2->spanLength > 0) {
                        spanGen2.Generate(alloc.GetSpanPtr(), x2, y2, span2->spanLength);
                        renBase.BlendColorHSpan(x2, y2, (uint32_t)span2->spanLength,
                                                alloc.GetSpanPtr(),
                                                span2->covers);
                    }
                }
            if (--numSpans2 == 0) {
                break;
            }
            ++span2;
        }
        if (y1 == y2) {
            raster1.SweepScanline(scanline1);
            y1 = scanline1.GetYLevel();
        }
    }
}

void BlendSourceIn(RasterizerScanlineAntialias& raster1, RasterizerScanlineAntialias& raster2,
                   GeometryScanline& scanline1, GeometryScanline& scanline2, RenderBase& renBase,
                   FillBase& alloc, SpanBase& spanGen1)
{
    if (!raster1.RewindScanlines() || !raster2.RewindScanlines()) {
        return;
    }

    scanline1.Reset(raster1.GetMinX(), raster1.GetMaxX());
    scanline2.Reset(raster2.GetMinX(), raster2.GetMaxX());

    int16_t allocMinx = (raster1.GetMinX() > raster2.GetMinX()) ? raster2.GetMinX() : raster1.GetMinX();
    int16_t allocMaxX = (raster1.GetMaxX() > raster2.GetMaxX()) ? raster1.GetMaxX() : raster2.GetMaxX();
    alloc.Resize(allocMaxX-allocMinx);
    int32_t y1 = 0;
    if (raster1.SweepScanline(scanline1)) {
        y1 = scanline1.GetYLevel();
        spanGen1.Prepare();
    }
    while (raster2.SweepScanline(scanline2)) {
        BlendSourceInLoop(raster1, scanline1, scanline2, spanGen1, renBase, alloc, y1);
    }
}

void BlendSourceOut(RasterizerScanlineAntialias& raster1, RasterizerScanlineAntialias& raster2,
                    GeometryScanline& scanline1, GeometryScanline& scanline2,
                    RenderBase& renBase, FillBase& alloc, SpanBase& spanGen1)
{
    if (!raster1.RewindScanlines() || !raster2.RewindScanlines()) {
        return;
    }
    scanline1.Reset(raster1.GetMinX(), raster1.GetMaxX());
    scanline2.Reset(raster2.GetMinX(), raster2.GetMaxX());
    int16_t allocMinx = (raster1.GetMinX() > raster2.GetMinX()) ? raster2.GetMinX() : raster1.GetMinX();
    int16_t allocMaxX = (raster1.GetMaxX() > raster2.GetMaxX()) ? raster1.GetMaxX() : raster2.GetMaxX();
    alloc.Resize(allocMaxX-allocMinx);
    int32_t y1 = 0;
    if (raster1.SweepScanline(scanline1)) {
        y1 = scanline1.GetYLevel();
        spanGen1.Prepare();
    }
    if (raster1.GetMinY() < raster2.GetMinY()) {
        do {
            y1 = scanline1.GetYLevel();
            if (y1 == raster2.GetMinY()) {
                break;
            }
            BlendSourceOutWhile(y1, scanline1, renBase, alloc, spanGen1);
        } while (raster1.SweepScanline(scanline1));
    }
    while (raster2.SweepScanline(scanline2)) {
        int32_t y2 = scanline2.GetYLevel();
        uint32_t numSpans2 = scanline2.NumSpans();
        GeometryScanline::ConstIterator span2 = scanline2.Begin();
        GeometryScanline::ConstIterator span1 = scanline1.Begin();
        while (true) {
            int32_t x2 = span2->x;
            if (y1 == y2) {
                int32_t x1 = span1->x;
                if (span2->spanLength > 0) {
                    if (span1->spanLength > 0) {
                        if ((x1 < x2) && (x2 + span2->spanLength) < (x1 + span1->spanLength)) {
                            GeometryScanline scanline3;
                            CalcOutScanlineAll(scanline3, x2, x1, span2, span1);
                            GeometryScanline::ConstIterator span3 = scanline3.Begin();
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span3->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span3->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span3->covers);
                        } else if ((x1 >= x2) && x1 < x2 + span2->spanLength &&
                                   ((x1 + span1->spanLength) >= (x2 + span2->spanLength))) {
                            GeometryScanline scanline4;
                            CalcOutScanlineLeft(scanline4, x1, x2, span1, span2);
                            GeometryScanline::ConstIterator span4 = scanline4.Begin();
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span4->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span4->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span4->covers);
                        } else if ((x1 <= x2) && (x1 + span1->spanLength) >= x2 &&
                                   ((x1 + span1->spanLength) <= (x2 + span2->spanLength))) {
                            GeometryScanline scanline3;
                            CalcOutScanlineRight(scanline3, x2, x1, span2, span1);
                            GeometryScanline::ConstIterator span3 = scanline3.Begin();
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span3->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span3->spanLength,
                                                    alloc.GetSpanPtr(), span3->covers);
                        } else if (((x1 + span1->spanLength) < x2) || ((x2 + span2->spanLength) < x1)) {
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span1->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span1->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span1->covers);
                        }
                    }
                }
                ++span1;
            }
            if (--numSpans2 == 0) {
                break;
            }
            ++span2;
        }
        if (y1 == y2 && y1 < raster2.GetMaxY() - 1) {
            if (raster1.SweepScanline(scanline1)) {
                y1 = scanline1.GetYLevel();
            }
        }
    }
    BlendSourceOutDrawResetRaster(raster1, scanline1, renBase, alloc, spanGen1);
}

void BlendSourceOutWhile(int32_t y1, GeometryScanline& scanline1, RenderBase& renBase,
                         FillBase& alloc, SpanBase& spanGen1)
{
    uint32_t numSpans = scanline1.NumSpans();
    typename GeometryScanline::ConstIterator span = scanline1.Begin();
    while (true) {
        int32_t x = span->x;
        if (span->spanLength > 0) {
            spanGen1.Generate(alloc.GetSpanPtr(), x, y1, span->spanLength);
            renBase.BlendColorHSpan(x, y1, (uint32_t)span->spanLength,
                                    alloc.GetSpanPtr(),
                                    span->covers);
        }
        if (--numSpans == 0) {
            break;
        }
        ++span;
    }
}

void BlendSourceOutDrawResetRaster(RasterizerScanlineAntialias& raster1, GeometryScanline& scanline1,
                                   RenderBase& renBase, FillBase& alloc, SpanBase& spanGen1)
{
    while (raster1.SweepScanline(scanline1)) {
        int32_t y = scanline1.GetYLevel();
        uint32_t numSpans = scanline1.NumSpans();
        GeometryScanline::ConstIterator span = scanline1.Begin();
        while (true) {
            int32_t x = span->x;
            if (span->spanLength > 0) {
                spanGen1.Generate(alloc.GetSpanPtr(), x, y, span->spanLength);
                renBase.BlendColorHSpan(x, y, (uint32_t)span->spanLength,
                                        alloc.GetSpanPtr(),
                                        span->covers);
            }
            if (--numSpans == 0) {
                break;
            }
            ++span;
        }
    }
}

void BlendSourceOver(RasterizerScanlineAntialias &raster1,
                     RasterizerScanlineAntialias &raster2,
                     GeometryScanline &scanline1,
                     GeometryScanline &scanline2,
                     RenderBase &renBase,
                     FillBase &alloc,
                     SpanBase&&spanGen1,
                     SpanBase &spanGen2)
{
    RenderScanlinesAntiAlias(raster1, scanline1, renBase, alloc, spanGen1);
    RenderScanlinesAntiAlias(raster2, scanline2, renBase, alloc, spanGen2);
}

void BlendXOR(RasterizerScanlineAntialias& raster1, RasterizerScanlineAntialias& raster2,
              GeometryScanline& scanline1, GeometryScanline& scanline2,
              RenderBase& renBase, FillBase& alloc, SpanBase& spanGen1, SpanBase& spanGen2)
{
    if (!raster1.RewindScanlines() || !raster2.RewindScanlines()) {
        return;
    }
    scanline1.Reset(raster1.GetMinX(), raster1.GetMaxX());
    scanline2.Reset(raster2.GetMinX(), raster2.GetMaxX());
    int16_t allocMinx = raster1.GetMinX() > raster2.GetMinX() ? raster2.GetMinX() : raster1.GetMinX();
    int16_t allocMaxX = raster1.GetMaxX() > raster2.GetMaxX() ? raster1.GetMaxX() : raster2.GetMaxX();
    alloc.Resize(allocMaxX-allocMinx);
    int32_t y1 = 0;
    if (raster1.SweepScanline(scanline1)) {
        y1 = scanline1.GetYLevel();
        spanGen1.Prepare();
    }
    BlendXORColorHspan(y1, raster1, raster2, scanline1, renBase, alloc, spanGen1);
    while (raster2.SweepScanline(scanline2)) {
        int32_t y2 = scanline2.GetYLevel();
        spanGen2.Prepare();
        uint32_t numSpans2 = scanline2.NumSpans();
        GeometryScanline::ConstIterator span2 = scanline2.Begin();
        GeometryScanline::ConstIterator span1 = scanline1.Begin();
        while (true) {
            int32_t x2 = span2->x;
            if (y1 == y2) {
                {
                int32_t x1 = span1->x;
                if (span2->spanLength > 0) {
                    if (span1->spanLength > 0) {
                        if ((x1 >= x2) && ((x1 + span1->spanLength) <= (x2 + span2->spanLength))) {
                            GeometryScanline scanline3;
                            CalcOutScanlineAll(scanline3, x1, x2, span1, span2);
                            GeometryScanline::ConstIterator span3 = scanline3.Begin();
                            spanGen2.Generate(alloc.GetSpanPtr(), x2, y2, span3->spanLength);
                            renBase.BlendColorHSpan(x2, y2, (uint32_t)span3->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span3->covers);
                        } else if (((x1 < x2) && ((x2 + span2->spanLength) < (x1 + span1->spanLength)))) {
                            GeometryScanline scanline3;
                            CalcOutScanlineAll(scanline3, x2, x1, span2, span1);
                            GeometryScanline::ConstIterator span3 = scanline3.Begin();
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span3->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span3->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span3->covers);
                        } else if ((x1 >= x2) && (x1 < x2 + span2->spanLength) &&
                            (x1 + span1->spanLength >= x2 + span2->spanLength)) {
                            GeometryScanline scanline3;
                            CalcOutScanlineRight(scanline3, x1, x2, span1, span2);
                            GeometryScanline::ConstIterator span3 = scanline3.Begin();
                            spanGen2.Generate(alloc.GetSpanPtr(), x2, y2, span3->spanLength);
                            renBase.BlendColorHSpan(x2, y2, (uint32_t)span3->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span3->covers);
                            GeometryScanline scanline4;
                            CalcOutScanlineLeft(scanline4, x1, x2, span1, span2);
                            GeometryScanline::ConstIterator span4 = scanline4.Begin();
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span4->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span4->spanLength,
                                                    alloc.GetSpanPtr(),
                                                    span4->covers);
                        } else if ((x1 <= x2) && (x1 + span1->spanLength >= x2) &&
                            (x1 + span1->spanLength <= x2 + span2->spanLength)) {
                            GeometryScanline scanline3;
                            CalcOutScanlineRight(scanline3, x2, x1, span2, span1);
                            GeometryScanline::ConstIterator span3 = scanline3.Begin();
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span3->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span3->spanLength,
                                                    alloc.GetSpanPtr(), span3->covers);
                            GeometryScanline scanline4;
                            CalcOutScanlineLeft(scanline4, x2, x1, span2, span1);
                            GeometryScanline::ConstIterator span4 = scanline4.Begin();
                            spanGen2.Generate(alloc.GetSpanPtr(), x2, y2, span4->spanLength);
                            renBase.BlendColorHSpan(x2, y2, (uint32_t)span4->spanLength,
                                                    alloc.GetSpanPtr(), span4->covers);
                        } else if ((x1 + span1->spanLength < x2)|| (x2+span2->spanLength < x1)) {
                            spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span1->spanLength);
                            renBase.BlendColorHSpan(x1, y2, (uint32_t)span1->spanLength,
                                                    alloc.GetSpanPtr(), span1->covers);
                            spanGen2.Generate(alloc.GetSpanPtr(), x2, y2, span2->spanLength);
                            renBase.BlendColorHSpan(x2, y2, (uint32_t)span2->spanLength,
                                                    alloc.GetSpanPtr(), span2->covers);
                        }
                    }
                }
                    ++span1;
                }
            } else if (span2->spanLength > 0) {
                spanGen2.Generate(alloc.GetSpanPtr(), x2, y2, span2->spanLength);
                renBase.BlendColorHSpan(x2, y2, (uint32_t)span2->spanLength, alloc.GetSpanPtr(), span2->covers);
            }
            if (--numSpans2 == 0) {
                break;
            }
            ++span2;
        }
        if (y1 == y2 && y1 < raster2.GetMaxY() - 1) {
            if (raster1.SweepScanline(scanline1)) {
                y1 = scanline1.GetYLevel();
            }
        }
    }
    // Draw the rest of raster1
    BlendXORDrawResetRaster(raster1, scanline1, renBase, alloc, spanGen1);
}

void BlendXORDrawResetRaster(RasterizerScanlineAntialias& raster1, GeometryScanline& scanline1,
                             RenderBase& renBase, FillBase& alloc, SpanBase& spanGen1)

{
    while (raster1.SweepScanline(scanline1)) {
        int32_t y = scanline1.GetYLevel();
        uint32_t numSpans = scanline1.NumSpans();
        GeometryScanline::ConstIterator span = scanline1.Begin();
        while (true) {
            int32_t x = span->x;
            if (span->spanLength > 0) {
                spanGen1.Generate(alloc.GetSpanPtr(), x, y, span->spanLength);
                renBase.BlendColorHSpan(x, y, (uint32_t)span->spanLength, alloc.GetSpanPtr(), span->covers);
            }
            if (--numSpans == 0) {
                break;
            }
            ++span;
        }
    }
}

void BlendXORColorHspan(int32_t& y1, RasterizerScanlineAntialias& raster1, RasterizerScanlineAntialias& raster2,
                        GeometryScanline& scanline1, RenderBase& renBase, FillBase& alloc, SpanBase& spanGen1)
{
    if (raster1.GetMinY() > raster2.GetMinY()) {
        return;
    }
    do {
        y1 = scanline1.GetYLevel();
        if (y1 == raster2.GetMinY()) {
            break;
        }
        uint32_t numSpans = scanline1.NumSpans();
        GeometryScanline::ConstIterator span = scanline1.Begin();
        while (true) {
            int32_t x = span->x;
            if (span->spanLength > 0) {
                spanGen1.Generate(alloc.GetSpanPtr(), x, y1, span->spanLength);
                renBase.BlendColorHSpan(x, y1, (uint32_t)span->spanLength,
                                        alloc.GetSpanPtr(), span->covers);
            }
            if (--numSpans == 0) {
                break;
            }
            ++span;
        }
    } while (raster1.SweepScanline(scanline1));
}

void BlendLIGHTER(RasterizerScanlineAntialias& raster1, RasterizerScanlineAntialias& raster2,
                  GeometryScanline& scanline1, GeometryScanline& scanline2,
                  RenderBase& renBase, FillBase& alloc, SpanBase& spanGen1, SpanBase& spanGen2)
{
    BlendXOR(raster1, raster2, scanline1, scanline2, renBase, alloc, spanGen1, spanGen2);
    SpanBlendColor spanBlendColor(spanGen1, spanGen2);
    BlendSourceIn(raster1, raster2, scanline1, scanline2, renBase, alloc, spanBlendColor);
}

void BlendSourceInLoop(RasterizerScanlineAntialias& raster1, GeometryScanline& scanline1, GeometryScanline& scanline2,
                       SpanBase& spanGen1, RenderBase& renBase, FillBase& alloc, int32_t& y1)
{
    int32_t y2 = scanline2.GetYLevel();
    uint32_t numSpans2 = scanline2.NumSpans();
    GeometryScanline::ConstIterator span2 = scanline2.Begin();
    GeometryScanline::ConstIterator span1 = scanline1.Begin();

    if (y2 > y1) {
        while (raster1.SweepScanline(scanline1)) {
            y1 = scanline1.GetYLevel();
            if (y1 == y2) {
                span1 = scanline1.Begin();
                break;
            }
        }
    }
    while (true) {
        int32_t x2 = span2->x;
        if (y1 == y2) {
            int32_t x1 = span1->x;
            if (span2->spanLength > 0) {
                if (span1->spanLength > 0) {
                    if (x1<=x2 && x2+span2->spanLength < x1+span1->spanLength) {
                        spanGen1.Generate(alloc.GetSpanPtr(), x2, y2, span2->spanLength);
                        renBase.BlendColorHSpan(x2, y2, (uint32_t)span2->spanLength,
                                                alloc.GetSpanPtr(), span2->covers);
                    } else if ((x1 >= x2) && (x1 + span1->spanLength <= x2+span2->spanLength)) {
                        spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span1->spanLength);
                        renBase.BlendColorHSpan(x1, y2, (uint32_t)span1->spanLength,
                                                alloc.GetSpanPtr(), span1->covers);
                    } else if ((x1 > x2) && (x1 < x2 + span2->spanLength) &&
                        (x1 + span1->spanLength >= x2 + span2->spanLength)) {
                        GeometryScanline scanline3;
                        CalcinterScanline(scanline3, x1, x2, span1, span2);
                        GeometryScanline::ConstIterator span3 = scanline3.Begin();
                        spanGen1.Generate(alloc.GetSpanPtr(), x1, y2, span3->spanLength);
                        renBase.BlendColorHSpan(x1, y2, (uint32_t)span3->spanLength,
                                                alloc.GetSpanPtr(), span3->covers);
                    } else if ((x1 < x2) && (x1 + span1->spanLength > x2) &&
                        (x1 + span1->spanLength <= x2 + span2->spanLength)) {
                        GeometryScanline scanline3;
                        CalcinterScanline(scanline3, x2, x1, span2, span1);
                        GeometryScanline::ConstIterator span3 = scanline3.Begin();
                        spanGen1.Generate(alloc.GetSpanPtr(), x2, y2, span3->spanLength);
                        renBase.BlendColorHSpan(x2, y2, (uint32_t)span3->spanLength,
                                                alloc.GetSpanPtr(), span3->covers);
                    }
                }
            }
            ++span1;
        }
        if (--numSpans2 == 0) {
            break;
        }
        ++span2;
    }
    if (y1 == y2) {
        raster1.SweepScanline(scanline1);
        y1 = scanline1.GetYLevel();
    }
}

void BlendSourceOver(RasterizerScanlineAntialias& raster1, RasterizerScanlineAntialias& raster2,
                     GeometryScanline& scanline1, GeometryScanline& scanline2,
                     RenderBase& renBase, FillBase& alloc, SpanBase& spanGen1, SpanBase& spanGen2)
{
    RenderScanlinesAntiAlias(raster1, scanline1, renBase, alloc, spanGen1);
    RenderScanlinesAntiAlias(raster2, scanline2, renBase, alloc, spanGen2);
}

void CalcinterScanline(GeometryScanline& scanline3, int32_t x1, int32_t x2,
                       GeometryScanline::ConstIterator span1, GeometryScanline::ConstIterator span2)
{
    scanline3.Reset(x1, x2 + span2->spanLength);
    uint32_t len3 = x2 + span2->spanLength - x1;
    uint8_t* cover1 = span1->covers;
    uint8_t* cover2 = span2->covers + (x1 - x2);
    int32_t x3 = x1;
    for (uint32_t i = 0; i < len3; i++, cover1++, cover2++) {
        if (*(cover1) != COVER_FULL) {
            scanline3.AddCell(x3++, *cover1);
        } else {
            scanline3.AddCell(x3++, *cover2);
        }
    }
}

void CalcOutScanlineRight(GeometryScanline& scanline, int32_t x1, int32_t x2,
                          GeometryScanline::ConstIterator span1, GeometryScanline::ConstIterator span2)
{
    uint8_t* cover1 = span1->covers;
    uint8_t* cover2 = span2->covers;
    scanline.Reset(x2, x2 + span2->spanLength);
    for (int32_t i = 1; i <= span2->spanLength; i++, cover2++) {
        if (x1 == x2) {
            scanline.AddCell(x2++, COVER_FULL - (*cover1));
            x1++;
            cover1++;
        } else {
            scanline.AddCell(x2++, *cover2);
        }
    }
}

void CalcOutScanlineLeft(GeometryScanline& scanline, int32_t x1, int32_t x2,
                         GeometryScanline::ConstIterator span1, GeometryScanline::ConstIterator span2)
{
    uint8_t* cover2 = span2->covers + (x1 - x2);
    scanline.Reset(x1, x1 + span1->spanLength);
    int32_t len1 = span2->spanLength - (x1 - x2); // Length of intersection
    int32_t len2 = span1->spanLength - len1;      // Length of intersection
    uint8_t* cover1 = span1->covers + len1;
    for (int32_t i = 0; i < len1; i++, cover2++) {
        scanline.AddCell(x1++, COVER_FULL - (*cover2));
    }

    for (int32_t i = 0; i < len2; i++, cover1++) {
        scanline.AddCell(x1++, *cover1);
    }
}

void CalcOutScanlineAll(GeometryScanline& scanline, int32_t x1, int32_t x2,
                        GeometryScanline::ConstIterator span1, GeometryScanline::ConstIterator span2)
{
    uint8_t* cover1 = span1->covers;
    uint8_t* cover2 = span2->covers;
    int32_t x3 = x1;
    scanline.Reset(x2, x2 + span2->spanLength);
    for (int32_t i = 0; i < span2->spanLength; i++, cover2++) {
        if (x3 == x2 && x3 <= x1 + span1->spanLength - 1) {
            scanline.AddCell(x2++, COVER_FULL - (*cover1));
            x3++;
            cover1++;
        } else {
            scanline.AddCell(x2++, *cover2);
        }
    }
}
} // namespace OHOS