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