1/*
2 * Copyright © 1998 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_DIX_CONFIG_H
24#include <dix-config.h>
25#endif
26
27#include "fb.h"
28
29/*
30 *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
31 *
32 *	**** **** **** **** **** **** **** ****
33 *			^
34 *	********  ********  ********  ********
35 *		  ^
36 *  leftShift = 12
37 *  rightShift = 20
38 *
39 *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
40 *
41 *	**** **** **** **** **** **** **** ****
42 *	^
43 *	********  ********  ********  ********
44 *		  ^
45 *
46 *  leftShift = 24
47 *  rightShift = 8
48 */
49
50#define LoadBits {\
51    if (leftShift) { \
52	bitsRight = (src < srcEnd ? READ(src++) : 0); \
53	bits = (FbStipLeft (bitsLeft, leftShift) | \
54		FbStipRight(bitsRight, rightShift)); \
55	bitsLeft = bitsRight; \
56    } else \
57	bits = (src < srcEnd ? READ(src++) : 0); \
58}
59
60#ifndef FBNOPIXADDR
61
62#define LaneCases1(n,a)	    case n: FbLaneCase(n,a); break
63#define LaneCases2(n,a)	    LaneCases1(n,a); LaneCases1(n+1,a)
64#define LaneCases4(n,a)	    LaneCases2(n,a); LaneCases2(n+2,a)
65#define LaneCases8(n,a)	    LaneCases4(n,a); LaneCases4(n+4,a)
66#define LaneCases16(n,a)    LaneCases8(n,a); LaneCases8(n+8,a)
67#define LaneCases32(n,a)    LaneCases16(n,a); LaneCases16(n+16,a)
68#define LaneCases64(n,a)    LaneCases32(n,a); LaneCases32(n+32,a)
69#define LaneCases128(n,a)   LaneCases64(n,a); LaneCases64(n+64,a)
70#define LaneCases256(n,a)   LaneCases128(n,a); LaneCases128(n+128,a)
71
72#if FB_SHIFT == 6
73#define LaneCases(a)	    LaneCases256(0,a)
74#endif
75
76#if FB_SHIFT == 5
77#define LaneCases(a)	    LaneCases16(0,a)
78#endif
79
80#if FB_SHIFT == 6
81CARD8	fb8Lane[256] = {
820, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
8322, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
8441, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
8560, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
8679, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
8798, 99, 100, 101, 102,103,104,105,106,107,108,109,110,111,112,113,114,115,
88116, 117, 118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,
89134, 135, 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,
90152, 153, 154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,
91170, 171, 172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,
92188, 189, 190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,
93206, 207, 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
94224, 225, 226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,
95242, 243, 244,245,246,247,248,249,250,251,252,253,254,255,
96};
97
98CARD8	fb16Lane[256] = {
99    0x00, 0x03, 0x0c, 0x0f,
100    0x30, 0x33, 0x3c, 0x3f,
101    0xc0, 0xc3, 0xcc, 0xcf,
102    0xf0, 0xf3, 0xfc, 0xff,
103};
104
105CARD8	fb32Lane[16] = {
106    0x00, 0x0f, 0xf0, 0xff,
107};
108#endif
109
110#if FB_SHIFT == 5
111CARD8	fb8Lane[16] = {
112    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
113};
114
115CARD8	fb16Lane[16] = {
116    0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117};
118
119CARD8	fb32Lane[16] = {
120    0, 15,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121};
122#endif
123
124CARD8	*fbLaneTable[33] = {
125    0, 0, 0, 0, 0, 0, 0, 0,
126    fb8Lane,  0, 0, 0, 0, 0, 0, 0,
127    fb16Lane, 0, 0, 0, 0, 0, 0, 0,
128    0, 0, 0, 0, 0, 0, 0, 0,
129    fb32Lane
130};
131#endif
132
133void
134fbBltOne (FbStip    *src,
135	  FbStride  srcStride,	    /* FbStip units per scanline */
136	  int	    srcX,	    /* bit position of source */
137	  FbBits    *dst,
138	  FbStride  dstStride,	    /* FbBits units per scanline */
139	  int	    dstX,	    /* bit position of dest */
140	  int	    dstBpp,	    /* bits per destination unit */
141
142	  int	    width,	    /* width in bits of destination */
143	  int	    height,	    /* height in scanlines */
144
145	  FbBits    fgand,	    /* rrop values */
146	  FbBits    fgxor,
147	  FbBits    bgand,
148	  FbBits    bgxor)
149{
150    const FbBits    *fbBits;
151    FbBits	    *srcEnd;
152    int		    pixelsPerDst;		/* dst pixels per FbBits */
153    int		    unitsPerSrc;		/* src patterns per FbStip */
154    int		    leftShift, rightShift;	/* align source with dest */
155    FbBits	    startmask, endmask;		/* dest scanline masks */
156    FbStip	    bits=0, bitsLeft, bitsRight;/* source bits */
157    FbStip	    left;
158    FbBits	    mask;
159    int		    nDst;			/* dest longwords (w.o. end) */
160    int		    w;
161    int		    n, nmiddle;
162    int		    dstS;			/* stipple-relative dst X coordinate */
163    Bool	    copy;			/* accelerate dest-invariant */
164    Bool	    transparent;		/* accelerate 0 nop */
165    int		    srcinc;			/* source units consumed */
166    Bool	    endNeedsLoad = FALSE;	/* need load for endmask */
167#ifndef FBNOPIXADDR
168    CARD8	    *fbLane;
169#endif
170    int		    startbyte, endbyte;
171
172#ifdef FB_24BIT
173    if (dstBpp == 24)
174    {
175	fbBltOne24 (src, srcStride, srcX,
176		    dst, dstStride, dstX, dstBpp,
177		    width, height,
178		    fgand, fgxor, bgand, bgxor);
179	return;
180    }
181#endif
182
183    /*
184     * Do not read past the end of the buffer!
185     */
186    srcEnd = src + height * srcStride;
187
188    /*
189     * Number of destination units in FbBits == number of stipple pixels
190     * used each time
191     */
192    pixelsPerDst = FB_UNIT / dstBpp;
193
194    /*
195     * Number of source stipple patterns in FbStip
196     */
197    unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
198
199    copy = FALSE;
200    transparent = FALSE;
201    if (bgand == 0 && fgand == 0)
202	copy = TRUE;
203    else if (bgand == FB_ALLONES && bgxor == 0)
204	transparent = TRUE;
205
206    /*
207     * Adjust source and dest to nearest FbBits boundary
208     */
209    src += srcX >> FB_STIP_SHIFT;
210    dst += dstX >> FB_SHIFT;
211    srcX &= FB_STIP_MASK;
212    dstX &= FB_MASK;
213
214    FbMaskBitsBytes(dstX, width, copy,
215		    startmask, startbyte, nmiddle, endmask, endbyte);
216
217    /*
218     * Compute effective dest alignment requirement for
219     * source -- must align source to dest unit boundary
220     */
221    dstS = dstX / dstBpp;
222    /*
223     * Compute shift constants for effective alignement
224     */
225    if (srcX >= dstS)
226    {
227	leftShift = srcX - dstS;
228	rightShift = FB_STIP_UNIT - leftShift;
229    }
230    else
231    {
232	rightShift = dstS - srcX;
233	leftShift = FB_STIP_UNIT - rightShift;
234    }
235    /*
236     * Get pointer to stipple mask array for this depth
237     */
238    fbBits = 0;	/* unused */
239    if (pixelsPerDst <= 8)
240	fbBits = fbStippleTable[pixelsPerDst];
241#ifndef FBNOPIXADDR
242    fbLane = 0;
243    if (transparent && fgand == 0 && dstBpp >= 8)
244	fbLane = fbLaneTable[dstBpp];
245#endif
246
247    /*
248     * Compute total number of destination words written, but
249     * don't count endmask
250     */
251    nDst = nmiddle;
252    if (startmask)
253	nDst++;
254
255    dstStride -= nDst;
256
257    /*
258     * Compute total number of source words consumed
259     */
260
261    srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
262
263    if (srcX > dstS)
264	srcinc++;
265    if (endmask)
266    {
267	endNeedsLoad = nDst % unitsPerSrc == 0;
268	if (endNeedsLoad)
269	    srcinc++;
270    }
271
272    srcStride -= srcinc;
273
274    /*
275     * Copy rectangle
276     */
277    while (height--)
278    {
279	w = nDst;	    /* total units across scanline */
280	n = unitsPerSrc;    /* units avail in single stipple */
281	if (n > w)
282	    n = w;
283
284	bitsLeft = 0;
285	if (srcX > dstS)
286	    bitsLeft = READ(src++);
287	if (n)
288	{
289	    /*
290	     * Load first set of stipple bits
291	     */
292	    LoadBits;
293
294	    /*
295	     * Consume stipple bits for startmask
296	     */
297	    if (startmask)
298	    {
299#if FB_UNIT > 32
300		if (pixelsPerDst == 16)
301		    mask = FbStipple16Bits(FbLeftStipBits(bits,16));
302		else
303#endif
304		    mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)];
305#ifndef FBNOPIXADDR
306		if (fbLane)
307		{
308		    fbTransparentSpan (dst, mask & startmask, fgxor, 1);
309		}
310		else
311#endif
312		{
313		    if (mask || !transparent)
314			FbDoLeftMaskByteStippleRRop (dst, mask,
315						     fgand, fgxor, bgand, bgxor,
316						     startbyte, startmask);
317		}
318		bits = FbStipLeft (bits, pixelsPerDst);
319		dst++;
320		n--;
321		w--;
322	    }
323	    /*
324	     * Consume stipple bits across scanline
325	     */
326	    for (;;)
327	    {
328		w -= n;
329		if (copy)
330		{
331		    while (n--)
332		    {
333#if FB_UNIT > 32
334			if (pixelsPerDst == 16)
335			    mask = FbStipple16Bits(FbLeftStipBits(bits,16));
336			else
337#endif
338			    mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)];
339			WRITE(dst, FbOpaqueStipple (mask, fgxor, bgxor));
340			dst++;
341			bits = FbStipLeft(bits, pixelsPerDst);
342		    }
343		}
344		else
345		{
346#ifndef FBNOPIXADDR
347		    if (fbLane)
348		    {
349			while (bits && n)
350			{
351			    switch (fbLane[FbLeftStipBits(bits,pixelsPerDst)]) {
352				LaneCases((CARD8 *) dst);
353			    }
354			    bits = FbStipLeft(bits,pixelsPerDst);
355			    dst++;
356			    n--;
357			}
358			dst += n;
359		    }
360		    else
361#endif
362		    {
363			while (n--)
364			{
365			    left = FbLeftStipBits(bits,pixelsPerDst);
366			    if (left || !transparent)
367			    {
368				mask = fbBits[left];
369				WRITE(dst, FbStippleRRop (READ(dst), mask,
370						          fgand, fgxor, bgand, bgxor));
371			    }
372			    dst++;
373			    bits = FbStipLeft(bits, pixelsPerDst);
374			}
375		    }
376		}
377		if (!w)
378		    break;
379		/*
380		 * Load another set and reset number of available units
381		 */
382		LoadBits;
383		n = unitsPerSrc;
384		if (n > w)
385		    n = w;
386	    }
387	}
388	/*
389	 * Consume stipple bits for endmask
390	 */
391	if (endmask)
392	{
393	    if (endNeedsLoad)
394	    {
395		LoadBits;
396	    }
397#if FB_UNIT > 32
398	    if (pixelsPerDst == 16)
399		mask = FbStipple16Bits(FbLeftStipBits(bits,16));
400	    else
401#endif
402		mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)];
403#ifndef FBNOPIXADDR
404	    if (fbLane)
405	    {
406		fbTransparentSpan (dst, mask & endmask, fgxor, 1);
407	    }
408	    else
409#endif
410	    {
411		if (mask || !transparent)
412		    FbDoRightMaskByteStippleRRop (dst, mask,
413						  fgand, fgxor, bgand, bgxor,
414						  endbyte, endmask);
415	    }
416	}
417	dst += dstStride;
418	src += srcStride;
419    }
420}
421
422#ifdef FB_24BIT
423
424/*
425 * Crufty macros to initialize the mask array, most of this
426 * is to avoid compile-time warnings about shift overflow
427 */
428
429#if BITMAP_BIT_ORDER == MSBFirst
430#define Mask24Pos(x,r) ((x)*24-(r))
431#else
432#define Mask24Pos(x,r) ((x)*24-((r) ? 24 - (r) : 0))
433#endif
434
435#define Mask24Neg(x,r)	(Mask24Pos(x,r) < 0 ? -Mask24Pos(x,r) : 0)
436#define Mask24Check(x,r)    (Mask24Pos(x,r) < 0 ? 0 : \
437			     Mask24Pos(x,r) >= FB_UNIT ? 0 : Mask24Pos(x,r))
438
439#define Mask24(x,r) (Mask24Pos(x,r) < FB_UNIT ? \
440		     (Mask24Pos(x,r) < 0 ? \
441		      0xffffffU >> Mask24Neg (x,r) : \
442		      0xffffffU << Mask24Check(x,r)) : 0)
443
444#define SelMask24(b,n,r)	((((b) >> n) & 1) * Mask24(n,r))
445
446/*
447 * Untested for MSBFirst or FB_UNIT == 32
448 */
449
450#if FB_UNIT == 64
451#define C4_24(b,r) \
452    (SelMask24(b,0,r) | \
453     SelMask24(b,1,r) | \
454     SelMask24(b,2,r) | \
455     SelMask24(b,3,r))
456
457#define FbStip24New(rot)    (2 + (rot != 0))
458#define FbStip24Len	    4
459
460const FbBits	fbStipple24Bits[3][1 << FbStip24Len] = {
461    /* rotate 0 */
462    {
463	C4_24( 0, 0), C4_24( 1, 0), C4_24( 2, 0), C4_24( 3, 0),
464	C4_24( 4, 0), C4_24( 5, 0), C4_24( 6, 0), C4_24( 7, 0),
465	C4_24( 8, 0), C4_24( 9, 0), C4_24(10, 0), C4_24(11, 0),
466	C4_24(12, 0), C4_24(13, 0), C4_24(14, 0), C4_24(15, 0),
467    },
468    /* rotate 8 */
469    {
470	C4_24( 0, 8), C4_24( 1, 8), C4_24( 2, 8), C4_24( 3, 8),
471	C4_24( 4, 8), C4_24( 5, 8), C4_24( 6, 8), C4_24( 7, 8),
472	C4_24( 8, 8), C4_24( 9, 8), C4_24(10, 8), C4_24(11, 8),
473	C4_24(12, 8), C4_24(13, 8), C4_24(14, 8), C4_24(15, 8),
474    },
475    /* rotate 16 */
476    {
477	C4_24( 0,16), C4_24( 1,16), C4_24( 2,16), C4_24( 3,16),
478	C4_24( 4,16), C4_24( 5,16), C4_24( 6,16), C4_24( 7,16),
479	C4_24( 8,16), C4_24( 9,16), C4_24(10,16), C4_24(11,16),
480	C4_24(12,16), C4_24(13,16), C4_24(14,16), C4_24(15,16),
481    }
482};
483
484#endif
485
486#if FB_UNIT == 32
487#define C2_24(b,r)  \
488    (SelMask24(b,0,r) | \
489     SelMask24(b,1,r))
490
491#define FbStip24Len	    2
492#if BITMAP_BIT_ORDER == MSBFirst
493#define FbStip24New(rot)    (1 + (rot == 0))
494#else
495#define FbStip24New(rot)    (1 + (rot == 8))
496#endif
497
498const FbBits	fbStipple24Bits[3][1 << FbStip24Len] = {
499    /* rotate 0 */
500    {
501	C2_24( 0, 0), C2_24 ( 1, 0), C2_24 ( 2, 0), C2_24 ( 3, 0),
502    },
503    /* rotate 8 */
504    {
505	C2_24( 0, 8), C2_24 ( 1, 8), C2_24 ( 2, 8), C2_24 ( 3, 8),
506    },
507    /* rotate 16 */
508    {
509	C2_24( 0,16), C2_24 ( 1,16), C2_24 ( 2,16), C2_24 ( 3,16),
510    }
511};
512#endif
513
514#if BITMAP_BIT_ORDER == LSBFirst
515
516#define FbMergeStip24Bits(left, right, new) \
517	(FbStipLeft (left, new) | FbStipRight ((right), (FbStip24Len - (new))))
518
519#define FbMergePartStip24Bits(left, right, llen, rlen) \
520	(left | FbStipRight(right, llen))
521
522#else
523
524#define FbMergeStip24Bits(left, right, new) \
525	((FbStipLeft (left, new) & ((1 << FbStip24Len) - 1)) | right)
526
527#define FbMergePartStip24Bits(left, right, llen, rlen) \
528	(FbStipLeft(left, rlen) | right)
529
530#endif
531
532#define fbFirstStipBits(len,stip) {\
533    int	__len = (len); \
534    if (len <= remain) { \
535	stip = FbLeftStipBits(bits, len); \
536    } else { \
537	stip = FbLeftStipBits(bits, remain); \
538	bits = (src < srcEnd ? READ(src++) : 0); \
539	__len = (len) - remain; \
540	stip = FbMergePartStip24Bits(stip, FbLeftStipBits(bits, __len), \
541				     remain, __len); \
542	remain = FB_STIP_UNIT; \
543    } \
544    bits = FbStipLeft (bits, __len); \
545    remain -= __len; \
546}
547
548#define fbInitStipBits(offset,len,stip) {\
549    bits = FbStipLeft (READ(src++),offset); \
550    remain = FB_STIP_UNIT - offset; \
551    fbFirstStipBits(len,stip); \
552    stip = FbMergeStip24Bits (0, stip, len); \
553}
554
555#define fbNextStipBits(rot,stip) {\
556    int	    __new = FbStip24New(rot); \
557    FbStip  __right; \
558    fbFirstStipBits(__new, __right); \
559    stip = FbMergeStip24Bits (stip, __right, __new); \
560    rot = FbNext24Rot (rot); \
561}
562
563/*
564 * Use deep mask tables that incorporate rotation, pull
565 * a variable number of bits out of the stipple and
566 * reuse the right bits as needed for the next write
567 *
568 * Yes, this is probably too much code, but most 24-bpp screens
569 * have no acceleration so this code is used for stipples, copyplane
570 * and text
571 */
572void
573fbBltOne24 (FbStip	*srcLine,
574	    FbStride	srcStride,  /* FbStip units per scanline */
575	    int		srcX,	    /* bit position of source */
576	    FbBits	*dst,
577	    FbStride	dstStride,  /* FbBits units per scanline */
578	    int		dstX,	    /* bit position of dest */
579	    int		dstBpp,	    /* bits per destination unit */
580
581	    int		width,	    /* width in bits of destination */
582	    int		height,	    /* height in scanlines */
583
584	    FbBits	fgand,	    /* rrop values */
585	    FbBits	fgxor,
586	    FbBits	bgand,
587	    FbBits	bgxor)
588{
589    FbStip	*src, *srcEnd;
590    FbBits	leftMask, rightMask, mask;
591    int		nlMiddle, nl;
592    FbStip	stip, bits;
593    int		remain;
594    int		dstS;
595    int		firstlen;
596    int		rot0, rot;
597    int		nDst;
598
599    /*
600     * Do not read past the end of the buffer!
601     */
602    srcEnd = srcLine + height * srcStride;
603
604    srcLine += srcX >> FB_STIP_SHIFT;
605    dst += dstX >> FB_SHIFT;
606    srcX &= FB_STIP_MASK;
607    dstX &= FB_MASK;
608    rot0 = FbFirst24Rot (dstX);
609
610    FbMaskBits (dstX, width, leftMask, nlMiddle, rightMask);
611
612    dstS = (dstX + 23) / 24;
613    firstlen = FbStip24Len - dstS;
614
615    nDst = nlMiddle;
616    if (leftMask)
617	nDst++;
618    dstStride -= nDst;
619
620    /* opaque copy */
621    if (bgand == 0 && fgand == 0)
622    {
623	while (height--)
624	{
625	    rot = rot0;
626	    src = srcLine;
627	    srcLine += srcStride;
628	    fbInitStipBits (srcX,firstlen, stip);
629	    if (leftMask)
630	    {
631		mask = fbStipple24Bits[rot >> 3][stip];
632		WRITE(dst, (READ(dst) & ~leftMask) |
633			    (FbOpaqueStipple (mask,
634					      FbRot24(fgxor, rot),
635					      FbRot24(bgxor, rot))
636			     & leftMask));
637		dst++;
638		fbNextStipBits(rot,stip);
639	    }
640	    nl = nlMiddle;
641	    while (nl--)
642	    {
643		mask = fbStipple24Bits[rot>>3][stip];
644		WRITE(dst, FbOpaqueStipple (mask,
645					    FbRot24(fgxor, rot),
646					    FbRot24(bgxor, rot)));
647		dst++;
648		fbNextStipBits(rot,stip);
649	    }
650	    if (rightMask)
651	    {
652		mask = fbStipple24Bits[rot >> 3][stip];
653		WRITE(dst, (READ(dst) & ~rightMask) |
654			    (FbOpaqueStipple (mask,
655					      FbRot24(fgxor, rot),
656					      FbRot24(bgxor, rot))
657			     & rightMask));
658	    }
659	    dst += dstStride;
660	    src += srcStride;
661	}
662    }
663    /* transparent copy */
664    else if (bgand == FB_ALLONES && bgxor == 0 && fgand == 0)
665    {
666	while (height--)
667	{
668	    rot = rot0;
669	    src = srcLine;
670	    srcLine += srcStride;
671	    fbInitStipBits (srcX, firstlen, stip);
672	    if (leftMask)
673	    {
674		if (stip)
675		{
676		    mask = fbStipple24Bits[rot >> 3][stip] & leftMask;
677		    WRITE(dst, (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
678		}
679		dst++;
680		fbNextStipBits (rot, stip);
681	    }
682	    nl = nlMiddle;
683	    while (nl--)
684	    {
685		if (stip)
686		{
687		    mask = fbStipple24Bits[rot>>3][stip];
688		    WRITE(dst, (READ(dst) & ~mask) | (FbRot24(fgxor,rot) & mask));
689		}
690		dst++;
691		fbNextStipBits (rot, stip);
692	    }
693	    if (rightMask)
694	    {
695		if (stip)
696		{
697		    mask = fbStipple24Bits[rot >> 3][stip] & rightMask;
698		    WRITE(dst, (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
699		}
700	    }
701	    dst += dstStride;
702	}
703    }
704    else
705    {
706	while (height--)
707	{
708	    rot = rot0;
709	    src = srcLine;
710	    srcLine += srcStride;
711	    fbInitStipBits (srcX, firstlen, stip);
712	    if (leftMask)
713	    {
714		mask = fbStipple24Bits[rot >> 3][stip];
715		WRITE(dst, FbStippleRRopMask (READ(dst), mask,
716					      FbRot24(fgand, rot),
717					      FbRot24(fgxor, rot),
718					      FbRot24(bgand, rot),
719					      FbRot24(bgxor, rot),
720					      leftMask));
721		dst++;
722		fbNextStipBits(rot,stip);
723	    }
724	    nl = nlMiddle;
725	    while (nl--)
726	    {
727		mask = fbStipple24Bits[rot >> 3][stip];
728		WRITE(dst, FbStippleRRop (READ(dst), mask,
729					  FbRot24(fgand, rot),
730					  FbRot24(fgxor, rot),
731					  FbRot24(bgand, rot),
732					  FbRot24(bgxor, rot)));
733		dst++;
734		fbNextStipBits(rot,stip);
735	    }
736	    if (rightMask)
737	    {
738		mask = fbStipple24Bits[rot >> 3][stip];
739		WRITE(dst, FbStippleRRopMask (READ(dst), mask,
740					      FbRot24(fgand, rot),
741					      FbRot24(fgxor, rot),
742					      FbRot24(bgand, rot),
743					      FbRot24(bgxor, rot),
744					      rightMask));
745	    }
746	    dst += dstStride;
747	}
748    }
749}
750#endif
751
752/*
753 * Not very efficient, but simple -- copy a single plane
754 * from an N bit image to a 1 bit image
755 */
756
757void
758fbBltPlane (FbBits	    *src,
759	    FbStride	    srcStride,
760	    int		    srcX,
761	    int		    srcBpp,
762
763	    FbStip	    *dst,
764	    FbStride	    dstStride,
765	    int		    dstX,
766
767	    int		    width,
768	    int		    height,
769
770	    FbStip	    fgand,
771	    FbStip	    fgxor,
772	    FbStip	    bgand,
773	    FbStip	    bgxor,
774	    Pixel	    planeMask)
775{
776    FbBits	*s;
777    FbBits	pm;
778    FbBits	srcMask;
779    FbBits	srcMaskFirst;
780    FbBits	srcMask0 = 0;
781    FbBits	srcBits;
782
783    FbStip	dstBits;
784    FbStip	*d;
785    FbStip	dstMask;
786    FbStip	dstMaskFirst;
787    FbStip	dstUnion;
788    int		w;
789    int		wt;
790    int		rot0;
791
792    if (!width)
793	return;
794
795    src += srcX >> FB_SHIFT;
796    srcX &= FB_MASK;
797
798    dst += dstX >> FB_STIP_SHIFT;
799    dstX &= FB_STIP_MASK;
800
801    w = width / srcBpp;
802
803    pm = fbReplicatePixel (planeMask, srcBpp);
804#ifdef FB_24BIT
805    if (srcBpp == 24)
806    {
807	int w = 24;
808
809	rot0 = FbFirst24Rot (srcX);
810	if (srcX + w > FB_UNIT)
811	    w = FB_UNIT - srcX;
812	srcMaskFirst = FbRot24(pm,rot0) & FbBitsMask(srcX,w);
813    }
814    else
815#endif
816    {
817	rot0 = 0;
818	srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
819	srcMask0 = pm & FbBitsMask(0, srcBpp);
820    }
821
822    dstMaskFirst = FbStipMask(dstX,1);
823    while (height--)
824    {
825	d = dst;
826	dst += dstStride;
827	s = src;
828	src += srcStride;
829
830	srcMask = srcMaskFirst;
831#ifdef FB_24BIT
832	if (srcBpp == 24)
833	    srcMask0 = FbRot24(pm,rot0) & FbBitsMask(0, srcBpp);
834#endif
835    	srcBits = READ(s++);
836
837	dstMask = dstMaskFirst;
838	dstUnion = 0;
839	dstBits = 0;
840
841	wt = w;
842
843	while (wt--)
844	{
845	    if (!srcMask)
846	    {
847		srcBits = READ(s++);
848#ifdef FB_24BIT
849		if (srcBpp == 24)
850		    srcMask0 = FbNext24Pix(srcMask0) & FbBitsMask(0,24);
851#endif
852		srcMask = srcMask0;
853	    }
854	    if (!dstMask)
855	    {
856		WRITE(d, FbStippleRRopMask(READ(d), dstBits,
857					   fgand, fgxor, bgand, bgxor,
858					   dstUnion));
859		d++;
860		dstMask = FbStipMask(0,1);
861		dstUnion = 0;
862		dstBits = 0;
863	    }
864	    if (srcBits & srcMask)
865		dstBits |= dstMask;
866	    dstUnion |= dstMask;
867	    if (srcBpp == FB_UNIT)
868		srcMask = 0;
869	    else
870		srcMask = FbScrRight(srcMask,srcBpp);
871	    dstMask = FbStipRight(dstMask,1);
872	}
873	if (dstUnion)
874	    WRITE(d, FbStippleRRopMask(READ(d),dstBits,
875				       fgand, fgxor, bgand, bgxor,
876				       dstUnion));
877    }
878}
879
880