1/*
2 *
3 * Copyright © 1998 Keith Packard
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#ifdef HAVE_DIX_CONFIG_H
25#include <dix-config.h>
26#endif
27
28#include "fb.h"
29#include	<X11/fonts/fontstruct.h>
30#include	"dixfontstr.h"
31
32static Bool
33fbGlyphIn(RegionPtr pRegion, int x, int y, int width, int height)
34{
35    BoxRec box;
36    BoxPtr pExtents = RegionExtents(pRegion);
37
38    /*
39     * Check extents by hand to avoid 16 bit overflows
40     */
41    if (x < (int) pExtents->x1)
42        return FALSE;
43    if ((int) pExtents->x2 < x + width)
44        return FALSE;
45    if (y < (int) pExtents->y1)
46        return FALSE;
47    if ((int) pExtents->y2 < y + height)
48        return FALSE;
49    box.x1 = x;
50    box.x2 = x + width;
51    box.y1 = y;
52    box.y2 = y + height;
53    return RegionContainsRect(pRegion, &box) == rgnIN;
54}
55
56void
57fbPolyGlyphBlt(DrawablePtr pDrawable,
58               GCPtr pGC,
59               int x,
60               int y,
61               unsigned int nglyph, CharInfoPtr * ppci, void *pglyphBase)
62{
63    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
64    CharInfoPtr pci;
65    unsigned char *pglyph;      /* pointer bits in glyph */
66    int gx, gy;
67    int gWidth, gHeight;        /* width and height of glyph */
68    FbStride gStride;           /* stride of glyph */
69    void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int);
70    FbBits *dst = 0;
71    FbStride dstStride = 0;
72    int dstBpp = 0;
73    int dstXoff = 0, dstYoff = 0;
74
75    glyph = 0;
76    if (pGC->fillStyle == FillSolid && pPriv->and == 0) {
77        dstBpp = pDrawable->bitsPerPixel;
78        switch (dstBpp) {
79        case 8:
80            glyph = fbGlyph8;
81            break;
82        case 16:
83            glyph = fbGlyph16;
84            break;
85        case 32:
86            glyph = fbGlyph32;
87            break;
88        }
89    }
90    x += pDrawable->x;
91    y += pDrawable->y;
92
93    while (nglyph--) {
94        pci = *ppci++;
95        pglyph = FONTGLYPHBITS(pglyphBase, pci);
96        gWidth = GLYPHWIDTHPIXELS(pci);
97        gHeight = GLYPHHEIGHTPIXELS(pci);
98        if (gWidth && gHeight) {
99            gx = x + pci->metrics.leftSideBearing;
100            gy = y - pci->metrics.ascent;
101            if (glyph && gWidth <= sizeof(FbStip) * 8 &&
102                fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) {
103                fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff,
104                              dstYoff);
105                (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
106                          (FbStip *) pglyph, pPriv->xor, gx + dstXoff, gHeight);
107                fbFinishAccess(pDrawable);
108            }
109            else {
110                gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
111                fbPushImage(pDrawable,
112                            pGC,
113                            (FbStip *) pglyph,
114                            gStride, 0, gx, gy, gWidth, gHeight);
115            }
116        }
117        x += pci->metrics.characterWidth;
118    }
119}
120
121void
122fbImageGlyphBlt(DrawablePtr pDrawable,
123                GCPtr pGC,
124                int x,
125                int y,
126                unsigned int nglyph, CharInfoPtr * ppciInit, void *pglyphBase)
127{
128    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
129    CharInfoPtr *ppci;
130    CharInfoPtr pci;
131    unsigned char *pglyph;      /* pointer bits in glyph */
132    int gWidth, gHeight;        /* width and height of glyph */
133    FbStride gStride;           /* stride of glyph */
134    Bool opaque;
135    int n;
136    int gx, gy;
137    void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int);
138    FbBits *dst = 0;
139    FbStride dstStride = 0;
140    int dstBpp = 0;
141    int dstXoff = 0, dstYoff = 0;
142
143    glyph = 0;
144    if (pPriv->and == 0) {
145        dstBpp = pDrawable->bitsPerPixel;
146        switch (dstBpp) {
147        case 8:
148            glyph = fbGlyph8;
149            break;
150        case 16:
151            glyph = fbGlyph16;
152            break;
153        case 32:
154            glyph = fbGlyph32;
155            break;
156        }
157    }
158
159    x += pDrawable->x;
160    y += pDrawable->y;
161
162    if (TERMINALFONT(pGC->font)
163        && !glyph) {
164        opaque = TRUE;
165    }
166    else {
167        int xBack, widthBack;
168        int yBack, heightBack;
169
170        ppci = ppciInit;
171        n = nglyph;
172        widthBack = 0;
173        while (n--)
174            widthBack += (*ppci++)->metrics.characterWidth;
175
176        xBack = x;
177        if (widthBack < 0) {
178            xBack += widthBack;
179            widthBack = -widthBack;
180        }
181        yBack = y - FONTASCENT(pGC->font);
182        heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
183        fbSolidBoxClipped(pDrawable,
184                          fbGetCompositeClip(pGC),
185                          xBack,
186                          yBack,
187                          xBack + widthBack,
188                          yBack + heightBack,
189                          fbAnd(GXcopy, pPriv->bg, pPriv->pm),
190                          fbXor(GXcopy, pPriv->bg, pPriv->pm));
191        opaque = FALSE;
192    }
193
194    ppci = ppciInit;
195    while (nglyph--) {
196        pci = *ppci++;
197        pglyph = FONTGLYPHBITS(pglyphBase, pci);
198        gWidth = GLYPHWIDTHPIXELS(pci);
199        gHeight = GLYPHHEIGHTPIXELS(pci);
200        if (gWidth && gHeight) {
201            gx = x + pci->metrics.leftSideBearing;
202            gy = y - pci->metrics.ascent;
203            if (glyph && gWidth <= sizeof(FbStip) * 8 &&
204                fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) {
205                fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff,
206                              dstYoff);
207                (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
208                          (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight);
209                fbFinishAccess(pDrawable);
210            }
211            else {
212                gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
213                fbPutXYImage(pDrawable,
214                             fbGetCompositeClip(pGC),
215                             pPriv->fg,
216                             pPriv->bg,
217                             pPriv->pm,
218                             GXcopy,
219                             opaque,
220                             gx,
221                             gy,
222                             gWidth, gHeight, (FbStip *) pglyph, gStride, 0);
223            }
224        }
225        x += pci->metrics.characterWidth;
226    }
227}
228