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