#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>

#include "pixman-private.h"
/*
 * There are two ways of handling alpha -- either as a single unified value or
 * a separate value for each component, hence each macro must have two
 * versions.  The unified alpha version has a 'U' at the end of the name,
 * the component version has a 'C'.  Similarly, functions which deal with
 * this difference will have two versions using the same convention.
 */

/*
 * Combine src and mask
 */
FASTCALL static void
pixman_fbCombineMaskU (uint32_t *src, const uint32_t *mask, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t a = *(mask + i) >> 24;
        uint32_t s = *(src + i);
        FbByteMul(s, a);
        *(src + i) = s;
    }
}

/*
 * All of the composing functions
 */

FASTCALL static void
fbCombineClear (uint32_t *dest, const uint32_t *src, int width)
{
    memset(dest, 0, width*sizeof(uint32_t));
}

FASTCALL static void
fbCombineSrcU (uint32_t *dest, const uint32_t *src, int width)
{
    memcpy(dest, src, width*sizeof(uint32_t));
}

/* if the Src is opaque, call fbCombineSrcU */
FASTCALL static void
fbCombineOverU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t d = *(dest + i);
        uint32_t ia = Alpha(~s);

        FbByteMulAdd(d, ia, s);
	*(dest + i) = d;
    }
}

/* if the Dst is opaque, this is a noop */
FASTCALL static void
fbCombineOverReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t d = *(dest + i);
        uint32_t ia = Alpha(~*(dest + i));
        FbByteMulAdd(s, ia, d);
	*(dest + i) = s;
    }
}

/* if the Dst is opaque, call fbCombineSrcU */
FASTCALL static void
fbCombineInU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t a = Alpha(*(dest + i));
        FbByteMul(s, a);
	*(dest + i) = s;
    }
}

/* if the Src is opaque, this is a noop */
FASTCALL static void
fbCombineInReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t d = *(dest + i);
        uint32_t a = Alpha(*(src + i));
        FbByteMul(d, a);
	*(dest + i) = d;
    }
}

/* if the Dst is opaque, call fbCombineClear */
FASTCALL static void
fbCombineOutU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t a = Alpha(~*(dest + i));
        FbByteMul(s, a);
	*(dest + i) = s;
    }
}

/* if the Src is opaque, call fbCombineClear */
FASTCALL static void
fbCombineOutReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t d = *(dest + i);
        uint32_t a = Alpha(~*(src + i));
        FbByteMul(d, a);
	*(dest + i) = d;
    }
}

/* if the Src is opaque, call fbCombineInU */
/* if the Dst is opaque, call fbCombineOverU */
/* if both the Src and Dst are opaque, call fbCombineSrcU */
FASTCALL static void
fbCombineAtopU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t d = *(dest + i);
        uint32_t dest_a = Alpha(d);
        uint32_t src_ia = Alpha(~s);

        FbByteAddMul(s, dest_a, d, src_ia);
	*(dest + i) = s;
    }
}

/* if the Src is opaque, call fbCombineOverReverseU */
/* if the Dst is opaque, call fbCombineInReverseU */
/* if both the Src and Dst are opaque, call fbCombineDstU */
FASTCALL static void
fbCombineAtopReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t d = *(dest + i);
        uint32_t src_a = Alpha(s);
        uint32_t dest_ia = Alpha(~d);

        FbByteAddMul(s, dest_ia, d, src_a);
	*(dest + i) = s;
    }
}

/* if the Src is opaque, call fbCombineOverU */
/* if the Dst is opaque, call fbCombineOverReverseU */
/* if both the Src and Dst are opaque, call fbCombineClear */
FASTCALL static void
fbCombineXorU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t d = *(dest + i);
        uint32_t src_ia = Alpha(~s);
        uint32_t dest_ia = Alpha(~d);

        FbByteAddMul(s, dest_ia, d, src_ia);
	*(dest + i) = s;
    }
}

FASTCALL static void
fbCombineAddU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t d = *(dest + i);
        FbByteAdd(d, s);
	*(dest + i) = d;
    }
}

