Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | } |