105b261ecSmrg/*
205b261ecSmrg * Copyright © 1998 Keith Packard
305b261ecSmrg *
405b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
505b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
605b261ecSmrg * the above copyright notice appear in all copies and that both that
705b261ecSmrg * copyright notice and this permission notice appear in supporting
805b261ecSmrg * documentation, and that the name of Keith Packard not be used in
905b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1005b261ecSmrg * specific, written prior permission.  Keith Packard makes no
1105b261ecSmrg * representations about the suitability of this software for any purpose.  It
1205b261ecSmrg * is provided "as is" without express or implied warranty.
1305b261ecSmrg *
1405b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1505b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1605b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1705b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1805b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1905b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2005b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2105b261ecSmrg */
2205b261ecSmrg
2305b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2405b261ecSmrg#include <dix-config.h>
2505b261ecSmrg#endif
2605b261ecSmrg
2705b261ecSmrg#include "fb.h"
2805b261ecSmrg
2935c4bbdfSmrg/*
3035c4bbdfSmrg * Stipple masks are independent of bit/byte order as long
3135c4bbdfSmrg * as bitorder == byteorder.  FB doesn't handle the case
3235c4bbdfSmrg * where these differ
3335c4bbdfSmrg */
3435c4bbdfSmrg#define BitsMask(x,w)	((FB_ALLONES << ((x) & FB_MASK)) & \
3535c4bbdfSmrg			 (FB_ALLONES >> ((FB_UNIT - ((x) + (w))) & FB_MASK)))
3635c4bbdfSmrg
3735c4bbdfSmrg#define Mask(x,w)	BitsMask((x)*(w),(w))
3835c4bbdfSmrg
3935c4bbdfSmrg#define SelMask(b,n,w)	((((b) >> n) & 1) * Mask(n,w))
4035c4bbdfSmrg
4135c4bbdfSmrg#define C1(b,w) \
4235c4bbdfSmrg    (SelMask(b,0,w))
4335c4bbdfSmrg
4435c4bbdfSmrg#define C2(b,w) \
4535c4bbdfSmrg    (SelMask(b,0,w) | \
4635c4bbdfSmrg     SelMask(b,1,w))
4735c4bbdfSmrg
4835c4bbdfSmrg#define C4(b,w) \
4935c4bbdfSmrg    (SelMask(b,0,w) | \
5035c4bbdfSmrg     SelMask(b,1,w) | \
5135c4bbdfSmrg     SelMask(b,2,w) | \
5235c4bbdfSmrg     SelMask(b,3,w))
5335c4bbdfSmrg
5435c4bbdfSmrg#define C8(b,w) \
5535c4bbdfSmrg    (SelMask(b,0,w) | \
5635c4bbdfSmrg     SelMask(b,1,w) | \
5735c4bbdfSmrg     SelMask(b,2,w) | \
5835c4bbdfSmrg     SelMask(b,3,w) | \
5935c4bbdfSmrg     SelMask(b,4,w) | \
6035c4bbdfSmrg     SelMask(b,5,w) | \
6135c4bbdfSmrg     SelMask(b,6,w) | \
6235c4bbdfSmrg     SelMask(b,7,w))
6335c4bbdfSmrg
6435c4bbdfSmrgstatic const FbBits fbStipple8Bits[256] = {
6535c4bbdfSmrg    C8(0, 4), C8(1, 4), C8(2, 4), C8(3, 4), C8(4, 4), C8(5, 4),
6635c4bbdfSmrg    C8(6, 4), C8(7, 4), C8(8, 4), C8(9, 4), C8(10, 4), C8(11, 4),
6735c4bbdfSmrg    C8(12, 4), C8(13, 4), C8(14, 4), C8(15, 4), C8(16, 4), C8(17, 4),
6835c4bbdfSmrg    C8(18, 4), C8(19, 4), C8(20, 4), C8(21, 4), C8(22, 4), C8(23, 4),
6935c4bbdfSmrg    C8(24, 4), C8(25, 4), C8(26, 4), C8(27, 4), C8(28, 4), C8(29, 4),
7035c4bbdfSmrg    C8(30, 4), C8(31, 4), C8(32, 4), C8(33, 4), C8(34, 4), C8(35, 4),
7135c4bbdfSmrg    C8(36, 4), C8(37, 4), C8(38, 4), C8(39, 4), C8(40, 4), C8(41, 4),
7235c4bbdfSmrg    C8(42, 4), C8(43, 4), C8(44, 4), C8(45, 4), C8(46, 4), C8(47, 4),
7335c4bbdfSmrg    C8(48, 4), C8(49, 4), C8(50, 4), C8(51, 4), C8(52, 4), C8(53, 4),
7435c4bbdfSmrg    C8(54, 4), C8(55, 4), C8(56, 4), C8(57, 4), C8(58, 4), C8(59, 4),
7535c4bbdfSmrg    C8(60, 4), C8(61, 4), C8(62, 4), C8(63, 4), C8(64, 4), C8(65, 4),
7635c4bbdfSmrg    C8(66, 4), C8(67, 4), C8(68, 4), C8(69, 4), C8(70, 4), C8(71, 4),
7735c4bbdfSmrg    C8(72, 4), C8(73, 4), C8(74, 4), C8(75, 4), C8(76, 4), C8(77, 4),
7835c4bbdfSmrg    C8(78, 4), C8(79, 4), C8(80, 4), C8(81, 4), C8(82, 4), C8(83, 4),
7935c4bbdfSmrg    C8(84, 4), C8(85, 4), C8(86, 4), C8(87, 4), C8(88, 4), C8(89, 4),
8035c4bbdfSmrg    C8(90, 4), C8(91, 4), C8(92, 4), C8(93, 4), C8(94, 4), C8(95, 4),
8135c4bbdfSmrg    C8(96, 4), C8(97, 4), C8(98, 4), C8(99, 4), C8(100, 4), C8(101, 4),
8235c4bbdfSmrg    C8(102, 4), C8(103, 4), C8(104, 4), C8(105, 4), C8(106, 4), C8(107, 4),
8335c4bbdfSmrg    C8(108, 4), C8(109, 4), C8(110, 4), C8(111, 4), C8(112, 4), C8(113, 4),
8435c4bbdfSmrg    C8(114, 4), C8(115, 4), C8(116, 4), C8(117, 4), C8(118, 4), C8(119, 4),
8535c4bbdfSmrg    C8(120, 4), C8(121, 4), C8(122, 4), C8(123, 4), C8(124, 4), C8(125, 4),
8635c4bbdfSmrg    C8(126, 4), C8(127, 4), C8(128, 4), C8(129, 4), C8(130, 4), C8(131, 4),
8735c4bbdfSmrg    C8(132, 4), C8(133, 4), C8(134, 4), C8(135, 4), C8(136, 4), C8(137, 4),
8835c4bbdfSmrg    C8(138, 4), C8(139, 4), C8(140, 4), C8(141, 4), C8(142, 4), C8(143, 4),
8935c4bbdfSmrg    C8(144, 4), C8(145, 4), C8(146, 4), C8(147, 4), C8(148, 4), C8(149, 4),
9035c4bbdfSmrg    C8(150, 4), C8(151, 4), C8(152, 4), C8(153, 4), C8(154, 4), C8(155, 4),
9135c4bbdfSmrg    C8(156, 4), C8(157, 4), C8(158, 4), C8(159, 4), C8(160, 4), C8(161, 4),
9235c4bbdfSmrg    C8(162, 4), C8(163, 4), C8(164, 4), C8(165, 4), C8(166, 4), C8(167, 4),
9335c4bbdfSmrg    C8(168, 4), C8(169, 4), C8(170, 4), C8(171, 4), C8(172, 4), C8(173, 4),
9435c4bbdfSmrg    C8(174, 4), C8(175, 4), C8(176, 4), C8(177, 4), C8(178, 4), C8(179, 4),
9535c4bbdfSmrg    C8(180, 4), C8(181, 4), C8(182, 4), C8(183, 4), C8(184, 4), C8(185, 4),
9635c4bbdfSmrg    C8(186, 4), C8(187, 4), C8(188, 4), C8(189, 4), C8(190, 4), C8(191, 4),
9735c4bbdfSmrg    C8(192, 4), C8(193, 4), C8(194, 4), C8(195, 4), C8(196, 4), C8(197, 4),
9835c4bbdfSmrg    C8(198, 4), C8(199, 4), C8(200, 4), C8(201, 4), C8(202, 4), C8(203, 4),
9935c4bbdfSmrg    C8(204, 4), C8(205, 4), C8(206, 4), C8(207, 4), C8(208, 4), C8(209, 4),
10035c4bbdfSmrg    C8(210, 4), C8(211, 4), C8(212, 4), C8(213, 4), C8(214, 4), C8(215, 4),
10135c4bbdfSmrg    C8(216, 4), C8(217, 4), C8(218, 4), C8(219, 4), C8(220, 4), C8(221, 4),
10235c4bbdfSmrg    C8(222, 4), C8(223, 4), C8(224, 4), C8(225, 4), C8(226, 4), C8(227, 4),
10335c4bbdfSmrg    C8(228, 4), C8(229, 4), C8(230, 4), C8(231, 4), C8(232, 4), C8(233, 4),
10435c4bbdfSmrg    C8(234, 4), C8(235, 4), C8(236, 4), C8(237, 4), C8(238, 4), C8(239, 4),
10535c4bbdfSmrg    C8(240, 4), C8(241, 4), C8(242, 4), C8(243, 4), C8(244, 4), C8(245, 4),
10635c4bbdfSmrg    C8(246, 4), C8(247, 4), C8(248, 4), C8(249, 4), C8(250, 4), C8(251, 4),
10735c4bbdfSmrg    C8(252, 4), C8(253, 4), C8(254, 4), C8(255, 4),
10835c4bbdfSmrg};
10935c4bbdfSmrg
11035c4bbdfSmrgstatic const FbBits fbStipple4Bits[16] = {
11135c4bbdfSmrg    C4(0, 8), C4(1, 8), C4(2, 8), C4(3, 8), C4(4, 8), C4(5, 8),
11235c4bbdfSmrg    C4(6, 8), C4(7, 8), C4(8, 8), C4(9, 8), C4(10, 8), C4(11, 8),
11335c4bbdfSmrg    C4(12, 8), C4(13, 8), C4(14, 8), C4(15, 8),
11435c4bbdfSmrg};
11535c4bbdfSmrg
11635c4bbdfSmrgstatic const FbBits fbStipple2Bits[4] = {
11735c4bbdfSmrg    C2(0, 16), C2(1, 16), C2(2, 16), C2(3, 16),
11835c4bbdfSmrg};
11935c4bbdfSmrg
12035c4bbdfSmrgstatic const FbBits fbStipple1Bits[2] = {
12135c4bbdfSmrg    C1(0, 32), C1(1, 32),
12235c4bbdfSmrg};
12335c4bbdfSmrg
12435c4bbdfSmrg#ifdef __clang__
12535c4bbdfSmrg/* shift overflow is intentional */
12635c4bbdfSmrg#pragma clang diagnostic ignored "-Wshift-overflow"
12735c4bbdfSmrg#endif
12835c4bbdfSmrg
12905b261ecSmrg/*
13005b261ecSmrg *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
13105b261ecSmrg *
13205b261ecSmrg *	**** **** **** **** **** **** **** ****
13305b261ecSmrg *			^
13405b261ecSmrg *	********  ********  ********  ********
13505b261ecSmrg *		  ^
13605b261ecSmrg *  leftShift = 12
13705b261ecSmrg *  rightShift = 20
13805b261ecSmrg *
13905b261ecSmrg *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
14005b261ecSmrg *
14105b261ecSmrg *	**** **** **** **** **** **** **** ****
14205b261ecSmrg *	^
14305b261ecSmrg *	********  ********  ********  ********
14405b261ecSmrg *		  ^
14505b261ecSmrg *
14605b261ecSmrg *  leftShift = 24
14705b261ecSmrg *  rightShift = 8
14805b261ecSmrg */
14905b261ecSmrg
15005b261ecSmrg#define LoadBits {\
15105b261ecSmrg    if (leftShift) { \
15205b261ecSmrg	bitsRight = (src < srcEnd ? READ(src++) : 0); \
15305b261ecSmrg	bits = (FbStipLeft (bitsLeft, leftShift) | \
15405b261ecSmrg		FbStipRight(bitsRight, rightShift)); \
15505b261ecSmrg	bitsLeft = bitsRight; \
15605b261ecSmrg    } else \
15705b261ecSmrg	bits = (src < srcEnd ? READ(src++) : 0); \
15805b261ecSmrg}
15905b261ecSmrg
16005b261ecSmrgvoid
16135c4bbdfSmrgfbBltOne(FbStip * src, FbStride srcStride,      /* FbStip units per scanline */
16235c4bbdfSmrg         int srcX,              /* bit position of source */
16335c4bbdfSmrg         FbBits * dst, FbStride dstStride,      /* FbBits units per scanline */
16435c4bbdfSmrg         int dstX,              /* bit position of dest */
16535c4bbdfSmrg         int dstBpp,            /* bits per destination unit */
16635c4bbdfSmrg         int width,             /* width in bits of destination */
16735c4bbdfSmrg         int height,            /* height in scanlines */
16835c4bbdfSmrg         FbBits fgand,          /* rrop values */
16935c4bbdfSmrg         FbBits fgxor, FbBits bgand, FbBits bgxor)
17005b261ecSmrg{
17135c4bbdfSmrg    const FbBits *fbBits;
17235c4bbdfSmrg    FbBits *srcEnd;
17335c4bbdfSmrg    int pixelsPerDst;           /* dst pixels per FbBits */
17435c4bbdfSmrg    int unitsPerSrc;            /* src patterns per FbStip */
17535c4bbdfSmrg    int leftShift, rightShift;  /* align source with dest */
17635c4bbdfSmrg    FbBits startmask, endmask;  /* dest scanline masks */
17735c4bbdfSmrg    FbStip bits = 0, bitsLeft, bitsRight;       /* source bits */
17835c4bbdfSmrg    FbStip left;
17935c4bbdfSmrg    FbBits mask;
18035c4bbdfSmrg    int nDst;                   /* dest longwords (w.o. end) */
18135c4bbdfSmrg    int w;
18235c4bbdfSmrg    int n, nmiddle;
18335c4bbdfSmrg    int dstS;                   /* stipple-relative dst X coordinate */
18435c4bbdfSmrg    Bool copy;                  /* accelerate dest-invariant */
18535c4bbdfSmrg    Bool transparent;           /* accelerate 0 nop */
18635c4bbdfSmrg    int srcinc;                 /* source units consumed */
18735c4bbdfSmrg    Bool endNeedsLoad = FALSE;  /* need load for endmask */
18835c4bbdfSmrg    int startbyte, endbyte;
18935c4bbdfSmrg
19005b261ecSmrg    /*
19105b261ecSmrg     * Do not read past the end of the buffer!
19205b261ecSmrg     */
19305b261ecSmrg    srcEnd = src + height * srcStride;
19405b261ecSmrg
19505b261ecSmrg    /*
19605b261ecSmrg     * Number of destination units in FbBits == number of stipple pixels
19705b261ecSmrg     * used each time
19805b261ecSmrg     */
19905b261ecSmrg    pixelsPerDst = FB_UNIT / dstBpp;
20005b261ecSmrg
20105b261ecSmrg    /*
20235c4bbdfSmrg     * Number of source stipple patterns in FbStip
20305b261ecSmrg     */
20405b261ecSmrg    unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
20535c4bbdfSmrg
20605b261ecSmrg    copy = FALSE;
20705b261ecSmrg    transparent = FALSE;
20805b261ecSmrg    if (bgand == 0 && fgand == 0)
20935c4bbdfSmrg        copy = TRUE;
21005b261ecSmrg    else if (bgand == FB_ALLONES && bgxor == 0)
21135c4bbdfSmrg        transparent = TRUE;
21205b261ecSmrg
21305b261ecSmrg    /*
21405b261ecSmrg     * Adjust source and dest to nearest FbBits boundary
21505b261ecSmrg     */
21605b261ecSmrg    src += srcX >> FB_STIP_SHIFT;
21705b261ecSmrg    dst += dstX >> FB_SHIFT;
21805b261ecSmrg    srcX &= FB_STIP_MASK;
21905b261ecSmrg    dstX &= FB_MASK;
22005b261ecSmrg
22135c4bbdfSmrg    FbMaskBitsBytes(dstX, width, copy,
22235c4bbdfSmrg                    startmask, startbyte, nmiddle, endmask, endbyte);
22305b261ecSmrg
22405b261ecSmrg    /*
22505b261ecSmrg     * Compute effective dest alignment requirement for
22605b261ecSmrg     * source -- must align source to dest unit boundary
22705b261ecSmrg     */
22805b261ecSmrg    dstS = dstX / dstBpp;
22905b261ecSmrg    /*
230ed6184dfSmrg     * Compute shift constants for effective alignment
23105b261ecSmrg     */
23235c4bbdfSmrg    if (srcX >= dstS) {
23335c4bbdfSmrg        leftShift = srcX - dstS;
23435c4bbdfSmrg        rightShift = FB_STIP_UNIT - leftShift;
23505b261ecSmrg    }
23635c4bbdfSmrg    else {
23735c4bbdfSmrg        rightShift = dstS - srcX;
23835c4bbdfSmrg        leftShift = FB_STIP_UNIT - rightShift;
23905b261ecSmrg    }
24005b261ecSmrg    /*
24105b261ecSmrg     * Get pointer to stipple mask array for this depth
24205b261ecSmrg     */
24335c4bbdfSmrg    fbBits = 0;                 /* unused */
24435c4bbdfSmrg    switch (pixelsPerDst) {
24535c4bbdfSmrg    case 8:
24635c4bbdfSmrg        fbBits = fbStipple8Bits;
24735c4bbdfSmrg        break;
24835c4bbdfSmrg    case 4:
24935c4bbdfSmrg        fbBits = fbStipple4Bits;
25035c4bbdfSmrg        break;
25135c4bbdfSmrg    case 2:
25235c4bbdfSmrg        fbBits = fbStipple2Bits;
25335c4bbdfSmrg        break;
25435c4bbdfSmrg    case 1:
25535c4bbdfSmrg        fbBits = fbStipple1Bits;
25635c4bbdfSmrg        break;
25735c4bbdfSmrg    default:
25835c4bbdfSmrg        return;
25935c4bbdfSmrg    }
26035c4bbdfSmrg
26105b261ecSmrg    /*
26235c4bbdfSmrg     * Compute total number of destination words written, but
26335c4bbdfSmrg     * don't count endmask
26405b261ecSmrg     */
26505b261ecSmrg    nDst = nmiddle;
26605b261ecSmrg    if (startmask)
26735c4bbdfSmrg        nDst++;
26835c4bbdfSmrg
26905b261ecSmrg    dstStride -= nDst;
27005b261ecSmrg
27105b261ecSmrg    /*
27205b261ecSmrg     * Compute total number of source words consumed
27305b261ecSmrg     */
27435c4bbdfSmrg
27505b261ecSmrg    srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
27635c4bbdfSmrg
27705b261ecSmrg    if (srcX > dstS)
27835c4bbdfSmrg        srcinc++;
27935c4bbdfSmrg    if (endmask) {
28035c4bbdfSmrg        endNeedsLoad = nDst % unitsPerSrc == 0;
28135c4bbdfSmrg        if (endNeedsLoad)
28235c4bbdfSmrg            srcinc++;
28305b261ecSmrg    }
28405b261ecSmrg
28505b261ecSmrg    srcStride -= srcinc;
28635c4bbdfSmrg
28705b261ecSmrg    /*
28805b261ecSmrg     * Copy rectangle
28905b261ecSmrg     */
29035c4bbdfSmrg    while (height--) {
29135c4bbdfSmrg        w = nDst;               /* total units across scanline */
29235c4bbdfSmrg        n = unitsPerSrc;        /* units avail in single stipple */
29335c4bbdfSmrg        if (n > w)
29435c4bbdfSmrg            n = w;
29535c4bbdfSmrg
29635c4bbdfSmrg        bitsLeft = 0;
29735c4bbdfSmrg        if (srcX > dstS)
29835c4bbdfSmrg            bitsLeft = READ(src++);
29935c4bbdfSmrg        if (n) {
30035c4bbdfSmrg            /*
30135c4bbdfSmrg             * Load first set of stipple bits
30235c4bbdfSmrg             */
30335c4bbdfSmrg            LoadBits;
30435c4bbdfSmrg
30535c4bbdfSmrg            /*
30635c4bbdfSmrg             * Consume stipple bits for startmask
30735c4bbdfSmrg             */
30835c4bbdfSmrg            if (startmask) {
30935c4bbdfSmrg                mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
31035c4bbdfSmrg                if (mask || !transparent)
31135c4bbdfSmrg                    FbDoLeftMaskByteStippleRRop(dst, mask,
31235c4bbdfSmrg                                                fgand, fgxor, bgand, bgxor,
31335c4bbdfSmrg                                                startbyte, startmask);
31435c4bbdfSmrg                bits = FbStipLeft(bits, pixelsPerDst);
31535c4bbdfSmrg                dst++;
31635c4bbdfSmrg                n--;
31735c4bbdfSmrg                w--;
31835c4bbdfSmrg            }
31935c4bbdfSmrg            /*
32035c4bbdfSmrg             * Consume stipple bits across scanline
32135c4bbdfSmrg             */
32235c4bbdfSmrg            for (;;) {
32335c4bbdfSmrg                w -= n;
32435c4bbdfSmrg                if (copy) {
32535c4bbdfSmrg                    while (n--) {
32635c4bbdfSmrg                        mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
32735c4bbdfSmrg                        WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor));
32835c4bbdfSmrg                        dst++;
32935c4bbdfSmrg                        bits = FbStipLeft(bits, pixelsPerDst);
33035c4bbdfSmrg                    }
33135c4bbdfSmrg                }
33235c4bbdfSmrg                else {
33335c4bbdfSmrg                    while (n--) {
33435c4bbdfSmrg                        left = FbLeftStipBits(bits, pixelsPerDst);
33535c4bbdfSmrg                        if (left || !transparent) {
33635c4bbdfSmrg                            mask = fbBits[left];
33735c4bbdfSmrg                            WRITE(dst, FbStippleRRop(READ(dst), mask, fgand,
33835c4bbdfSmrg                                                     fgxor, bgand, bgxor));
33935c4bbdfSmrg                        }
34035c4bbdfSmrg                        dst++;
34135c4bbdfSmrg                        bits = FbStipLeft(bits, pixelsPerDst);
34235c4bbdfSmrg                    }
34335c4bbdfSmrg                }
34435c4bbdfSmrg                if (!w)
34535c4bbdfSmrg                    break;
34635c4bbdfSmrg                /*
34735c4bbdfSmrg                 * Load another set and reset number of available units
34835c4bbdfSmrg                 */
34935c4bbdfSmrg                LoadBits;
35035c4bbdfSmrg                n = unitsPerSrc;
35135c4bbdfSmrg                if (n > w)
35235c4bbdfSmrg                    n = w;
35335c4bbdfSmrg            }
35435c4bbdfSmrg        }
35535c4bbdfSmrg        /*
35635c4bbdfSmrg         * Consume stipple bits for endmask
35735c4bbdfSmrg         */
35835c4bbdfSmrg        if (endmask) {
35935c4bbdfSmrg            if (endNeedsLoad) {
36035c4bbdfSmrg                LoadBits;
36135c4bbdfSmrg            }
36235c4bbdfSmrg            mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
36335c4bbdfSmrg            if (mask || !transparent)
36435c4bbdfSmrg                FbDoRightMaskByteStippleRRop(dst, mask, fgand, fgxor,
36535c4bbdfSmrg                                             bgand, bgxor, endbyte, endmask);
36635c4bbdfSmrg        }
36735c4bbdfSmrg        dst += dstStride;
36835c4bbdfSmrg        src += srcStride;
36905b261ecSmrg    }
37005b261ecSmrg}
37105b261ecSmrg
37205b261ecSmrg/*
37305b261ecSmrg * Not very efficient, but simple -- copy a single plane
37405b261ecSmrg * from an N bit image to a 1 bit image
37505b261ecSmrg */
37635c4bbdfSmrg
37705b261ecSmrgvoid
37835c4bbdfSmrgfbBltPlane(FbBits * src,
37935c4bbdfSmrg           FbStride srcStride,
38035c4bbdfSmrg           int srcX,
38135c4bbdfSmrg           int srcBpp,
38235c4bbdfSmrg           FbStip * dst,
38335c4bbdfSmrg           FbStride dstStride,
38435c4bbdfSmrg           int dstX,
38535c4bbdfSmrg           int width,
38635c4bbdfSmrg           int height,
38735c4bbdfSmrg           FbStip fgand,
38835c4bbdfSmrg           FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask)
38905b261ecSmrg{
39035c4bbdfSmrg    FbBits *s;
39135c4bbdfSmrg    FbBits pm;
39235c4bbdfSmrg    FbBits srcMask;
39335c4bbdfSmrg    FbBits srcMaskFirst;
39435c4bbdfSmrg    FbBits srcMask0 = 0;
39535c4bbdfSmrg    FbBits srcBits;
39635c4bbdfSmrg
39735c4bbdfSmrg    FbStip dstBits;
39835c4bbdfSmrg    FbStip *d;
39935c4bbdfSmrg    FbStip dstMask;
40035c4bbdfSmrg    FbStip dstMaskFirst;
40135c4bbdfSmrg    FbStip dstUnion;
40235c4bbdfSmrg    int w;
40335c4bbdfSmrg    int wt;
40405b261ecSmrg
40505b261ecSmrg    if (!width)
40635c4bbdfSmrg        return;
40735c4bbdfSmrg
40805b261ecSmrg    src += srcX >> FB_SHIFT;
40905b261ecSmrg    srcX &= FB_MASK;
41005b261ecSmrg
41105b261ecSmrg    dst += dstX >> FB_STIP_SHIFT;
41205b261ecSmrg    dstX &= FB_STIP_MASK;
41335c4bbdfSmrg
41405b261ecSmrg    w = width / srcBpp;
41505b261ecSmrg
41635c4bbdfSmrg    pm = fbReplicatePixel(planeMask, srcBpp);
4171b5d61b8Smrg    srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
4181b5d61b8Smrg    srcMask0 = pm & FbBitsMask(0, srcBpp);
41935c4bbdfSmrg
42035c4bbdfSmrg    dstMaskFirst = FbStipMask(dstX, 1);
42135c4bbdfSmrg    while (height--) {
42235c4bbdfSmrg        d = dst;
42335c4bbdfSmrg        dst += dstStride;
42435c4bbdfSmrg        s = src;
42535c4bbdfSmrg        src += srcStride;
42635c4bbdfSmrg
42735c4bbdfSmrg        srcMask = srcMaskFirst;
42835c4bbdfSmrg        srcBits = READ(s++);
42935c4bbdfSmrg
43035c4bbdfSmrg        dstMask = dstMaskFirst;
43135c4bbdfSmrg        dstUnion = 0;
43235c4bbdfSmrg        dstBits = 0;
43335c4bbdfSmrg
43435c4bbdfSmrg        wt = w;
43535c4bbdfSmrg
43635c4bbdfSmrg        while (wt--) {
43735c4bbdfSmrg            if (!srcMask) {
43835c4bbdfSmrg                srcBits = READ(s++);
43935c4bbdfSmrg                srcMask = srcMask0;
44035c4bbdfSmrg            }
44135c4bbdfSmrg            if (!dstMask) {
44235c4bbdfSmrg                WRITE(d, FbStippleRRopMask(READ(d), dstBits,
44335c4bbdfSmrg                                           fgand, fgxor, bgand, bgxor,
44435c4bbdfSmrg                                           dstUnion));
44535c4bbdfSmrg                d++;
44635c4bbdfSmrg                dstMask = FbStipMask(0, 1);
44735c4bbdfSmrg                dstUnion = 0;
44835c4bbdfSmrg                dstBits = 0;
44935c4bbdfSmrg            }
45035c4bbdfSmrg            if (srcBits & srcMask)
45135c4bbdfSmrg                dstBits |= dstMask;
45235c4bbdfSmrg            dstUnion |= dstMask;
45335c4bbdfSmrg            if (srcBpp == FB_UNIT)
45435c4bbdfSmrg                srcMask = 0;
45535c4bbdfSmrg            else
45635c4bbdfSmrg                srcMask = FbScrRight(srcMask, srcBpp);
45735c4bbdfSmrg            dstMask = FbStipRight(dstMask, 1);
45835c4bbdfSmrg        }
45935c4bbdfSmrg        if (dstUnion)
46035c4bbdfSmrg            WRITE(d, FbStippleRRopMask(READ(d), dstBits,
46135c4bbdfSmrg                                       fgand, fgxor, bgand, bgxor, dstUnion));
46205b261ecSmrg    }
46305b261ecSmrg}
464