/* if the Src is opaque, call fbCombineAddU */
/* if the Dst is opaque, call fbCombineAddU */
/* if both the Src and Dst are opaque, call fbCombineAddU */
FASTCALL static void
fbCombineSaturateU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t  s = *(src + i);
        uint32_t d = *(dest + i);
        uint16_t  sa, da;

        sa = s >> 24;
        da = ~d >> 24;
        if (sa > da)
        {
            sa = FbIntDiv(da, sa);
            FbByteMul(s, sa);
        };
        FbByteAdd(d, s);
	*(dest + i) = d;
    }
}


/*
 * All of the disjoint composing functions

 The four entries in the first column indicate what source contributions
 come from each of the four areas of the picture -- areas covered by neither
 A nor B, areas covered only by A, areas covered only by B and finally
 areas covered by both A and B.

 Disjoint			Conjoint
 Fa		Fb		Fa		Fb
 (0,0,0,0)	0		0		0		0
 (0,A,0,A)	1		0		1		0
 (0,0,B,B)	0		1		0		1
 (0,A,B,A)	1		min((1-a)/b,1)	1		max(1-a/b,0)
 (0,A,B,B)	min((1-b)/a,1)	1		max(1-b/a,0)	1
 (0,0,0,A)	max(1-(1-b)/a,0) 0		min(1,b/a)	0
 (0,0,0,B)	0		max(1-(1-a)/b,0) 0		min(a/b,1)
 (0,A,0,0)	min(1,(1-b)/a)	0		max(1-b/a,0)	0
 (0,0,B,0)	0		min(1,(1-a)/b)	0		max(1-a/b,0)
 (0,0,B,A)	max(1-(1-b)/a,0) min(1,(1-a)/b)	 min(1,b/a)	max(1-a/b,0)
 (0,A,0,B)	min(1,(1-b)/a)	max(1-(1-a)/b,0) max(1-b/a,0)	min(1,a/b)
 (0,A,B,0)	min(1,(1-b)/a)	min(1,(1-a)/b)	max(1-b/a,0)	max(1-a/b,0)

*/

#define CombineAOut 1
#define CombineAIn  2
#define CombineBOut 4
#define CombineBIn  8

#define CombineClear	0
#define CombineA	(CombineAOut|CombineAIn)
#define CombineB	(CombineBOut|CombineBIn)
#define CombineAOver	(CombineAOut|CombineBOut|CombineAIn)
#define CombineBOver	(CombineAOut|CombineBOut|CombineBIn)
#define CombineAAtop	(CombineBOut|CombineAIn)
#define CombineBAtop	(CombineAOut|CombineBIn)
#define CombineXor	(CombineAOut|CombineBOut)

/* portion covered by a but not b */
FASTCALL static uint8_t
fbCombineDisjointOutPart (uint8_t a, uint8_t b)
{
    /* min (1, (1-b) / a) */

    b = ~b;		    /* 1 - b */
    if (b >= a)		    /* 1 - b >= a -> (1-b)/a >= 1 */
	return 0xff;	    /* 1 */
    return FbIntDiv(b,a);   /* (1-b) / a */
}

/* portion covered by both a and b */
FASTCALL static uint8_t
fbCombineDisjointInPart (uint8_t a, uint8_t b)
{
    /* max (1-(1-b)/a,0) */
    /*  = - min ((1-b)/a - 1, 0) */
    /*  = 1 - min (1, (1-b)/a) */

    b = ~b;		    /* 1 - b */
    if (b >= a)		    /* 1 - b >= a -> (1-b)/a >= 1 */
	return 0;	    /* 1 - 1 */
    return ~FbIntDiv(b,a);  /* 1 - (1-b) / a */
}

/* portion covered by a but not b */
FASTCALL static uint8_t
fbCombineConjointOutPart (uint8_t a, uint8_t b)
{
    /* max (1-b/a,0) */
    /* = 1-min(b/a,1) */

    /* min (1, (1-b) / a) */

    if (b >= a)		    /* b >= a -> b/a >= 1 */
	return 0x00;	    /* 0 */
    return ~FbIntDiv(b,a);   /* 1 - b/a */
}

