Edit

IABSD.fr/xenocara/xserver/fb/fbpixmap.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2007-11-24 17:55:21
    Hash : b14d6de7
    Message : xserver 1.4

  • xserver/fb/fbpixmap.c
  • /*
     * 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 <stdlib.h>
    
    #include "fb.h"
    
    PixmapPtr
    fbCreatePixmapBpp (ScreenPtr pScreen, int width, int height, int depth, int bpp)
    {
        PixmapPtr	pPixmap;
        size_t	datasize;
        size_t	paddedWidth;
        int		adjust;
        int		base;
    
        paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits);
        if (paddedWidth / 4 > 32767 || height > 32767)
    	return NullPixmap;
        datasize = height * paddedWidth;
        base = pScreen->totalPixmapSize;
        adjust = 0;
        if (base & 7)
    	adjust = 8 - (base & 7);
        datasize += adjust;
    #ifdef FB_DEBUG
        datasize += 2 * paddedWidth;
    #endif
        pPixmap = AllocatePixmap(pScreen, datasize);
        if (!pPixmap)
    	return NullPixmap;
        pPixmap->drawable.type = DRAWABLE_PIXMAP;
        pPixmap->drawable.class = 0;
        pPixmap->drawable.pScreen = pScreen;
        pPixmap->drawable.depth = depth;
        pPixmap->drawable.bitsPerPixel = bpp;
        pPixmap->drawable.id = 0;
        pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
        pPixmap->drawable.x = 0;
        pPixmap->drawable.y = 0;
        pPixmap->drawable.width = width;
        pPixmap->drawable.height = height;
        pPixmap->devKind = paddedWidth;
        pPixmap->refcnt = 1;
        pPixmap->devPrivate.ptr = (pointer) ((char *)pPixmap + base + adjust);
    #ifdef FB_DEBUG
        pPixmap->devPrivate.ptr = (void *) ((char *) pPixmap->devPrivate.ptr + paddedWidth);
        fbInitializeDrawable (&pPixmap->drawable);
    #endif
    
    #ifdef COMPOSITE
        pPixmap->screen_x = 0;
        pPixmap->screen_y = 0;
    #endif
    
        return pPixmap;
    }
    
    PixmapPtr
    fbCreatePixmap (ScreenPtr pScreen, int width, int height, int depth)
    {
        int	bpp;
        bpp = BitsPerPixel (depth);
    #ifdef FB_SCREEN_PRIVATE
        if (bpp == 32 && depth <= 24)
    	bpp = fbGetScreenPrivate(pScreen)->pix32bpp;
    #endif
        return fbCreatePixmapBpp (pScreen, width, height, depth, bpp);
    }
    
    Bool
    fbDestroyPixmap (PixmapPtr pPixmap)
    {
        if(--pPixmap->refcnt)
    	return TRUE;
        xfree(pPixmap);
        return TRUE;
    }
    
    #define ADDRECT(reg,r,fr,rx1,ry1,rx2,ry2)			\
    if (((rx1) < (rx2)) && ((ry1) < (ry2)) &&			\
        (!((reg)->data->numRects &&					\
           ((r-1)->y1 == (ry1)) &&					\
           ((r-1)->y2 == (ry2)) &&					\
           ((r-1)->x1 <= (rx1)) &&					\
           ((r-1)->x2 >= (rx2)))))					\
    {								\
        if ((reg)->data->numRects == (reg)->data->size)		\
        {								\
    	miRectAlloc(reg, 1);					\
    	fr = REGION_BOXPTR(reg);				\
    	r = fr + (reg)->data->numRects;				\
        }								\
        r->x1 = (rx1);						\
        r->y1 = (ry1);						\
        r->x2 = (rx2);						\
        r->y2 = (ry2);						\
        (reg)->data->numRects++;					\
        if(r->x1 < (reg)->extents.x1)				\
    	(reg)->extents.x1 = r->x1;				\
        if(r->x2 > (reg)->extents.x2)				\
    	(reg)->extents.x2 = r->x2;				\
        r++;							\
    }
    
    /* Convert bitmap clip mask into clipping region. 
     * First, goes through each line and makes boxes by noting the transitions
     * from 0 to 1 and 1 to 0.
     * Then it coalesces the current line with the previous if they have boxes
     * at the same X coordinates.
     */
    RegionPtr
    fbPixmapToRegion(PixmapPtr pPix)
    {
        register RegionPtr	pReg;
        FbBits		*pw, w;
        register int	ib;
        int			width, h, base, rx1 = 0, crects;
        FbBits		*pwLineEnd;
        int			irectPrevStart, irectLineStart;
        register BoxPtr	prectO, prectN;
        BoxPtr		FirstRect, rects, prectLineStart;
        Bool		fInBox, fSame;
        register FbBits	mask0 = FB_ALLONES & ~FbScrRight(FB_ALLONES, 1);
        FbBits		*pwLine;
        int			nWidth;
        
        pReg = REGION_CREATE(pPix->drawable.pScreen, NULL, 1);
        if(!pReg)
    	return NullRegion;
        FirstRect = REGION_BOXPTR(pReg);
        rects = FirstRect;
    
        fbPrepareAccess(&pPix->drawable);
    
        pwLine = (FbBits *) pPix->devPrivate.ptr;
        nWidth = pPix->devKind >> (FB_SHIFT-3);
    
        width = pPix->drawable.width;
        pReg->extents.x1 = width - 1;
        pReg->extents.x2 = 0;
        irectPrevStart = -1;
        for(h = 0; h < pPix->drawable.height; h++)
        {
    	pw = pwLine;
    	pwLine += nWidth;
    	irectLineStart = rects - FirstRect;
    	/* If the Screen left most bit of the word is set, we're starting in
    	 * a box */
    	if(READ(pw) & mask0)
    	{
    	    fInBox = TRUE;
    	    rx1 = 0;
    	}
    	else
    	    fInBox = FALSE;
    	/* Process all words which are fully in the pixmap */
    	pwLineEnd = pw + (width >> FB_SHIFT);
    	for (base = 0; pw < pwLineEnd; base += FB_UNIT)
    	{
    	    w = READ(pw++);
    	    if (fInBox)
    	    {
    		if (!~w)
    		    continue;
    	    }
    	    else
    	    {
    		if (!w)
    		    continue;
    	    }
    	    for(ib = 0; ib < FB_UNIT; ib++)
    	    {
    	        /* If the Screen left most bit of the word is set, we're
    		 * starting a box */
    		if(w & mask0)
    		{
    		    if(!fInBox)
    		    {
    			rx1 = base + ib;
    			/* start new box */
    			fInBox = TRUE;
    		    }
    		}
    		else
    		{
    		    if(fInBox)
    		    {
    			/* end box */
    			ADDRECT(pReg, rects, FirstRect,
    				rx1, h, base + ib, h + 1);
    			fInBox = FALSE;
    		    }
    		}
    		/* Shift the word VISUALLY left one. */
    		w = FbScrLeft(w, 1);
    	    }
    	}
    	if(width & FB_MASK)
    	{
    	    /* Process final partial word on line */
    	    w = READ(pw++);
    	    for(ib = 0; ib < (width & FB_MASK); ib++)
    	    {
    	        /* If the Screen left most bit of the word is set, we're
    		 * starting a box */
    		if(w & mask0)
    		{
    		    if(!fInBox)
    		    {
    			rx1 = base + ib;
    			/* start new box */
    			fInBox = TRUE;
    		    }
    		}
    		else
    		{
    		    if(fInBox)
    		    {
    			/* end box */
    			ADDRECT(pReg, rects, FirstRect,
    				rx1, h, base + ib, h + 1);
    			fInBox = FALSE;
    		    }
    		}
    		/* Shift the word VISUALLY left one. */
    		w = FbScrLeft(w, 1);
    	    }
    	}
    	/* If scanline ended with last bit set, end the box */
    	if(fInBox)
    	{
    	    ADDRECT(pReg, rects, FirstRect,
    		    rx1, h, base + (width & FB_MASK), h + 1);
    	}
    	/* if all rectangles on this line have the same x-coords as
    	 * those on the previous line, then add 1 to all the previous  y2s and 
    	 * throw away all the rectangles from this line 
    	 */
    	fSame = FALSE;
    	if(irectPrevStart != -1)
    	{
    	    crects = irectLineStart - irectPrevStart;
    	    if(crects == ((rects - FirstRect) - irectLineStart))
    	    {
    	        prectO = FirstRect + irectPrevStart;
    	        prectN = prectLineStart = FirstRect + irectLineStart;
    		fSame = TRUE;
    	        while(prectO < prectLineStart)
    		{
    		    if((prectO->x1 != prectN->x1) || (prectO->x2 != prectN->x2))
    		    {
    			  fSame = FALSE;
    			  break;
    		    }
    		    prectO++;
    		    prectN++;
    		}
    		if (fSame)
    		{
    		    prectO = FirstRect + irectPrevStart;
    		    while(prectO < prectLineStart)
    		    {
    			prectO->y2 += 1;
    			prectO++;
    		    }
    		    rects -= crects;
    		    pReg->data->numRects -= crects;
    		}
    	    }
    	}
    	if(!fSame)
    	    irectPrevStart = irectLineStart;
        }
        if (!pReg->data->numRects)
    	pReg->extents.x1 = pReg->extents.x2 = 0;
        else
        {
    	pReg->extents.y1 = REGION_BOXPTR(pReg)->y1;
    	pReg->extents.y2 = REGION_END(pReg)->y2;
    	if (pReg->data->numRects == 1)
    	{
    	    xfree(pReg->data);
    	    pReg->data = (RegDataPtr)NULL;
    	}
        }
    
        fbFinishAccess(&pPix->drawable);
    #ifdef DEBUG
        if (!miValidRegion(pReg))
    	FatalError("Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__);
    #endif
        return(pReg);
    }
    
    #ifdef FB_DEBUG
    
    #ifndef WIN32
    #include <stdio.h>
    #else
    #include <dbg.h>
    #endif
    
    static Bool
    fbValidateBits (FbStip *bits, int stride, FbStip data)
    {
        while (stride--)
        {
    	if (*bits != data)
    	{
    #ifdef WIN32
    	    NCD_DEBUG ((DEBUG_FAILURE, "fdValidateBits failed at 0x%x (is 0x%x want 0x%x)",
    			bits, *bits, data));
    #else
    	    fprintf (stderr, "fbValidateBits failed\n");
    #endif
    	    return FALSE;
    	}
    	bits++;
        }
    }
    
    void
    fbValidateDrawable (DrawablePtr pDrawable)
    {
        FbStip	*bits, *first, *last;
        int		stride, bpp;
        int		xoff, yoff;
        int		height;
        Bool	failed;
        
        if (pDrawable->type != DRAWABLE_PIXMAP)
    	pDrawable = (DrawablePtr) fbGetWindowPixmap(pDrawable);
        fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff);
        first = bits - stride;
        last = bits + stride * pDrawable->height;
        if (!fbValidateBits (first, stride, FB_HEAD_BITS) ||
    	!fbValidateBits (last, stride, FB_TAIL_BITS))
    	fbInitializeDrawable(pDrawable);
        fbFinishAccess (pDrawable);
    }
    
    void
    fbSetBits (FbStip *bits, int stride, FbStip data)
    {
        while (stride--)
    	*bits++ = data;
    }
    
    void
    fbInitializeDrawable (DrawablePtr pDrawable)
    {
        FbStip  *bits, *first, *last;
        int	    stride, bpp;
        int	    xoff, yoff;
        
        fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff);
        first = bits - stride;
        last = bits + stride * pDrawable->height;
        fbSetBits (first, stride, FB_HEAD_BITS);
        fbSetBits (last, stride, FB_TAIL_BITS);
        fbFinishAccess (pDrawable);
    }
    #endif /* FB_DEBUG */