javauis/lcdui_akn/lcdgd/src/lcd16bpp.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 14:23:59 +0300
branchRCL_3
changeset 83 26b2b12093af
parent 19 04becd199f91
permissions -rw-r--r--
Revision: v2.2.17 Kit: 201041

/*
* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/

#include <e32std.h>
#include <gdi.h>
#include <graphicsaccelerator.h>
#include <j2me/jdebug.h>

#include "lcdgdrvif.h"
#include "lcdbitblt.h"
#include "lcd16bpp.h"
#include "lcdtransform.h"
#include "lcdgdrvutil.h"

#ifdef _DEBUG
inline TInt BPP(const TAcceleratedBitmapInfo* aBitmap)
{
    if (aBitmap->iDisplayMode == EColor16M)
    {
        return 24;
    }
    return (1<<aBitmap->iPixelShift);
}

inline TBool VALID(const TAcceleratedBitmapInfo* aDstBitmap, const TAcceleratedBitmapInfo* aSrcBitmap)
{
    if (aDstBitmap && aSrcBitmap)
    {
        return (NULL != aDstBitmap->iAddress) &&
               (NULL != aSrcBitmap->iAddress) &&
               (aDstBitmap->iDisplayMode == aSrcBitmap->iDisplayMode) &&
               (BPP(aDstBitmap)==16);
    }
    return EFalse;
}
#endif


extern void DrawRegion16Bpp1BppTo16BppOpaque
(
    const TAcceleratedBitmapInfo* aDstColorBitmap,      // must be 16bpp mode
    const TAcceleratedBitmapInfo* /*aDstAlphaBitmap*/,
    const TRect&                  aDstRect,             // must be clipped to destination
    const TAcceleratedBitmapInfo* aSrcColorBitmap,      // must match aDstColorBitmap mode
    const TAcceleratedBitmapInfo* aSrcAlphaBitmap,      // must be EGray2
    const TLcdTransform&          aTransform            // includes anchor
)
{
    ASSERT(aDstColorBitmap);
    ASSERT(aSrcColorBitmap);
    ASSERT(aSrcAlphaBitmap);
    ASSERT(aDstColorBitmap->iDisplayMode == aSrcColorBitmap->iDisplayMode);
    ASSERT(BPP(aDstColorBitmap) == 16);
    ASSERT(aSrcAlphaBitmap->iDisplayMode == EGray2);

    TPoint srcPoint = aTransform(aDstRect.iTl);

    TInt dudx = aTransform.iDuDx;
    TInt dudy = aTransform.iDuDy;
    TInt dvdx = aTransform.iDvDx;
    TInt dvdy = aTransform.iDvDy;
    TInt u0   = srcPoint.iX;
    TInt v0   = srcPoint.iY;

    const TInt width = aDstRect.Width();

    const TInt srcLinePitch = aSrcColorBitmap->iLinePitch;
    const TInt mskLinePitch = aSrcAlphaBitmap->iLinePitch;
    const TInt dstLinePitch = aDstColorBitmap->iLinePitch;

    TUint8* srcAddress = aSrcColorBitmap->iAddress;
    TUint8* mskAddress = aSrcAlphaBitmap->iAddress; // 1 bpp
    TUint8* dstAddress = aDstColorBitmap->iAddress;

    TInt u;
    TInt v;
    TInt x = aDstRect.iTl.iX;
    TInt y = aDstRect.iTl.iY;
    TInt h = aDstRect.Height();

    //
    // Iterate over destination pixels.
    //
    dstAddress += (y*dstLinePitch + x*sizeof(TUint16));
    for (; h>0; --h)
    {
        TUint16* dst = (TUint16*)(dstAddress);
        TUint16* end = dst + width;
        u=u0;
        v=v0;
        while (dst < end)
        {
            TInt m = *(mskAddress + v*mskLinePitch + (u>>3));
            if (m & (1<<(u&0x7)))
            {
                TUint16 srcColor = *(TUint16*)(srcAddress + v*srcLinePitch + u*sizeof(TUint16));
                *dst = srcColor;
            }
            ++dst;
            u+=dudx;
            v+=dvdx;
        }
        u0+=dudy;
        v0+=dvdy;
        dstAddress += dstLinePitch;
    }
}


