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/*
24 * This file defines functions for drawing some primitives using
25 * underlying datatypes instead of masks
26 */
27
28#define isClipped(c,ul,lr)  (((c) | ((c) - (ul)) | ((lr) - (c))) & 0x80008000)
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33
34#ifdef BITSSTORE
35#define STORE(b,x)  BITSSTORE(b,x)
36#else
37#define STORE(b,x)  WRITE((b), (x))
38#endif
39
40#ifdef BITSRROP
41#define RROP(b,a,x)	BITSRROP(b,a,x)
42#else
43#define RROP(b,a,x)	WRITE((b), FbDoRRop (READ(b), (a), (x)))
44#endif
45
46#ifdef BITSUNIT
47#define UNIT BITSUNIT
48#define USE_SOLID
49#else
50#define UNIT BITS
51#endif
52
53/*
54 * Define the following before including this file:
55 *
56 *  BRESSOLID	name of function for drawing a solid segment
57 *  BRESDASH	name of function for drawing a dashed segment
58 *  DOTS	name of function for drawing dots
59 *  ARC		name of function for drawing a solid arc
60 *  BITS	type of underlying unit
61 */
62
63#ifdef BRESSOLID
64void
65BRESSOLID(DrawablePtr pDrawable,
66          GCPtr pGC,
67          int dashOffset,
68          int signdx,
69          int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
70{
71    FbBits *dst;
72    FbStride dstStride;
73    int dstBpp;
74    int dstXoff, dstYoff;
75    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
76    UNIT *bits;
77    FbStride bitsStride;
78    FbStride majorStep, minorStep;
79    BITS xor = (BITS) pPriv->xor;
80
81    fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
82    bits =
83        ((UNIT *) (dst + ((y1 + dstYoff) * dstStride))) + (x1 + dstXoff);
84    bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
85    if (signdy < 0)
86        bitsStride = -bitsStride;
87    if (axis == X_AXIS) {
88        majorStep = signdx;
89        minorStep = bitsStride;
90    }
91    else {
92        majorStep = bitsStride;
93        minorStep = signdx;
94    }
95    while (len--) {
96        STORE(bits, xor);
97        bits += majorStep;
98        e += e1;
99        if (e >= 0) {
100            bits += minorStep;
101            e += e3;
102        }
103    }
104
105    fbFinishAccess(pDrawable);
106}
107#endif
108
109#ifdef BRESDASH
110void
111BRESDASH(DrawablePtr pDrawable,
112         GCPtr pGC,
113         int dashOffset,
114         int signdx,
115         int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
116{
117    FbBits *dst;
118    FbStride dstStride;
119    int dstBpp;
120    int dstXoff, dstYoff;
121    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
122    UNIT *bits;
123    FbStride bitsStride;
124    FbStride majorStep, minorStep;
125    BITS xorfg, xorbg;
126
127    FbDashDeclare;
128    int dashlen;
129    Bool even;
130    Bool doOdd;
131
132    fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
133    doOdd = pGC->lineStyle == LineDoubleDash;
134    xorfg = (BITS) pPriv->xor;
135    xorbg = (BITS) pPriv->bgxor;
136
137    FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
138
139    bits =
140        ((UNIT *) (dst + ((y1 + dstYoff) * dstStride))) + (x1 + dstXoff);
141    bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
142    if (signdy < 0)
143        bitsStride = -bitsStride;
144    if (axis == X_AXIS) {
145        majorStep = signdx;
146        minorStep = bitsStride;
147    }
148    else {
149        majorStep = bitsStride;
150        minorStep = signdx;
151    }
152    if (dashlen >= len)
153        dashlen = len;
154    if (doOdd) {
155        if (!even)
156            goto doubleOdd;
157        for (;;) {
158            len -= dashlen;
159            while (dashlen--) {
160                STORE(bits, xorfg);
161                bits += majorStep;
162                if ((e += e1) >= 0) {
163                    e += e3;
164                    bits += minorStep;
165                }
166            }
167            if (!len)
168                break;
169
170            FbDashNextEven(dashlen);
171
172            if (dashlen >= len)
173                dashlen = len;
174 doubleOdd:
175            len -= dashlen;
176            while (dashlen--) {
177                STORE(bits, xorbg);
178                bits += majorStep;
179                if ((e += e1) >= 0) {
180                    e += e3;
181                    bits += minorStep;
182                }
183            }
184            if (!len)
185                break;
186
187            FbDashNextOdd(dashlen);
188
189            if (dashlen >= len)
190                dashlen = len;
191        }
192    }
193    else {
194        if (!even)
195            goto onOffOdd;
196        for (;;) {
197            len -= dashlen;
198            while (dashlen--) {
199                STORE(bits, xorfg);
200                bits += majorStep;
201                if ((e += e1) >= 0) {
202                    e += e3;
203                    bits += minorStep;
204                }
205            }
206            if (!len)
207                break;
208
209            FbDashNextEven(dashlen);
210
211            if (dashlen >= len)
212                dashlen = len;
213 onOffOdd:
214            len -= dashlen;
215            while (dashlen--) {
216                bits += majorStep;
217                if ((e += e1) >= 0) {
218                    e += e3;
219                    bits += minorStep;
220                }
221            }
222            if (!len)
223                break;
224
225            FbDashNextOdd(dashlen);
226
227            if (dashlen >= len)
228                dashlen = len;
229        }
230    }
231
232    fbFinishAccess(pDrawable);
233}
234#endif
235
236#ifdef DOTS
237void
238DOTS(FbBits * dst,
239     FbStride dstStride,
240     int dstBpp,
241     BoxPtr pBox,
242     xPoint * ptsOrig,
243     int npt, int xorg, int yorg, int xoff, int yoff, FbBits and, FbBits xor)
244{
245    INT32 *pts = (INT32 *) ptsOrig;
246    UNIT *bits = (UNIT *) dst;
247    UNIT *point;
248    BITS bxor = (BITS) xor;
249    BITS band = (BITS) and;
250    FbStride bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
251    INT32 ul, lr;
252    INT32 pt;
253
254    ul = coordToInt(pBox->x1 - xorg, pBox->y1 - yorg);
255    lr = coordToInt(pBox->x2 - xorg - 1, pBox->y2 - yorg - 1);
256
257    bits += bitsStride * (yorg + yoff) + (xorg + xoff);
258
259    if (and == 0) {
260        while (npt--) {
261            pt = *pts++;
262            if (!isClipped(pt, ul, lr)) {
263                point = bits + intToY(pt) * bitsStride + intToX(pt);
264                STORE(point, bxor);
265            }
266        }
267    }
268    else {
269        while (npt--) {
270            pt = *pts++;
271            if (!isClipped(pt, ul, lr)) {
272                point = bits + intToY(pt) * bitsStride + intToX(pt);
273                RROP(point, band, bxor);
274            }
275        }
276    }
277}
278#endif
279
280#ifdef ARC
281
282#define ARCCOPY(d)  STORE(d,xorBits)
283#define ARCRROP(d)  RROP(d,andBits,xorBits)
284
285void
286ARC(FbBits * dst,
287    FbStride dstStride,
288    int dstBpp, xArc * arc, int drawX, int drawY, FbBits and, FbBits xor)
289{
290    UNIT *bits;
291    FbStride bitsStride;
292    miZeroArcRec info;
293    Bool do360;
294    int x;
295    UNIT *yorgp, *yorgop;
296    BITS andBits, xorBits;
297    int yoffset, dyoffset;
298    int y, a, b, d, mask;
299    int k1, k3, dx, dy;
300
301    bits = (UNIT *) dst;
302    bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
303    andBits = (BITS) and;
304    xorBits = (BITS) xor;
305    do360 = miZeroArcSetup(arc, &info, TRUE);
306    yorgp = bits + ((info.yorg + drawY) * bitsStride);
307    yorgop = bits + ((info.yorgo + drawY) * bitsStride);
308    info.xorg = (info.xorg + drawX);
309    info.xorgo = (info.xorgo + drawX);
310    MIARCSETUP();
311    yoffset = y ? bitsStride : 0;
312    dyoffset = 0;
313    mask = info.initialMask;
314
315    if (!(arc->width & 1)) {
316        if (andBits == 0) {
317            if (mask & 2)
318                ARCCOPY(yorgp + info.xorgo);
319            if (mask & 8)
320                ARCCOPY(yorgop + info.xorgo);
321        }
322        else {
323            if (mask & 2)
324                ARCRROP(yorgp + info.xorgo);
325            if (mask & 8)
326                ARCRROP(yorgop + info.xorgo);
327        }
328    }
329    if (!info.end.x || !info.end.y) {
330        mask = info.end.mask;
331        info.end = info.altend;
332    }
333    if (do360 && (arc->width == arc->height) && !(arc->width & 1)) {
334        int xoffset = bitsStride;
335        UNIT *yorghb = yorgp + (info.h * bitsStride) + info.xorg;
336        UNIT *yorgohb = yorghb - info.h;
337
338        yorgp += info.xorg;
339        yorgop += info.xorg;
340        yorghb += info.h;
341        while (1) {
342            if (andBits == 0) {
343                ARCCOPY(yorgp + yoffset + x);
344                ARCCOPY(yorgp + yoffset - x);
345                ARCCOPY(yorgop - yoffset - x);
346                ARCCOPY(yorgop - yoffset + x);
347            }
348            else {
349                ARCRROP(yorgp + yoffset + x);
350                ARCRROP(yorgp + yoffset - x);
351                ARCRROP(yorgop - yoffset - x);
352                ARCRROP(yorgop - yoffset + x);
353            }
354            if (a < 0)
355                break;
356            if (andBits == 0) {
357                ARCCOPY(yorghb - xoffset - y);
358                ARCCOPY(yorgohb - xoffset + y);
359                ARCCOPY(yorgohb + xoffset + y);
360                ARCCOPY(yorghb + xoffset - y);
361            }
362            else {
363                ARCRROP(yorghb - xoffset - y);
364                ARCRROP(yorgohb - xoffset + y);
365                ARCRROP(yorgohb + xoffset + y);
366                ARCRROP(yorghb + xoffset - y);
367            }
368            xoffset += bitsStride;
369            MIARCCIRCLESTEP(yoffset += bitsStride;
370                );
371        }
372        yorgp -= info.xorg;
373        yorgop -= info.xorg;
374        x = info.w;
375        yoffset = info.h * bitsStride;
376    }
377    else if (do360) {
378        while (y < info.h || x < info.w) {
379            MIARCOCTANTSHIFT(dyoffset = bitsStride;
380                );
381            if (andBits == 0) {
382                ARCCOPY(yorgp + yoffset + info.xorg + x);
383                ARCCOPY(yorgp + yoffset + info.xorgo - x);
384                ARCCOPY(yorgop - yoffset + info.xorgo - x);
385                ARCCOPY(yorgop - yoffset + info.xorg + x);
386            }
387            else {
388                ARCRROP(yorgp + yoffset + info.xorg + x);
389                ARCRROP(yorgp + yoffset + info.xorgo - x);
390                ARCRROP(yorgop - yoffset + info.xorgo - x);
391                ARCRROP(yorgop - yoffset + info.xorg + x);
392            }
393            MIARCSTEP(yoffset += dyoffset;
394                      , yoffset += bitsStride;
395                );
396        }
397    }
398    else {
399        while (y < info.h || x < info.w) {
400            MIARCOCTANTSHIFT(dyoffset = bitsStride;
401                );
402            if ((x == info.start.x) || (y == info.start.y)) {
403                mask = info.start.mask;
404                info.start = info.altstart;
405            }
406            if (andBits == 0) {
407                if (mask & 1)
408                    ARCCOPY(yorgp + yoffset + info.xorg + x);
409                if (mask & 2)
410                    ARCCOPY(yorgp + yoffset + info.xorgo - x);
411                if (mask & 4)
412                    ARCCOPY(yorgop - yoffset + info.xorgo - x);
413                if (mask & 8)
414                    ARCCOPY(yorgop - yoffset + info.xorg + x);
415            }
416            else {
417                if (mask & 1)
418                    ARCRROP(yorgp + yoffset + info.xorg + x);
419                if (mask & 2)
420                    ARCRROP(yorgp + yoffset + info.xorgo - x);
421                if (mask & 4)
422                    ARCRROP(yorgop - yoffset + info.xorgo - x);
423                if (mask & 8)
424                    ARCRROP(yorgop - yoffset + info.xorg + x);
425            }
426            if ((x == info.end.x) || (y == info.end.y)) {
427                mask = info.end.mask;
428                info.end = info.altend;
429            }
430            MIARCSTEP(yoffset += dyoffset;
431                      , yoffset += bitsStride;
432                );
433        }
434    }
435    if ((x == info.start.x) || (y == info.start.y))
436        mask = info.start.mask;
437    if (andBits == 0) {
438        if (mask & 1)
439            ARCCOPY(yorgp + yoffset + info.xorg + x);
440        if (mask & 4)
441            ARCCOPY(yorgop - yoffset + info.xorgo - x);
442        if (arc->height & 1) {
443            if (mask & 2)
444                ARCCOPY(yorgp + yoffset + info.xorgo - x);
445            if (mask & 8)
446                ARCCOPY(yorgop - yoffset + info.xorg + x);
447        }
448    }
449    else {
450        if (mask & 1)
451            ARCRROP(yorgp + yoffset + info.xorg + x);
452        if (mask & 4)
453            ARCRROP(yorgop - yoffset + info.xorgo - x);
454        if (arc->height & 1) {
455            if (mask & 2)
456                ARCRROP(yorgp + yoffset + info.xorgo - x);
457            if (mask & 8)
458                ARCRROP(yorgop - yoffset + info.xorg + x);
459        }
460    }
461}
462
463#undef ARCCOPY
464#undef ARCRROP
465#endif
466
467#ifdef GLYPH
468#if BITMAP_BIT_ORDER == LSBFirst
469#define WRITE_ADDR1(n)	    (n)
470#define WRITE_ADDR2(n)	    (n)
471#define WRITE_ADDR4(n)	    (n)
472#else
473#define WRITE_ADDR1(n)	    ((n) ^ 3)
474#define WRITE_ADDR2(n)	    ((n) ^ 2)
475#define WRITE_ADDR4(n)	    ((n))
476#endif
477
478#define WRITE1(d,n,fg)	    WRITE(d + WRITE_ADDR1(n), (BITS) (fg))
479
480#ifdef BITS2
481#define WRITE2(d,n,fg)	    WRITE((BITS2 *) &((d)[WRITE_ADDR2(n)]), (BITS2) (fg))
482#else
483#define WRITE2(d,n,fg)	    (WRITE1(d,n,fg), WRITE1(d,(n)+1,fg))
484#endif
485
486#ifdef BITS4
487#define WRITE4(d,n,fg)	    WRITE((BITS4 *) &((d)[WRITE_ADDR4(n)]), (BITS4) (fg))
488#else
489#define WRITE4(d,n,fg)	    (WRITE2(d,n,fg), WRITE2(d,(n)+2,fg))
490#endif
491
492void
493GLYPH(FbBits * dstBits,
494      FbStride dstStride,
495      int dstBpp, FbStip * stipple, FbBits fg, int x, int height)
496{
497    int lshift;
498    FbStip bits;
499    BITS *dstLine;
500    BITS *dst;
501    int n;
502    int shift;
503
504    dstLine = (BITS *) dstBits;
505    dstLine += x & ~3;
506    dstStride *= (sizeof(FbBits) / sizeof(BITS));
507    shift = x & 3;
508    lshift = 4 - shift;
509    while (height--) {
510        bits = *stipple++;
511        dst = (BITS *) dstLine;
512        n = lshift;
513        while (bits) {
514            switch (FbStipMoveLsb(FbLeftStipBits(bits, n), 4, n)) {
515            case 0:
516                break;
517            case 1:
518                WRITE1(dst, 0, fg);
519                break;
520            case 2:
521                WRITE1(dst, 1, fg);
522                break;
523            case 3:
524                WRITE2(dst, 0, fg);
525                break;
526            case 4:
527                WRITE1(dst, 2, fg);
528                break;
529            case 5:
530                WRITE1(dst, 0, fg);
531                WRITE1(dst, 2, fg);
532                break;
533            case 6:
534                WRITE1(dst, 1, fg);
535                WRITE1(dst, 2, fg);
536                break;
537            case 7:
538                WRITE2(dst, 0, fg);
539                WRITE1(dst, 2, fg);
540                break;
541            case 8:
542                WRITE1(dst, 3, fg);
543                break;
544            case 9:
545                WRITE1(dst, 0, fg);
546                WRITE1(dst, 3, fg);
547                break;
548            case 10:
549                WRITE1(dst, 1, fg);
550                WRITE1(dst, 3, fg);
551                break;
552            case 11:
553                WRITE2(dst, 0, fg);
554                WRITE1(dst, 3, fg);
555                break;
556            case 12:
557                WRITE2(dst, 2, fg);
558                break;
559            case 13:
560                WRITE1(dst, 0, fg);
561                WRITE2(dst, 2, fg);
562                break;
563            case 14:
564                WRITE1(dst, 1, fg);
565                WRITE2(dst, 2, fg);
566                break;
567            case 15:
568                WRITE4(dst, 0, fg);
569                break;
570            }
571            bits = FbStipLeft(bits, n);
572            n = 4;
573            dst += 4;
574        }
575        dstLine += dstStride;
576    }
577}
578
579#undef WRITE_ADDR1
580#undef WRITE_ADDR2
581#undef WRITE_ADDR4
582#undef WRITE1
583#undef WRITE2
584#undef WRITE4
585
586#endif
587
588#ifdef POLYLINE
589void
590POLYLINE(DrawablePtr pDrawable,
591         GCPtr pGC, int mode, int npt, DDXPointPtr ptsOrig)
592{
593    INT32 *pts = (INT32 *) ptsOrig;
594    int xoff = pDrawable->x;
595    int yoff = pDrawable->y;
596    unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
597    BoxPtr pBox = RegionExtents(fbGetCompositeClip(pGC));
598
599    FbBits *dst;
600    int dstStride;
601    int dstBpp;
602    int dstXoff, dstYoff;
603
604    UNIT *bits, *bitsBase;
605    FbStride bitsStride;
606    BITS xor = fbGetGCPrivate(pGC)->xor;
607    BITS and = fbGetGCPrivate(pGC)->and;
608    int dashoffset = 0;
609
610    INT32 ul, lr;
611    INT32 pt1, pt2;
612
613    int e, e1, e3, len;
614    int stepmajor, stepminor;
615    int octant;
616
617    if (mode == CoordModePrevious)
618        fbFixCoordModePrevious(npt, ptsOrig);
619
620    fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
621    bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
622    bitsBase =
623        ((UNIT *) dst) + (yoff + dstYoff) * bitsStride + (xoff + dstXoff);
624    ul = coordToInt(pBox->x1 - xoff, pBox->y1 - yoff);
625    lr = coordToInt(pBox->x2 - xoff - 1, pBox->y2 - yoff - 1);
626
627    pt1 = *pts++;
628    npt--;
629    pt2 = *pts++;
630    npt--;
631    for (;;) {
632        if (isClipped(pt1, ul, lr) | isClipped(pt2, ul, lr)) {
633            fbSegment(pDrawable, pGC,
634                      intToX(pt1) + xoff, intToY(pt1) + yoff,
635                      intToX(pt2) + xoff, intToY(pt2) + yoff,
636                      npt == 0 && pGC->capStyle != CapNotLast, &dashoffset);
637            if (!npt) {
638                fbFinishAccess(pDrawable);
639                return;
640            }
641            pt1 = pt2;
642            pt2 = *pts++;
643            npt--;
644        }
645        else {
646            bits = bitsBase + intToY(pt1) * bitsStride + intToX(pt1);
647            for (;;) {
648                CalcLineDeltas(intToX(pt1), intToY(pt1),
649                               intToX(pt2), intToY(pt2),
650                               len, e1, stepmajor, stepminor, 1, bitsStride,
651                               octant);
652                if (len < e1) {
653                    e3 = len;
654                    len = e1;
655                    e1 = e3;
656
657                    e3 = stepminor;
658                    stepminor = stepmajor;
659                    stepmajor = e3;
660                    SetYMajorOctant(octant);
661                }
662                e = -len;
663                e1 <<= 1;
664                e3 = e << 1;
665                FIXUP_ERROR(e, octant, bias);
666                if (and == 0) {
667                    while (len--) {
668                        STORE(bits, xor);
669                        bits += stepmajor;
670                        e += e1;
671                        if (e >= 0) {
672                            bits += stepminor;
673                            e += e3;
674                        }
675                    }
676                }
677                else {
678                    while (len--) {
679                        RROP(bits, and, xor);
680                        bits += stepmajor;
681                        e += e1;
682                        if (e >= 0) {
683                            bits += stepminor;
684                            e += e3;
685                        }
686                    }
687                }
688                if (!npt) {
689                    if (pGC->capStyle != CapNotLast &&
690                        pt2 != *((INT32 *) ptsOrig)) {
691                        RROP(bits, and, xor);
692                    }
693                    fbFinishAccess(pDrawable);
694                    return;
695                }
696                pt1 = pt2;
697                pt2 = *pts++;
698                --npt;
699                if (isClipped(pt2, ul, lr))
700                    break;
701            }
702        }
703    }
704
705    fbFinishAccess(pDrawable);
706}
707#endif
708
709#ifdef POLYSEGMENT
710void
711POLYSEGMENT(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pseg)
712{
713    INT32 *pts = (INT32 *) pseg;
714    int xoff = pDrawable->x;
715    int yoff = pDrawable->y;
716    unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
717    BoxPtr pBox = RegionExtents(fbGetCompositeClip(pGC));
718
719    FbBits *dst;
720    int dstStride;
721    int dstBpp;
722    int dstXoff, dstYoff;
723
724    UNIT *bits, *bitsBase;
725    FbStride bitsStride;
726    FbBits xorBits = fbGetGCPrivate(pGC)->xor;
727    FbBits andBits = fbGetGCPrivate(pGC)->and;
728    BITS xor = xorBits;
729    BITS and = andBits;
730    int dashoffset = 0;
731
732    INT32 ul, lr;
733    INT32 pt1, pt2;
734
735    int e, e1, e3, len;
736    int stepmajor, stepminor;
737    int octant;
738    Bool capNotLast;
739
740    fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
741    bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
742    bitsBase =
743        ((UNIT *) dst) + (yoff + dstYoff) * bitsStride + (xoff + dstXoff);
744    ul = coordToInt(pBox->x1 - xoff, pBox->y1 - yoff);
745    lr = coordToInt(pBox->x2 - xoff - 1, pBox->y2 - yoff - 1);
746
747    capNotLast = pGC->capStyle == CapNotLast;
748
749    while (nseg--) {
750        pt1 = *pts++;
751        pt2 = *pts++;
752        if (isClipped(pt1, ul, lr) | isClipped(pt2, ul, lr)) {
753            fbSegment(pDrawable, pGC,
754                      intToX(pt1) + xoff, intToY(pt1) + yoff,
755                      intToX(pt2) + xoff, intToY(pt2) + yoff,
756                      !capNotLast, &dashoffset);
757        }
758        else {
759            CalcLineDeltas(intToX(pt1), intToY(pt1),
760                           intToX(pt2), intToY(pt2),
761                           len, e1, stepmajor, stepminor, 1, bitsStride,
762                           octant);
763            if (e1 == 0 && len > 3) {
764                int x1, x2;
765                FbBits *dstLine;
766                int dstX, width;
767                FbBits startmask, endmask;
768                int nmiddle;
769
770                if (stepmajor < 0) {
771                    x1 = intToX(pt2);
772                    x2 = intToX(pt1) + 1;
773                    if (capNotLast)
774                        x1++;
775                }
776                else {
777                    x1 = intToX(pt1);
778                    x2 = intToX(pt2);
779                    if (!capNotLast)
780                        x2++;
781                }
782                dstX = (x1 + xoff + dstXoff) * (sizeof(UNIT) * 8);
783                width = (x2 - x1) * (sizeof(UNIT) * 8);
784
785                dstLine = dst + (intToY(pt1) + yoff + dstYoff) * dstStride;
786                dstLine += dstX >> FB_SHIFT;
787                dstX &= FB_MASK;
788                FbMaskBits(dstX, width, startmask, nmiddle, endmask);
789                if (startmask) {
790                    WRITE(dstLine,
791                          FbDoMaskRRop(READ(dstLine), andBits, xorBits,
792                                       startmask));
793                    dstLine++;
794                }
795                if (!andBits)
796                    while (nmiddle--)
797                        WRITE(dstLine++, xorBits);
798                else
799                    while (nmiddle--) {
800                        WRITE(dstLine,
801                              FbDoRRop(READ(dstLine), andBits, xorBits));
802                        dstLine++;
803                    }
804                if (endmask)
805                    WRITE(dstLine,
806                          FbDoMaskRRop(READ(dstLine), andBits, xorBits,
807                                       endmask));
808            }
809            else {
810                bits = bitsBase + intToY(pt1) * bitsStride + intToX(pt1);
811                if (len < e1) {
812                    e3 = len;
813                    len = e1;
814                    e1 = e3;
815
816                    e3 = stepminor;
817                    stepminor = stepmajor;
818                    stepmajor = e3;
819                    SetYMajorOctant(octant);
820                }
821                e = -len;
822                e1 <<= 1;
823                e3 = e << 1;
824                FIXUP_ERROR(e, octant, bias);
825                if (!capNotLast)
826                    len++;
827                if (and == 0) {
828                    while (len--) {
829                        STORE(bits, xor);
830                        bits += stepmajor;
831                        e += e1;
832                        if (e >= 0) {
833                            bits += stepminor;
834                            e += e3;
835                        }
836                    }
837                }
838                else {
839                    while (len--) {
840                        RROP(bits, and, xor);
841                        bits += stepmajor;
842                        e += e1;
843                        if (e >= 0) {
844                            bits += stepminor;
845                            e += e3;
846                        }
847                    }
848                }
849            }
850        }
851    }
852
853    fbFinishAccess(pDrawable);
854}
855#endif
856
857#undef STORE
858#undef RROP
859#undef UNIT
860#undef USE_SOLID
861
862#undef isClipped
863