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