#ifdef LCDGD_SUPPORT_MATCHED_MASK_BITMAP
LOCAL_C void BlitLine16Bpp16BppTo16BppOpaque
(
    TUint8* aDstAddress,
    TInt    aWidth,
    TUint8* aColorAddress,
    TInt    aColorPixelPitch,
    TUint8* aMaskAddress,
    TInt    aMaskPixelPitch
)
{
    TUint16* dst = (TUint16*)(aDstAddress);
    TUint16* end = dst + aWidth;

    TUint8* colorAddr = aColorAddress;
    TUint8* maskAddr = aMaskAddress;

    while (dst < end)
    {
        TUint16 srcMask = *(TUint16*)maskAddr;
        TUint16 srcColor = *(TUint16*)colorAddr;
        TUint16 dstColor = *dst;

        dstColor = (srcColor & srcMask) | (dstColor & ~srcMask);

        *dst++ = dstColor;

        // Advance to next pixel in the line in each bitmap.
        colorAddr += aColorPixelPitch;
        maskAddr += aMaskPixelPitch;
    }
}


extern void DrawRegion16Bpp16BppTo16BppOpaque
(
    const TAcceleratedBitmapInfo* aDstColorBitmap,
    const TAcceleratedBitmapInfo* /*aDstAlphaBitmap*/,
    const TRect&                  aDstRect,             // must be clipped to destination
    const TAcceleratedBitmapInfo* aSrcColorBitmap,
    const TAcceleratedBitmapInfo* aSrcAlphaBitmap,      // mask
    const TLcdTransform&          aTransform            // includes anchor
)
{
    ASSERT(aDstColorBitmap->iDisplayMode == aSrcColorBitmap->iDisplayMode);
    ASSERT(aSrcColorBitmap->iDisplayMode == aSrcAlphaBitmap->iDisplayMode);
    ASSERT(BPP(aDstColorBitmap) == 16);

    GenericMaskBlit(aDstColorBitmap, aDstRect, aSrcColorBitmap, aTransform,
                    aSrcAlphaBitmap, ETrue, BlitLine16Bpp16BppTo16BppOpaque);
}
#endif


extern void DrawImage16Bpp1BppTo16BppOpaque
(
    const TAcceleratedBitmapInfo* aDstColorBitmap,
    const TAcceleratedBitmapInfo* /*aDstAlphaBitmap*/,
    const TRect&                  aDstRect,             // must be clipped to destination
    const TAcceleratedBitmapInfo* aSrcColorBitmap,
    const TAcceleratedBitmapInfo* aSrcAlphaBitmap,      // mask
    const TLcdTransform&          aTransform            // includes anchor
)
{
    ASSERT(aDstColorBitmap->iDisplayMode == aSrcColorBitmap->iDisplayMode);
    ASSERT(aSrcAlphaBitmap->iDisplayMode == EGray2);
    ASSERT(BPP(aDstColorBitmap) == 16);

    ASSERT(aTransform.iDuDx == 1);
    ASSERT(aTransform.iDuDy == 0);
    ASSERT(aTransform.iDvDx == 0);
    ASSERT(aTransform.iDvDy == 1);

    TPoint srcPoint = aTransform(aDstRect.iTl);

    ASSERT(srcPoint.iX == (aDstRect.iTl.iX + aTransform.iU0));
    ASSERT(srcPoint.iY == (aDstRect.iTl.iY + aTransform.iV0));

    TInt u0   = srcPoint.iX;
    TInt v0   = srcPoint.iY;
    TInt u = u0;
    TInt v = v0;
    TInt mu;    // mask u coord
    TInt m = 0; // mask byte

    const TInt width = aDstRect.Width();

    const TInt srcLinePitch = aSrcColorBitmap->iLinePitch;
    const TInt mskLinePitch = aSrcAlphaBitmap->iLinePitch;
    const TInt dstLinePitch = aDstColorBitmap->iLinePitch;

    TUint8* srcAddress = aSrcColorBitmap->iAddress;
    TUint8* mskAddress = aSrcAlphaBitmap->iAddress; // 1 bpp
    TUint8* dstAddress = aDstColorBitmap->iAddress;

    TInt x = aDstRect.iTl.iX;
    TInt y = aDstRect.iTl.iY;
    TInt h = aDstRect.Height();

#ifdef _DEBUG
    const TSize   srcSize  = aSrcColorBitmap->iSize;
    const TUint16* srcStart = (TUint16*)srcAddress;
    const TUint16* srcLimit = (TUint16*)(srcAddress + (srcSize.iHeight-1)*srcLinePitch + srcSize.iWidth*sizeof(TUint16));
#endif

    //
    // Start address of destination pixels.
    //
    dstAddress += ((y*dstLinePitch) + (x*sizeof(TUint16)));

    //
    // Start address of source pixels
    //
    srcAddress += ((v*srcLinePitch) + (u*sizeof(TUint16)));
    mskAddress += ((v*mskLinePitch) + (u>>3));

    for (; h>0; --h)
    {
        TUint16* src = (TUint16*)srcAddress;
        TUint8*  msk = mskAddress;
        TUint16* dst = (TUint16*)dstAddress;
        TUint16* end = dst + width;
        u=u0;
        mu=-1;
        while (dst < end)
        {
#ifdef _DEBUG
            ASSERT((srcStart <= src) && (src <= srcLimit));
#endif
            if (mu != (u>>3))
            {
                mu = (u>>3);
                m  = *msk++;
            }
            if (m & (1<<(u&0x7)))
            {
                *dst = *src;
            }
            ++src;
            ++dst;
            ++u;
        }
        dstAddress += dstLinePitch;
        srcAddress += srcLinePitch;
        mskAddress += mskLinePitch;
    }
}

