fbbltone.c revision 35c4bbdf
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 * Stipple masks are independent of bit/byte order as long
31 * as bitorder == byteorder.  FB doesn't handle the case
32 * where these differ
33 */
34#define BitsMask(x,w)	((FB_ALLONES << ((x) & FB_MASK)) & \
35			 (FB_ALLONES >> ((FB_UNIT - ((x) + (w))) & FB_MASK)))
36
37#define Mask(x,w)	BitsMask((x)*(w),(w))
38
39#define SelMask(b,n,w)	((((b) >> n) & 1) * Mask(n,w))
40
41#define C1(b,w) \
42    (SelMask(b,0,w))
43
44#define C2(b,w) \
45    (SelMask(b,0,w) | \
46     SelMask(b,1,w))
47
48#define C4(b,w) \
49    (SelMask(b,0,w) | \
50     SelMask(b,1,w) | \
51     SelMask(b,2,w) | \
52     SelMask(b,3,w))
53
54#define C8(b,w) \
55    (SelMask(b,0,w) | \
56     SelMask(b,1,w) | \
57     SelMask(b,2,w) | \
58     SelMask(b,3,w) | \
59     SelMask(b,4,w) | \
60     SelMask(b,5,w) | \
61     SelMask(b,6,w) | \
62     SelMask(b,7,w))
63
64static const FbBits fbStipple8Bits[256] = {
65    C8(0, 4), C8(1, 4), C8(2, 4), C8(3, 4), C8(4, 4), C8(5, 4),
66    C8(6, 4), C8(7, 4), C8(8, 4), C8(9, 4), C8(10, 4), C8(11, 4),
67    C8(12, 4), C8(13, 4), C8(14, 4), C8(15, 4), C8(16, 4), C8(17, 4),
68    C8(18, 4), C8(19, 4), C8(20, 4), C8(21, 4), C8(22, 4), C8(23, 4),
69    C8(24, 4), C8(25, 4), C8(26, 4), C8(27, 4), C8(28, 4), C8(29, 4),
70    C8(30, 4), C8(31, 4), C8(32, 4), C8(33, 4), C8(34, 4), C8(35, 4),
71    C8(36, 4), C8(37, 4), C8(38, 4), C8(39, 4), C8(40, 4), C8(41, 4),
72    C8(42, 4), C8(43, 4), C8(44, 4), C8(45, 4), C8(46, 4), C8(47, 4),
73    C8(48, 4), C8(49, 4), C8(50, 4), C8(51, 4), C8(52, 4), C8(53, 4),
74    C8(54, 4), C8(55, 4), C8(56, 4), C8(57, 4), C8(58, 4), C8(59, 4),
75    C8(60, 4), C8(61, 4), C8(62, 4), C8(63, 4), C8(64, 4), C8(65, 4),
76    C8(66, 4), C8(67, 4), C8(68, 4), C8(69, 4), C8(70, 4), C8(71, 4),
77    C8(72, 4), C8(73, 4), C8(74, 4), C8(75, 4), C8(76, 4), C8(77, 4),
78    C8(78, 4), C8(79, 4), C8(80, 4), C8(81, 4), C8(82, 4), C8(83, 4),
79    C8(84, 4), C8(85, 4), C8(86, 4), C8(87, 4), C8(88, 4), C8(89, 4),
80    C8(90, 4), C8(91, 4), C8(92, 4), C8(93, 4), C8(94, 4), C8(95, 4),
81    C8(96, 4), C8(97, 4), C8(98, 4), C8(99, 4), C8(100, 4), C8(101, 4),
82    C8(102, 4), C8(103, 4), C8(104, 4), C8(105, 4), C8(106, 4), C8(107, 4),
83    C8(108, 4), C8(109, 4), C8(110, 4), C8(111, 4), C8(112, 4), C8(113, 4),
84    C8(114, 4), C8(115, 4), C8(116, 4), C8(117, 4), C8(118, 4), C8(119, 4),
85    C8(120, 4), C8(121, 4), C8(122, 4), C8(123, 4), C8(124, 4), C8(125, 4),
86    C8(126, 4), C8(127, 4), C8(128, 4), C8(129, 4), C8(130, 4), C8(131, 4),
87    C8(132, 4), C8(133, 4), C8(134, 4), C8(135, 4), C8(136, 4), C8(137, 4),
88    C8(138, 4), C8(139, 4), C8(140, 4), C8(141, 4), C8(142, 4), C8(143, 4),
89    C8(144, 4), C8(145, 4), C8(146, 4), C8(147, 4), C8(148, 4), C8(149, 4),
90    C8(150, 4), C8(151, 4), C8(152, 4), C8(153, 4), C8(154, 4), C8(155, 4),
91    C8(156, 4), C8(157, 4), C8(158, 4), C8(159, 4), C8(160, 4), C8(161, 4),
92    C8(162, 4), C8(163, 4), C8(164, 4), C8(165, 4), C8(166, 4), C8(167, 4),
93    C8(168, 4), C8(169, 4), C8(170, 4), C8(171, 4), C8(172, 4), C8(173, 4),
94    C8(174, 4), C8(175, 4), C8(176, 4), C8(177, 4), C8(178, 4), C8(179, 4),
95    C8(180, 4), C8(181, 4), C8(182, 4), C8(183, 4), C8(184, 4), C8(185, 4),
96    C8(186, 4), C8(187, 4), C8(188, 4), C8(189, 4), C8(190, 4), C8(191, 4),
97    C8(192, 4), C8(193, 4), C8(194, 4), C8(195, 4), C8(196, 4), C8(197, 4),
98    C8(198, 4), C8(199, 4), C8(200, 4), C8(201, 4), C8(202, 4), C8(203, 4),
99    C8(204, 4), C8(205, 4), C8(206, 4), C8(207, 4), C8(208, 4), C8(209, 4),
100    C8(210, 4), C8(211, 4), C8(212, 4), C8(213, 4), C8(214, 4), C8(215, 4),
101    C8(216, 4), C8(217, 4), C8(218, 4), C8(219, 4), C8(220, 4), C8(221, 4),
102    C8(222, 4), C8(223, 4), C8(224, 4), C8(225, 4), C8(226, 4), C8(227, 4),
103    C8(228, 4), C8(229, 4), C8(230, 4), C8(231, 4), C8(232, 4), C8(233, 4),
104    C8(234, 4), C8(235, 4), C8(236, 4), C8(237, 4), C8(238, 4), C8(239, 4),
105    C8(240, 4), C8(241, 4), C8(242, 4), C8(243, 4), C8(244, 4), C8(245, 4),
106    C8(246, 4), C8(247, 4), C8(248, 4), C8(249, 4), C8(250, 4), C8(251, 4),
107    C8(252, 4), C8(253, 4), C8(254, 4), C8(255, 4),
108};
109
110static const FbBits fbStipple4Bits[16] = {
111    C4(0, 8), C4(1, 8), C4(2, 8), C4(3, 8), C4(4, 8), C4(5, 8),
112    C4(6, 8), C4(7, 8), C4(8, 8), C4(9, 8), C4(10, 8), C4(11, 8),
113    C4(12, 8), C4(13, 8), C4(14, 8), C4(15, 8),
114};
115
116static const FbBits fbStipple2Bits[4] = {
117    C2(0, 16), C2(1, 16), C2(2, 16), C2(3, 16),
118};
119
120static const FbBits fbStipple1Bits[2] = {
121    C1(0, 32), C1(1, 32),
122};
123
124#ifdef __clang__
125/* shift overflow is intentional */
126#pragma clang diagnostic ignored "-Wshift-overflow"
127#endif
128
129/*
130 *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
131 *
132 *	**** **** **** **** **** **** **** ****
133 *			^
134 *	********  ********  ********  ********
135 *		  ^
136 *  leftShift = 12
137 *  rightShift = 20
138 *
139 *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
140 *
141 *	**** **** **** **** **** **** **** ****
142 *	^
143 *	********  ********  ********  ********
144 *		  ^
145 *
146 *  leftShift = 24
147 *  rightShift = 8
148 */
149
150#define LoadBits {\
151    if (leftShift) { \
152	bitsRight = (src < srcEnd ? READ(src++) : 0); \
153	bits = (FbStipLeft (bitsLeft, leftShift) | \
154		FbStipRight(bitsRight, rightShift)); \
155	bitsLeft = bitsRight; \
156    } else \
157	bits = (src < srcEnd ? READ(src++) : 0); \
158}
159
160void
161fbBltOne(FbStip * src, FbStride srcStride,      /* FbStip units per scanline */
162         int srcX,              /* bit position of source */
163         FbBits * dst, FbStride dstStride,      /* FbBits units per scanline */
164         int dstX,              /* bit position of dest */
165         int dstBpp,            /* bits per destination unit */
166         int width,             /* width in bits of destination */
167         int height,            /* height in scanlines */
168         FbBits fgand,          /* rrop values */
169         FbBits fgxor, FbBits bgand, FbBits bgxor)
170{
171    const FbBits *fbBits;
172    FbBits *srcEnd;
173    int pixelsPerDst;           /* dst pixels per FbBits */
174    int unitsPerSrc;            /* src patterns per FbStip */
175    int leftShift, rightShift;  /* align source with dest */
176    FbBits startmask, endmask;  /* dest scanline masks */
177    FbStip bits = 0, bitsLeft, bitsRight;       /* source bits */
178    FbStip left;
179    FbBits mask;
180    int nDst;                   /* dest longwords (w.o. end) */
181    int w;
182    int n, nmiddle;
183    int dstS;                   /* stipple-relative dst X coordinate */
184    Bool copy;                  /* accelerate dest-invariant */
185    Bool transparent;           /* accelerate 0 nop */
186    int srcinc;                 /* source units consumed */
187    Bool endNeedsLoad = FALSE;  /* need load for endmask */
188    int startbyte, endbyte;
189
190    if (dstBpp == 24) {
191        fbBltOne24(src, srcStride, srcX,
192                   dst, dstStride, dstX, dstBpp,
193                   width, height, fgand, fgxor, bgand, bgxor);
194        return;
195    }
196
197    /*
198     * Do not read past the end of the buffer!
199     */
200    srcEnd = src + height * srcStride;
201
202    /*
203     * Number of destination units in FbBits == number of stipple pixels
204     * used each time
205     */
206    pixelsPerDst = FB_UNIT / dstBpp;
207
208    /*
209     * Number of source stipple patterns in FbStip
210     */
211    unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
212
213    copy = FALSE;
214    transparent = FALSE;
215    if (bgand == 0 && fgand == 0)
216        copy = TRUE;
217    else if (bgand == FB_ALLONES && bgxor == 0)
218        transparent = TRUE;
219
220    /*
221     * Adjust source and dest to nearest FbBits boundary
222     */
223    src += srcX >> FB_STIP_SHIFT;
224    dst += dstX >> FB_SHIFT;
225    srcX &= FB_STIP_MASK;
226    dstX &= FB_MASK;
227
228    FbMaskBitsBytes(dstX, width, copy,
229                    startmask, startbyte, nmiddle, endmask, endbyte);
230
231    /*
232     * Compute effective dest alignment requirement for
233     * source -- must align source to dest unit boundary
234     */
235    dstS = dstX / dstBpp;
236    /*
237     * Compute shift constants for effective alignement
238     */
239    if (srcX >= dstS) {
240        leftShift = srcX - dstS;
241        rightShift = FB_STIP_UNIT - leftShift;
242    }
243    else {
244        rightShift = dstS - srcX;
245        leftShift = FB_STIP_UNIT - rightShift;
246    }
247    /*
248     * Get pointer to stipple mask array for this depth
249     */
250    fbBits = 0;                 /* unused */
251    switch (pixelsPerDst) {
252    case 8:
253        fbBits = fbStipple8Bits;
254        break;
255    case 4:
256        fbBits = fbStipple4Bits;
257        break;
258    case 2:
259        fbBits = fbStipple2Bits;
260        break;
261    case 1:
262        fbBits = fbStipple1Bits;
263        break;
264    default:
265        return;
266    }
267
268    /*
269     * Compute total number of destination words written, but
270     * don't count endmask
271     */
272    nDst = nmiddle;
273    if (startmask)
274        nDst++;
275
276    dstStride -= nDst;
277
278    /*
279     * Compute total number of source words consumed
280     */
281
282    srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
283
284    if (srcX > dstS)
285        srcinc++;
286    if (endmask) {
287        endNeedsLoad = nDst % unitsPerSrc == 0;
288        if (endNeedsLoad)
289            srcinc++;
290    }
291
292    srcStride -= srcinc;
293
294    /*
295     * Copy rectangle
296     */
297    while (height--) {
298        w = nDst;               /* total units across scanline */
299        n = unitsPerSrc;        /* units avail in single stipple */
300        if (n > w)
301            n = w;
302
303        bitsLeft = 0;
304        if (srcX > dstS)
305            bitsLeft = READ(src++);
306        if (n) {
307            /*
308             * Load first set of stipple bits
309             */
310            LoadBits;
311
312            /*
313             * Consume stipple bits for startmask
314             */
315            if (startmask) {
316                mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
317                if (mask || !transparent)
318                    FbDoLeftMaskByteStippleRRop(dst, mask,
319                                                fgand, fgxor, bgand, bgxor,
320                                                startbyte, startmask);
321                bits = FbStipLeft(bits, pixelsPerDst);
322                dst++;
323                n--;
324                w--;
325            }
326            /*
327             * Consume stipple bits across scanline
328             */
329            for (;;) {
330                w -= n;
331                if (copy) {
332                    while (n--) {
333                        mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
334                        WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor));
335                        dst++;
336                        bits = FbStipLeft(bits, pixelsPerDst);
337                    }
338                }
339                else {
340                    while (n--) {
341                        left = FbLeftStipBits(bits, pixelsPerDst);
342                        if (left || !transparent) {
343                            mask = fbBits[left];
344                            WRITE(dst, FbStippleRRop(READ(dst), mask, fgand,
345                                                     fgxor, bgand, bgxor));
346                        }
347                        dst++;
348                        bits = FbStipLeft(bits, pixelsPerDst);
349                    }
350                }
351                if (!w)
352                    break;
353                /*
354                 * Load another set and reset number of available units
355                 */
356                LoadBits;
357                n = unitsPerSrc;
358                if (n > w)
359                    n = w;
360            }
361        }
362        /*
363         * Consume stipple bits for endmask
364         */
365        if (endmask) {
366            if (endNeedsLoad) {
367                LoadBits;
368            }
369            mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
370            if (mask || !transparent)
371                FbDoRightMaskByteStippleRRop(dst, mask, fgand, fgxor,
372                                             bgand, bgxor, endbyte, endmask);
373        }
374        dst += dstStride;
375        src += srcStride;
376    }
377}
378
379/*
380 * Crufty macros to initialize the mask array, most of this
381 * is to avoid compile-time warnings about shift overflow
382 */
383
384#if BITMAP_BIT_ORDER == MSBFirst
385#define Mask24Pos(x,r) ((x)*24-(r))
386#else
387#define Mask24Pos(x,r) ((x)*24-((r) ? 24 - (r) : 0))
388#endif
389
390#define Mask24Neg(x,r)	(Mask24Pos(x,r) < 0 ? -Mask24Pos(x,r) : 0)
391#define Mask24Check(x,r)    (Mask24Pos(x,r) < 0 ? 0 : \
392			     Mask24Pos(x,r) >= FB_UNIT ? 0 : Mask24Pos(x,r))
393
394#define Mask24(x,r) (Mask24Pos(x,r) < FB_UNIT ? \
395		     (Mask24Pos(x,r) < 0 ? \
396		      0xffffffU >> Mask24Neg (x,r) : \
397		      0xffffffU << Mask24Check(x,r)) : 0)
398
399#define SelMask24(b,n,r)	((((b) >> n) & 1) * Mask24(n,r))
400
401#define C2_24(b,r)  \
402    (SelMask24(b,0,r) | \
403     SelMask24(b,1,r))
404
405#define FbStip24Len	    2
406#if BITMAP_BIT_ORDER == MSBFirst
407#define FbStip24New(rot)    (1 + (rot == 0))
408#else
409#define FbStip24New(rot)    (1 + (rot == 8))
410#endif
411
412const FbBits fbStipple24Bits[3][1 << FbStip24Len] = {
413    /* rotate 0 */
414    {
415     C2_24(0, 0), C2_24(1, 0), C2_24(2, 0), C2_24(3, 0),
416     },
417    /* rotate 8 */
418    {
419     C2_24(0, 8), C2_24(1, 8), C2_24(2, 8), C2_24(3, 8),
420     },
421    /* rotate 16 */
422    {
423     C2_24(0, 16), C2_24(1, 16), C2_24(2, 16), C2_24(3, 16),
424     }
425};
426
427#if BITMAP_BIT_ORDER == LSBFirst
428
429#define FbMergeStip24Bits(left, right, new) \
430	(FbStipLeft (left, new) | FbStipRight ((right), (FbStip24Len - (new))))
431
432#define FbMergePartStip24Bits(left, right, llen, rlen) \
433	(left | FbStipRight(right, llen))
434
435#else
436
437#define FbMergeStip24Bits(left, right, new) \
438	((FbStipLeft (left, new) & ((1 << FbStip24Len) - 1)) | right)
439
440#define FbMergePartStip24Bits(left, right, llen, rlen) \
441	(FbStipLeft(left, rlen) | right)
442
443#endif
444
445#define fbFirstStipBits(len,stip) {\
446    int	__len = (len); \
447    if (len <= remain) { \
448	stip = FbLeftStipBits(bits, len); \
449    } else { \
450	stip = FbLeftStipBits(bits, remain); \
451	bits = (src < srcEnd ? READ(src++) : 0); \
452	__len = (len) - remain; \
453	stip = FbMergePartStip24Bits(stip, FbLeftStipBits(bits, __len), \
454				     remain, __len); \
455	remain = FB_STIP_UNIT; \
456    } \
457    bits = FbStipLeft (bits, __len); \
458    remain -= __len; \
459}
460
461#define fbInitStipBits(offset,len,stip) {\
462    bits = FbStipLeft (READ(src++),offset); \
463    remain = FB_STIP_UNIT - offset; \
464    fbFirstStipBits(len,stip); \
465    stip = FbMergeStip24Bits (0, stip, len); \
466}
467
468#define fbNextStipBits(rot,stip) {\
469    int	    __new = FbStip24New(rot); \
470    FbStip  __right; \
471    fbFirstStipBits(__new, __right); \
472    stip = FbMergeStip24Bits (stip, __right, __new); \
473    rot = FbNext24Rot (rot); \
474}
475
476/*
477 * Use deep mask tables that incorporate rotation, pull
478 * a variable number of bits out of the stipple and
479 * reuse the right bits as needed for the next write
480 *
481 * Yes, this is probably too much code, but most 24-bpp screens
482 * have no acceleration so this code is used for stipples, copyplane
483 * and text
484 */
485void
486fbBltOne24(FbStip * srcLine, FbStride srcStride,        /* FbStip units per scanline */
487           int srcX,            /* bit position of source */
488           FbBits * dst, FbStride dstStride,    /* FbBits units per scanline */
489           int dstX,            /* bit position of dest */
490           int dstBpp,          /* bits per destination unit */
491           int width,           /* width in bits of destination */
492           int height,          /* height in scanlines */
493           FbBits fgand,        /* rrop values */
494           FbBits fgxor, FbBits bgand, FbBits bgxor)
495{
496    FbStip *src, *srcEnd;
497    FbBits leftMask, rightMask, mask;
498    int nlMiddle, nl;
499    FbStip stip, bits;
500    int remain;
501    int dstS;
502    int firstlen;
503    int rot0, rot;
504    int nDst;
505
506    /*
507     * Do not read past the end of the buffer!
508     */
509    srcEnd = srcLine + height * srcStride;
510
511    srcLine += srcX >> FB_STIP_SHIFT;
512    dst += dstX >> FB_SHIFT;
513    srcX &= FB_STIP_MASK;
514    dstX &= FB_MASK;
515    rot0 = FbFirst24Rot(dstX);
516
517    FbMaskBits(dstX, width, leftMask, nlMiddle, rightMask);
518
519    dstS = (dstX + 23) / 24;
520    firstlen = FbStip24Len - dstS;
521
522    nDst = nlMiddle;
523    if (leftMask)
524        nDst++;
525    dstStride -= nDst;
526
527    /* opaque copy */
528    if (bgand == 0 && fgand == 0) {
529        while (height--) {
530            rot = rot0;
531            src = srcLine;
532            srcLine += srcStride;
533            fbInitStipBits(srcX, firstlen, stip);
534            if (leftMask) {
535                mask = fbStipple24Bits[rot >> 3][stip];
536                WRITE(dst, (READ(dst) & ~leftMask) |
537                      (FbOpaqueStipple(mask,
538                                       FbRot24(fgxor, rot), FbRot24(bgxor, rot))
539                       & leftMask));
540                dst++;
541                fbNextStipBits(rot, stip);
542            }
543            nl = nlMiddle;
544            while (nl--) {
545                mask = fbStipple24Bits[rot >> 3][stip];
546                WRITE(dst, FbOpaqueStipple(mask,
547                                           FbRot24(fgxor, rot),
548                                           FbRot24(bgxor, rot)));
549                dst++;
550                fbNextStipBits(rot, stip);
551            }
552            if (rightMask) {
553                mask = fbStipple24Bits[rot >> 3][stip];
554                WRITE(dst, (READ(dst) & ~rightMask) |
555                      (FbOpaqueStipple(mask,
556                                       FbRot24(fgxor, rot), FbRot24(bgxor, rot))
557                       & rightMask));
558            }
559            dst += dstStride;
560            src += srcStride;
561        }
562    }
563    /* transparent copy */
564    else if (bgand == FB_ALLONES && bgxor == 0 && fgand == 0) {
565        while (height--) {
566            rot = rot0;
567            src = srcLine;
568            srcLine += srcStride;
569            fbInitStipBits(srcX, firstlen, stip);
570            if (leftMask) {
571                if (stip) {
572                    mask = fbStipple24Bits[rot >> 3][stip] & leftMask;
573                    WRITE(dst,
574                          (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
575                }
576                dst++;
577                fbNextStipBits(rot, stip);
578            }
579            nl = nlMiddle;
580            while (nl--) {
581                if (stip) {
582                    mask = fbStipple24Bits[rot >> 3][stip];
583                    WRITE(dst,
584                          (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
585                }
586                dst++;
587                fbNextStipBits(rot, stip);
588            }
589            if (rightMask) {
590                if (stip) {
591                    mask = fbStipple24Bits[rot >> 3][stip] & rightMask;
592                    WRITE(dst,
593                          (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
594                }
595            }
596            dst += dstStride;
597        }
598    }
599    else {
600        while (height--) {
601            rot = rot0;
602            src = srcLine;
603            srcLine += srcStride;
604            fbInitStipBits(srcX, firstlen, stip);
605            if (leftMask) {
606                mask = fbStipple24Bits[rot >> 3][stip];
607                WRITE(dst, FbStippleRRopMask(READ(dst), mask,
608                                             FbRot24(fgand, rot),
609                                             FbRot24(fgxor, rot),
610                                             FbRot24(bgand, rot),
611                                             FbRot24(bgxor, rot), leftMask));
612                dst++;
613                fbNextStipBits(rot, stip);
614            }
615            nl = nlMiddle;
616            while (nl--) {
617                mask = fbStipple24Bits[rot >> 3][stip];
618                WRITE(dst, FbStippleRRop(READ(dst), mask,
619                                         FbRot24(fgand, rot),
620                                         FbRot24(fgxor, rot),
621                                         FbRot24(bgand, rot),
622                                         FbRot24(bgxor, rot)));
623                dst++;
624                fbNextStipBits(rot, stip);
625            }
626            if (rightMask) {
627                mask = fbStipple24Bits[rot >> 3][stip];
628                WRITE(dst, FbStippleRRopMask(READ(dst), mask,
629                                             FbRot24(fgand, rot),
630                                             FbRot24(fgxor, rot),
631                                             FbRot24(bgand, rot),
632                                             FbRot24(bgxor, rot), rightMask));
633            }
634            dst += dstStride;
635        }
636    }
637}
638
639/*
640 * Not very efficient, but simple -- copy a single plane
641 * from an N bit image to a 1 bit image
642 */
643
644void
645fbBltPlane(FbBits * src,
646           FbStride srcStride,
647           int srcX,
648           int srcBpp,
649           FbStip * dst,
650           FbStride dstStride,
651           int dstX,
652           int width,
653           int height,
654           FbStip fgand,
655           FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask)
656{
657    FbBits *s;
658    FbBits pm;
659    FbBits srcMask;
660    FbBits srcMaskFirst;
661    FbBits srcMask0 = 0;
662    FbBits srcBits;
663
664    FbStip dstBits;
665    FbStip *d;
666    FbStip dstMask;
667    FbStip dstMaskFirst;
668    FbStip dstUnion;
669    int w;
670    int wt;
671    int rot0;
672
673    if (!width)
674        return;
675
676    src += srcX >> FB_SHIFT;
677    srcX &= FB_MASK;
678
679    dst += dstX >> FB_STIP_SHIFT;
680    dstX &= FB_STIP_MASK;
681
682    w = width / srcBpp;
683
684    pm = fbReplicatePixel(planeMask, srcBpp);
685    if (srcBpp == 24) {
686        int tmpw = 24;
687
688        rot0 = FbFirst24Rot(srcX);
689        if (srcX + tmpw > FB_UNIT)
690            tmpw = FB_UNIT - srcX;
691        srcMaskFirst = FbRot24(pm, rot0) & FbBitsMask(srcX, tmpw);
692    }
693    else {
694        rot0 = 0;
695        srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
696        srcMask0 = pm & FbBitsMask(0, srcBpp);
697    }
698
699    dstMaskFirst = FbStipMask(dstX, 1);
700    while (height--) {
701        d = dst;
702        dst += dstStride;
703        s = src;
704        src += srcStride;
705
706        srcMask = srcMaskFirst;
707        if (srcBpp == 24)
708            srcMask0 = FbRot24(pm, rot0) & FbBitsMask(0, srcBpp);
709        srcBits = READ(s++);
710
711        dstMask = dstMaskFirst;
712        dstUnion = 0;
713        dstBits = 0;
714
715        wt = w;
716
717        while (wt--) {
718            if (!srcMask) {
719                srcBits = READ(s++);
720                if (srcBpp == 24)
721                    srcMask0 = FbNext24Pix(srcMask0) & FbBitsMask(0, 24);
722                srcMask = srcMask0;
723            }
724            if (!dstMask) {
725                WRITE(d, FbStippleRRopMask(READ(d), dstBits,
726                                           fgand, fgxor, bgand, bgxor,
727                                           dstUnion));
728                d++;
729                dstMask = FbStipMask(0, 1);
730                dstUnion = 0;
731                dstBits = 0;
732            }
733            if (srcBits & srcMask)
734                dstBits |= dstMask;
735            dstUnion |= dstMask;
736            if (srcBpp == FB_UNIT)
737                srcMask = 0;
738            else
739                srcMask = FbScrRight(srcMask, srcBpp);
740            dstMask = FbStipRight(dstMask, 1);
741        }
742        if (dstUnion)
743            WRITE(d, FbStippleRRopMask(READ(d), dstBits,
744                                       fgand, fgxor, bgand, bgxor, dstUnion));
745    }
746}
747