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
25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
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
76miCopyArea(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 isn't realized, this is easy */
100    if (pDstDrawable->type == DRAWABLE_WINDOW &&
101        !((WindowPtr) pDstDrawable)->realized)
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 *
267miGetPlane(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
373miOpqStipDrawable(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
515miCopyPlane(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
604miGetImage(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
694miPutImage(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