LOCAL_C void FillTriangle16Bpp64
(
    const TAcceleratedBitmapInfo* aBitmap,
    const TPoint aPoints[],
    TUint32 aColor16Bpp,
    const TRect& aClipRect
)
{
    TRect clipRect(aBitmap->iSize);
    clipRect.Intersection(aClipRect);
    const TInt64 clipX1 = (TInt64)(clipRect.iTl.iX);
    const TInt64 clipY1 = (TInt64)(clipRect.iTl.iY);
    const TInt64 clipX2 = (TInt64)(clipRect.iBr.iX);
    const TInt64 clipY2 = (TInt64)(clipRect.iBr.iY);

    TInt i;

    TInt ymin=0;
    TInt ymax=0;
    TInt xmin=0;
    TInt xmax=0;

    for (i=1; i<3; i++)
    {
        if (aPoints[i].iX < aPoints[xmin].iX) xmin = i;
        if (aPoints[i].iX > aPoints[xmax].iX) xmax = i;
        if (aPoints[i].iY < aPoints[ymin].iY) ymin = i;
        if (aPoints[i].iY > aPoints[ymax].iY) ymax = i;
    }
    const TInt ymid = 3 - (ymax + ymin);

//  const TInt64 minX = aPoints[xmin].iX;
//  const TInt64 maxX = aPoints[xmax].iX;

    TEdge64 edges[3];

    //
    // Long edge top to bottom.
    //
    edges[0].iDy = (TInt64)(aPoints[ymax].iY) - (TInt64)(aPoints[ymin].iY);
    if (edges[0].iDy == 0)
    {
        return;
    }
    edges[0].iDx = (TInt64)(aPoints[ymax].iX) - (TInt64)(aPoints[ymin].iX);
    edges[0].iX  = (TInt64)(aPoints[ymin].iX);
    edges[0].iF  = 0;
    edges[0].iD  = edges[0].iDy;
    edges[0].iDe = Sign(edges[0].iDx);
    Increment(edges[0].iIx, edges[0].iIf, edges[0].iDx, edges[0].iDy);
    ASSERT(edges[0].iDy >= 0);

    //
    // Short top edge, or flat top
    //
    edges[1].iDx = (TInt64)(aPoints[ymid].iX) - (TInt64)(aPoints[ymin].iX);
    edges[1].iDy = (TInt64)(aPoints[ymid].iY) - (TInt64)(aPoints[ymin].iY);
    edges[1].iX  = (TInt64)(aPoints[ymin].iX);
    edges[1].iF  = 0;
    edges[1].iD  = edges[1].iDy;
    edges[1].iDe = Sign(edges[1].iDx);
    ASSERT(edges[1].iDy >= 0);

    //
    // Short bottom edge or flat bottom
    //
    edges[2].iDx = (TInt64)(aPoints[ymax].iX) - (TInt64)(aPoints[ymid].iX);
    edges[2].iDy = (TInt64)(aPoints[ymax].iY) - (TInt64)(aPoints[ymid].iY);
    edges[2].iX  = (TInt64)(aPoints[ymid].iX);
    edges[2].iF  = 0;
    edges[2].iD  = edges[2].iDy;
    edges[2].iDe = Sign(edges[2].iDx);
    ASSERT(edges[2].iDy >= 0);

    const TBool flatTop    = (edges[1].iDy == 0);
    const TBool flatBottom = (edges[2].iDy == 0);

    //
    // work out whether long edge is left most or right most.
    //
    // compare slopes of long edge and top edge.
    //
    TBool longEdgeRight;
    if (flatTop)
    {
        longEdgeRight = (aPoints[ymid].iX < aPoints[ymin].iX);
    }
    else
    {
        longEdgeRight = (edges[0].iDx*edges[1].iDy) > (edges[1].iDx*edges[0].iDy);
    }

    TInt64   y    = (TInt64)aPoints[ymin].iY;
    TInt64   yEnd = Min(aPoints[ymid].iY, clipY2);
    TEdge64* el   = NULL;
    TEdge64* er   = NULL;
    TInt64   m;     // number of lines to skip
    TInt64   x1;    // start of clipped scan (inclusive)
    TInt64   x2;    // end of clipped scan (exclusive), exclusive overrides inclusive

    TInt64 eliX;    // Locals used to speed access to edge information in loops.
    TInt64 eliF;
    TInt64 eliD;
    TInt64 eriX;
    TInt64 eriF;
    TInt64 eriD;

    TUint8* base = aBitmap->iAddress;
    TUint8* line = NULL;
    TInt linePitch = aBitmap->iLinePitch;
    TUint16* dst;
    TUint16* end;
    TUint32 color16 = (TUint32)aColor16Bpp;

    //
    // render top half.
    //
    if (!flatTop)
    {
        Increment(edges[1].iIx, edges[1].iIf, edges[1].iDx, edges[1].iDy);
        if (longEdgeRight)
        {
            er = &edges[0];
            el = &edges[1];
        }
        else
        {
            er = &edges[1];
            el = &edges[0];
        }
        eliX = el->iX;
        eliF = el->iF;
        eliD = el->iD;
        eriX = er->iX;
        eriF = er->iF;
        eriD = er->iD;

        //
        // Clip to top of clip rect.
        //
        if (y < clipY1)
        {
            TInt64 yTop = Min(clipY1, yEnd);

            m = (yTop - y);

            double leftSlope = (double)(el->iDx)/(double)(el->iDy);

            eliX += (leftSlope * ((double)m));

            double rightSlope = (double)(er->iDx)/(double)(er->iDy);

            eriX += (rightSlope * ((double)m));
            y = yTop;
        }

        ASSERT(((1 - eriD) <= eriF) && (eriF <= 0));
        ASSERT(((1 - eliD) <= eliF) && (eliF <= 0));

#ifdef PLOT_TOP_VERTEX
        // special case top vertex - can produce pimple so prob best avoided.
        if (aClipRect.Contains(aPoints[ymin]))
        {
            line = base + aPoints[ymin].iY*linePitch;
            ((TUint16*)line)[aPoints[ymin].iX] = color16;
        }
#endif

        line = base + y*linePitch;
        for (; y<yEnd; y++)
        {
            ASSERT(eliX <= eriX);
            if ((eliX < clipX2) && (eriX > clipX1))
            {
                x1 = Max(eliX, clipX1); // inclusive (ceil)
                x2 = Min(eriX, clipX2); // exclusive (floor)

                dst = (TUint16*)(line + x1*sizeof(TUint16));
                end = (TUint16*)(line + x2*sizeof(TUint16));
                while (dst < end)
                {
                    *dst++ = color16;
                }
            }
            eliX += el->iIx;
            eliF += el->iIf;
            if (eliF > 0)
            {
                eliX ++;
                eliF -= eliD;
            }

            eriX += er->iIx;
            eriF += er->iIf;
            if (eriF > 0)
            {
                eriX ++;
                eriF -= eriD;
            }

            line += linePitch;
        }

        el->iX = eliX;
        el->iF = eliF;
        el->iD = eliD;
        er->iX = eriX;
        er->iF = eriF;
        er->iD = eriD;
    }

    if (!flatBottom)
    {
        Increment(edges[2].iIx, edges[2].iIf, edges[2].iDx, edges[2].iDy);
        if (longEdgeRight)
        {
            // initialize short left edge
            er = &edges[0];
            el = &edges[2];
        }
        else
        {
            // initialize short right edge
            er = &edges[2];
            el = &edges[0];
        }
        eliX = el->iX;
        eliF = el->iF;
        eliD = el->iD;
        eriX = er->iX;
        eriF = er->iF;
        eriD = er->iD;

        //
        // clip to top edge of clip rect.
        //
        //
        // Clip to top of clip rect.
        //
        if (y < clipY1)
        {
            m = (clipY1 - y);

            double leftSlope = (double)(el->iDx)/(double)(el->iDy);

            eliX += (leftSlope * m);

            double rightSlope = (double)(er->iDx)/(double)(er->iDy);

            eriX += (rightSlope * m);

            y = clipY1;
        }

        line = base + y*linePitch;
        yEnd = Min(aPoints[ymax].iY, clipY2);
        for (; y<yEnd; y++)     // ignore last line - as pixel will be on bottom edge.
        {
            ASSERT(eliX <= eriX);
            if ((eliX < clipX2) && (eriX > clipX1))
            {
                x1 = Max(eliX, clipX1); // inclusive (ceil)
                x2 = Min(eriX, clipX2); // exclusive (floor)

                dst = (TUint16*)(line + x1*sizeof(TUint16));
                end = (TUint16*)(line + x2*sizeof(TUint16));
                while (dst < end)
                {
                    *dst++ = color16;
                }
            }

            eliX += el->iIx;
            eliF += el->iIf;
            if (eliF > 0)
            {
                eliX ++;
                eliF -= eliD;
            }

            eriX += er->iIx;
            eriF += er->iIf;
            if (eriF > 0)
            {
                eriX ++;
                eriF -= eriD;
            }

            line += linePitch;
        }

        el->iX = eliX;
        el->iF = eliF;
        el->iD = eliD;
        er->iX = eriX;
        er->iF = eriF;
        er->iD = eriD;
    }
}

