1 /***********************************************************
3 Copyright 1987, 1998 The Open Group
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
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
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.
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
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.
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
45 ******************************************************************/
46 /* Author: Todd Newman (aided and abetted by Mr. Drewry) */
48 #ifdef HAVE_DIX_CONFIG_H
49 #include <dix-config.h>
53 #include <X11/Xprotostr.h>
57 #include "pixmapstr.h"
58 #include "windowstr.h"
59 #include "scrnintstr.h"
61 #include "regionstr.h"
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.
76 miCopyArea(DrawablePtr pSrcDrawable
,
77 DrawablePtr pDstDrawable
,
79 int xIn
, int yIn
, int widthSrc
, int heightSrc
, int xOut
, int yOut
)
81 DDXPointPtr ppt
, pptFirst
;
82 unsigned int *pwidthFirst
, *pwidth
, *pbits
;
83 BoxRec srcBox
, *prect
;
85 /* may be a new region, or just a copy */
86 RegionPtr prgnSrcClip
;
88 /* non-0 if we've created a src clip */
89 RegionPtr prgnExposed
;
91 int srcx
, srcy
, dstx
, dsty
, i
, j
, y
, width
, height
, xMin
, xMax
, yMin
, yMax
;
92 unsigned int *ordering
;
96 srcx
= xIn
+ pSrcDrawable
->x
;
97 srcy
= yIn
+ pSrcDrawable
->y
;
99 /* If the destination isn't realized, this is easy */
100 if (pDstDrawable
->type
== DRAWABLE_WINDOW
&&
101 !((WindowPtr
) pDstDrawable
)->realized
)
104 /* clip the source */
105 if (pSrcDrawable
->type
== DRAWABLE_PIXMAP
) {
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
;
113 prgnSrcClip
= RegionCreate(&box
, 1);
117 if (pGC
->subWindowMode
== IncludeInferiors
) {
118 prgnSrcClip
= NotClippedByChildren((WindowPtr
) pSrcDrawable
);
122 prgnSrcClip
= &((WindowPtr
) pSrcDrawable
)->clipList
;
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. */
129 srcBox
.x2
= srcx
+ widthSrc
;
130 srcBox
.y2
= srcy
+ heightSrc
;
134 if (pGC
->miTranslate
) {
135 dstx
+= pDstDrawable
->x
;
136 dsty
+= pDstDrawable
->y
;
139 pptFirst
= ppt
= malloc(heightSrc
* sizeof(DDXPointRec
));
140 pwidthFirst
= pwidth
= malloc(heightSrc
* sizeof(unsigned int));
141 numRects
= RegionNumRects(prgnSrcClip
);
142 boxes
= RegionRects(prgnSrcClip
);
143 ordering
= malloc(numRects
* sizeof(unsigned int));
144 if (!pptFirst
|| !pwidthFirst
|| !ordering
) {
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.
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
++)
161 else { /* within same drawable, must sequence moves carefully! */
162 if (dsty
<= srcBox
.y1
) { /* Scroll up or stationary vertical.
164 if (dstx
<= srcBox
.x1
) /* Scroll left or stationary horizontal.
165 Horizontal order OK as well */
166 for (i
= 0; i
< numRects
; 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
))
174 /* reverse the horizontal band in the output ordering */
175 for (j
--; j
>= xMax
; j
--, i
++)
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
))
188 /* reverse the horizontal band in the output ordering */
189 for (j
++; j
<= yMin
; j
++, i
--, yMax
++)
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
197 for (i
= 0, j
= numRects
- 1; i
< numRects
; i
++, j
--)
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
)
213 pwidth
= pwidthFirst
;
215 height
= yMax
- yMin
;
218 for (j
= 0; j
< height
; j
++) {
219 /* We must untranslate before calling GetSpans */
224 pbits
= malloc(height
* PixmapBytePad(width
, pSrcDrawable
->depth
));
226 (*pSrcDrawable
->pScreen
->GetSpans
) (pSrcDrawable
, width
, pptFirst
,
227 (int *) pwidthFirst
, height
,
230 pwidth
= pwidthFirst
;
231 xMin
-= (srcx
- dstx
);
232 y
= yMin
- (srcy
- dsty
);
233 for (j
= 0; j
< height
; j
++) {
239 (*pGC
->ops
->SetSpans
) (pDstDrawable
, pGC
, (char *) pbits
, pptFirst
,
240 (int *) pwidthFirst
, height
, TRUE
);
244 prgnExposed
= miHandleExposures(pSrcDrawable
, pDstDrawable
, pGC
, xIn
, yIn
,
245 widthSrc
, heightSrc
, xOut
, yOut
,
248 RegionDestroy(prgnSrcClip
);
256 /* MIGETPLANE -- gets a bitmap representing one plane of pDraw
257 * A helper used for CopyPlane and XY format GetImage
258 * No clever strategy here, we grab a scanline at a time, pull out the
259 * bits and then stuff them in a 1 bit deep map.
262 * This should be replaced with something more general. mi shouldn't have to
263 * care about such things as scanline padding et alia.
267 miGetPlane(DrawablePtr pDraw
, int planeNum
, /* number of the bitPlane */
268 int sx
, int sy
, int w
, int h
, MiBits
* result
)
270 int i
, j
, k
, width
, bitsPerPixel
, widthInBytes
;
271 DDXPointRec pt
= { 0, 0 };
274 unsigned char *pCharsOut
= NULL
;
276 #if BITMAP_SCANLINE_UNIT == 8
277 #define OUT_TYPE unsigned char
279 #if BITMAP_SCANLINE_UNIT == 16
280 #define OUT_TYPE CARD16
282 #if BITMAP_SCANLINE_UNIT == 32
283 #define OUT_TYPE CARD32
285 #if BITMAP_SCANLINE_UNIT == 64
286 #define OUT_TYPE CARD64
294 widthInBytes
= BitmapBytePad(w
);
296 result
= calloc(h
, widthInBytes
);
299 bitsPerPixel
= pDraw
->bitsPerPixel
;
300 pOut
= (OUT_TYPE
*) result
;
301 if (bitsPerPixel
== 1) {
302 pCharsOut
= (unsigned char *) result
;
306 delta
= (widthInBytes
/ (BITMAP_SCANLINE_UNIT
/ 8)) -
307 (w
/ BITMAP_SCANLINE_UNIT
);
309 #if IMAGE_BYTE_ORDER == MSBFirst
310 planeNum
+= (32 - bitsPerPixel
);
314 for (i
= h
; --i
>= 0; pt
.y
++) {
316 if (bitsPerPixel
== 1) {
317 (*pDraw
->pScreen
->GetSpans
) (pDraw
, width
, &pt
, &width
, 1,
319 pCharsOut
+= widthInBytes
;
323 for (j
= w
; --j
>= 0; pt
.x
++) {
324 /* Fetch the next pixel */
325 (*pDraw
->pScreen
->GetSpans
) (pDraw
, width
, &pt
, &width
, 1,
328 * Now get the bit and insert into a bitmap in XY format.
330 bit
= (pixel
>> planeNum
) & 1;
332 /* XXX assuming bit order == byte order */
333 #if BITMAP_BIT_ORDER == LSBFirst
336 bit
<<= ((BITMAP_SCANLINE_UNIT
- 1) - k
);
339 /* XXX assuming byte order == LSBFirst */
340 if (screenInfo
.bitmapBitOrder
== LSBFirst
)
343 bit
<<= ((screenInfo
.bitmapScanlineUnit
- 1) -
344 (k
% screenInfo
.bitmapScanlineUnit
)) +
345 ((k
/ screenInfo
.bitmapScanlineUnit
) *
346 screenInfo
.bitmapScanlineUnit
);
348 *pOut
|= (OUT_TYPE
) bit
;
350 if (k
== BITMAP_SCANLINE_UNIT
) {
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.
373 miOpqStipDrawable(DrawablePtr pDraw
, GCPtr pGC
, RegionPtr prgnSrc
,
374 MiBits
* pbits
, int srcx
, int w
, int h
, int dstx
, int dsty
)
378 int *pwidth
, *pwidthFirst
;
380 PixmapPtr pStipple
, pPixmap
;
383 DDXPointPtr ppt
, pptFirst
;
385 RegionPtr prgnSrcClip
;
387 pPixmap
= (*pDraw
->pScreen
->CreatePixmap
)
388 (pDraw
->pScreen
, w
+ srcx
, h
, 1, CREATE_PIXMAP_USAGE_SCRATCH
);
392 /* Put the image into a 1 bit deep pixmap */
393 pGCT
= GetScratchGC(1, pDraw
->pScreen
);
395 (*pDraw
->pScreen
->DestroyPixmap
) (pPixmap
);
398 /* First set the whole pixmap to 0 */
400 ChangeGC(NullClient
, pGCT
, GCBackground
, gcv
);
401 ValidateGC((DrawablePtr
) pPixmap
, pGCT
);
402 miClearDrawable((DrawablePtr
) pPixmap
, pGCT
);
403 ppt
= pptFirst
= malloc(h
* sizeof(DDXPointRec
));
404 pwidth
= pwidthFirst
= malloc(h
* sizeof(int));
405 if (!pptFirst
|| !pwidthFirst
) {
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.
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
);
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
++) {
427 *pwidth
++ = w
+ srcx
;
430 (*pGCT
->ops
->SetSpans
) ((DrawablePtr
) pPixmap
, pGCT
, (char *) pbits
,
431 pptFirst
, pwidthFirst
, h
, TRUE
);
435 /* Save current values from the client GC */
436 oldfill
= pGC
->fillStyle
;
437 pStipple
= pGC
->stipple
;
440 oldOrg
= pGC
->patOrg
;
442 /* Set a new stipple in the drawable */
443 gcv
[0].val
= FillStippled
;
444 gcv
[1].ptr
= pPixmap
;
445 gcv
[2].val
= dstx
- srcx
;
448 ChangeGC(NullClient
, pGC
,
449 GCFillStyle
| GCStipple
| GCTileStipXOrigin
| GCTileStipYOrigin
,
451 ValidateGC(pDraw
, pGC
);
453 /* Fill the drawable with the stipple. This will draw the
454 * foreground color whereever 1 bits are set, leaving everything
455 * with 0 bits untouched. Note that the part outside the clip
456 * region is all 0s. */
461 (*pGC
->ops
->PolyFillRect
) (pDraw
, pGC
, 1, &rect
);
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);
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"
474 oldfg
= pGC
->fgPixel
;
475 gcv
[0].val
= pGC
->bgPixel
;
477 gcv
[2].ptr
= pPixmap
;
478 ChangeGC(NullClient
, pGC
, GCForeground
| GCBackground
| GCStipple
, gcv
);
479 ValidateGC(pDraw
, pGC
);
480 /* PolyFillRect might have bashed the rectangle */
485 (*pGC
->ops
->PolyFillRect
) (pDraw
, pGC
, 1, &rect
);
487 /* Now put things back */
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
);
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);
504 (*pDraw
->pScreen
->DestroyPixmap
) (pPixmap
);
508 /* MICOPYPLANE -- public entry for the CopyPlane request.
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
515 miCopyPlane(DrawablePtr pSrcDrawable
,
516 DrawablePtr pDstDrawable
,
520 int width
, int height
, int dstx
, int dsty
, unsigned long bitPlane
)
524 RegionPtr prgnSrc
, prgnExposed
;
526 /* incorporate the source clip */
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
;
545 prgnSrc
= RegionCreate(&box
, 1);
547 if (pSrcDrawable
->type
!= DRAWABLE_PIXMAP
) {
548 /* clip to visible drawable */
550 if (pGC
->subWindowMode
== IncludeInferiors
) {
551 RegionPtr clipList
= NotClippedByChildren((WindowPtr
) pSrcDrawable
);
553 RegionIntersect(prgnSrc
, prgnSrc
, clipList
);
554 RegionDestroy(clipList
);
557 RegionIntersect(prgnSrc
, prgnSrc
,
558 &((WindowPtr
) pSrcDrawable
)->clipList
);
561 box
= *RegionExtents(prgnSrc
);
562 RegionTranslate(prgnSrc
, -box
.x1
, -box
.y1
);
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,
573 box
.x2
- box
.x1
, box
.y2
- box
.y1
, (MiBits
*) NULL
);
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
);
581 prgnExposed
= miHandleExposures(pSrcDrawable
, pDstDrawable
, pGC
, srcx
, srcy
,
582 width
, height
, dstx
, dsty
, bitPlane
);
583 RegionDestroy(prgnSrc
);
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
592 * two different strategies are used, depending on whether we're getting the
593 * image in Z format or XY 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.
601 * get the single plane specified in planemask
604 miGetImage(DrawablePtr pDraw
, int sx
, int sy
, int w
, int h
,
605 unsigned int format
, unsigned long planeMask
, char *pDst
)
608 int i
, linelength
, width
, srcx
, srcy
;
609 DDXPointRec pt
= { 0, 0 };
610 PixmapPtr pPixmap
= NULL
;
613 depth
= pDraw
->depth
;
614 if (format
== ZPixmap
) {
615 if ((((1LL << depth
) - 1) & planeMask
) != (1LL << depth
) - 1) {
619 pGC
= GetScratchGC(depth
, pDraw
->pScreen
);
622 pPixmap
= (*pDraw
->pScreen
->CreatePixmap
)
623 (pDraw
->pScreen
, w
, 1, depth
, CREATE_PIXMAP_USAGE_SCRATCH
);
629 * Clear the pixmap before doing anything else
631 ValidateGC((DrawablePtr
) pPixmap
, pGC
);
634 (*pGC
->ops
->FillSpans
) ((DrawablePtr
) pPixmap
, pGC
, 1, &xpt
, &width
,
637 /* alu is already GXCopy */
638 gcv
.val
= (XID
) planeMask
;
639 ChangeGC(NullClient
, pGC
, GCPlaneMask
, &gcv
);
640 ValidateGC((DrawablePtr
) pPixmap
, pGC
);
643 linelength
= PixmapBytePad(w
, depth
);
644 srcx
= sx
+ pDraw
->x
;
645 srcy
= sy
+ pDraw
->y
;
646 for (i
= 0; i
< h
; i
++) {
650 (*pDraw
->pScreen
->GetSpans
) (pDraw
, w
, &pt
, &width
, 1, pDst
);
655 (*pGC
->ops
->SetSpans
) ((DrawablePtr
) pPixmap
, pGC
, pDst
,
656 &pt
, &width
, 1, TRUE
);
657 (*pDraw
->pScreen
->GetSpans
) ((DrawablePtr
) pPixmap
, w
, &pt
,
663 (*pGC
->pScreen
->DestroyPixmap
) (pPixmap
);
668 (void) miGetPlane(pDraw
, ffs(planeMask
) - 1, sx
, sy
, w
, h
,
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
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
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.)
691 * This part is simple, just call SetSpans
694 miPutImage(DrawablePtr pDraw
, GCPtr pGC
, int depth
,
695 int x
, int y
, int w
, int h
, int leftPad
, int format
, char *pImage
)
697 DDXPointPtr pptFirst
, ppt
;
698 int *pwidthFirst
, *pwidth
;
701 unsigned long oldFg
, oldBg
;
703 unsigned long oldPlanemask
;
716 prgnSrc
= RegionCreate(&box
, 1);
718 miOpqStipDrawable(pDraw
, pGC
, prgnSrc
, (MiBits
*) pImage
,
719 leftPad
, w
, h
, x
, y
);
720 RegionDestroy(prgnSrc
);
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
);
733 for (i
= 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
);
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
,
747 ValidateGC(pDraw
, pGC
);
751 ppt
= pptFirst
= malloc(h
* sizeof(DDXPointRec
));
752 pwidth
= pwidthFirst
= malloc(h
* sizeof(int));
753 if (!pptFirst
|| !pwidthFirst
) {
758 if (pGC
->miTranslate
) {
763 for (i
= 0; i
< h
; i
++) {
770 (*pGC
->ops
->SetSpans
) (pDraw
, pGC
, (char *) pImage
, pptFirst
,
771 pwidthFirst
, h
, TRUE
);