fbglyph.c revision 35c4bbdf
17ec681f3Smrg/*
27ec681f3Smrg *
37ec681f3Smrg * Copyright © 1998 Keith Packard
47ec681f3Smrg *
57ec681f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its
67ec681f3Smrg * documentation for any purpose is hereby granted without fee, provided that
77ec681f3Smrg * the above copyright notice appear in all copies and that both that
87ec681f3Smrg * copyright notice and this permission notice appear in supporting
97ec681f3Smrg * documentation, and that the name of Keith Packard not be used in
107ec681f3Smrg * advertising or publicity pertaining to distribution of the software without
117ec681f3Smrg * specific, written prior permission.  Keith Packard makes no
127ec681f3Smrg * representations about the suitability of this software for any purpose.  It
137ec681f3Smrg * is provided "as is" without express or implied warranty.
147ec681f3Smrg *
157ec681f3Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
167ec681f3Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
177ec681f3Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
187ec681f3Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
197ec681f3Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
207ec681f3Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
217ec681f3Smrg * PERFORMANCE OF THIS SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg#ifdef HAVE_DIX_CONFIG_H
257ec681f3Smrg#include <dix-config.h>
267ec681f3Smrg#endif
277ec681f3Smrg
287ec681f3Smrg#include "fb.h"
297ec681f3Smrg#include	<X11/fonts/fontstruct.h>
307ec681f3Smrg#include	"dixfontstr.h"
317ec681f3Smrg
327ec681f3Smrgstatic Bool
337ec681f3SmrgfbGlyphIn(RegionPtr pRegion, int x, int y, int width, int height)
347ec681f3Smrg{
357ec681f3Smrg    BoxRec box;
367ec681f3Smrg    BoxPtr pExtents = RegionExtents(pRegion);
377ec681f3Smrg
387ec681f3Smrg    /*
397ec681f3Smrg     * Check extents by hand to avoid 16 bit overflows
407ec681f3Smrg     */
417ec681f3Smrg    if (x < (int) pExtents->x1)
427ec681f3Smrg        return FALSE;
437ec681f3Smrg    if ((int) pExtents->x2 < x + width)
447ec681f3Smrg        return FALSE;
457ec681f3Smrg    if (y < (int) pExtents->y1)
467ec681f3Smrg        return FALSE;
477ec681f3Smrg    if ((int) pExtents->y2 < y + height)
487ec681f3Smrg        return FALSE;
497ec681f3Smrg    box.x1 = x;
507ec681f3Smrg    box.x2 = x + width;
517ec681f3Smrg    box.y1 = y;
527ec681f3Smrg    box.y2 = y + height;
537ec681f3Smrg    return RegionContainsRect(pRegion, &box) == rgnIN;
547ec681f3Smrg}
557ec681f3Smrg
567ec681f3Smrg#define WRITE1(d,n,fg)	WRITE((d) + (n), (CARD8) fg)
577ec681f3Smrg#define WRITE2(d,n,fg)	WRITE((CARD16 *) &(d[n]), (CARD16) fg)
587ec681f3Smrg#define WRITE4(d,n,fg)	WRITE((CARD32 *) &(d[n]), (CARD32) fg)
597ec681f3Smrg#define WRITE8(d)	WRITE4(d,0,_ABCA), WRITE4(d,4,_BCAB)
607ec681f3Smrg
617ec681f3Smrg/*
627ec681f3Smrg * This is a bit tricky, but it's brief.  Write 12 bytes worth
637ec681f3Smrg * of dest, which is four pixels, at a time.  This gives constant
647ec681f3Smrg * code for each pattern as they're always aligned the same
657ec681f3Smrg *
667ec681f3Smrg *  a b c d  a b c d  a b c d	bytes
677ec681f3Smrg *  A B C A  B C A B  C A B C	pixels
687ec681f3Smrg *
697ec681f3Smrg *    f0        f1       f2
707ec681f3Smrg *  A B C A  B C A B  C A B C	pixels LSB
717ec681f3Smrg *  C A B C  A B C A  B C A B	pixels MSB
727ec681f3Smrg *
737ec681f3Smrg *		LSB	MSB
747ec681f3Smrg *  A		f0	f1
757ec681f3Smrg *  B		f1	f2
767ec681f3Smrg *  C		f2	f0
777ec681f3Smrg *  A B		f0	f2
787ec681f3Smrg *  B C		f1	f0
797ec681f3Smrg *  C A		f2	f1
807ec681f3Smrg *  A B C A	f0	f1
817ec681f3Smrg *  B C A B	f1    	f2
827ec681f3Smrg *  C A B C	f2	f0
837ec681f3Smrg */
847ec681f3Smrg
857ec681f3Smrg#undef _A
867ec681f3Smrg#undef _B
877ec681f3Smrg#undef _C
887ec681f3Smrg#undef _AB
897ec681f3Smrg#undef _BC
907ec681f3Smrg#undef _CA
917ec681f3Smrg#undef _ABCA
927ec681f3Smrg#undef _BCAB
937ec681f3Smrg#undef _CABC
947ec681f3Smrg
957ec681f3Smrg#if IMAGE_BYTE_ORDER == MSBFirst
967ec681f3Smrg#define _A	f1
977ec681f3Smrg#define _B	f2
987ec681f3Smrg#define _C	f0
997ec681f3Smrg#define _AB	f2
1007ec681f3Smrg#define _BC	f0
1017ec681f3Smrg#define _CA	f1
1027ec681f3Smrg#define _ABCA	f1
1037ec681f3Smrg#define _BCAB	f2
1047ec681f3Smrg#define _CABC	f0
1057ec681f3Smrg#define CASE(a,b,c,d)	((a << 3) | (b << 2) | (c << 1) | d)
1067ec681f3Smrg#else
1077ec681f3Smrg#define _A	f0
1087ec681f3Smrg#define _B	f1
1097ec681f3Smrg#define _C	f2
1107ec681f3Smrg#define _AB	f0
1117ec681f3Smrg#define _BC	f1
1127ec681f3Smrg#define _CA	f2
1137ec681f3Smrg#define _ABCA	f0
1147ec681f3Smrg#define _BCAB	f1
1157ec681f3Smrg#define _CABC	f2
1167ec681f3Smrg#define CASE(a,b,c,d)	(a | (b << 1) | (c << 2) | (d << 3))
1177ec681f3Smrg#endif
1187ec681f3Smrg
1197ec681f3Smrgstatic void
1207ec681f3SmrgfbGlyph24(FbBits * dstBits,
1217ec681f3Smrg          FbStride dstStride,
1227ec681f3Smrg          int dstBpp, FbStip * stipple, FbBits fg, int x, int height)
1237ec681f3Smrg{
1247ec681f3Smrg    int lshift;
1257ec681f3Smrg    FbStip bits;
1267ec681f3Smrg    CARD8 *dstLine;
1277ec681f3Smrg    CARD8 *dst;
1287ec681f3Smrg    FbStip f0, f1, f2;
1297ec681f3Smrg    int n;
1307ec681f3Smrg    int shift;
1317ec681f3Smrg
1327ec681f3Smrg    f0 = fg;
1337ec681f3Smrg    f1 = FbRot24(f0, 16);
1347ec681f3Smrg    f2 = FbRot24(f0, 8);
1357ec681f3Smrg
1367ec681f3Smrg    dstLine = (CARD8 *) dstBits;
1377ec681f3Smrg    dstLine += (x & ~3) * 3;
1387ec681f3Smrg    dstStride *= (sizeof(FbBits) / sizeof(CARD8));
1397ec681f3Smrg    shift = x & 3;
1407ec681f3Smrg    lshift = 4 - shift;
1417ec681f3Smrg    while (height--) {
1427ec681f3Smrg        bits = READ(stipple++);
1437ec681f3Smrg        n = lshift;
1447ec681f3Smrg        dst = dstLine;
1457ec681f3Smrg        while (bits) {
1467ec681f3Smrg            switch (FbStipMoveLsb(FbLeftStipBits(bits, n), 4, n)) {
1477ec681f3Smrg            case CASE(0, 0, 0, 0):
1487ec681f3Smrg                break;
1497ec681f3Smrg            case CASE(1, 0, 0, 0):
1507ec681f3Smrg                WRITE2(dst, 0, _AB);
1517ec681f3Smrg                WRITE1(dst, 2, _C);
1527ec681f3Smrg                break;
1537ec681f3Smrg            case CASE(0, 1, 0, 0):
1547ec681f3Smrg                WRITE1(dst, 3, _A);
1557ec681f3Smrg                WRITE2(dst, 4, _BC);
1567ec681f3Smrg                break;
1577ec681f3Smrg            case CASE(1, 1, 0, 0):
1587ec681f3Smrg                WRITE4(dst, 0, _ABCA);
1597ec681f3Smrg                WRITE2(dst, 4, _BC);
1607ec681f3Smrg                break;
1617ec681f3Smrg            case CASE(0, 0, 1, 0):
1627ec681f3Smrg                WRITE2(dst, 6, _AB);
1637ec681f3Smrg                WRITE1(dst, 8, _C);
1647ec681f3Smrg                break;
1657ec681f3Smrg            case CASE(1, 0, 1, 0):
1667ec681f3Smrg                WRITE2(dst, 0, _AB);
1677ec681f3Smrg                WRITE1(dst, 2, _C);
1687ec681f3Smrg
1697ec681f3Smrg                WRITE2(dst, 6, _AB);
1707ec681f3Smrg                WRITE1(dst, 8, _C);
1717ec681f3Smrg                break;
1727ec681f3Smrg            case CASE(0, 1, 1, 0):
1737ec681f3Smrg                WRITE1(dst, 3, _A);
1747ec681f3Smrg                WRITE4(dst, 4, _BCAB);
1757ec681f3Smrg                WRITE1(dst, 8, _C);
1767ec681f3Smrg                break;
1777ec681f3Smrg            case CASE(1, 1, 1, 0):
1787ec681f3Smrg                WRITE8(dst);
1797ec681f3Smrg                WRITE1(dst, 8, _C);
1807ec681f3Smrg                break;
1817ec681f3Smrg            case CASE(0, 0, 0, 1):
1827ec681f3Smrg                WRITE1(dst, 9, _A);
1837ec681f3Smrg                WRITE2(dst, 10, _BC);
1847ec681f3Smrg                break;
1857ec681f3Smrg            case CASE(1, 0, 0, 1):
1867ec681f3Smrg                WRITE2(dst, 0, _AB);
1877ec681f3Smrg                WRITE1(dst, 2, _C);
1887ec681f3Smrg
1897ec681f3Smrg                WRITE1(dst, 9, _A);
1907ec681f3Smrg                WRITE2(dst, 10, _BC);
1917ec681f3Smrg                break;
1927ec681f3Smrg            case CASE(0, 1, 0, 1):
1937ec681f3Smrg                WRITE1(dst, 3, _A);
1947ec681f3Smrg                WRITE2(dst, 4, _BC);
1957ec681f3Smrg
1967ec681f3Smrg                WRITE1(dst, 9, _A);
1977ec681f3Smrg                WRITE2(dst, 10, _BC);
1987ec681f3Smrg                break;
1997ec681f3Smrg            case CASE(1, 1, 0, 1):
2007ec681f3Smrg                WRITE4(dst, 0, _ABCA);
2017ec681f3Smrg                WRITE2(dst, 4, _BC);
2027ec681f3Smrg
2037ec681f3Smrg                WRITE1(dst, 9, _A);
2047ec681f3Smrg                WRITE2(dst, 10, _BC);
2057ec681f3Smrg                break;
2067ec681f3Smrg            case CASE(0, 0, 1, 1):
2077ec681f3Smrg                WRITE2(dst, 6, _AB);
2087ec681f3Smrg                WRITE4(dst, 8, _CABC);
2097ec681f3Smrg                break;
2107ec681f3Smrg            case CASE(1, 0, 1, 1):
2117ec681f3Smrg                WRITE2(dst, 0, _AB);
2127ec681f3Smrg                WRITE1(dst, 2, _C);
2137ec681f3Smrg
2147ec681f3Smrg                WRITE2(dst, 6, _AB);
215                WRITE4(dst, 8, _CABC);
216                break;
217            case CASE(0, 1, 1, 1):
218                WRITE1(dst, 3, _A);
219                WRITE4(dst, 4, _BCAB);
220                WRITE4(dst, 8, _CABC);
221                break;
222            case CASE(1, 1, 1, 1):
223                WRITE8(dst);
224                WRITE4(dst, 8, _CABC);
225                break;
226            }
227            bits = FbStipLeft(bits, n);
228            n = 4;
229            dst += 12;
230        }
231        dstLine += dstStride;
232    }
233}
234
235void
236fbPolyGlyphBlt(DrawablePtr pDrawable,
237               GCPtr pGC,
238               int x,
239               int y,
240               unsigned int nglyph, CharInfoPtr * ppci, void *pglyphBase)
241{
242    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
243    CharInfoPtr pci;
244    unsigned char *pglyph;      /* pointer bits in glyph */
245    int gx, gy;
246    int gWidth, gHeight;        /* width and height of glyph */
247    FbStride gStride;           /* stride of glyph */
248    void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int);
249    FbBits *dst = 0;
250    FbStride dstStride = 0;
251    int dstBpp = 0;
252    int dstXoff = 0, dstYoff = 0;
253
254    glyph = 0;
255    if (pGC->fillStyle == FillSolid && pPriv->and == 0) {
256        dstBpp = pDrawable->bitsPerPixel;
257        switch (dstBpp) {
258        case 8:
259            glyph = fbGlyph8;
260            break;
261        case 16:
262            glyph = fbGlyph16;
263            break;
264        case 24:
265            glyph = fbGlyph24;
266            break;
267        case 32:
268            glyph = fbGlyph32;
269            break;
270        }
271    }
272    x += pDrawable->x;
273    y += pDrawable->y;
274
275    while (nglyph--) {
276        pci = *ppci++;
277        pglyph = FONTGLYPHBITS(pglyphBase, pci);
278        gWidth = GLYPHWIDTHPIXELS(pci);
279        gHeight = GLYPHHEIGHTPIXELS(pci);
280        if (gWidth && gHeight) {
281            gx = x + pci->metrics.leftSideBearing;
282            gy = y - pci->metrics.ascent;
283            if (glyph && gWidth <= sizeof(FbStip) * 8 &&
284                fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) {
285                fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff,
286                              dstYoff);
287                (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
288                          (FbStip *) pglyph, pPriv->xor, gx + dstXoff, gHeight);
289                fbFinishAccess(pDrawable);
290            }
291            else {
292                gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
293                fbPushImage(pDrawable,
294                            pGC,
295                            (FbStip *) pglyph,
296                            gStride, 0, gx, gy, gWidth, gHeight);
297            }
298        }
299        x += pci->metrics.characterWidth;
300    }
301}
302
303void
304fbImageGlyphBlt(DrawablePtr pDrawable,
305                GCPtr pGC,
306                int x,
307                int y,
308                unsigned int nglyph, CharInfoPtr * ppciInit, void *pglyphBase)
309{
310    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
311    CharInfoPtr *ppci;
312    CharInfoPtr pci;
313    unsigned char *pglyph;      /* pointer bits in glyph */
314    int gWidth, gHeight;        /* width and height of glyph */
315    FbStride gStride;           /* stride of glyph */
316    Bool opaque;
317    int n;
318    int gx, gy;
319    void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int);
320    FbBits *dst = 0;
321    FbStride dstStride = 0;
322    int dstBpp = 0;
323    int dstXoff = 0, dstYoff = 0;
324
325    glyph = 0;
326    if (pPriv->and == 0) {
327        dstBpp = pDrawable->bitsPerPixel;
328        switch (dstBpp) {
329        case 8:
330            glyph = fbGlyph8;
331            break;
332        case 16:
333            glyph = fbGlyph16;
334            break;
335        case 24:
336            glyph = fbGlyph24;
337            break;
338        case 32:
339            glyph = fbGlyph32;
340            break;
341        }
342    }
343
344    x += pDrawable->x;
345    y += pDrawable->y;
346
347    if (TERMINALFONT(pGC->font)
348        && !glyph) {
349        opaque = TRUE;
350    }
351    else {
352        int xBack, widthBack;
353        int yBack, heightBack;
354
355        ppci = ppciInit;
356        n = nglyph;
357        widthBack = 0;
358        while (n--)
359            widthBack += (*ppci++)->metrics.characterWidth;
360
361        xBack = x;
362        if (widthBack < 0) {
363            xBack += widthBack;
364            widthBack = -widthBack;
365        }
366        yBack = y - FONTASCENT(pGC->font);
367        heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
368        fbSolidBoxClipped(pDrawable,
369                          fbGetCompositeClip(pGC),
370                          xBack,
371                          yBack,
372                          xBack + widthBack,
373                          yBack + heightBack,
374                          fbAnd(GXcopy, pPriv->bg, pPriv->pm),
375                          fbXor(GXcopy, pPriv->bg, pPriv->pm));
376        opaque = FALSE;
377    }
378
379    ppci = ppciInit;
380    while (nglyph--) {
381        pci = *ppci++;
382        pglyph = FONTGLYPHBITS(pglyphBase, pci);
383        gWidth = GLYPHWIDTHPIXELS(pci);
384        gHeight = GLYPHHEIGHTPIXELS(pci);
385        if (gWidth && gHeight) {
386            gx = x + pci->metrics.leftSideBearing;
387            gy = y - pci->metrics.ascent;
388            if (glyph && gWidth <= sizeof(FbStip) * 8 &&
389                fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) {
390                fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff,
391                              dstYoff);
392                (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
393                          (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight);
394                fbFinishAccess(pDrawable);
395            }
396            else {
397                gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
398                fbPutXYImage(pDrawable,
399                             fbGetCompositeClip(pGC),
400                             pPriv->fg,
401                             pPriv->bg,
402                             pPriv->pm,
403                             GXcopy,
404                             opaque,
405                             gx,
406                             gy,
407                             gWidth, gHeight, (FbStip *) pglyph, gStride, 0);
408            }
409        }
410        x += pci->metrics.characterWidth;
411    }
412}
413