/* portion covered by both a and b */
FASTCALL static uint8_t
fbCombineConjointInPart (uint8_t a, uint8_t b)
{
    /* min (1,b/a) */

    if (b >= a)		    /* b >= a -> b/a >= 1 */
	return 0xff;	    /* 1 */
    return FbIntDiv(b,a);   /* b/a */
}

FASTCALL static void
fbCombineDisjointGeneralU (uint32_t *dest, const uint32_t *src, int width, uint8_t combine)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t d = *(dest + i);
        uint32_t m,n,o,p;
        uint16_t Fa, Fb, t, u, v;
        uint8_t sa = s >> 24;
        uint8_t da = d >> 24;

        switch (combine & CombineA) {
        default:
            Fa = 0;
            break;
        case CombineAOut:
            Fa = fbCombineDisjointOutPart (sa, da);
            break;
        case CombineAIn:
            Fa = fbCombineDisjointInPart (sa, da);
            break;
        case CombineA:
            Fa = 0xff;
            break;
        }

        switch (combine & CombineB) {
        default:
            Fb = 0;
            break;
        case CombineBOut:
            Fb = fbCombineDisjointOutPart (da, sa);
            break;
        case CombineBIn:
            Fb = fbCombineDisjointInPart (da, sa);
            break;
        case CombineB:
            Fb = 0xff;
            break;
        }
        m = FbGen (s,d,0,Fa,Fb,t, u, v);
        n = FbGen (s,d,8,Fa,Fb,t, u, v);
        o = FbGen (s,d,16,Fa,Fb,t, u, v);
        p = FbGen (s,d,24,Fa,Fb,t, u, v);
        s = m|n|o|p;
	*(dest + i) = s;
    }
}

FASTCALL static void
fbCombineDisjointOverU (uint32_t *dest, const uint32_t *src, int width)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t  s = *(src + i);
        uint16_t  a = s >> 24;

        if (a != 0x00)
        {
            if (a != 0xff)
            {
                uint32_t d = *(dest + i);
                a = fbCombineDisjointOutPart (d >> 24, a);
                FbByteMulAdd(d, a, s);
                s = d;
            }
	    *(dest + i) = s;
        }
    }
}

FASTCALL static void
fbCombineDisjointInU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineDisjointGeneralU (dest, src, width, CombineAIn);
}

FASTCALL static void
fbCombineDisjointInReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineDisjointGeneralU (dest, src, width, CombineBIn);
}

FASTCALL static void
fbCombineDisjointOutU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineDisjointGeneralU (dest, src, width, CombineAOut);
}

FASTCALL static void
fbCombineDisjointOutReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineDisjointGeneralU (dest, src, width, CombineBOut);
}

FASTCALL static void
fbCombineDisjointAtopU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineDisjointGeneralU (dest, src, width, CombineAAtop);
}

FASTCALL static void
fbCombineDisjointAtopReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineDisjointGeneralU (dest, src, width, CombineBAtop);
}

FASTCALL static void
fbCombineDisjointXorU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineDisjointGeneralU (dest, src, width, CombineXor);
}

