Add patch that contain Mali fixes.
[deb_xorg-server.git] / mi / mibitblt.c
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 #ifndef HAVE_FFS
66 extern 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 RegionPtr
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 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 = 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) {
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 = malloc(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 (unsigned long) 0);
247 if (realSrcClip)
248 RegionDestroy(prgnSrcClip);
249
250 free(ordering);
251 free(pwidthFirst);
252 free(pptFirst);
253 return prgnExposed;
254 }
255
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.
260 */
261 /*
262 * This should be replaced with something more general. mi shouldn't have to
263 * care about such things as scanline padding et alia.
264 */
265 static
266 MiBits *
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 static void
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 = malloc(h * sizeof(DDXPointRec));
404 pwidth = pwidthFirst = malloc(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 whereever 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 RegionPtr
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, bitPlane);
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 void
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 void
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 = 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 = malloc(h * sizeof(DDXPointRec));
752 pwidth = pwidthFirst = malloc(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 }