extern void FillTriangle16Bpp32
(
    const TAcceleratedBitmapInfo* aBitmap,
    const TPoint aPoints[],
    TUint32 aColor16Bpp,
    const TRect& aClipRect
)
{
    TRect clipRect(aBitmap->iSize);
    clipRect.Intersection(aClipRect);
    const TInt clipX1 = clipRect.iTl.iX;
    const TInt clipY1 = clipRect.iTl.iY;
    const TInt clipX2 = clipRect.iBr.iX;
    const TInt clipY2 = clipRect.iBr.iY;

    TInt i;

    TInt ymin=0;
    TInt ymax=0;
    TInt xmin=0;
    TInt xmax=0;

    for (i=1; i<3; i++)
    {
        if (aPoints[i].iX < aPoints[xmin].iX) xmin = i;
        if (aPoints[i].iX > aPoints[xmax].iX) xmax = i;
        if (aPoints[i].iY < aPoints[ymin].iY) ymin = i;
        if (aPoints[i].iY > aPoints[ymax].iY) ymax = i;
    }
    const TInt ymid = 3 - (ymax + ymin);


    TEdge edges[3];

    //
    // Long edge top to bottom.
    //
    edges[0].iDy = aPoints[ymax].iY - aPoints[ymin].iY;
    if (edges[0].iDy == 0)
    {
        return;
    }
    edges[0].iDx = aPoints[ymax].iX - aPoints[ymin].iX;
    edges[0].iX  = aPoints[ymin].iX;
    edges[0].iF  = 0;
    edges[0].iD  = edges[0].iDy;
    edges[0].iDe = Sign(edges[0].iDx);
    Increment(edges[0].iIx, edges[0].iIf, edges[0].iDx, edges[0].iDy);
    ASSERT(edges[0].iDy >= 0);

    //
    // Short top edge, or flat top
    //
    edges[1].iDx = aPoints[ymid].iX - aPoints[ymin].iX;
    edges[1].iDy = aPoints[ymid].iY - aPoints[ymin].iY;
    edges[1].iX  = aPoints[ymin].iX;
    edges[1].iF  = 0;
    edges[1].iD  = edges[1].iDy;
    edges[1].iDe = Sign(edges[1].iDx);
    ASSERT(edges[1].iDy >= 0);

    //
    // Short bottom edge or flat bottom
    //
    edges[2].iDx = aPoints[ymax].iX - aPoints[ymid].iX;
    edges[2].iDy = aPoints[ymax].iY - aPoints[ymid].iY;
    edges[2].iX  = aPoints[ymid].iX;
    edges[2].iF  = 0;
    edges[2].iD  = edges[2].iDy;
    edges[2].iDe = Sign(edges[2].iDx);
    ASSERT(edges[2].iDy >= 0);

    const TBool flatTop    = (edges[1].iDy == 0);
    const TBool flatBottom = (edges[2].iDy == 0);

    //
    // work out whether long edge is left most or right most.
    //
    // compare slopes of long edge and top edge.
    //
    TBool longEdgeRight;
    if (flatTop)
    {
        longEdgeRight = (aPoints[ymid].iX < aPoints[ymin].iX);
    }
    else
    {
        longEdgeRight = (edges[0].iDx*edges[1].iDy) > (edges[1].iDx*edges[0].iDy);
    }

    TInt y    = aPoints[ymin].iY;
    TInt yEnd = Min(aPoints[ymid].iY, clipY2);
    TEdge* el = NULL;
    TEdge* er = NULL;
    TInt m;     // number of lines to skip
    TInt x1;    // start of clipped scan (inclusive)
    TInt x2;    // end of clipped scan (exclusive), exclusive overrides inclusive

    TInt eliX;  // Locals used to speed access to edge information in loops.
    TInt eliF;
    TInt eliD;
    TInt eriX;
    TInt eriF;
    TInt eriD;


    TUint8* base = aBitmap->iAddress;
    TUint8* line = NULL;
    TInt linePitch = aBitmap->iLinePitch;
    TUint16* dst;
    TUint16* end;
    TUint16 color16 = (TUint16)aColor16Bpp;

    //
    // render top half.
    //
    if (!flatTop)
    {
        Increment(edges[1].iIx, edges[1].iIf, edges[1].iDx, edges[1].iDy);
        if (longEdgeRight)
        {
            er = &edges[0];
            el = &edges[1];
        }
        else
        {
            er = &edges[1];
            el = &edges[0];
        }
        eliX = el->iX;
        eliF = el->iF;
        eliD = el->iD;
        eriX = er->iX;
        eriF = er->iF;
        eriD = er->iD;

        //
        // Clip to top of clip rect.
        //
        if (y < clipY1)
        {
            TInt yTop = Min(clipY1, yEnd);

            m = (yTop - y);

            eliX += m*el->iIx;
            eliF += m*el->iIf;
            while (eliF > 0)
            {
                eliX ++;
                eliF -= eliD;
            }

            eriX += m*er->iIx;
            eriF += m*er->iIf;
            while (eriF > 0)
            {
                eriX ++;
                eriF -= eriD;
            }

            y = yTop;
        }

        ASSERT(((1 - eriD) <= eriF) && (eriF <= 0));
        ASSERT(((1 - eliD) <= eliF) && (eliF <= 0));

#ifdef PLOT_TOP_VERTEX
        // special case top vertex - can produce pimple so prob best avoided.
        if (aClipRect.Contains(aPoints[ymin]))
        {
            line = base + aPoints[ymin].iY*linePitch;
            ((TUint16*)line)[aPoints[ymin].iX] = color16;
        }
#endif

        line = base + y*linePitch;
        for (; y<yEnd; y++)
        {
            ASSERT(eliX <= eriX);
            if ((eliX < clipX2) && (eriX > clipX1))
            {
                x1 = Max(eliX, clipX1); // inclusive (ceil)
                x2 = Min(eriX, clipX2); // exclusive (floor)

                dst = (TUint16*)(line + x1*sizeof(TUint16));
                end = (TUint16*)(line + x2*sizeof(TUint16));
                while (dst < end)
                {
                    *dst++ = color16;
                }
            }

            eliX += el->iIx;
            eliF += el->iIf;
            if (eliF > 0)
            {
                eliX ++;
                eliF -= eliD;
            }

            eriX += er->iIx;
            eriF += er->iIf;
            if (eriF > 0)
            {
                eriX ++;
                eriF -= eriD;
            }

            line += linePitch;
        }

        el->iX = eliX;
        el->iF = eliF;
        el->iD = eliD;
        er->iX = eriX;
        er->iF = eriF;
        er->iD = eriD;
    }

    if (!flatBottom)
    {
        Increment(edges[2].iIx, edges[2].iIf, edges[2].iDx, edges[2].iDy);
        if (longEdgeRight)
        {
            // initialize short left edge
            er = &edges[0];
            el = &edges[2];
        }
        else
        {
            // initialize short right edge
            er = &edges[2];
            el = &edges[0];
        }
        eliX = el->iX;
        eliF = el->iF;
        eliD = el->iD;
        eriX = er->iX;
        eriF = er->iF;
        eriD = er->iD;

        //
        // clip to top edge of clip rect.
        //
        //
        // Clip to top of clip rect.
        //
        if (y < clipY1)
        {
            m = (clipY1 - y);

            eliX += m*el->iIx;
            eliF += m*el->iIf;
            while (eliF > 0)
            {
                eliX ++;
                eliF -= eliD;
            }

            eriX += m*er->iIx;
            eriF += m*er->iIf;
            while (eriF > 0)
            {
                eriX ++;
                eriF -= eriD;
            }
            y = clipY1;
        }

        line = base + y*linePitch;
        yEnd = Min(aPoints[ymax].iY, clipY2);
        for (; y<yEnd; y++)     // ignore last line - as pixel will be on bottom edge.
        {
            ASSERT(eliX <= eriX);
            if ((eliX < clipX2) && (eriX > clipX1))
            {
                x1 = Max(eliX, clipX1); // inclusive (ceil)
                x2 = Min(eriX, clipX2); // exclusive (floor)

                dst = (TUint16*)(line + x1*sizeof(TUint16));
                end = (TUint16*)(line + x2*sizeof(TUint16));
                while (dst < end)
                {
                    *dst++ = color16;
                }
            }

            eliX += el->iIx;
            eliF += el->iIf;
            if (eliF > 0)
            {
                eliX ++;
                eliF -= eliD;
            }

            eriX += er->iIx;
            eriF += er->iIf;
            if (eriF > 0)
            {
                eriX ++;
                eriF -= eriD;
            }

            line += linePitch;
        }

        el->iX = eliX;
        el->iF = eliF;
        el->iD = eliD;
        er->iX = eriX;
        er->iF = eriF;
        er->iD = eriD;
    }
}

