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