FASTCALL static void
fbCombineConjointGeneralU (uint32_t *dest, const uint32_t *src, int width, uint8_t combine)
{
    int i;
    for (i = 0; i < width; ++i) {
        uint32_t  s = *(src + i);
        uint32_t d = *(dest + i);
        uint32_t  m,n,o,p;
        uint16_t  Fa, Fb, t, u, v;
        uint8_t sa = s >> 24;
        uint8_t da = d >> 24;

        switch (combine & CombineA) {
        default:
            Fa = 0;
            break;
        case CombineAOut:
            Fa = fbCombineConjointOutPart (sa, da);
            break;
        case CombineAIn:
            Fa = fbCombineConjointInPart (sa, da);
            break;
        case CombineA:
            Fa = 0xff;
            break;
        }

        switch (combine & CombineB) {
        default:
            Fb = 0;
            break;
        case CombineBOut:
            Fb = fbCombineConjointOutPart (da, sa);
            break;
        case CombineBIn:
            Fb = fbCombineConjointInPart (da, sa);
            break;
        case CombineB:
            Fb = 0xff;
            break;
        }
        m = FbGen (s,d,0,Fa,Fb,t, u, v);
        n = FbGen (s,d,8,Fa,Fb,t, u, v);
        o = FbGen (s,d,16,Fa,Fb,t, u, v);
        p = FbGen (s,d,24,Fa,Fb,t, u, v);
        s = m|n|o|p;
	*(dest + i) = s;
    }
}

FASTCALL static void
fbCombineConjointOverU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineAOver);
}


FASTCALL static void
fbCombineConjointOverReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineBOver);
}


FASTCALL static void
fbCombineConjointInU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineAIn);
}


FASTCALL static void
fbCombineConjointInReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineBIn);
}

FASTCALL static void
fbCombineConjointOutU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineAOut);
}

FASTCALL static void
fbCombineConjointOutReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineBOut);
}

FASTCALL static void
fbCombineConjointAtopU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineAAtop);
}

FASTCALL static void
fbCombineConjointAtopReverseU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineBAtop);
}

FASTCALL static void
fbCombineConjointXorU (uint32_t *dest, const uint32_t *src, int width)
{
    fbCombineConjointGeneralU (dest, src, width, CombineXor);
}

/********************************************************************************/
/*************************** Per Channel functions ******************************/
/********************************************************************************/

FASTCALL static void
fbCombineMaskC (uint32_t *src, uint32_t *mask)
{
    uint32_t a = *mask;

    uint32_t	x;
    uint16_t	xa;

    if (!a)
    {
	*(src) = 0;
	return;
    }

    x = *(src);
    if (a == 0xffffffff)
    {
	x = x >> 24;
	x |= x << 8;
	x |= x << 16;
	*(mask) = x;
	return;
    }

    xa = x >> 24;
    FbByteMulC(x, a);
    *(src) = x;
    FbByteMul(a, xa);
    *(mask) = a;
}

FASTCALL static void
fbCombineMaskValueC (uint32_t *src, const uint32_t *mask)
{
    uint32_t a = *mask;
    uint32_t	x;

    if (!a)
    {
	*(src) = 0;
	return;
    }

    if (a == 0xffffffff)
	return;

    x = *(src);
    FbByteMulC(x, a);
    *(src) =x;
}

FASTCALL static void
fbCombineMaskAlphaC (const uint32_t *src, uint32_t *mask)
{
    uint32_t a = *(mask);
    uint32_t	x;

    if (!a)
	return;

    x = *(src) >> 24;
    if (x == 0xff)
	return;
    if (a == 0xffffffff)
    {
	x = x >> 24;
	x |= x << 8;
	x |= x << 16;
	*(mask) = x;
	return;
    }

    FbByteMul(a, x);
    *(mask) = a;
}



FASTCALL static void
fbCombineClearC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    memset(dest, 0, width*sizeof(uint32_t));
}

FASTCALL static void
fbCombineSrcC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
	uint32_t s = *(src + i);
	uint32_t m = *(mask + i);

	fbCombineMaskValueC (&s, &m);

	*(dest) = s;
    }
}

FASTCALL static void
fbCombineOverC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
	uint32_t s = *(src + i);
	uint32_t m = *(mask + i);
	uint32_t a;

	fbCombineMaskC (&s, &m);

	a = ~m;
        if (a != 0xffffffff)
        {
            if (a)
            {
                uint32_t d = *(dest + i);
                FbByteMulAddC(d, a, s);
                s = d;
            }
	    *(dest + i) = s;
        }
    }
}