LOCAL_C TBool IsPathologicalTriangle(const TPoint aPoints[3])
{
    TInt minX = aPoints[0].iX;
    TInt maxX = aPoints[0].iX;
    TInt minY = aPoints[0].iY;
    TInt maxY = aPoints[0].iY;

    for (TInt i = 1; i <= 2; i++)
    {
        TInt x = aPoints[i].iX;
        TInt y = aPoints[i].iY;

        if (x < minX)
        {
            minX = x;
        }
        if (x > maxX)
        {
            maxX = x;
        }
        if (y < minY)
        {
            minY = y;
        }
        if (y > maxY)
        {
            maxY = y;
        }
    }
    if (minX < 0)
    {
        if (maxX >= (0x7FFFFFFF + minX))
        {
            return ETrue;
        }
        if (-minX > 0xFFFFF)
        {
            return ETrue;
        }
    }
    if (maxX > 0)
    {
        if ((maxX == 0x7FFFFFFF) && (minX == 0))
        {
            return ETrue;
        }
        if (maxX > 0xFFFFF)
        {
            return ETrue;
        }
    }
    if (minY < 0)
    {
        if (maxY >= (0x7FFFFFFF + minY))
        {
            return ETrue;
        }
        if (-minY > 0xFFFFF)
        {
            return ETrue;
        }
    }
    if (maxY > 0)
    {
        if ((maxY == 0x7FFFFFFF) && (minY == 0))
        {
            return ETrue;
        }
        if (maxY > 0xFFFFF)
        {
            return ETrue;
        }
    }
    return EFalse;
}

