mibitblt.c revision 05b261ec
1/***********************************************************
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47/* Author: Todd Newman  (aided and abetted by Mr. Drewry) */
48
49#ifdef HAVE_DIX_CONFIG_H
50#include <dix-config.h>
51#endif
52
53#include <X11/X.h>
54#include <X11/Xprotostr.h>
55
56#include "misc.h"
57#include "gcstruct.h"
58#include "pixmapstr.h"
59#include "windowstr.h"
60#include "scrnintstr.h"
61#include "mi.h"
62#include "regionstr.h"
63#include <X11/Xmd.h>
64#include "servermd.h"
65
66#ifndef HAS_FFS
67extern int ffs(int);
68#endif
69
70/* MICOPYAREA -- public entry for the CopyArea request
71 * For each rectangle in the source region
72 *     get the pixels with GetSpans
73 *     set them in the destination with SetSpans
74 * We let SetSpans worry about clipping to the destination.
75 */
76_X_EXPORT RegionPtr
77miCopyArea(pSrcDrawable, pDstDrawable,
78	    pGC, xIn, yIn, widthSrc, heightSrc, xOut, yOut)
79    DrawablePtr 	pSrcDrawable;
80    DrawablePtr 	pDstDrawable;
81    GCPtr 		pGC;
82    int 		xIn, yIn;
83    int 		widthSrc, heightSrc;
84    int 		xOut, yOut;
85{
86    DDXPointPtr		ppt, pptFirst;
87    unsigned int	*pwidthFirst, *pwidth, *pbits;
88    BoxRec 		srcBox, *prect;
89    			/* may be a new region, or just a copy */
90    RegionPtr 		prgnSrcClip;
91    			/* non-0 if we've created a src clip */
92    RegionPtr		prgnExposed;
93    int 		realSrcClip = 0;
94    int			srcx, srcy, dstx, dsty, i, j, y, width, height,
95    			xMin, xMax, yMin, yMax;
96    unsigned int	*ordering;
97    int			numRects;
98    BoxPtr		boxes;
99
100    srcx = xIn + pSrcDrawable->x;
101    srcy = yIn + pSrcDrawable->y;
102
103    /* If the destination isn't realized, this is easy */
104    if (pDstDrawable->type == DRAWABLE_WINDOW &&
105	!((WindowPtr)pDstDrawable)->realized)
106	return (RegionPtr)NULL;
107
108    /* clip the source */
109    if (pSrcDrawable->type == DRAWABLE_PIXMAP)
110    {
111	BoxRec box;
112
113	box.x1 = pSrcDrawable->x;
114	box.y1 = pSrcDrawable->y;
115	box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
116	box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
117
118	prgnSrcClip = REGION_CREATE(pGC->pScreen, &box, 1);
119	realSrcClip = 1;
120    }
121    else
122    {
123	if (pGC->subWindowMode == IncludeInferiors) {
124	    prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable);
125	    realSrcClip = 1;
126	} else
127	    prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
128    }
129
130    /* If the src drawable is a window, we need to translate the srcBox so
131     * that we can compare it with the window's clip region later on. */
132    srcBox.x1 = srcx;
133    srcBox.y1 = srcy;
134    srcBox.x2 = srcx  + widthSrc;
135    srcBox.y2 = srcy  + heightSrc;
136
137    dstx = xOut;
138    dsty = yOut;
139    if (pGC->miTranslate)
140    {
141	dstx += pDstDrawable->x;
142	dsty += pDstDrawable->y;
143    }
144
145    pptFirst = ppt = (DDXPointPtr)
146        ALLOCATE_LOCAL(heightSrc * sizeof(DDXPointRec));
147    pwidthFirst = pwidth = (unsigned int *)
148        ALLOCATE_LOCAL(heightSrc * sizeof(unsigned int));
149    numRects = REGION_NUM_RECTS(prgnSrcClip);
150    boxes = REGION_RECTS(prgnSrcClip);
151    ordering = (unsigned int *)
152        ALLOCATE_LOCAL(numRects * sizeof(unsigned int));
153    if(!pptFirst || !pwidthFirst || !ordering)
154    {
155       if (ordering)
156	   DEALLOCATE_LOCAL(ordering);
157       if (pwidthFirst)
158           DEALLOCATE_LOCAL(pwidthFirst);
159       if (pptFirst)
160           DEALLOCATE_LOCAL(pptFirst);
161       return (RegionPtr)NULL;
162    }
163
164    /* If not the same drawable then order of move doesn't matter.
165       Following assumes that boxes are sorted from top
166       to bottom and left to right.
167    */
168    if ((pSrcDrawable != pDstDrawable) &&
169	((pGC->subWindowMode != IncludeInferiors) ||
170	 (pSrcDrawable->type == DRAWABLE_PIXMAP) ||
171	 (pDstDrawable->type == DRAWABLE_PIXMAP)))
172      for (i=0; i < numRects; i++)
173        ordering[i] = i;
174    else { /* within same drawable, must sequence moves carefully! */
175      if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical.
176                                  Vertical order OK */
177        if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal.
178                                  Horizontal order OK as well */
179          for (i=0; i < numRects; i++)
180            ordering[i] = i;
181        else { /* scroll right. must reverse horizontal banding of rects. */
182          for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) {
183            /* find extent of current horizontal band */
184            y=boxes[i].y1; /* band has this y coordinate */
185            while ((j < numRects) && (boxes[j].y1 == y))
186              j++;
187            /* reverse the horizontal band in the output ordering */
188            for (j-- ; j >= xMax; j--, i++)
189              ordering[i] = j;
190          }
191        }
192      }
193      else { /* Scroll down. Must reverse vertical banding. */
194        if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */
195          for (i=numRects-1, j=i-1, yMin=i, yMax=0;
196              i >= 0;
197              j=i-1, yMin=i) {
198            /* find extent of current horizontal band */
199            y=boxes[i].y1; /* band has this y coordinate */
200            while ((j >= 0) && (boxes[j].y1 == y))
201              j--;
202            /* reverse the horizontal band in the output ordering */
203            for (j++ ; j <= yMin; j++, i--, yMax++)
204              ordering[yMax] = j;
205          }
206        }
207        else /* Scroll right or horizontal stationary.
208                Reverse horizontal order as well (if stationary, horizontal
209                order can be swapped without penalty and this is faster
210                to compute). */
211          for (i=0, j=numRects-1; i < numRects; i++, j--)
212              ordering[i] = j;
213      }
214    }
215
216     for(i = 0; i < numRects; i++)
217     {
218        prect = &boxes[ordering[i]];
219  	xMin = max(prect->x1, srcBox.x1);
220  	xMax = min(prect->x2, srcBox.x2);
221  	yMin = max(prect->y1, srcBox.y1);
222	yMax = min(prect->y2, srcBox.y2);
223	/* is there anything visible here? */
224	if(xMax <= xMin || yMax <= yMin)
225	    continue;
226
227        ppt = pptFirst;
228	pwidth = pwidthFirst;
229	y = yMin;
230	height = yMax - yMin;
231	width = xMax - xMin;
232
233	for(j = 0; j < height; j++)
234	{
235	    /* We must untranslate before calling GetSpans */
236	    ppt->x = xMin;
237	    ppt++->y = y++;
238	    *pwidth++ = width;
239	}
240	pbits = (unsigned int *)xalloc(height * PixmapBytePad(width,
241					     pSrcDrawable->depth));
242	if (pbits)
243	{
244	    (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst,
245			(int *)pwidthFirst, height, (char *)pbits);
246	    ppt = pptFirst;
247	    pwidth = pwidthFirst;
248	    xMin -= (srcx - dstx);
249	    y = yMin - (srcy - dsty);
250	    for(j = 0; j < height; j++)
251	    {
252		ppt->x = xMin;
253		ppt++->y = y++;
254		*pwidth++ = width;
255	    }
256
257	    (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst,
258				  (int *)pwidthFirst, height, TRUE);
259	    xfree(pbits);
260	}
261    }
262    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
263		      widthSrc, heightSrc, xOut, yOut, (unsigned long)0);
264    if(realSrcClip)
265	REGION_DESTROY(pGC->pScreen, prgnSrcClip);
266
267    DEALLOCATE_LOCAL(ordering);
268    DEALLOCATE_LOCAL(pwidthFirst);
269    DEALLOCATE_LOCAL(pptFirst);
270    return prgnExposed;
271}
272
273/* MIGETPLANE -- gets a bitmap representing one plane of pDraw
274 * A helper used for CopyPlane and XY format GetImage
275 * No clever strategy here, we grab a scanline at a time, pull out the
276 * bits and then stuff them in a 1 bit deep map.
277 */
278/*
279 * This should be replaced with something more general.  mi shouldn't have to
280 * care about such things as scanline padding et alia.
281 */
282static
283MiBits	*
284miGetPlane(
285    DrawablePtr		pDraw,
286    int			planeNum,	/* number of the bitPlane */
287    int			sx,
288    int			sy,
289    int			w,
290    int			h,
291    MiBits	*result)
292{
293    int			i, j, k, width, bitsPerPixel, widthInBytes;
294    DDXPointRec 	pt = {0, 0};
295    MiBits	pixel;
296    MiBits	bit;
297    unsigned char	*pCharsOut = NULL;
298
299#if BITMAP_SCANLINE_UNIT == 8
300#define OUT_TYPE unsigned char
301#endif
302#if BITMAP_SCANLINE_UNIT == 16
303#define OUT_TYPE CARD16
304#endif
305#if BITMAP_SCANLINE_UNIT == 32
306#define OUT_TYPE CARD32
307#endif
308#if BITMAP_SCANLINE_UNIT == 64
309#define OUT_TYPE CARD64
310#endif
311
312    OUT_TYPE		*pOut;
313    int			delta = 0;
314
315    sx += pDraw->x;
316    sy += pDraw->y;
317    widthInBytes = BitmapBytePad(w);
318    if(!result)
319        result = (MiBits *)xalloc(h * widthInBytes);
320    if (!result)
321	return (MiBits *)NULL;
322    bitsPerPixel = pDraw->bitsPerPixel;
323    bzero((char *)result, h * widthInBytes);
324    pOut = (OUT_TYPE *) result;
325    if(bitsPerPixel == 1)
326    {
327	pCharsOut = (unsigned char *) result;
328    	width = w;
329    }
330    else
331    {
332	delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) -
333	    (w / BITMAP_SCANLINE_UNIT);
334	width = 1;
335#if IMAGE_BYTE_ORDER == MSBFirst
336	planeNum += (32 - bitsPerPixel);
337#endif
338    }
339    pt.y = sy;
340    for (i = h; --i >= 0; pt.y++)
341    {
342	pt.x = sx;
343	if(bitsPerPixel == 1)
344	{
345	    (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
346					(char *)pCharsOut);
347	    pCharsOut += widthInBytes;
348	}
349	else
350	{
351	    k = 0;
352	    for(j = w; --j >= 0; pt.x++)
353	    {
354		/* Fetch the next pixel */
355		(*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
356					    (char *)&pixel);
357		/*
358		 * Now get the bit and insert into a bitmap in XY format.
359		 */
360		bit = (pixel >> planeNum) & 1;
361#if 0
362		/* XXX assuming bit order == byte order */
363#if BITMAP_BIT_ORDER == LSBFirst
364		bit <<= k;
365#else
366		bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k);
367#endif
368#else
369		/* XXX assuming byte order == LSBFirst */
370		if (screenInfo.bitmapBitOrder == LSBFirst)
371			bit <<= k;
372		else
373			bit <<= ((screenInfo.bitmapScanlineUnit - 1) -
374				 (k % screenInfo.bitmapScanlineUnit)) +
375				((k / screenInfo.bitmapScanlineUnit) *
376				 screenInfo.bitmapScanlineUnit);
377#endif
378		*pOut |= (OUT_TYPE) bit;
379		k++;
380		if (k == BITMAP_SCANLINE_UNIT)
381		{
382		    pOut++;
383		    k = 0;
384		}
385	    }
386	    pOut += delta;
387	}
388    }
389    return(result);
390
391}
392
393/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw.
394 * Drawing through the clip mask we SetSpans() the bits into a
395 * bitmap and stipple those bits onto the destination drawable by doing a
396 * PolyFillRect over the whole drawable,
397 * then we invert the bitmap by copying it onto itself with an alu of
398 * GXinvert, invert the foreground/background colors of the gc, and draw
399 * the background bits.
400 * Note how the clipped out bits of the bitmap are always the background
401 * color so that the stipple never causes FillRect to draw them.
402 */
403static void
404miOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc,
405		  MiBits *pbits, int srcx, int w, int h, int dstx, int dsty)
406{
407    int		oldfill, i;
408    unsigned long oldfg;
409    int		*pwidth, *pwidthFirst;
410    ChangeGCVal	gcv[6];
411    PixmapPtr	pStipple, pPixmap;
412    DDXPointRec	oldOrg;
413    GCPtr	pGCT;
414    DDXPointPtr ppt, pptFirst;
415    xRectangle rect;
416    RegionPtr	prgnSrcClip;
417
418    pPixmap = (*pDraw->pScreen->CreatePixmap)
419			   (pDraw->pScreen, w + srcx, h, 1);
420    if (!pPixmap)
421	return;
422
423    /* Put the image into a 1 bit deep pixmap */
424    pGCT = GetScratchGC(1, pDraw->pScreen);
425    if (!pGCT)
426    {
427	(*pDraw->pScreen->DestroyPixmap)(pPixmap);
428	return;
429    }
430    /* First set the whole pixmap to 0 */
431    gcv[0].val = 0;
432    dixChangeGC(NullClient, pGCT, GCBackground, NULL, gcv);
433    ValidateGC((DrawablePtr)pPixmap, pGCT);
434    miClearDrawable((DrawablePtr)pPixmap, pGCT);
435    ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec));
436    pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int));
437    if(!pptFirst || !pwidthFirst)
438    {
439	if (pwidthFirst) DEALLOCATE_LOCAL(pwidthFirst);
440	if (pptFirst) DEALLOCATE_LOCAL(pptFirst);
441	FreeScratchGC(pGCT);
442	return;
443    }
444
445    /* we need a temporary region because ChangeClip must be assumed
446       to destroy what it's sent.  note that this means we don't
447       have to free prgnSrcClip ourselves.
448    */
449    prgnSrcClip = REGION_CREATE(pGCT->pScreen, NULL, 0);
450    REGION_COPY(pGCT->pScreen, prgnSrcClip, prgnSrc);
451    REGION_TRANSLATE(pGCT->pScreen, prgnSrcClip, srcx, 0);
452    (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0);
453    ValidateGC((DrawablePtr)pPixmap, pGCT);
454
455    /* Since we know pDraw is always a pixmap, we never need to think
456     * about translation here */
457    for(i = 0; i < h; i++)
458    {
459	ppt->x = 0;
460	ppt++->y = i;
461	*pwidth++ = w + srcx;
462    }
463
464    (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits,
465			   pptFirst, pwidthFirst, h, TRUE);
466    DEALLOCATE_LOCAL(pwidthFirst);
467    DEALLOCATE_LOCAL(pptFirst);
468
469
470    /* Save current values from the client GC */
471    oldfill = pGC->fillStyle;
472    pStipple = pGC->stipple;
473    if(pStipple)
474        pStipple->refcnt++;
475    oldOrg = pGC->patOrg;
476
477    /* Set a new stipple in the drawable */
478    gcv[0].val = FillStippled;
479    gcv[1].ptr = pPixmap;
480    gcv[2].val = dstx - srcx;
481    gcv[3].val = dsty;
482
483    dixChangeGC(NullClient, pGC,
484             GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
485	     NULL, gcv);
486    ValidateGC(pDraw, pGC);
487
488    /* Fill the drawable with the stipple.  This will draw the
489     * foreground color whereever 1 bits are set, leaving everything
490     * with 0 bits untouched.  Note that the part outside the clip
491     * region is all 0s.  */
492    rect.x = dstx;
493    rect.y = dsty;
494    rect.width = w;
495    rect.height = h;
496    (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
497
498    /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only
499     * within the clipping region, the part outside is still all 0s */
500    gcv[0].val = GXinvert;
501    dixChangeGC(NullClient, pGCT, GCFunction, NULL, gcv);
502    ValidateGC((DrawablePtr)pPixmap, pGCT);
503    (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap,
504			   pGCT, 0, 0, w + srcx, h, 0, 0);
505
506    /* Swap foreground and background colors on the GC for the drawable.
507     * Now when we fill the drawable, we will fill in the "Background"
508     * values */
509    oldfg = pGC->fgPixel;
510    gcv[0].val = pGC->bgPixel;
511    gcv[1].val = oldfg;
512    gcv[2].ptr = pPixmap;
513    dixChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple,
514		NULL, gcv);
515    ValidateGC(pDraw, pGC);
516    /* PolyFillRect might have bashed the rectangle */
517    rect.x = dstx;
518    rect.y = dsty;
519    rect.width = w;
520    rect.height = h;
521    (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
522
523    /* Now put things back */
524    if(pStipple)
525        pStipple->refcnt--;
526    gcv[0].val = oldfg;
527    gcv[1].val = pGC->fgPixel;
528    gcv[2].val = oldfill;
529    gcv[3].ptr = pStipple;
530    gcv[4].val = oldOrg.x;
531    gcv[5].val = oldOrg.y;
532    dixChangeGC(NullClient, pGC,
533        GCForeground | GCBackground | GCFillStyle | GCStipple |
534	GCTileStipXOrigin | GCTileStipYOrigin, NULL, gcv);
535
536    ValidateGC(pDraw, pGC);
537    /* put what we hope is a smaller clip region back in the scratch gc */
538    (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0);
539    FreeScratchGC(pGCT);
540    (*pDraw->pScreen->DestroyPixmap)(pPixmap);
541
542}
543
544/* MICOPYPLANE -- public entry for the CopyPlane request.
545 * strategy:
546 * First build up a bitmap out of the bits requested
547 * build a source clip
548 * Use the bitmap we've built up as a Stipple for the destination
549 */
550_X_EXPORT RegionPtr
551miCopyPlane(pSrcDrawable, pDstDrawable,
552	    pGC, srcx, srcy, width, height, dstx, dsty, bitPlane)
553    DrawablePtr 	pSrcDrawable;
554    DrawablePtr		pDstDrawable;
555    GCPtr		pGC;
556    int 		srcx, srcy;
557    int 		width, height;
558    int 		dstx, dsty;
559    unsigned long	bitPlane;
560{
561    MiBits	*ptile;
562    BoxRec 		box;
563    RegionPtr		prgnSrc, prgnExposed;
564
565    /* incorporate the source clip */
566
567    box.x1 = srcx + pSrcDrawable->x;
568    box.y1 = srcy + pSrcDrawable->y;
569    box.x2 = box.x1 + width;
570    box.y2 = box.y1 + height;
571    /* clip to visible drawable */
572    if (box.x1 < pSrcDrawable->x)
573	box.x1 = pSrcDrawable->x;
574    if (box.y1 < pSrcDrawable->y)
575	box.y1 = pSrcDrawable->y;
576    if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
577	box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
578    if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
579	box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
580    if (box.x1 > box.x2)
581	box.x2 = box.x1;
582    if (box.y1 > box.y2)
583	box.y2 = box.y1;
584    prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1);
585
586    if (pSrcDrawable->type != DRAWABLE_PIXMAP) {
587	/* clip to visible drawable */
588
589	if (pGC->subWindowMode == IncludeInferiors)
590	{
591	    RegionPtr	clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable);
592	    REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, clipList);
593	    REGION_DESTROY(pGC->pScreen, clipList);
594	} else
595	    REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc,
596				       &((WindowPtr)pSrcDrawable)->clipList);
597    }
598
599    box = *REGION_EXTENTS(pGC->pScreen, prgnSrc);
600    REGION_TRANSLATE(pGC->pScreen, prgnSrc, -box.x1, -box.y1);
601
602    if ((box.x2 > box.x1) && (box.y2 > box.y1))
603    {
604	/* minimize the size of the data extracted */
605	/* note that we convert the plane mask bitPlane into a plane number */
606	box.x1 -= pSrcDrawable->x;
607	box.x2 -= pSrcDrawable->x;
608	box.y1 -= pSrcDrawable->y;
609	box.y2 -= pSrcDrawable->y;
610	ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1,
611			   box.x1, box.y1,
612			   box.x2 - box.x1, box.y2 - box.y1,
613			   (MiBits *) NULL);
614	if (ptile)
615	{
616	    miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0,
617			      box.x2 - box.x1, box.y2 - box.y1,
618			      dstx + box.x1 - srcx, dsty + box.y1 - srcy);
619	    xfree(ptile);
620	}
621    }
622    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
623		      width, height, dstx, dsty, bitPlane);
624    REGION_DESTROY(pGC->pScreen, prgnSrc);
625    return prgnExposed;
626}
627
628/* MIGETIMAGE -- public entry for the GetImage Request
629 * We're getting the image into a memory buffer. While we have to use GetSpans
630 * to read a line from the device (since we don't know what that looks like),
631 * we can just write into the destination buffer
632 *
633 * two different strategies are used, depending on whether we're getting the
634 * image in Z format or XY format
635 * Z format:
636 * Line at a time, GetSpans a line into the destination buffer, then if the
637 * planemask is not all ones, we do a SetSpans into a temporary buffer (to get
638 * bits turned off) and then another GetSpans to get stuff back (because
639 * pixmaps are opaque, and we are passed in the memory to write into).  This is
640 * pretty ugly and slow but works.  Life is hard.
641 * XY format:
642 * get the single plane specified in planemask
643 */
644_X_EXPORT void
645miGetImage(pDraw, sx, sy, w, h, format, planeMask, pDst)
646    DrawablePtr 	pDraw;
647    int			sx, sy, w, h;
648    unsigned int 	format;
649    unsigned long 	planeMask;
650    char *              pDst;
651{
652    unsigned char	depth;
653    int			i, linelength, width, srcx, srcy;
654    DDXPointRec		pt = {0, 0};
655    XID			gcv[2];
656    PixmapPtr		pPixmap = (PixmapPtr)NULL;
657    GCPtr		pGC = NULL;
658
659    depth = pDraw->depth;
660    if(format == ZPixmap)
661    {
662	if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 )
663	{
664	    xPoint pt;
665
666	    pGC = GetScratchGC(depth, pDraw->pScreen);
667	    if (!pGC)
668		return;
669            pPixmap = (*pDraw->pScreen->CreatePixmap)
670			       (pDraw->pScreen, w, 1, depth);
671	    if (!pPixmap)
672	    {
673		FreeScratchGC(pGC);
674		return;
675	    }
676 	    /*
677 	     * Clear the pixmap before doing anything else
678 	     */
679 	    ValidateGC((DrawablePtr)pPixmap, pGC);
680 	    pt.x = pt.y = 0;
681            width = w;
682	    (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width,
683				   TRUE);
684
685	    /* alu is already GXCopy */
686	    gcv[0] = (XID)planeMask;
687	    DoChangeGC(pGC, GCPlaneMask, gcv, 0);
688	    ValidateGC((DrawablePtr)pPixmap, pGC);
689	}
690
691        linelength = PixmapBytePad(w, depth);
692	srcx = sx + pDraw->x;
693	srcy = sy + pDraw->y;
694	for(i = 0; i < h; i++)
695	{
696	    pt.x = srcx;
697	    pt.y = srcy + i;
698	    width = w;
699	    (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst);
700	    if (pPixmap)
701	    {
702	       pt.x = 0;
703	       pt.y = 0;
704	       width = w;
705	       (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst,
706				     &pt, &width, 1, TRUE);
707	       (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt,
708					   &width, 1, pDst);
709	    }
710	    pDst += linelength;
711	}
712	if (pPixmap)
713	{
714	    (*pGC->pScreen->DestroyPixmap)(pPixmap);
715	    FreeScratchGC(pGC);
716	}
717    }
718    else
719    {
720	(void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h,
721			  (MiBits *)pDst);
722    }
723}
724
725/* MIPUTIMAGE -- public entry for the PutImage request
726 * Here we benefit from knowing the format of the bits pointed to by pImage,
727 * even if we don't know how pDraw represents them.
728 * Three different strategies are used depending on the format
729 * XYBitmap Format:
730 * 	we just use the Opaque Stipple helper function to cover the destination
731 * 	Note that this covers all the planes of the drawable with the
732 *	foreground color (masked with the GC planemask) where there are 1 bits
733 *	and the background color (masked with the GC planemask) where there are
734 *	0 bits
735 * XYPixmap format:
736 *	what we're called with is a series of XYBitmaps, but we only want
737 *	each XYPixmap to update 1 plane, instead of updating all of them.
738 * 	we set the foreground color to be all 1s and the background to all 0s
739 *	then for each plane, we set the plane mask to only effect that one
740 *	plane and recursive call ourself with the format set to XYBitmap
741 *	(This clever idea courtesy of RGD.)
742 * ZPixmap format:
743 *	This part is simple, just call SetSpans
744 */
745_X_EXPORT void
746miPutImage(pDraw, pGC, depth, x, y, w, h, leftPad, format, pImage)
747    DrawablePtr		pDraw;
748    GCPtr		pGC;
749    int 		depth, x, y, w, h, leftPad;
750    int			format;
751    char		*pImage;
752{
753    DDXPointPtr		pptFirst, ppt;
754    int			*pwidthFirst, *pwidth;
755    RegionPtr		prgnSrc;
756    BoxRec		box;
757    unsigned long	oldFg, oldBg;
758    XID			gcv[3];
759    unsigned long	oldPlanemask;
760    unsigned long	i;
761    long		bytesPer;
762
763    if (!w || !h)
764	return;
765    switch(format)
766    {
767      case XYBitmap:
768
769	box.x1 = 0;
770	box.y1 = 0;
771	box.x2 = w;
772	box.y2 = h;
773	prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1);
774
775        miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage,
776			  leftPad, w, h, x, y);
777	REGION_DESTROY(pGC->pScreen, prgnSrc);
778	break;
779
780      case XYPixmap:
781	depth = pGC->depth;
782	oldPlanemask = pGC->planemask;
783	oldFg = pGC->fgPixel;
784	oldBg = pGC->bgPixel;
785	gcv[0] = (XID)~0;
786	gcv[1] = (XID)0;
787	DoChangeGC(pGC, GCForeground | GCBackground, gcv, 0);
788	bytesPer = (long)h * BitmapBytePad(w + leftPad);
789
790	for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer)
791	{
792	    if (i & oldPlanemask)
793	    {
794	        gcv[0] = (XID)i;
795	        DoChangeGC(pGC, GCPlaneMask, gcv, 0);
796	        ValidateGC(pDraw, pGC);
797	        (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad,
798			         XYBitmap, (char *)pImage);
799	    }
800	}
801	gcv[0] = (XID)oldPlanemask;
802	gcv[1] = (XID)oldFg;
803	gcv[2] = (XID)oldBg;
804	DoChangeGC(pGC, GCPlaneMask | GCForeground | GCBackground, gcv, 0);
805	ValidateGC(pDraw, pGC);
806	break;
807
808      case ZPixmap:
809    	ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec));
810    	pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int));
811	if(!pptFirst || !pwidthFirst)
812        {
813	   if (pwidthFirst)
814               DEALLOCATE_LOCAL(pwidthFirst);
815           if (pptFirst)
816               DEALLOCATE_LOCAL(pptFirst);
817           return;
818        }
819	if (pGC->miTranslate)
820	{
821	    x += pDraw->x;
822	    y += pDraw->y;
823	}
824
825	for(i = 0; i < h; i++)
826	{
827	    ppt->x = x;
828	    ppt->y = y + i;
829	    ppt++;
830	    *pwidth++ = w;
831	}
832
833	(*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst,
834			      pwidthFirst, h, TRUE);
835	DEALLOCATE_LOCAL(pwidthFirst);
836	DEALLOCATE_LOCAL(pptFirst);
837	break;
838    }
839}
840