/*
 * Copyright © 1998 Keith Packard
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

#include "fb.h"

void
fbPushPattern (DrawablePtr  pDrawable,
	       GCPtr	    pGC,
	       
	       FbStip	    *src,
	       FbStride	    srcStride,
	       int	    srcX,

	       int	    x,
	       int	    y,

	       int	    width,
	       int	    height)
{
    FbStip	    *s, bitsMask, bitsMask0, bits;
    int		    xspan;
    int		    w;
    int		    lenspan;
    
    src += srcX >> FB_STIP_SHIFT;
    srcX &= FB_STIP_MASK;
    
    bitsMask0 = FbStipMask (srcX, 1);
    
    while (height--)
    {
	bitsMask = bitsMask0;
	w = width;
	s = src;
	src += srcStride;
	bits = READ(s++);
	xspan = x;
	while (w)
	{
	    if (bits & bitsMask)
	    {
		lenspan = 0;
		do
		{
		    lenspan++;
		    if (lenspan == w)
			break;
		    bitsMask = FbStipRight (bitsMask, 1);
		    if (!bitsMask)
		    {
			bits = READ(s++);
			bitsMask = FbBitsMask(0,1);
		    }
		} while (bits & bitsMask);
		fbFill (pDrawable, pGC, xspan, y, lenspan, 1);
		xspan += lenspan;
		w -= lenspan;
	    }
	    else
	    {
		do
		{
		    w--;
		    xspan++;
		    if (!w)
			break;
		    bitsMask = FbStipRight (bitsMask, 1);
		    if (!bitsMask)
		    {
			bits = READ(s++);
			bitsMask = FbBitsMask(0,1);
		    }
		} while (!(bits & bitsMask));
	    }
	}
	y++;
    }
}

void
fbPushFill (DrawablePtr	pDrawable,
	    GCPtr	pGC,

	    FbStip	*src,
	    FbStride	srcStride,
	    int		srcX,
	    
	    int		x,
	    int		y,
	    int		width,
	    int		height)
{
    FbGCPrivPtr	pPriv = fbGetGCPrivate(pGC);
    
    if (pGC->fillStyle == FillSolid)
    {
	FbBits	    *dst;
	FbStride    dstStride;
	int	    dstBpp;
	int	    dstXoff, dstYoff;
	int	    dstX;
	int	    dstWidth;

	fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
	dst = dst + (y + dstYoff) * dstStride;
	dstX = (x + dstXoff) * dstBpp;
	dstWidth = width * dstBpp;
	if (dstBpp == 1)
	{
	    fbBltStip (src,
		       srcStride,
		       srcX,
    
		       (FbStip *) dst,
		       FbBitsStrideToStipStride (dstStride),
		       dstX,
    
		       dstWidth,
		       height,
    
		       FbStipple1Rop(pGC->alu,pGC->fgPixel),
		       pPriv->pm,
		       dstBpp);
	}
	else
	{
	    fbBltOne (src,
		      srcStride,
		      srcX,
    
		      dst,
		      dstStride,
		      dstX,
		      dstBpp,
    
		      dstWidth,
		      height,
    
		      pPriv->and, pPriv->xor,
		      fbAnd(GXnoop,(FbBits) 0,FB_ALLONES),
		      fbXor(GXnoop,(FbBits) 0,FB_ALLONES));
	}
	fbFinishAccess (pDrawable);
    }
    else
    {
	fbPushPattern (pDrawable, pGC, src, srcStride, srcX,
		       x, y, width, height);
    }
}
	    
void
fbPushImage (DrawablePtr    pDrawable,
	     GCPtr	    pGC,
	     
	     FbStip	    *src,
	     FbStride	    srcStride,
	     int	    srcX,

	     int	    x,
	     int	    y,
	     int	    width,
	     int	    height)
{
    RegionPtr	pClip = fbGetCompositeClip (pGC);
    int		nbox;
    BoxPtr	pbox;
    int		x1, y1, x2, y2;
    
    for (nbox = REGION_NUM_RECTS (pClip),
	 pbox = REGION_RECTS(pClip);
	 nbox--;
	 pbox++)
    {
	x1 = x;
	y1 = y;
	x2 = x + width;
	y2 = y + height;
	if (x1 < pbox->x1)
	    x1 = pbox->x1;
	if (y1 < pbox->y1)
	    y1 = pbox->y1;
	if (x2 > pbox->x2)
	    x2 = pbox->x2;
	if (y2 > pbox->y2)
	    y2 = pbox->y2;
	if (x1 >= x2 || y1 >= y2)
	    continue;
	fbPushFill (pDrawable,
		    pGC,

		    src + (y1 - y) * srcStride,
		    srcStride,
		    srcX + (x1 - x),

		    x1,
		    y1,
		    x2 - x1,
		    y2 - y1);
    }
}
	     
void
fbPushPixels (GCPtr	    pGC,
	      PixmapPtr	    pBitmap,
	      DrawablePtr   pDrawable,
	      int	    dx,
	      int	    dy,
	      int	    xOrg,
	      int	    yOrg)
{
    FbStip	*stip;
    FbStride	stipStride;
    int		stipBpp;
    int		stipXoff, stipYoff; /* Assumed to be zero */

    fbGetStipDrawable (&pBitmap->drawable, stip, stipStride, stipBpp, stipXoff, stipYoff);

    fbPushImage (pDrawable, pGC,
		 stip, stipStride, 0,
		 xOrg, yOrg, dx, dy);
}