mibitblt.c revision 706f2543
1706f2543Smrg/***********************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg
25706f2543Smrg
26706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27706f2543Smrg
28706f2543Smrg                        All Rights Reserved
29706f2543Smrg
30706f2543SmrgPermission to use, copy, modify, and distribute this software and its
31706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
32706f2543Smrgprovided that the above copyright notice appear in all copies and that
33706f2543Smrgboth that copyright notice and this permission notice appear in
34706f2543Smrgsupporting documentation, and that the name of Digital not be
35706f2543Smrgused in advertising or publicity pertaining to distribution of the
36706f2543Smrgsoftware without specific, written prior permission.
37706f2543Smrg
38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44706f2543SmrgSOFTWARE.
45706f2543Smrg
46706f2543Smrg******************************************************************/
47706f2543Smrg/* Author: Todd Newman  (aided and abetted by Mr. Drewry) */
48706f2543Smrg
49706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
50706f2543Smrg#include <dix-config.h>
51706f2543Smrg#endif
52706f2543Smrg
53706f2543Smrg#include <X11/X.h>
54706f2543Smrg#include <X11/Xprotostr.h>
55706f2543Smrg
56706f2543Smrg#include "misc.h"
57706f2543Smrg#include "gcstruct.h"
58706f2543Smrg#include "pixmapstr.h"
59706f2543Smrg#include "windowstr.h"
60706f2543Smrg#include "scrnintstr.h"
61706f2543Smrg#include "mi.h"
62706f2543Smrg#include "regionstr.h"
63706f2543Smrg#include <X11/Xmd.h>
64706f2543Smrg#include "servermd.h"
65706f2543Smrg
66706f2543Smrg#ifndef HAS_FFS
67706f2543Smrgextern int ffs(int);
68706f2543Smrg#endif
69706f2543Smrg
70706f2543Smrg/* MICOPYAREA -- public entry for the CopyArea request
71706f2543Smrg * For each rectangle in the source region
72706f2543Smrg *     get the pixels with GetSpans
73706f2543Smrg *     set them in the destination with SetSpans
74706f2543Smrg * We let SetSpans worry about clipping to the destination.
75706f2543Smrg */
76706f2543SmrgRegionPtr
77706f2543SmrgmiCopyArea(DrawablePtr  pSrcDrawable,
78706f2543Smrg           DrawablePtr  pDstDrawable,
79706f2543Smrg           GCPtr        pGC,
80706f2543Smrg           int          xIn,
81706f2543Smrg           int          yIn,
82706f2543Smrg           int          widthSrc,
83706f2543Smrg           int          heightSrc,
84706f2543Smrg           int          xOut,
85706f2543Smrg           int          yOut)
86706f2543Smrg{
87706f2543Smrg    DDXPointPtr		ppt, pptFirst;
88706f2543Smrg    unsigned int	*pwidthFirst, *pwidth, *pbits;
89706f2543Smrg    BoxRec 		srcBox, *prect;
90706f2543Smrg    			/* may be a new region, or just a copy */
91706f2543Smrg    RegionPtr 		prgnSrcClip;
92706f2543Smrg    			/* non-0 if we've created a src clip */
93706f2543Smrg    RegionPtr		prgnExposed;
94706f2543Smrg    int 		realSrcClip = 0;
95706f2543Smrg    int			srcx, srcy, dstx, dsty, i, j, y, width, height,
96706f2543Smrg    			xMin, xMax, yMin, yMax;
97706f2543Smrg    unsigned int	*ordering;
98706f2543Smrg    int			numRects;
99706f2543Smrg    BoxPtr		boxes;
100706f2543Smrg
101706f2543Smrg    srcx = xIn + pSrcDrawable->x;
102706f2543Smrg    srcy = yIn + pSrcDrawable->y;
103706f2543Smrg
104706f2543Smrg    /* If the destination isn't realized, this is easy */
105706f2543Smrg    if (pDstDrawable->type == DRAWABLE_WINDOW &&
106706f2543Smrg	!((WindowPtr)pDstDrawable)->realized)
107706f2543Smrg	return NULL;
108706f2543Smrg
109706f2543Smrg    /* clip the source */
110706f2543Smrg    if (pSrcDrawable->type == DRAWABLE_PIXMAP)
111706f2543Smrg    {
112706f2543Smrg	BoxRec box;
113706f2543Smrg
114706f2543Smrg	box.x1 = pSrcDrawable->x;
115706f2543Smrg	box.y1 = pSrcDrawable->y;
116706f2543Smrg	box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
117706f2543Smrg	box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
118706f2543Smrg
119706f2543Smrg	prgnSrcClip = RegionCreate(&box, 1);
120706f2543Smrg	realSrcClip = 1;
121706f2543Smrg    }
122706f2543Smrg    else
123706f2543Smrg    {
124706f2543Smrg	if (pGC->subWindowMode == IncludeInferiors) {
125706f2543Smrg	    prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable);
126706f2543Smrg	    realSrcClip = 1;
127706f2543Smrg	} else
128706f2543Smrg	    prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
129706f2543Smrg    }
130706f2543Smrg
131706f2543Smrg    /* If the src drawable is a window, we need to translate the srcBox so
132706f2543Smrg     * that we can compare it with the window's clip region later on. */
133706f2543Smrg    srcBox.x1 = srcx;
134706f2543Smrg    srcBox.y1 = srcy;
135706f2543Smrg    srcBox.x2 = srcx  + widthSrc;
136706f2543Smrg    srcBox.y2 = srcy  + heightSrc;
137706f2543Smrg
138706f2543Smrg    dstx = xOut;
139706f2543Smrg    dsty = yOut;
140706f2543Smrg    if (pGC->miTranslate)
141706f2543Smrg    {
142706f2543Smrg	dstx += pDstDrawable->x;
143706f2543Smrg	dsty += pDstDrawable->y;
144706f2543Smrg    }
145706f2543Smrg
146706f2543Smrg    pptFirst = ppt = malloc(heightSrc * sizeof(DDXPointRec));
147706f2543Smrg    pwidthFirst = pwidth = malloc(heightSrc * sizeof(unsigned int));
148706f2543Smrg    numRects = RegionNumRects(prgnSrcClip);
149706f2543Smrg    boxes = RegionRects(prgnSrcClip);
150706f2543Smrg    ordering = malloc(numRects * sizeof(unsigned int));
151706f2543Smrg    if(!pptFirst || !pwidthFirst || !ordering)
152706f2543Smrg    {
153706f2543Smrg       free(ordering);
154706f2543Smrg       free(pwidthFirst);
155706f2543Smrg       free(pptFirst);
156706f2543Smrg       return NULL;
157706f2543Smrg    }
158706f2543Smrg
159706f2543Smrg    /* If not the same drawable then order of move doesn't matter.
160706f2543Smrg       Following assumes that boxes are sorted from top
161706f2543Smrg       to bottom and left to right.
162706f2543Smrg    */
163706f2543Smrg    if ((pSrcDrawable != pDstDrawable) &&
164706f2543Smrg	((pGC->subWindowMode != IncludeInferiors) ||
165706f2543Smrg	 (pSrcDrawable->type == DRAWABLE_PIXMAP) ||
166706f2543Smrg	 (pDstDrawable->type == DRAWABLE_PIXMAP)))
167706f2543Smrg      for (i=0; i < numRects; i++)
168706f2543Smrg        ordering[i] = i;
169706f2543Smrg    else { /* within same drawable, must sequence moves carefully! */
170706f2543Smrg      if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical.
171706f2543Smrg                                  Vertical order OK */
172706f2543Smrg        if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal.
173706f2543Smrg                                  Horizontal order OK as well */
174706f2543Smrg          for (i=0; i < numRects; i++)
175706f2543Smrg            ordering[i] = i;
176706f2543Smrg        else { /* scroll right. must reverse horizontal banding of rects. */
177706f2543Smrg          for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) {
178706f2543Smrg            /* find extent of current horizontal band */
179706f2543Smrg            y=boxes[i].y1; /* band has this y coordinate */
180706f2543Smrg            while ((j < numRects) && (boxes[j].y1 == y))
181706f2543Smrg              j++;
182706f2543Smrg            /* reverse the horizontal band in the output ordering */
183706f2543Smrg            for (j-- ; j >= xMax; j--, i++)
184706f2543Smrg              ordering[i] = j;
185706f2543Smrg          }
186706f2543Smrg        }
187706f2543Smrg      }
188706f2543Smrg      else { /* Scroll down. Must reverse vertical banding. */
189706f2543Smrg        if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */
190706f2543Smrg          for (i=numRects-1, j=i-1, yMin=i, yMax=0;
191706f2543Smrg              i >= 0;
192706f2543Smrg              j=i-1, yMin=i) {
193706f2543Smrg            /* find extent of current horizontal band */
194706f2543Smrg            y=boxes[i].y1; /* band has this y coordinate */
195706f2543Smrg            while ((j >= 0) && (boxes[j].y1 == y))
196706f2543Smrg              j--;
197706f2543Smrg            /* reverse the horizontal band in the output ordering */
198706f2543Smrg            for (j++ ; j <= yMin; j++, i--, yMax++)
199706f2543Smrg              ordering[yMax] = j;
200706f2543Smrg          }
201706f2543Smrg        }
202706f2543Smrg        else /* Scroll right or horizontal stationary.
203706f2543Smrg                Reverse horizontal order as well (if stationary, horizontal
204706f2543Smrg                order can be swapped without penalty and this is faster
205706f2543Smrg                to compute). */
206706f2543Smrg          for (i=0, j=numRects-1; i < numRects; i++, j--)
207706f2543Smrg              ordering[i] = j;
208706f2543Smrg      }
209706f2543Smrg    }
210706f2543Smrg
211706f2543Smrg     for(i = 0; i < numRects; i++)
212706f2543Smrg     {
213706f2543Smrg        prect = &boxes[ordering[i]];
214706f2543Smrg  	xMin = max(prect->x1, srcBox.x1);
215706f2543Smrg  	xMax = min(prect->x2, srcBox.x2);
216706f2543Smrg  	yMin = max(prect->y1, srcBox.y1);
217706f2543Smrg	yMax = min(prect->y2, srcBox.y2);
218706f2543Smrg	/* is there anything visible here? */
219706f2543Smrg	if(xMax <= xMin || yMax <= yMin)
220706f2543Smrg	    continue;
221706f2543Smrg
222706f2543Smrg        ppt = pptFirst;
223706f2543Smrg	pwidth = pwidthFirst;
224706f2543Smrg	y = yMin;
225706f2543Smrg	height = yMax - yMin;
226706f2543Smrg	width = xMax - xMin;
227706f2543Smrg
228706f2543Smrg	for(j = 0; j < height; j++)
229706f2543Smrg	{
230706f2543Smrg	    /* We must untranslate before calling GetSpans */
231706f2543Smrg	    ppt->x = xMin;
232706f2543Smrg	    ppt++->y = y++;
233706f2543Smrg	    *pwidth++ = width;
234706f2543Smrg	}
235706f2543Smrg	pbits = malloc(height * PixmapBytePad(width, pSrcDrawable->depth));
236706f2543Smrg	if (pbits)
237706f2543Smrg	{
238706f2543Smrg	    (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst,
239706f2543Smrg			(int *)pwidthFirst, height, (char *)pbits);
240706f2543Smrg	    ppt = pptFirst;
241706f2543Smrg	    pwidth = pwidthFirst;
242706f2543Smrg	    xMin -= (srcx - dstx);
243706f2543Smrg	    y = yMin - (srcy - dsty);
244706f2543Smrg	    for(j = 0; j < height; j++)
245706f2543Smrg	    {
246706f2543Smrg		ppt->x = xMin;
247706f2543Smrg		ppt++->y = y++;
248706f2543Smrg		*pwidth++ = width;
249706f2543Smrg	    }
250706f2543Smrg
251706f2543Smrg	    (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst,
252706f2543Smrg				  (int *)pwidthFirst, height, TRUE);
253706f2543Smrg	    free(pbits);
254706f2543Smrg	}
255706f2543Smrg    }
256706f2543Smrg    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
257706f2543Smrg		      widthSrc, heightSrc, xOut, yOut, (unsigned long)0);
258706f2543Smrg    if(realSrcClip)
259706f2543Smrg	RegionDestroy(prgnSrcClip);
260706f2543Smrg
261706f2543Smrg    free(ordering);
262706f2543Smrg    free(pwidthFirst);
263706f2543Smrg    free(pptFirst);
264706f2543Smrg    return prgnExposed;
265706f2543Smrg}
266706f2543Smrg
267706f2543Smrg/* MIGETPLANE -- gets a bitmap representing one plane of pDraw
268706f2543Smrg * A helper used for CopyPlane and XY format GetImage
269706f2543Smrg * No clever strategy here, we grab a scanline at a time, pull out the
270706f2543Smrg * bits and then stuff them in a 1 bit deep map.
271706f2543Smrg */
272706f2543Smrg/*
273706f2543Smrg * This should be replaced with something more general.  mi shouldn't have to
274706f2543Smrg * care about such things as scanline padding et alia.
275706f2543Smrg */
276706f2543Smrgstatic
277706f2543SmrgMiBits	*
278706f2543SmrgmiGetPlane(
279706f2543Smrg    DrawablePtr		pDraw,
280706f2543Smrg    int			planeNum,	/* number of the bitPlane */
281706f2543Smrg    int			sx,
282706f2543Smrg    int			sy,
283706f2543Smrg    int			w,
284706f2543Smrg    int			h,
285706f2543Smrg    MiBits	*result)
286706f2543Smrg{
287706f2543Smrg    int			i, j, k, width, bitsPerPixel, widthInBytes;
288706f2543Smrg    DDXPointRec 	pt = {0, 0};
289706f2543Smrg    MiBits	pixel;
290706f2543Smrg    MiBits	bit;
291706f2543Smrg    unsigned char	*pCharsOut = NULL;
292706f2543Smrg
293706f2543Smrg#if BITMAP_SCANLINE_UNIT == 8
294706f2543Smrg#define OUT_TYPE unsigned char
295706f2543Smrg#endif
296706f2543Smrg#if BITMAP_SCANLINE_UNIT == 16
297706f2543Smrg#define OUT_TYPE CARD16
298706f2543Smrg#endif
299706f2543Smrg#if BITMAP_SCANLINE_UNIT == 32
300706f2543Smrg#define OUT_TYPE CARD32
301706f2543Smrg#endif
302706f2543Smrg#if BITMAP_SCANLINE_UNIT == 64
303706f2543Smrg#define OUT_TYPE CARD64
304706f2543Smrg#endif
305706f2543Smrg
306706f2543Smrg    OUT_TYPE		*pOut;
307706f2543Smrg    int			delta = 0;
308706f2543Smrg
309706f2543Smrg    sx += pDraw->x;
310706f2543Smrg    sy += pDraw->y;
311706f2543Smrg    widthInBytes = BitmapBytePad(w);
312706f2543Smrg    if(!result)
313706f2543Smrg        result = calloc(h, widthInBytes);
314706f2543Smrg    if (!result)
315706f2543Smrg	return NULL;
316706f2543Smrg    bitsPerPixel = pDraw->bitsPerPixel;
317706f2543Smrg    pOut = (OUT_TYPE *) result;
318706f2543Smrg    if(bitsPerPixel == 1)
319706f2543Smrg    {
320706f2543Smrg	pCharsOut = (unsigned char *) result;
321706f2543Smrg    	width = w;
322706f2543Smrg    }
323706f2543Smrg    else
324706f2543Smrg    {
325706f2543Smrg	delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) -
326706f2543Smrg	    (w / BITMAP_SCANLINE_UNIT);
327706f2543Smrg	width = 1;
328706f2543Smrg#if IMAGE_BYTE_ORDER == MSBFirst
329706f2543Smrg	planeNum += (32 - bitsPerPixel);
330706f2543Smrg#endif
331706f2543Smrg    }
332706f2543Smrg    pt.y = sy;
333706f2543Smrg    for (i = h; --i >= 0; pt.y++)
334706f2543Smrg    {
335706f2543Smrg	pt.x = sx;
336706f2543Smrg	if(bitsPerPixel == 1)
337706f2543Smrg	{
338706f2543Smrg	    (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
339706f2543Smrg					(char *)pCharsOut);
340706f2543Smrg	    pCharsOut += widthInBytes;
341706f2543Smrg	}
342706f2543Smrg	else
343706f2543Smrg	{
344706f2543Smrg	    k = 0;
345706f2543Smrg	    for(j = w; --j >= 0; pt.x++)
346706f2543Smrg	    {
347706f2543Smrg		/* Fetch the next pixel */
348706f2543Smrg		(*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
349706f2543Smrg					    (char *)&pixel);
350706f2543Smrg		/*
351706f2543Smrg		 * Now get the bit and insert into a bitmap in XY format.
352706f2543Smrg		 */
353706f2543Smrg		bit = (pixel >> planeNum) & 1;
354706f2543Smrg#if 0
355706f2543Smrg		/* XXX assuming bit order == byte order */
356706f2543Smrg#if BITMAP_BIT_ORDER == LSBFirst
357706f2543Smrg		bit <<= k;
358706f2543Smrg#else
359706f2543Smrg		bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k);
360706f2543Smrg#endif
361706f2543Smrg#else
362706f2543Smrg		/* XXX assuming byte order == LSBFirst */
363706f2543Smrg		if (screenInfo.bitmapBitOrder == LSBFirst)
364706f2543Smrg			bit <<= k;
365706f2543Smrg		else
366706f2543Smrg			bit <<= ((screenInfo.bitmapScanlineUnit - 1) -
367706f2543Smrg				 (k % screenInfo.bitmapScanlineUnit)) +
368706f2543Smrg				((k / screenInfo.bitmapScanlineUnit) *
369706f2543Smrg				 screenInfo.bitmapScanlineUnit);
370706f2543Smrg#endif
371706f2543Smrg		*pOut |= (OUT_TYPE) bit;
372706f2543Smrg		k++;
373706f2543Smrg		if (k == BITMAP_SCANLINE_UNIT)
374706f2543Smrg		{
375706f2543Smrg		    pOut++;
376706f2543Smrg		    k = 0;
377706f2543Smrg		}
378706f2543Smrg	    }
379706f2543Smrg	    pOut += delta;
380706f2543Smrg	}
381706f2543Smrg    }
382706f2543Smrg    return result;
383706f2543Smrg
384706f2543Smrg}
385706f2543Smrg
386706f2543Smrg/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw.
387706f2543Smrg * Drawing through the clip mask we SetSpans() the bits into a
388706f2543Smrg * bitmap and stipple those bits onto the destination drawable by doing a
389706f2543Smrg * PolyFillRect over the whole drawable,
390706f2543Smrg * then we invert the bitmap by copying it onto itself with an alu of
391706f2543Smrg * GXinvert, invert the foreground/background colors of the gc, and draw
392706f2543Smrg * the background bits.
393706f2543Smrg * Note how the clipped out bits of the bitmap are always the background
394706f2543Smrg * color so that the stipple never causes FillRect to draw them.
395706f2543Smrg */
396706f2543Smrgstatic void
397706f2543SmrgmiOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc,
398706f2543Smrg		  MiBits *pbits, int srcx, int w, int h, int dstx, int dsty)
399706f2543Smrg{
400706f2543Smrg    int		oldfill, i;
401706f2543Smrg    unsigned long oldfg;
402706f2543Smrg    int		*pwidth, *pwidthFirst;
403706f2543Smrg    ChangeGCVal	gcv[6];
404706f2543Smrg    PixmapPtr	pStipple, pPixmap;
405706f2543Smrg    DDXPointRec	oldOrg;
406706f2543Smrg    GCPtr	pGCT;
407706f2543Smrg    DDXPointPtr ppt, pptFirst;
408706f2543Smrg    xRectangle rect;
409706f2543Smrg    RegionPtr	prgnSrcClip;
410706f2543Smrg
411706f2543Smrg    pPixmap = (*pDraw->pScreen->CreatePixmap)
412706f2543Smrg			   (pDraw->pScreen, w + srcx, h, 1,
413706f2543Smrg			    CREATE_PIXMAP_USAGE_SCRATCH);
414706f2543Smrg    if (!pPixmap)
415706f2543Smrg	return;
416706f2543Smrg
417706f2543Smrg    /* Put the image into a 1 bit deep pixmap */
418706f2543Smrg    pGCT = GetScratchGC(1, pDraw->pScreen);
419706f2543Smrg    if (!pGCT)
420706f2543Smrg    {
421706f2543Smrg	(*pDraw->pScreen->DestroyPixmap)(pPixmap);
422706f2543Smrg	return;
423706f2543Smrg    }
424706f2543Smrg    /* First set the whole pixmap to 0 */
425706f2543Smrg    gcv[0].val = 0;
426706f2543Smrg    ChangeGC(NullClient, pGCT, GCBackground, gcv);
427706f2543Smrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
428706f2543Smrg    miClearDrawable((DrawablePtr)pPixmap, pGCT);
429706f2543Smrg    ppt = pptFirst = malloc(h * sizeof(DDXPointRec));
430706f2543Smrg    pwidth = pwidthFirst = malloc(h * sizeof(int));
431706f2543Smrg    if(!pptFirst || !pwidthFirst)
432706f2543Smrg    {
433706f2543Smrg	free(pwidthFirst);
434706f2543Smrg	free(pptFirst);
435706f2543Smrg	FreeScratchGC(pGCT);
436706f2543Smrg	return;
437706f2543Smrg    }
438706f2543Smrg
439706f2543Smrg    /* we need a temporary region because ChangeClip must be assumed
440706f2543Smrg       to destroy what it's sent.  note that this means we don't
441706f2543Smrg       have to free prgnSrcClip ourselves.
442706f2543Smrg    */
443706f2543Smrg    prgnSrcClip = RegionCreate(NULL, 0);
444706f2543Smrg    RegionCopy(prgnSrcClip, prgnSrc);
445706f2543Smrg    RegionTranslate(prgnSrcClip, srcx, 0);
446706f2543Smrg    (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0);
447706f2543Smrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
448706f2543Smrg
449706f2543Smrg    /* Since we know pDraw is always a pixmap, we never need to think
450706f2543Smrg     * about translation here */
451706f2543Smrg    for(i = 0; i < h; i++)
452706f2543Smrg    {
453706f2543Smrg	ppt->x = 0;
454706f2543Smrg	ppt++->y = i;
455706f2543Smrg	*pwidth++ = w + srcx;
456706f2543Smrg    }
457706f2543Smrg
458706f2543Smrg    (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits,
459706f2543Smrg			   pptFirst, pwidthFirst, h, TRUE);
460706f2543Smrg    free(pwidthFirst);
461706f2543Smrg    free(pptFirst);
462706f2543Smrg
463706f2543Smrg
464706f2543Smrg    /* Save current values from the client GC */
465706f2543Smrg    oldfill = pGC->fillStyle;
466706f2543Smrg    pStipple = pGC->stipple;
467706f2543Smrg    if(pStipple)
468706f2543Smrg        pStipple->refcnt++;
469706f2543Smrg    oldOrg = pGC->patOrg;
470706f2543Smrg
471706f2543Smrg    /* Set a new stipple in the drawable */
472706f2543Smrg    gcv[0].val = FillStippled;
473706f2543Smrg    gcv[1].ptr = pPixmap;
474706f2543Smrg    gcv[2].val = dstx - srcx;
475706f2543Smrg    gcv[3].val = dsty;
476706f2543Smrg
477706f2543Smrg    ChangeGC(NullClient, pGC,
478706f2543Smrg             GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
479706f2543Smrg	     gcv);
480706f2543Smrg    ValidateGC(pDraw, pGC);
481706f2543Smrg
482706f2543Smrg    /* Fill the drawable with the stipple.  This will draw the
483706f2543Smrg     * foreground color whereever 1 bits are set, leaving everything
484706f2543Smrg     * with 0 bits untouched.  Note that the part outside the clip
485706f2543Smrg     * region is all 0s.  */
486706f2543Smrg    rect.x = dstx;
487706f2543Smrg    rect.y = dsty;
488706f2543Smrg    rect.width = w;
489706f2543Smrg    rect.height = h;
490706f2543Smrg    (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
491706f2543Smrg
492706f2543Smrg    /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only
493706f2543Smrg     * within the clipping region, the part outside is still all 0s */
494706f2543Smrg    gcv[0].val = GXinvert;
495706f2543Smrg    ChangeGC(NullClient, pGCT, GCFunction, gcv);
496706f2543Smrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
497706f2543Smrg    (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap,
498706f2543Smrg			   pGCT, 0, 0, w + srcx, h, 0, 0);
499706f2543Smrg
500706f2543Smrg    /* Swap foreground and background colors on the GC for the drawable.
501706f2543Smrg     * Now when we fill the drawable, we will fill in the "Background"
502706f2543Smrg     * values */
503706f2543Smrg    oldfg = pGC->fgPixel;
504706f2543Smrg    gcv[0].val = pGC->bgPixel;
505706f2543Smrg    gcv[1].val = oldfg;
506706f2543Smrg    gcv[2].ptr = pPixmap;
507706f2543Smrg    ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, gcv);
508706f2543Smrg    ValidateGC(pDraw, pGC);
509706f2543Smrg    /* PolyFillRect might have bashed the rectangle */
510706f2543Smrg    rect.x = dstx;
511706f2543Smrg    rect.y = dsty;
512706f2543Smrg    rect.width = w;
513706f2543Smrg    rect.height = h;
514706f2543Smrg    (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
515706f2543Smrg
516706f2543Smrg    /* Now put things back */
517706f2543Smrg    if(pStipple)
518706f2543Smrg        pStipple->refcnt--;
519706f2543Smrg    gcv[0].val = oldfg;
520706f2543Smrg    gcv[1].val = pGC->fgPixel;
521706f2543Smrg    gcv[2].val = oldfill;
522706f2543Smrg    gcv[3].ptr = pStipple;
523706f2543Smrg    gcv[4].val = oldOrg.x;
524706f2543Smrg    gcv[5].val = oldOrg.y;
525706f2543Smrg    ChangeGC(NullClient, pGC,
526706f2543Smrg        GCForeground | GCBackground | GCFillStyle | GCStipple |
527706f2543Smrg	GCTileStipXOrigin | GCTileStipYOrigin, gcv);
528706f2543Smrg
529706f2543Smrg    ValidateGC(pDraw, pGC);
530706f2543Smrg    /* put what we hope is a smaller clip region back in the scratch gc */
531706f2543Smrg    (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0);
532706f2543Smrg    FreeScratchGC(pGCT);
533706f2543Smrg    (*pDraw->pScreen->DestroyPixmap)(pPixmap);
534706f2543Smrg
535706f2543Smrg}
536706f2543Smrg
537706f2543Smrg/* MICOPYPLANE -- public entry for the CopyPlane request.
538706f2543Smrg * strategy:
539706f2543Smrg * First build up a bitmap out of the bits requested
540706f2543Smrg * build a source clip
541706f2543Smrg * Use the bitmap we've built up as a Stipple for the destination
542706f2543Smrg */
543706f2543SmrgRegionPtr
544706f2543SmrgmiCopyPlane( DrawablePtr pSrcDrawable,
545706f2543Smrg             DrawablePtr pDstDrawable,
546706f2543Smrg             GCPtr pGC,
547706f2543Smrg             int srcx,
548706f2543Smrg             int srcy,
549706f2543Smrg             int width,
550706f2543Smrg             int height,
551706f2543Smrg             int dstx,
552706f2543Smrg             int dsty,
553706f2543Smrg             unsigned long bitPlane)
554706f2543Smrg{
555706f2543Smrg    MiBits	*ptile;
556706f2543Smrg    BoxRec 		box;
557706f2543Smrg    RegionPtr		prgnSrc, prgnExposed;
558706f2543Smrg
559706f2543Smrg    /* incorporate the source clip */
560706f2543Smrg
561706f2543Smrg    box.x1 = srcx + pSrcDrawable->x;
562706f2543Smrg    box.y1 = srcy + pSrcDrawable->y;
563706f2543Smrg    box.x2 = box.x1 + width;
564706f2543Smrg    box.y2 = box.y1 + height;
565706f2543Smrg    /* clip to visible drawable */
566706f2543Smrg    if (box.x1 < pSrcDrawable->x)
567706f2543Smrg	box.x1 = pSrcDrawable->x;
568706f2543Smrg    if (box.y1 < pSrcDrawable->y)
569706f2543Smrg	box.y1 = pSrcDrawable->y;
570706f2543Smrg    if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
571706f2543Smrg	box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
572706f2543Smrg    if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
573706f2543Smrg	box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
574706f2543Smrg    if (box.x1 > box.x2)
575706f2543Smrg	box.x2 = box.x1;
576706f2543Smrg    if (box.y1 > box.y2)
577706f2543Smrg	box.y2 = box.y1;
578706f2543Smrg    prgnSrc = RegionCreate(&box, 1);
579706f2543Smrg
580706f2543Smrg    if (pSrcDrawable->type != DRAWABLE_PIXMAP) {
581706f2543Smrg	/* clip to visible drawable */
582706f2543Smrg
583706f2543Smrg	if (pGC->subWindowMode == IncludeInferiors)
584706f2543Smrg	{
585706f2543Smrg	    RegionPtr	clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable);
586706f2543Smrg	    RegionIntersect(prgnSrc, prgnSrc, clipList);
587706f2543Smrg	    RegionDestroy(clipList);
588706f2543Smrg	} else
589706f2543Smrg	    RegionIntersect(prgnSrc, prgnSrc,
590706f2543Smrg				       &((WindowPtr)pSrcDrawable)->clipList);
591706f2543Smrg    }
592706f2543Smrg
593706f2543Smrg    box = *RegionExtents(prgnSrc);
594706f2543Smrg    RegionTranslate(prgnSrc, -box.x1, -box.y1);
595706f2543Smrg
596706f2543Smrg    if ((box.x2 > box.x1) && (box.y2 > box.y1))
597706f2543Smrg    {
598706f2543Smrg	/* minimize the size of the data extracted */
599706f2543Smrg	/* note that we convert the plane mask bitPlane into a plane number */
600706f2543Smrg	box.x1 -= pSrcDrawable->x;
601706f2543Smrg	box.x2 -= pSrcDrawable->x;
602706f2543Smrg	box.y1 -= pSrcDrawable->y;
603706f2543Smrg	box.y2 -= pSrcDrawable->y;
604706f2543Smrg	ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1,
605706f2543Smrg			   box.x1, box.y1,
606706f2543Smrg			   box.x2 - box.x1, box.y2 - box.y1,
607706f2543Smrg			   (MiBits *) NULL);
608706f2543Smrg	if (ptile)
609706f2543Smrg	{
610706f2543Smrg	    miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0,
611706f2543Smrg			      box.x2 - box.x1, box.y2 - box.y1,
612706f2543Smrg			      dstx + box.x1 - srcx, dsty + box.y1 - srcy);
613706f2543Smrg	    free(ptile);
614706f2543Smrg	}
615706f2543Smrg    }
616706f2543Smrg    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
617706f2543Smrg		      width, height, dstx, dsty, bitPlane);
618706f2543Smrg    RegionDestroy(prgnSrc);
619706f2543Smrg    return prgnExposed;
620706f2543Smrg}
621706f2543Smrg
622706f2543Smrg/* MIGETIMAGE -- public entry for the GetImage Request
623706f2543Smrg * We're getting the image into a memory buffer. While we have to use GetSpans
624706f2543Smrg * to read a line from the device (since we don't know what that looks like),
625706f2543Smrg * we can just write into the destination buffer
626706f2543Smrg *
627706f2543Smrg * two different strategies are used, depending on whether we're getting the
628706f2543Smrg * image in Z format or XY format
629706f2543Smrg * Z format:
630706f2543Smrg * Line at a time, GetSpans a line into the destination buffer, then if the
631706f2543Smrg * planemask is not all ones, we do a SetSpans into a temporary buffer (to get
632706f2543Smrg * bits turned off) and then another GetSpans to get stuff back (because
633706f2543Smrg * pixmaps are opaque, and we are passed in the memory to write into).  This is
634706f2543Smrg * pretty ugly and slow but works.  Life is hard.
635706f2543Smrg * XY format:
636706f2543Smrg * get the single plane specified in planemask
637706f2543Smrg */
638706f2543Smrgvoid
639706f2543SmrgmiGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h,
640706f2543Smrg            unsigned int format, unsigned long planeMask, char *pDst)
641706f2543Smrg{
642706f2543Smrg    unsigned char	depth;
643706f2543Smrg    int			i, linelength, width, srcx, srcy;
644706f2543Smrg    DDXPointRec		pt = {0, 0};
645706f2543Smrg    PixmapPtr		pPixmap = NULL;
646706f2543Smrg    GCPtr		pGC = NULL;
647706f2543Smrg
648706f2543Smrg    depth = pDraw->depth;
649706f2543Smrg    if(format == ZPixmap)
650706f2543Smrg    {
651706f2543Smrg	if ( (((1LL<<depth)-1)&planeMask) != (1LL<<depth)-1 )
652706f2543Smrg	{
653706f2543Smrg	    ChangeGCVal gcv;
654706f2543Smrg	    xPoint pt;
655706f2543Smrg
656706f2543Smrg	    pGC = GetScratchGC(depth, pDraw->pScreen);
657706f2543Smrg	    if (!pGC)
658706f2543Smrg		return;
659706f2543Smrg            pPixmap = (*pDraw->pScreen->CreatePixmap)
660706f2543Smrg			       (pDraw->pScreen, w, 1, depth,
661706f2543Smrg			        CREATE_PIXMAP_USAGE_SCRATCH);
662706f2543Smrg	    if (!pPixmap)
663706f2543Smrg	    {
664706f2543Smrg		FreeScratchGC(pGC);
665706f2543Smrg		return;
666706f2543Smrg	    }
667706f2543Smrg 	    /*
668706f2543Smrg 	     * Clear the pixmap before doing anything else
669706f2543Smrg 	     */
670706f2543Smrg 	    ValidateGC((DrawablePtr)pPixmap, pGC);
671706f2543Smrg 	    pt.x = pt.y = 0;
672706f2543Smrg            width = w;
673706f2543Smrg	    (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width,
674706f2543Smrg				   TRUE);
675706f2543Smrg
676706f2543Smrg	    /* alu is already GXCopy */
677706f2543Smrg	    gcv.val = (XID)planeMask;
678706f2543Smrg	    ChangeGC(NullClient, pGC, GCPlaneMask, &gcv);
679706f2543Smrg	    ValidateGC((DrawablePtr)pPixmap, pGC);
680706f2543Smrg	}
681706f2543Smrg
682706f2543Smrg        linelength = PixmapBytePad(w, depth);
683706f2543Smrg	srcx = sx + pDraw->x;
684706f2543Smrg	srcy = sy + pDraw->y;
685706f2543Smrg	for(i = 0; i < h; i++)
686706f2543Smrg	{
687706f2543Smrg	    pt.x = srcx;
688706f2543Smrg	    pt.y = srcy + i;
689706f2543Smrg	    width = w;
690706f2543Smrg	    (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst);
691706f2543Smrg	    if (pPixmap)
692706f2543Smrg	    {
693706f2543Smrg	       pt.x = 0;
694706f2543Smrg	       pt.y = 0;
695706f2543Smrg	       width = w;
696706f2543Smrg	       (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst,
697706f2543Smrg				     &pt, &width, 1, TRUE);
698706f2543Smrg	       (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt,
699706f2543Smrg					   &width, 1, pDst);
700706f2543Smrg	    }
701706f2543Smrg	    pDst += linelength;
702706f2543Smrg	}
703706f2543Smrg	if (pPixmap)
704706f2543Smrg	{
705706f2543Smrg	    (*pGC->pScreen->DestroyPixmap)(pPixmap);
706706f2543Smrg	    FreeScratchGC(pGC);
707706f2543Smrg	}
708706f2543Smrg    }
709706f2543Smrg    else
710706f2543Smrg    {
711706f2543Smrg	(void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h,
712706f2543Smrg			  (MiBits *)pDst);
713706f2543Smrg    }
714706f2543Smrg}
715706f2543Smrg
716706f2543Smrg/* MIPUTIMAGE -- public entry for the PutImage request
717706f2543Smrg * Here we benefit from knowing the format of the bits pointed to by pImage,
718706f2543Smrg * even if we don't know how pDraw represents them.
719706f2543Smrg * Three different strategies are used depending on the format
720706f2543Smrg * XYBitmap Format:
721706f2543Smrg * 	we just use the Opaque Stipple helper function to cover the destination
722706f2543Smrg * 	Note that this covers all the planes of the drawable with the
723706f2543Smrg *	foreground color (masked with the GC planemask) where there are 1 bits
724706f2543Smrg *	and the background color (masked with the GC planemask) where there are
725706f2543Smrg *	0 bits
726706f2543Smrg * XYPixmap format:
727706f2543Smrg *	what we're called with is a series of XYBitmaps, but we only want
728706f2543Smrg *	each XYPixmap to update 1 plane, instead of updating all of them.
729706f2543Smrg * 	we set the foreground color to be all 1s and the background to all 0s
730706f2543Smrg *	then for each plane, we set the plane mask to only effect that one
731706f2543Smrg *	plane and recursive call ourself with the format set to XYBitmap
732706f2543Smrg *	(This clever idea courtesy of RGD.)
733706f2543Smrg * ZPixmap format:
734706f2543Smrg *	This part is simple, just call SetSpans
735706f2543Smrg */
736706f2543Smrgvoid
737706f2543SmrgmiPutImage( DrawablePtr pDraw, GCPtr pGC, int depth,
738706f2543Smrg            int x, int y, int w, int h,
739706f2543Smrg            int leftPad, int format, char *pImage)
740706f2543Smrg{
741706f2543Smrg    DDXPointPtr		pptFirst, ppt;
742706f2543Smrg    int			*pwidthFirst, *pwidth;
743706f2543Smrg    RegionPtr		prgnSrc;
744706f2543Smrg    BoxRec		box;
745706f2543Smrg    unsigned long	oldFg, oldBg;
746706f2543Smrg    ChangeGCVal		gcv[3];
747706f2543Smrg    unsigned long	oldPlanemask;
748706f2543Smrg    unsigned long	i;
749706f2543Smrg    long		bytesPer;
750706f2543Smrg
751706f2543Smrg    if (!w || !h)
752706f2543Smrg	return;
753706f2543Smrg    switch(format)
754706f2543Smrg    {
755706f2543Smrg      case XYBitmap:
756706f2543Smrg
757706f2543Smrg	box.x1 = 0;
758706f2543Smrg	box.y1 = 0;
759706f2543Smrg	box.x2 = w;
760706f2543Smrg	box.y2 = h;
761706f2543Smrg	prgnSrc = RegionCreate(&box, 1);
762706f2543Smrg
763706f2543Smrg        miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage,
764706f2543Smrg			  leftPad, w, h, x, y);
765706f2543Smrg	RegionDestroy(prgnSrc);
766706f2543Smrg	break;
767706f2543Smrg
768706f2543Smrg      case XYPixmap:
769706f2543Smrg	depth = pGC->depth;
770706f2543Smrg	oldPlanemask = pGC->planemask;
771706f2543Smrg	oldFg = pGC->fgPixel;
772706f2543Smrg	oldBg = pGC->bgPixel;
773706f2543Smrg	gcv[0].val = (XID)~0;
774706f2543Smrg	gcv[1].val = (XID)0;
775706f2543Smrg	ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv);
776706f2543Smrg	bytesPer = (long)h * BitmapBytePad(w + leftPad);
777706f2543Smrg
778706f2543Smrg	for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer)
779706f2543Smrg	{
780706f2543Smrg	    if (i & oldPlanemask)
781706f2543Smrg	    {
782706f2543Smrg	        gcv[0].val = (XID)i;
783706f2543Smrg	        ChangeGC(NullClient, pGC, GCPlaneMask, gcv);
784706f2543Smrg	        ValidateGC(pDraw, pGC);
785706f2543Smrg	        (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad,
786706f2543Smrg			         XYBitmap, (char *)pImage);
787706f2543Smrg	    }
788706f2543Smrg	}
789706f2543Smrg	gcv[0].val = (XID)oldPlanemask;
790706f2543Smrg	gcv[1].val = (XID)oldFg;
791706f2543Smrg	gcv[2].val = (XID)oldBg;
792706f2543Smrg	ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground, gcv);
793706f2543Smrg	ValidateGC(pDraw, pGC);
794706f2543Smrg	break;
795706f2543Smrg
796706f2543Smrg      case ZPixmap:
797706f2543Smrg        ppt = pptFirst = malloc(h * sizeof(DDXPointRec));
798706f2543Smrg        pwidth = pwidthFirst = malloc(h * sizeof(int));
799706f2543Smrg	if(!pptFirst || !pwidthFirst)
800706f2543Smrg        {
801706f2543Smrg	   free(pwidthFirst);
802706f2543Smrg           free(pptFirst);
803706f2543Smrg           return;
804706f2543Smrg        }
805706f2543Smrg	if (pGC->miTranslate)
806706f2543Smrg	{
807706f2543Smrg	    x += pDraw->x;
808706f2543Smrg	    y += pDraw->y;
809706f2543Smrg	}
810706f2543Smrg
811706f2543Smrg	for(i = 0; i < h; i++)
812706f2543Smrg	{
813706f2543Smrg	    ppt->x = x;
814706f2543Smrg	    ppt->y = y + i;
815706f2543Smrg	    ppt++;
816706f2543Smrg	    *pwidth++ = w;
817706f2543Smrg	}
818706f2543Smrg
819706f2543Smrg	(*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst,
820706f2543Smrg			      pwidthFirst, h, TRUE);
821706f2543Smrg	free(pwidthFirst);
822706f2543Smrg	free(pptFirst);
823706f2543Smrg	break;
824706f2543Smrg    }
825706f2543Smrg}
826