File: | mi/mibitblt.c |
Location: | line 669, column 1 |
Description: | Potential memory leak |
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_H1 | |||
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_FFS1 | |||
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 | _X_COLD__attribute__((__cold__)) 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_WINDOW0 && | |||
101 | !((WindowPtr) pDstDrawable)->realized) | |||
102 | return NULL((void*)0); | |||
103 | ||||
104 | /* clip the source */ | |||
105 | if (pSrcDrawable->type == DRAWABLE_PIXMAP1) { | |||
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 == IncludeInferiors1) { | |||
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))xreallocarray(((void*)0), (heightSrc), (sizeof(DDXPointRec))); | |||
140 | pwidthFirst = pwidth = xallocarray(heightSrc, sizeof(unsigned int))xreallocarray(((void*)0), (heightSrc), (sizeof(unsigned int)) ); | |||
141 | numRects = RegionNumRects(prgnSrcClip); | |||
142 | boxes = RegionRects(prgnSrcClip); | |||
143 | ordering = xallocarray(numRects, sizeof(unsigned int))xreallocarray(((void*)0), (numRects), (sizeof(unsigned int))); | |||
144 | if (!pptFirst || !pwidthFirst || !ordering) { | |||
145 | free(ordering); | |||
146 | free(pwidthFirst); | |||
147 | free(pptFirst); | |||
148 | return NULL((void*)0); | |||
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 != IncludeInferiors1) || | |||
157 | (pSrcDrawable->type == DRAWABLE_PIXMAP1) || | |||
158 | (pDstDrawable->type == DRAWABLE_PIXMAP1))) | |||
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)(((prect->x1) > (srcBox.x1)) ? (prect->x1) : (srcBox .x1)); | |||
205 | xMax = min(prect->x2, srcBox.x2)(((prect->x2) < (srcBox.x2)) ? (prect->x2) : (srcBox .x2)); | |||
206 | yMin = max(prect->y1, srcBox.y1)(((prect->y1) > (srcBox.y1)) ? (prect->y1) : (srcBox .y1)); | |||
207 | yMax = min(prect->y2, srcBox.y2)(((prect->y2) < (srcBox.y2)) ? (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))xreallocarray(((void*)0), (height), (((PixmapWidthPaddingInfo [pSrcDrawable->depth].notPower2 ? (((int)(width) * PixmapWidthPaddingInfo [pSrcDrawable->depth].bytesPerPixel + PixmapWidthPaddingInfo [pSrcDrawable->depth].bytesPerPixel) >> PixmapWidthPaddingInfo [pSrcDrawable->depth].padBytesLog2) : ((int)((width) + PixmapWidthPaddingInfo [pSrcDrawable->depth].padRoundUp) >> PixmapWidthPaddingInfo [pSrcDrawable->depth].padPixelsLog2)) << PixmapWidthPaddingInfo [pSrcDrawable->depth].padBytesLog2))); | |||
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, TRUE1); | |||
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__attribute__((__cold__)) static MiBitsCARD32 * | |||
265 | miGetPlane(DrawablePtr pDraw, int planeNum, /* number of the bitPlane */ | |||
266 | int sx, int sy, int w, int h, MiBitsCARD32 * result) | |||
267 | { | |||
268 | int i, j, k, width, bitsPerPixel, widthInBytes; | |||
269 | DDXPointRec pt = { 0, 0 }; | |||
270 | MiBitsCARD32 pixel; | |||
271 | MiBitsCARD32 bit; | |||
272 | unsigned char *pCharsOut = NULL((void*)0); | |||
273 | ||||
274 | #if BITMAP_SCANLINE_UNIT32 == 8 | |||
275 | #define OUT_TYPECARD32 unsigned char | |||
276 | #endif | |||
277 | #if BITMAP_SCANLINE_UNIT32 == 16 | |||
278 | #define OUT_TYPECARD32 CARD16 | |||
279 | #endif | |||
280 | #if BITMAP_SCANLINE_UNIT32 == 32 | |||
281 | #define OUT_TYPECARD32 CARD32 | |||
282 | #endif | |||
283 | #if BITMAP_SCANLINE_UNIT32 == 64 | |||
284 | #define OUT_TYPECARD32 CARD64 | |||
285 | #endif | |||
286 | ||||
287 | OUT_TYPECARD32 *pOut; | |||
288 | int delta = 0; | |||
289 | ||||
290 | sx += pDraw->x; | |||
291 | sy += pDraw->y; | |||
292 | widthInBytes = BitmapBytePad(w)(((int)((w) + 32 - 1) >> 5) << 2); | |||
293 | if (!result) | |||
294 | result = calloc(h, widthInBytes); | |||
295 | if (!result) | |||
296 | return NULL((void*)0); | |||
297 | bitsPerPixel = pDraw->bitsPerPixel; | |||
298 | pOut = (OUT_TYPECARD32 *) result; | |||
299 | if (bitsPerPixel == 1) { | |||
300 | pCharsOut = (unsigned char *) result; | |||
301 | width = w; | |||
302 | } | |||
303 | else { | |||
304 | delta = (widthInBytes / (BITMAP_SCANLINE_UNIT32 / 8)) - | |||
305 | (w / BITMAP_SCANLINE_UNIT32); | |||
306 | width = 1; | |||
307 | #if IMAGE_BYTE_ORDER0 == MSBFirst1 | |||
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_ORDER0 == LSBFirst0 | |||
332 | bit <<= k; | |||
333 | #else | |||
334 | bit <<= ((BITMAP_SCANLINE_UNIT32 - 1) - k); | |||
335 | #endif | |||
336 | #else | |||
337 | /* XXX assuming byte order == LSBFirst */ | |||
338 | if (screenInfo.bitmapBitOrder == LSBFirst0) | |||
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_TYPECARD32) bit; | |||
347 | k++; | |||
348 | if (k == BITMAP_SCANLINE_UNIT32) { | |||
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__attribute__((__cold__)) static void | |||
371 | miOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, | |||
372 | MiBitsCARD32 * 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_SCRATCH1); | |||
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((ClientPtr) 0), pGCT, GCBackground(1L<<3), gcv); | |||
399 | ValidateGC((DrawablePtr) pPixmap, pGCT); | |||
400 | miClearDrawable((DrawablePtr) pPixmap, pGCT); | |||
401 | ppt = pptFirst = xallocarray(h, sizeof(DDXPointRec))xreallocarray(((void*)0), (h), (sizeof(DDXPointRec))); | |||
402 | pwidth = pwidthFirst = xallocarray(h, sizeof(int))xreallocarray(((void*)0), (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((void*)0), 0); | |||
415 | RegionCopy(prgnSrcClip, prgnSrc); | |||
416 | RegionTranslate(prgnSrcClip, srcx, 0); | |||
417 | (*pGCT->funcs->ChangeClip) (pGCT, CT_REGION2, 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, TRUE1); | |||
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 = FillStippled2; | |||
442 | gcv[1].ptr = pPixmap; | |||
443 | gcv[2].val = dstx - srcx; | |||
444 | gcv[3].val = dsty; | |||
445 | ||||
446 | ChangeGC(NullClient((ClientPtr) 0), pGC, | |||
447 | GCFillStyle(1L<<8) | GCStipple(1L<<11) | GCTileStipXOrigin(1L<<12) | GCTileStipYOrigin(1L<<13), | |||
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 = GXinvert0xa; | |||
464 | ChangeGC(NullClient((ClientPtr) 0), pGCT, GCFunction(1L<<0), 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((ClientPtr) 0), pGC, GCForeground(1L<<2) | GCBackground(1L<<3) | GCStipple(1L<<11), 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((ClientPtr) 0), pGC, | |||
495 | GCForeground(1L<<2) | GCBackground(1L<<3) | GCFillStyle(1L<<8) | GCStipple(1L<<11) | | |||
496 | GCTileStipXOrigin(1L<<12) | GCTileStipYOrigin(1L<<13), 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_NONE0, NULL((void*)0), 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__attribute__((__cold__)) RegionPtr | |||
513 | miCopyPlane(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 | MiBitsCARD32 *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_PIXMAP1) { | |||
546 | /* clip to visible drawable */ | |||
547 | ||||
548 | if (pGC->subWindowMode == IncludeInferiors1) { | |||
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, (MiBitsCARD32 *) NULL((void*)0)); | |||
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__attribute__((__cold__)) void | |||
602 | miGetImage(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((void*)0); | |||
609 | GCPtr pGC = NULL((void*)0); | |||
610 | ||||
611 | depth = pDraw->depth; | |||
612 | if (format == ZPixmap2) { | |||
| ||||
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_SCRATCH1); | |||
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 | TRUE1); | |||
634 | ||||
635 | /* alu is already GXCopy */ | |||
636 | gcv.val = (XID) planeMask; | |||
637 | ChangeGC(NullClient((ClientPtr) 0), pGC, GCPlaneMask(1L<<1), &gcv); | |||
638 | ValidateGC((DrawablePtr) pPixmap, pGC); | |||
639 | } | |||
640 | ||||
641 | linelength = PixmapBytePad(w, depth)((PixmapWidthPaddingInfo[depth].notPower2 ? (((int)(w) * PixmapWidthPaddingInfo [depth].bytesPerPixel + PixmapWidthPaddingInfo[depth].bytesPerPixel ) >> PixmapWidthPaddingInfo[depth].padBytesLog2) : ((int )((w) + PixmapWidthPaddingInfo[depth].padRoundUp) >> PixmapWidthPaddingInfo [depth].padPixelsLog2)) << PixmapWidthPaddingInfo[depth ].padBytesLog2); | |||
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, TRUE1); | |||
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 | (MiBitsCARD32 *) 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__attribute__((__cold__)) void | |||
692 | miPutImage(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 XYBitmap0: | |||
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, (MiBitsCARD32 *) pImage, | |||
717 | leftPad, w, h, x, y); | |||
718 | RegionDestroy(prgnSrc); | |||
719 | break; | |||
720 | ||||
721 | case XYPixmap1: | |||
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((ClientPtr) 0), pGC, GCForeground(1L<<2) | GCBackground(1L<<3), gcv); | |||
729 | bytesPer = (long) h *BitmapBytePad(w + leftPad)(((int)((w + leftPad) + 32 - 1) >> 5) << 2); | |||
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((ClientPtr) 0), pGC, GCPlaneMask(1L<<1), gcv); | |||
735 | ValidateGC(pDraw, pGC); | |||
736 | (*pGC->ops->PutImage) (pDraw, pGC, 1, x, y, w, h, leftPad, | |||
737 | XYBitmap0, (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((ClientPtr) 0), pGC, GCPlaneMask(1L<<1) | GCForeground(1L<<2) | GCBackground(1L<<3), | |||
744 | gcv); | |||
745 | ValidateGC(pDraw, pGC); | |||
746 | break; | |||
747 | ||||
748 | case ZPixmap2: | |||
749 | ppt = pptFirst = xallocarray(h, sizeof(DDXPointRec))xreallocarray(((void*)0), (h), (sizeof(DDXPointRec))); | |||
750 | pwidth = pwidthFirst = xallocarray(h, sizeof(int))xreallocarray(((void*)0), (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, TRUE1); | |||
770 | free(pwidthFirst); | |||
771 | free(pptFirst); | |||
772 | break; | |||
773 | } | |||
774 | } |