FASTCALL static void
fbCombineOverReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t d = *(dest + i);
        uint32_t a = ~d >> 24;

        if (a)
        {
            uint32_t s = *(src + i);
	    uint32_t m = *(mask + i);

	    fbCombineMaskValueC (&s, &m);

            if (a != 0xff)
            {
                FbByteMulAdd(s, a, d);
            }
	    *(dest + i) = s;
        }
    }
}

FASTCALL static void
fbCombineInC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t d = *(dest + i);
        uint16_t a = d >> 24;
        uint32_t s = 0;
        if (a)
        {
	    uint32_t m = *(mask + i);

	    s = *(src + i);
	    fbCombineMaskValueC (&s, &m);
            if (a != 0xff)
            {
                FbByteMul(s, a);
            }
        }
	*(dest + i) = s;
    }
}

FASTCALL static void
fbCombineInReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t m = *(mask + i);
        uint32_t a;

	fbCombineMaskAlphaC (&s, &m);

	a = m;
        if (a != 0xffffffff)
        {
            uint32_t d = 0;
            if (a)
            {
                d = *(dest + i);
                FbByteMulC(d, a);
            }
	    *(dest + i) = d;
        }
    }
}

FASTCALL static void
fbCombineOutC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t d = *(dest + i);
        uint16_t a = ~d >> 24;
        uint32_t s = 0;
        if (a)
        {
	    uint32_t m = *(mask + i);

	    s = *(src + i);
	    fbCombineMaskValueC (&s, &m);

            if (a != 0xff)
            {
                FbByteMul(s, a);
            }
        }
	*(dest + i) = s;
    }
}

FASTCALL static void
fbCombineOutReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
	uint32_t s = *(src + i);
	uint32_t m = *(mask + i);
	uint32_t a;

	fbCombineMaskAlphaC (&s, &m);

        a = ~m;
        if (a != 0xffffffff)
        {
            uint32_t d = 0;
            if (a)
            {
                d = *(dest + i);
                FbByteMulC(d, a);
            }
	    *(dest + i) = d;
        }
    }
}

FASTCALL static void
fbCombineAtopC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t d = *(dest + i);
        uint32_t s = *(src + i);
        uint32_t m = *(mask + i);
        uint32_t ad;
        uint16_t as = d >> 24;

	fbCombineMaskC (&s, &m);

        ad = ~m;

        FbByteAddMulC(d, ad, s, as);
	*(dest + i) = d;
    }
}

FASTCALL static void
fbCombineAtopReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {

        uint32_t d = *(dest + i);
        uint32_t s = *(src + i);
        uint32_t m = *(mask + i);
        uint32_t ad;
        uint16_t as = ~d >> 24;

	fbCombineMaskC (&s, &m);

	ad = m;

        FbByteAddMulC(d, ad, s, as);
	*(dest + i) = d;
    }
}

FASTCALL static void
fbCombineXorC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t d = *(dest + i);
        uint32_t s = *(src + i);
        uint32_t m = *(mask + i);
        uint32_t ad;
        uint16_t as = ~d >> 24;

	fbCombineMaskC (&s, &m);

	ad = ~m;

        FbByteAddMulC(d, ad, s, as);
	*(dest + i) = d;
    }
}

FASTCALL static void
fbCombineAddC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t s = *(src + i);
        uint32_t m = *(mask + i);
        uint32_t d = *(dest + i);

	fbCombineMaskValueC (&s, &m);

        FbByteAdd(d, s);
	*(dest + i) = d;
    }
}

FASTCALL static void
fbCombineSaturateC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t  s, d;
        uint16_t  sa, sr, sg, sb, da;
        uint16_t  t, u, v;
        uint32_t  m,n,o,p;

        d = *(dest + i);
        s = *(src + i);
	m = *(mask + i);

	fbCombineMaskC (&s, &m);

        sa = (m >> 24);
        sr = (m >> 16) & 0xff;
        sg = (m >>  8) & 0xff;
        sb = (m      ) & 0xff;
        da = ~d >> 24;

        if (sb <= da)
            m = FbAdd(s,d,0,t);
        else
            m = FbGen (s, d, 0, (da << 8) / sb, 0xff, t, u, v);

        if (sg <= da)
            n = FbAdd(s,d,8,t);
        else
            n = FbGen (s, d, 8, (da << 8) / sg, 0xff, t, u, v);

        if (sr <= da)
            o = FbAdd(s,d,16,t);
        else
            o = FbGen (s, d, 16, (da << 8) / sr, 0xff, t, u, v);

        if (sa <= da)
            p = FbAdd(s,d,24,t);
        else
            p = FbGen (s, d, 24, (da << 8) / sa, 0xff, t, u, v);

	*(dest + i) = m|n|o|p;
    }
}