extern void FillTriangle16Bpp
(
    const TAcceleratedBitmapInfo* aBitmap,
    const TPoint aPoints[],
    TUint32 aColor16Bpp,
    const TRect& aClipRect
)
{
    if (!IsPathologicalTriangle(aPoints))
    {
        FillTriangle16Bpp32(aBitmap, aPoints, aColor16Bpp, aClipRect);
    }
    else
    {
        FillTriangle16Bpp64(aBitmap, aPoints, aColor16Bpp, aClipRect);
    }
}

LOCAL_C void BlitLineSixteenBppSimple
(
    TUint8* aDstAddress,
    TInt    aWidth,
    TUint8* aColorAddress,
    TInt    DEBUG_ONLY(aColorPixelPitch)
)
{
    ASSERT(aColorPixelPitch == sizeof(TUint16));
#ifdef USE_MEM_COPY_FOR_SIMPLE_BLIT
    Mem::Copy(aDstAddress, aColorAddress, aWidth * sizeof(TUint16));
#else
    TUint16* dst = (TUint16*)aDstAddress;
    TUint16* src = (TUint16*)aColorAddress;
    TUint16* end = dst + aWidth;
    while (dst < end)
    {
        *dst++ = *src++;
    }
#endif
}


/**
 * Opaque 16bpp to 16bpp bitblt with simple transform.
 */
