1 /* Combined Purdue/PurduePlus patches, level 2.0, 1/17/89 */
2 /***********************************************************
3 
4 Copyright (c) 1987  X Consortium
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 Except as contained in this notice, the name of the X Consortium shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the X Consortium.
26 
27 
28 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
29 
30                         All Rights Reserved
31 
32 Permission to use, copy, modify, and distribute this software and its
33 documentation for any purpose and without fee is hereby granted,
34 provided that the above copyright notice appear in all copies and that
35 both that copyright notice and this permission notice appear in
36 supporting documentation, and that the name of Digital not be
37 used in advertising or publicity pertaining to distribution of the
38 software without specific, written prior permission.
39 
40 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
41 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
42 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
43 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
44 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
45 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
46 SOFTWARE.
47 
48 ******************************************************************/
49 /* $XConsortium: mfbbitblt.c,v 5.25 94/04/17 20:28:16 dpw Exp $ */
50 #include "X.h"
51 #include "Xprotostr.h"
52 
53 #include "miscstruct.h"
54 #include "regionstr.h"
55 #include "gcstruct.h"
56 #include "windowstr.h"
57 #include "pixmapstr.h"
58 #include "scrnintstr.h"
59 
60 #include "mi.h"
61 
62 #include "mfb.h"
63 #include "maskbits.h"
64 
65 
66 /* CopyArea and CopyPlane for a monchrome frame buffer
67 
68 
69     clip the source rectangle to the source's available bits.  (this
70 avoids copying unnecessary pieces that will just get exposed anyway.)
71 this becomes the new shape of the destination.
72     clip the destination region to the composite clip in the
73 GC.  this requires translating the destination region to (dstx, dsty).
74     build a list of source points, one for each rectangle in the
75 destination.  this is a simple translation.
76     go do the multiple rectangle copies
77     do graphics exposures
78 */
79 /** Optimized for drawing pixmaps into windows, especially when drawing into
80  ** unobscured windows.  Calls to the general-purpose region code were
81  ** replaced with rectangle-to-rectangle clipping comparisions.  This is
82  ** possible, since the pixmap is a single rectangle.  In an unobscured
83  ** window, the destination clip is also a single rectangle, and region
84  ** code can be avoided entirely.  This is a big savings, since the region
85  ** code uses XAlloc() and makes many function calls.
86  **
87  ** In addition, if source is a pixmap, there is no need to call the
88  ** expensive miHandleExposures() routine.  Instead, we simply return NULL.
89  **
90  ** Previously, drawing a pixmap into an unobscured window executed at least
91  ** 8 XAlloc()'s, 30 function calls, and hundreds of lines of code.
92  **
93  ** Now, the same operation requires no XAlloc()'s, no region function calls,
94  ** and much less overhead.  Nice for drawing lots of small pixmaps.
95  */
96 
97 void
mfbDoBitblt(pSrc,pDst,alu,prgnDst,pptSrc)98 mfbDoBitblt (pSrc, pDst, alu, prgnDst, pptSrc)
99     DrawablePtr	    pSrc, pDst;
100     int		    alu;
101     RegionPtr	    prgnDst;
102     DDXPointPtr	    pptSrc;
103 {
104     switch (alu)
105     {
106     case GXcopy:
107 	mfbDoBitbltCopy (pSrc, pDst, alu, prgnDst, pptSrc);
108 	break;
109     case GXxor:
110 	mfbDoBitbltXor (pSrc, pDst, alu, prgnDst, pptSrc);
111 	break;
112     case GXcopyInverted:
113 	mfbDoBitbltCopyInverted (pSrc, pDst, alu, prgnDst, pptSrc);
114 	break;
115     case GXor:
116 	mfbDoBitbltOr (pSrc, pDst, alu, prgnDst, pptSrc);
117 	break;
118     default:
119 	mfbDoBitbltGeneral (pSrc, pDst, alu, prgnDst, pptSrc);
120 	break;
121     }
122 }
123 
124 RegionPtr
mfbCopyArea(pSrcDrawable,pDstDrawable,pGC,srcx,srcy,width,height,dstx,dsty)125 mfbCopyArea(pSrcDrawable, pDstDrawable,
126 	    pGC, srcx, srcy, width, height, dstx, dsty)
127 register DrawablePtr pSrcDrawable;
128 register DrawablePtr pDstDrawable;
129 register GC *pGC;
130 int srcx, srcy;
131 int width, height;
132 int dstx, dsty;
133 {
134     RegionPtr prgnSrcClip;	/* may be a new region, or just a copy */
135     Bool freeSrcClip = FALSE;
136 
137     RegionPtr prgnExposed;
138     RegionRec rgnDst;
139     DDXPointPtr pptSrc;
140     register DDXPointPtr ppt;
141     register BoxPtr pbox;
142     int i;
143     register int dx;
144     register int dy;
145     xRectangle origSource;
146     DDXPointRec origDest;
147     int numRects;
148     BoxRec fastBox;
149     int fastClip = 0;		/* for fast clipping with pixmap source */
150     int fastExpose = 0;		/* for fast exposures with pixmap source */
151     void (*localDoBitBlt)();
152 
153     origSource.x = srcx;
154     origSource.y = srcy;
155     origSource.width = width;
156     origSource.height = height;
157     origDest.x = dstx;
158     origDest.y = dsty;
159 
160     if ((pSrcDrawable != pDstDrawable) &&
161 	pSrcDrawable->pScreen->SourceValidate)
162     {
163 	(*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, srcx, srcy, width, height);
164     }
165 
166     switch (pGC->alu) {
167     case GXcopy:
168 	localDoBitBlt = mfbDoBitbltCopy;
169 	break;
170     case GXcopyInverted:
171 	localDoBitBlt = mfbDoBitbltCopyInverted;
172 	break;
173     case GXxor:
174 	localDoBitBlt = mfbDoBitbltXor;
175 	break;
176     case GXor:
177 	localDoBitBlt = mfbDoBitbltOr;
178 	break;
179     default:
180 	localDoBitBlt = mfbDoBitbltGeneral;
181 	break;
182     }
183 
184     srcx += pSrcDrawable->x;
185     srcy += pSrcDrawable->y;
186 
187     /* clip the source */
188 
189     if (pSrcDrawable->type == DRAWABLE_PIXMAP)
190     {
191 	if ((pSrcDrawable == pDstDrawable) &&
192 	    (pGC->clientClipType == CT_NONE))
193 	{
194 	    prgnSrcClip = ((mfbPrivGC *)(pGC->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip;
195 	}
196 	else
197 	{
198 	    fastClip = 1;
199 	}
200     }
201     else
202     {
203 	if (pGC->subWindowMode == IncludeInferiors)
204 	{
205 	    if (!((WindowPtr) pSrcDrawable)->parent)
206 	    {
207 		/*
208 		 * special case bitblt from root window in
209 		 * IncludeInferiors mode; just like from a pixmap
210 		 */
211 		fastClip = 1;
212 	    }
213 	    else if ((pSrcDrawable == pDstDrawable) &&
214 		(pGC->clientClipType == CT_NONE))
215 	    {
216 		prgnSrcClip = ((mfbPrivGC *)(pGC->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip;
217 	    }
218 	    else
219 	    {
220 		prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable);
221 		freeSrcClip = TRUE;
222 	    }
223 	}
224 	else
225 	{
226 	    prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
227 	}
228     }
229 
230     fastBox.x1 = srcx;
231     fastBox.y1 = srcy;
232     fastBox.x2 = srcx + width;
233     fastBox.y2 = srcy + height;
234 
235     /* Don't create a source region if we are doing a fast clip */
236     if (fastClip)
237     {
238 	fastExpose = 1;
239 	/*
240 	 * clip the source; if regions extend beyond the source size,
241  	 * make sure exposure events get sent
242 	 */
243 	if (fastBox.x1 < pSrcDrawable->x)
244 	{
245 	    fastBox.x1 = pSrcDrawable->x;
246 	    fastExpose = 0;
247 	}
248 	if (fastBox.y1 < pSrcDrawable->y)
249 	{
250 	    fastBox.y1 = pSrcDrawable->y;
251 	    fastExpose = 0;
252 	}
253 	if (fastBox.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
254 	{
255 	    fastBox.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
256 	    fastExpose = 0;
257 	}
258 	if (fastBox.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
259 	{
260 	    fastBox.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
261 	    fastExpose = 0;
262 	}
263     }
264     else
265     {
266 	REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
267 	REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip);
268     }
269 
270     dstx += pDstDrawable->x;
271     dsty += pDstDrawable->y;
272 
273     if (pDstDrawable->type == DRAWABLE_WINDOW)
274     {
275 	if (!((WindowPtr)pDstDrawable)->realized)
276 	{
277 	    if (!fastClip)
278 		REGION_UNINIT(pGC->pScreen, &rgnDst);
279 	    if (freeSrcClip)
280 		REGION_DESTROY(pGC->pScreen, prgnSrcClip);
281 	    return NULL;
282 	}
283     }
284 
285     dx = srcx - dstx;
286     dy = srcy - dsty;
287 
288     /* Translate and clip the dst to the destination composite clip */
289     if (fastClip)
290     {
291 	RegionPtr cclip;
292 
293         /* Translate the region directly */
294         fastBox.x1 -= dx;
295         fastBox.x2 -= dx;
296         fastBox.y1 -= dy;
297         fastBox.y2 -= dy;
298 
299 	/* If the destination composite clip is one rectangle we can
300 	   do the clip directly.  Otherwise we have to create a full
301 	   blown region and call intersect */
302 	cclip = ((mfbPrivGC *)(pGC->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip;
303         if (REGION_NUM_RECTS(cclip) == 1)
304         {
305 	    BoxPtr pBox = REGION_RECTS(cclip);
306 
307 	    if (fastBox.x1 < pBox->x1) fastBox.x1 = pBox->x1;
308 	    if (fastBox.x2 > pBox->x2) fastBox.x2 = pBox->x2;
309 	    if (fastBox.y1 < pBox->y1) fastBox.y1 = pBox->y1;
310 	    if (fastBox.y2 > pBox->y2) fastBox.y2 = pBox->y2;
311 
312 	    /* Check to see if the region is empty */
313 	    if (fastBox.x1 >= fastBox.x2 || fastBox.y1 >= fastBox.y2)
314 	    {
315 		REGION_INIT(pGC->pScreen, &rgnDst, NullBox, 0);
316 	    }
317 	    else
318 	    {
319 		REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
320 	    }
321 	}
322         else
323 	{
324 	    /* We must turn off fastClip now, since we must create
325 	       a full blown region.  It is intersected with the
326 	       composite clip below. */
327 	    fastClip = 0;
328 	    REGION_INIT(pGC->pScreen, &rgnDst, &fastBox,1);
329 	}
330     }
331     else
332     {
333         REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy);
334     }
335 
336     if (!fastClip)
337     {
338 	REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst,
339 	 ((mfbPrivGC *)(pGC->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip);
340     }
341 
342     /* Do bit blitting */
343     numRects = REGION_NUM_RECTS(&rgnDst);
344     if (numRects && width && height)
345     {
346 	if(!(pptSrc = (DDXPointPtr)ALLOCATE_LOCAL(numRects *
347 						  sizeof(DDXPointRec))))
348 	{
349 	    REGION_UNINIT(pGC->pScreen, &rgnDst);
350 	    if (freeSrcClip)
351 		REGION_DESTROY(pGC->pScreen, prgnSrcClip);
352 	    return NULL;
353 	}
354 	pbox = REGION_RECTS(&rgnDst);
355 	ppt = pptSrc;
356 	for (i = numRects; --i >= 0; pbox++, ppt++)
357 	{
358 	    ppt->x = pbox->x1 + dx;
359 	    ppt->y = pbox->y1 + dy;
360 	}
361 
362 	if (pGC->planemask & 1)
363 	    (*localDoBitBlt) (pSrcDrawable, pDstDrawable, pGC->alu, &rgnDst, pptSrc);
364 
365 	DEALLOCATE_LOCAL(pptSrc);
366     }
367 
368     prgnExposed = NULL;
369     if (((mfbPrivGC *)(pGC->devPrivates[mfbGCPrivateIndex].ptr))->fExpose)
370     {
371         /* Pixmap sources generate a NoExposed (we return NULL to do this) */
372         if (!fastExpose)
373 	    prgnExposed =
374 		miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
375 				  origSource.x, origSource.y,
376 				  (int)origSource.width,
377 				  (int)origSource.height,
378 				  origDest.x, origDest.y, (unsigned long)0);
379     }
380     REGION_UNINIT(pGC->pScreen, &rgnDst);
381     if (freeSrcClip)
382 	REGION_DESTROY(pGC->pScreen, prgnSrcClip);
383     return prgnExposed;
384 }
385 
386 /*
387  * Devices which use mfb for 1-bit pixmap support
388  * must register a function for n-to-1 copy operations
389  */
390 
391 static unsigned long	copyPlaneGeneration;
392 static int		copyPlaneScreenIndex = -1;
393 
394 Bool
mfbRegisterCopyPlaneProc(pScreen,proc)395 mfbRegisterCopyPlaneProc (pScreen, proc)
396     ScreenPtr	pScreen;
397     RegionPtr	(*proc)();
398 {
399     if (copyPlaneGeneration != serverGeneration)
400     {
401 	copyPlaneScreenIndex = AllocateScreenPrivateIndex();
402 	if (copyPlaneScreenIndex < 0)
403 	    return FALSE;
404 	copyPlaneGeneration = serverGeneration;
405     }
406     pScreen->devPrivates[copyPlaneScreenIndex].fptr = (pointer (*)()) proc;
407     return TRUE;
408 }
409 
410 /*
411     if fg == 1 and bg ==0, we can do an ordinary CopyArea.
412     if fg == bg, we can do a CopyArea with alu = mfbReduceRop(alu, fg)
413     if fg == 0 and bg == 1, we use the same rasterop, with
414 	source operand inverted.
415 
416     CopyArea deals with all of the graphics exposure events.
417     This code depends on knowing that we can change the
418 alu in the GC without having to call ValidateGC() before calling
419 CopyArea().
420 
421 */
422 
423 RegionPtr
mfbCopyPlane(pSrcDrawable,pDstDrawable,pGC,srcx,srcy,width,height,dstx,dsty,plane)424 mfbCopyPlane(pSrcDrawable, pDstDrawable,
425 	    pGC, srcx, srcy, width, height, dstx, dsty, plane)
426 DrawablePtr pSrcDrawable, pDstDrawable;
427 register GC *pGC;
428 int srcx, srcy;
429 int width, height;
430 int dstx, dsty;
431 unsigned long plane;
432 {
433     int alu;
434     RegionPtr	prgnExposed;
435     RegionPtr	(*copyPlane)();
436 
437     if (pSrcDrawable->depth != 1)
438     {
439 	if (copyPlaneScreenIndex >= 0 &&
440 	    (copyPlane = (RegionPtr (*)())
441 		pSrcDrawable->pScreen->devPrivates[copyPlaneScreenIndex].fptr)
442 	    )
443 	{
444 	    return (*copyPlane) (pSrcDrawable, pDstDrawable,
445 			   pGC, srcx, srcy, width, height, dstx, dsty, plane);
446 	}
447 	else
448 	{
449 	    FatalError ("No copyPlane proc registered for depth %d\n",
450 			pSrcDrawable->depth);
451 	}
452     }
453     if (plane != 1)
454 	return NULL;
455 
456     if ((pGC->fgPixel & 1) == 1 && (pGC->bgPixel & 1) == 0)
457     {
458 	prgnExposed = (*pGC->ops->CopyArea)(pSrcDrawable, pDstDrawable,
459 			 pGC, srcx, srcy, width, height, dstx, dsty);
460     }
461     else if ((pGC->fgPixel & 1) == (pGC->bgPixel & 1))
462     {
463 	alu = pGC->alu;
464 	pGC->alu = mfbReduceRop(pGC->alu, pGC->fgPixel);
465 	prgnExposed = (*pGC->ops->CopyArea)(pSrcDrawable, pDstDrawable,
466 			 pGC, srcx, srcy, width, height, dstx, dsty);
467 	pGC->alu = alu;
468     }
469     else /* need to invert the src */
470     {
471 	alu = pGC->alu;
472 	pGC->alu = InverseAlu[alu];
473 	prgnExposed = (*pGC->ops->CopyArea)(pSrcDrawable, pDstDrawable,
474 			 pGC, srcx, srcy, width, height, dstx, dsty);
475 	pGC->alu = alu;
476     }
477     return prgnExposed;
478 }
479