FASTCALL static void
fbCombineDisjointGeneralC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width, uint8_t combine)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t  s, d;
        uint32_t  m,n,o,p;
        uint32_t  Fa, Fb;
        uint16_t  t, u, v;
        uint32_t  sa;
        uint8_t   da;

        s = *(src + i);
        m = *(mask + i);
        d = *(dest + i);
        da = d >> 24;

	fbCombineMaskC (&s, &m);

	sa = m;

        switch (combine & CombineA) {
        default:
            Fa = 0;
            break;
        case CombineAOut:
            m = fbCombineDisjointOutPart ((uint8_t) (sa >> 0), da);
            n = fbCombineDisjointOutPart ((uint8_t) (sa >> 8), da) << 8;
            o = fbCombineDisjointOutPart ((uint8_t) (sa >> 16), da) << 16;
            p = fbCombineDisjointOutPart ((uint8_t) (sa >> 24), da) << 24;
            Fa = m|n|o|p;
            break;
        case CombineAIn:
            m = fbCombineDisjointInPart ((uint8_t) (sa >> 0), da);
            n = fbCombineDisjointInPart ((uint8_t) (sa >> 8), da) << 8;
            o = fbCombineDisjointInPart ((uint8_t) (sa >> 16), da) << 16;
            p = fbCombineDisjointInPart ((uint8_t) (sa >> 24), da) << 24;
            Fa = m|n|o|p;
            break;
        case CombineA:
            Fa = 0xffffffff;
            break;
        }

        switch (combine & CombineB) {
        default:
            Fb = 0;
            break;
        case CombineBOut:
            m = fbCombineDisjointOutPart (da, (uint8_t) (sa >> 0));
            n = fbCombineDisjointOutPart (da, (uint8_t) (sa >> 8)) << 8;
            o = fbCombineDisjointOutPart (da, (uint8_t) (sa >> 16)) << 16;
            p = fbCombineDisjointOutPart (da, (uint8_t) (sa >> 24)) << 24;
            Fb = m|n|o|p;
            break;
        case CombineBIn:
            m = fbCombineDisjointInPart (da, (uint8_t) (sa >> 0));
            n = fbCombineDisjointInPart (da, (uint8_t) (sa >> 8)) << 8;
            o = fbCombineDisjointInPart (da, (uint8_t) (sa >> 16)) << 16;
            p = fbCombineDisjointInPart (da, (uint8_t) (sa >> 24)) << 24;
            Fb = m|n|o|p;
            break;
        case CombineB:
            Fb = 0xffffffff;
            break;
        }
        m = FbGen (s,d,0,FbGet8(Fa,0),FbGet8(Fb,0),t, u, v);
        n = FbGen (s,d,8,FbGet8(Fa,8),FbGet8(Fb,8),t, u, v);
        o = FbGen (s,d,16,FbGet8(Fa,16),FbGet8(Fb,16),t, u, v);
        p = FbGen (s,d,24,FbGet8(Fa,24),FbGet8(Fb,24),t, u, v);
        s = m|n|o|p;
	*(dest + i) = s;
    }
}

FASTCALL static void
fbCombineDisjointOverC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineDisjointGeneralC (dest, src, mask, width, CombineAOver);
}

FASTCALL static void
fbCombineDisjointInC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineDisjointGeneralC (dest, src, mask, width, CombineAIn);
}

FASTCALL static void
fbCombineDisjointInReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineDisjointGeneralC (dest, src, mask, width, CombineBIn);
}

FASTCALL static void
fbCombineDisjointOutC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineDisjointGeneralC (dest, src, mask, width, CombineAOut);
}

FASTCALL static void
fbCombineDisjointOutReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineDisjointGeneralC (dest, src, mask, width, CombineBOut);
}

FASTCALL static void
fbCombineDisjointAtopC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineDisjointGeneralC (dest, src, mask, width, CombineAAtop);
}

FASTCALL static void
fbCombineDisjointAtopReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineDisjointGeneralC (dest, src, mask, width, CombineBAtop);
}

FASTCALL static void
fbCombineDisjointXorC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineDisjointGeneralC (dest, src, mask, width, CombineXor);
}

FASTCALL static void
fbCombineConjointGeneralC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width, uint8_t combine)
{
    int i;

    for (i = 0; i < width; ++i) {
        uint32_t  s, d;
        uint32_t  m,n,o,p;
        uint32_t  Fa, Fb;
        uint16_t  t, u, v;
        uint32_t  sa;
        uint8_t   da;

        s = *(src + i);
        m = *(mask + i);
        d = *(dest + i);
        da = d >> 24;

	fbCombineMaskC (&s, &m);

        sa = m;

        switch (combine & CombineA) {
        default:
            Fa = 0;
            break;
        case CombineAOut:
            m = fbCombineConjointOutPart ((uint8_t) (sa >> 0), da);
            n = fbCombineConjointOutPart ((uint8_t) (sa >> 8), da) << 8;
            o = fbCombineConjointOutPart ((uint8_t) (sa >> 16), da) << 16;
            p = fbCombineConjointOutPart ((uint8_t) (sa >> 24), da) << 24;
            Fa = m|n|o|p;
            break;
        case CombineAIn:
            m = fbCombineConjointInPart ((uint8_t) (sa >> 0), da);
            n = fbCombineConjointInPart ((uint8_t) (sa >> 8), da) << 8;
            o = fbCombineConjointInPart ((uint8_t) (sa >> 16), da) << 16;
            p = fbCombineConjointInPart ((uint8_t) (sa >> 24), da) << 24;
            Fa = m|n|o|p;
            break;
        case CombineA:
            Fa = 0xffffffff;
            break;
        }

        switch (combine & CombineB) {
        default:
            Fb = 0;
            break;
        case CombineBOut:
            m = fbCombineConjointOutPart (da, (uint8_t) (sa >> 0));
            n = fbCombineConjointOutPart (da, (uint8_t) (sa >> 8)) << 8;
            o = fbCombineConjointOutPart (da, (uint8_t) (sa >> 16)) << 16;
            p = fbCombineConjointOutPart (da, (uint8_t) (sa >> 24)) << 24;
            Fb = m|n|o|p;
            break;
        case CombineBIn:
            m = fbCombineConjointInPart (da, (uint8_t) (sa >> 0));
            n = fbCombineConjointInPart (da, (uint8_t) (sa >> 8)) << 8;
            o = fbCombineConjointInPart (da, (uint8_t) (sa >> 16)) << 16;
            p = fbCombineConjointInPart (da, (uint8_t) (sa >> 24)) << 24;
            Fb = m|n|o|p;
            break;
        case CombineB:
            Fb = 0xffffffff;
            break;
        }
        m = FbGen (s,d,0,FbGet8(Fa,0),FbGet8(Fb,0),t, u, v);
        n = FbGen (s,d,8,FbGet8(Fa,8),FbGet8(Fb,8),t, u, v);
        o = FbGen (s,d,16,FbGet8(Fa,16),FbGet8(Fb,16),t, u, v);
        p = FbGen (s,d,24,FbGet8(Fa,24),FbGet8(Fb,24),t, u, v);
        s = m|n|o|p;
	*(dest + i) = s;
    }
}

FASTCALL static void
fbCombineConjointOverC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineAOver);
}

FASTCALL static void
fbCombineConjointOverReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineBOver);
}