extern void BitBltSixteenBppSimple
(
    const TAcceleratedBitmapInfo*   aDstColorBitmap,
    const TAcceleratedBitmapInfo*   /*aDstAlphaBitmap*/,
    const TRect&                    aDstRect,
    const TAcceleratedBitmapInfo*   aSrcColorBitmap,
    const TAcceleratedBitmapInfo*   /*aSrcAlphaBitmap*/,
    const TLcdTransform&            aTransform
)
{
    //
    // Translation or translation & vertical reflection case.
    //
    ASSERT(aTransform.iDuDx == 1);
    ASSERT(aTransform.iDuDy == 0);
    ASSERT(aTransform.iDvDx == 0);
    ASSERT(aTransform.iDvDy == 1 || aTransform.iDvDy == -1);

    GenericBlit(aDstColorBitmap, aDstRect, aSrcColorBitmap, aTransform,
                BlitLineSixteenBppSimple);
}


LOCAL_C void BlitLineSixteenBpp
(
    TUint8* aDstAddress,
    TInt    aWidth,
    TUint8* aColorAddress,
    TInt    aColorPixelPitch
)
{
    TUint16* dst = (TUint16*)aDstAddress;
    TUint16* end = dst + aWidth;

    TUint8* colorAddr = aColorAddress;
    while (dst < end)
    {
        *dst++ = *(TUint16*)colorAddr;
        colorAddr += aColorPixelPitch;
    }
}


/**
 * Opaque 16bpp to 16bpp bitblt with transform.
 */
extern void BitBltSixteenBpp
(
    const TAcceleratedBitmapInfo*   aDstColorBitmap,
    const TAcceleratedBitmapInfo*   /*aDstAlphaBitmap*/,
    const TRect&                    aDstRect,
    const TAcceleratedBitmapInfo*   aSrcColorBitmap,
    const TAcceleratedBitmapInfo*   /*aSrcAlphaBitmap*/,
    const TLcdTransform&            aTransform
)
{
    GenericBlit(aDstColorBitmap, aDstRect, aSrcColorBitmap, aTransform,
                BlitLineSixteenBpp);
}

extern void BitBltSixteenBppOneBpp
(
    const TAcceleratedBitmapInfo*   aDstColorBitmap,
    const TAcceleratedBitmapInfo*   aDstAlphaBitmap,
    const TRect&                    aDstRect,
    const TAcceleratedBitmapInfo*   aSrcColorBitmap,
    const TAcceleratedBitmapInfo*   aSrcAlphaBitmap,
    const TLcdTransform&            aTransform
)
{
    BitBltSixteenBpp(aDstColorBitmap, NULL, aDstRect, aSrcColorBitmap, NULL, aTransform);
    BitBltOneBpp(aDstAlphaBitmap, NULL, aDstRect, aSrcAlphaBitmap, NULL, aTransform);
}

extern void BitBltSixteenBppSixteenBpp
(
    const TAcceleratedBitmapInfo*   aDstColorBitmap,
    const TAcceleratedBitmapInfo*   aDstAlphaBitmap,
    const TRect&                    aDstRect,
    const TAcceleratedBitmapInfo*   aSrcColorBitmap,
    const TAcceleratedBitmapInfo*   aSrcAlphaBitmap,
    const TLcdTransform&            aTransform
)
{
    BitBltSixteenBpp(aDstColorBitmap, NULL, aDstRect, aSrcColorBitmap, NULL, aTransform);
    BitBltSixteenBpp(aDstAlphaBitmap, NULL, aDstRect, aSrcAlphaBitmap, NULL, aTransform);
}

extern void BitBltSixteenBppEightBpp
(
    const TAcceleratedBitmapInfo*   aDstColorBitmap,
    const TAcceleratedBitmapInfo*   aDstAlphaBitmap,
    const TRect&                    aDstRect,
    const TAcceleratedBitmapInfo*   aSrcColorBitmap,
    const TAcceleratedBitmapInfo*   aSrcAlphaBitmap,
    const TLcdTransform&            aTransform
)
{
    BitBltSixteenBpp(aDstColorBitmap, NULL, aDstRect, aSrcColorBitmap, NULL, aTransform);
    BitBltEightBpp(aDstAlphaBitmap, NULL, aDstRect, aSrcAlphaBitmap, NULL, aTransform);
}