FASTCALL static void
fbCombineConjointInC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineAIn);
}

FASTCALL static void
fbCombineConjointInReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineBIn);
}

FASTCALL static void
fbCombineConjointOutC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineAOut);
}

FASTCALL static void
fbCombineConjointOutReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineBOut);
}

FASTCALL static void
fbCombineConjointAtopC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineAAtop);
}

FASTCALL static void
fbCombineConjointAtopReverseC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineBAtop);
}

FASTCALL static void
fbCombineConjointXorC (uint32_t *dest, uint32_t *src, uint32_t *mask, int width)
{
    fbCombineConjointGeneralC (dest, src, mask, width, CombineXor);
}

static CombineFuncU pixman_fbCombineFuncU[] = {
    fbCombineClear,
    fbCombineSrcU,
    NULL, /* CombineDst */
    fbCombineOverU,
    fbCombineOverReverseU,
    fbCombineInU,
    fbCombineInReverseU,
    fbCombineOutU,
    fbCombineOutReverseU,
    fbCombineAtopU,
    fbCombineAtopReverseU,
    fbCombineXorU,
    fbCombineAddU,
    fbCombineSaturateU,
    NULL,
    NULL,
    fbCombineClear,
    fbCombineSrcU,
    NULL, /* CombineDst */
    fbCombineDisjointOverU,
    fbCombineSaturateU, /* DisjointOverReverse */
    fbCombineDisjointInU,
    fbCombineDisjointInReverseU,
    fbCombineDisjointOutU,
    fbCombineDisjointOutReverseU,
    fbCombineDisjointAtopU,
    fbCombineDisjointAtopReverseU,
    fbCombineDisjointXorU,
    NULL,
    NULL,
    NULL,
    NULL,
    fbCombineClear,
    fbCombineSrcU,
    NULL, /* CombineDst */
    fbCombineConjointOverU,
    fbCombineConjointOverReverseU,
    fbCombineConjointInU,
    fbCombineConjointInReverseU,
    fbCombineConjointOutU,
    fbCombineConjointOutReverseU,
    fbCombineConjointAtopU,
    fbCombineConjointAtopReverseU,
    fbCombineConjointXorU,
    NULL /* Noop */
};

static CombineFuncC pixman_fbCombineFuncC[] = {
    fbCombineClearC,
    fbCombineSrcC,
    NULL, /* Dest */
    fbCombineOverC,
    fbCombineOverReverseC,
    fbCombineInC,
    fbCombineInReverseC,
    fbCombineOutC,
    fbCombineOutReverseC,
    fbCombineAtopC,
    fbCombineAtopReverseC,
    fbCombineXorC,
    fbCombineAddC,
    fbCombineSaturateC,
    NULL,
    NULL,
    fbCombineClearC,	    /* 0x10 */
    fbCombineSrcC,
    NULL, /* Dest */
    fbCombineDisjointOverC,
    fbCombineSaturateC, /* DisjointOverReverse */
    fbCombineDisjointInC,
    fbCombineDisjointInReverseC,
    fbCombineDisjointOutC,
    fbCombineDisjointOutReverseC,
    fbCombineDisjointAtopC,
    fbCombineDisjointAtopReverseC,
    fbCombineDisjointXorC,  /* 0x1b */
    NULL,
    NULL,
    NULL,
    NULL,
    fbCombineClearC,
    fbCombineSrcC,
    NULL, /* Dest */
    fbCombineConjointOverC,
    fbCombineConjointOverReverseC,
    fbCombineConjointInC,
    fbCombineConjointInReverseC,
    fbCombineConjointOutC,
    fbCombineConjointOutReverseC,
    fbCombineConjointAtopC,
    fbCombineConjointAtopReverseC,
    fbCombineConjointXorC,
    NULL /* Noop */
};

FbComposeFunctions pixman_composeFunctions = {
    pixman_fbCombineFuncU,
    pixman_fbCombineFuncC,
    pixman_fbCombineMaskU
};
