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
32Bool
33fbGlyphIn (RegionPtr	pRegion,
34	   int		x,
35	   int		y,
36	   int		width,
37	   int		height)
38{
39    BoxRec  box;
40    BoxPtr  pExtents = RegionExtents(pRegion);
41
42    /*
43     * Check extents by hand to avoid 16 bit overflows
44     */
45    if (x < (int) pExtents->x1)
46	return FALSE;
47    if ((int) pExtents->x2 < x + width)
48	return FALSE;
49    if (y < (int) pExtents->y1)
50	return FALSE;
51    if ((int) pExtents->y2 < y + height)
52	return FALSE;
53    box.x1 = x;
54    box.x2 = x + width;
55    box.y1 = y;
56    box.y2 = y + height;
57    return RegionContainsRect(pRegion, &box) == rgnIN;
58}
59
60#ifdef FB_24BIT
61#ifndef FBNOPIXADDR
62
63#define WRITE1(d,n,fg)	WRITE((d) + (n), (CARD8) fg)
64#define WRITE2(d,n,fg)	WRITE((CARD16 *) &(d[n]), (CARD16) fg)
65#define WRITE4(d,n,fg)	WRITE((CARD32 *) &(d[n]), (CARD32) fg)
66#if FB_UNIT == 6 && IMAGE_BYTE_ORDER == LSBFirst
67#define WRITE8(d)	WRITE((FbBits *) &(d[0]), fg)
68#else
69#define WRITE8(d)	WRITE4(d,0,_ABCA), WRITE4(d,4,_BCAB)
70#endif
71
72/*
73 * This is a bit tricky, but it's brief.  Write 12 bytes worth
74 * of dest, which is four pixels, at a time.  This gives constant
75 * code for each pattern as they're always aligned the same
76 *
77 *  a b c d  a b c d  a b c d	bytes
78 *  A B C A  B C A B  C A B C	pixels
79 *
80 *    f0        f1       f2
81 *  A B C A  B C A B  C A B C	pixels LSB
82 *  C A B C  A B C A  B C A B	pixels MSB
83 *
84 *		LSB	MSB
85 *  A		f0	f1
86 *  B		f1	f2
87 *  C		f2	f0
88 *  A B		f0	f2
89 *  B C		f1	f0
90 *  C A		f2	f1
91 *  A B C A	f0	f1
92 *  B C A B	f1    	f2
93 *  C A B C	f2	f0
94 */
95
96#undef _A
97#undef _B
98#undef _C
99#undef _AB
100#undef _BC
101#undef _CA
102#undef _ABCA
103#undef _BCAB
104#undef _CABC
105
106#if IMAGE_BYTE_ORDER == MSBFirst
107#define _A	f1
108#define _B	f2
109#define _C	f0
110#define _AB	f2
111#define _BC	f0
112#define _CA	f1
113#define _ABCA	f1
114#define _BCAB	f2
115#define _CABC	f0
116#define CASE(a,b,c,d)	((a << 3) | (b << 2) | (c << 1) | d)
117#else
118#define _A	f0
119#define _B	f1
120#define _C	f2
121#define _AB	f0
122#define _BC	f1
123#define _CA	f2
124#define _ABCA	f0
125#define _BCAB	f1
126#define _CABC	f2
127#define CASE(a,b,c,d)	(a | (b << 1) | (c << 2) | (d << 3))
128#endif
129
130void
131fbGlyph24 (FbBits   *dstBits,
132	   FbStride dstStride,
133	   int	    dstBpp,
134	   FbStip   *stipple,
135	   FbBits   fg,
136	   int	    x,
137	   int	    height)
138{
139    int	    lshift;
140    FbStip  bits;
141    CARD8   *dstLine;
142    CARD8   *dst;
143    FbStip  f0, f1, f2;
144    int	    n;
145    int	    shift;
146
147    f0 = fg;
148    f1 = FbRot24(f0,16);
149    f2 = FbRot24(f0,8);
150
151    dstLine = (CARD8 *) dstBits;
152    dstLine += (x & ~3) * 3;
153    dstStride *= (sizeof (FbBits) / sizeof (CARD8));
154    shift = x & 3;
155    lshift = 4 - shift;
156    while (height--)
157    {
158	bits = READ(stipple++);
159	n = lshift;
160	dst = dstLine;
161	while (bits)
162	{
163	    switch (FbStipMoveLsb (FbLeftStipBits (bits, n), 4, n)) {
164	    case CASE(0,0,0,0):
165		break;
166	    case CASE(1,0,0,0):
167		WRITE2(dst,0,_AB);
168		WRITE1(dst,2,_C);
169		break;
170	    case CASE(0,1,0,0):
171		WRITE1(dst,3,_A);
172		WRITE2(dst,4,_BC);
173		break;
174	    case CASE(1,1,0,0):
175		WRITE4(dst,0,_ABCA);
176		WRITE2(dst,4,_BC);
177		break;
178	    case CASE(0,0,1,0):
179		WRITE2(dst,6,_AB);
180		WRITE1(dst,8,_C);
181		break;
182	    case CASE(1,0,1,0):
183		WRITE2(dst,0,_AB);
184		WRITE1(dst,2,_C);
185
186		WRITE2(dst,6,_AB);
187		WRITE1(dst,8,_C);
188		break;
189	    case CASE(0,1,1,0):
190		WRITE1(dst,3,_A);
191		WRITE4(dst,4,_BCAB);
192		WRITE1(dst,8,_C);
193		break;
194	    case CASE(1,1,1,0):
195		WRITE8(dst);
196		WRITE1(dst,8,_C);
197		break;
198	    case CASE(0,0,0,1):
199		WRITE1(dst,9,_A);
200		WRITE2(dst,10,_BC);
201		break;
202	    case CASE(1,0,0,1):
203		WRITE2(dst,0,_AB);
204		WRITE1(dst,2,_C);
205
206		WRITE1(dst,9,_A);
207		WRITE2(dst,10,_BC);
208		break;
209	    case CASE(0,1,0,1):
210		WRITE1(dst,3,_A);
211		WRITE2(dst,4,_BC);
212
213		WRITE1(dst,9,_A);
214		WRITE2(dst,10,_BC);
215		break;
216	    case CASE(1,1,0,1):
217		WRITE4(dst,0,_ABCA);
218		WRITE2(dst,4,_BC);
219
220		WRITE1(dst,9,_A);
221		WRITE2(dst,10,_BC);
222		break;
223	    case CASE(0,0,1,1):
224		WRITE2(dst,6,_AB);
225		WRITE4(dst,8,_CABC);
226		break;
227	    case CASE(1,0,1,1):
228		WRITE2(dst,0,_AB);
229		WRITE1(dst,2,_C);
230
231		WRITE2(dst,6,_AB);
232		WRITE4(dst,8,_CABC);
233		break;
234	    case CASE(0,1,1,1):
235		WRITE1(dst,3,_A);
236		WRITE4(dst,4,_BCAB);
237		WRITE4(dst,8,_CABC);
238		break;
239	    case CASE(1,1,1,1):
240		WRITE8(dst);
241		WRITE4(dst,8,_CABC);
242		break;
243	    }
244	    bits = FbStipLeft (bits, n);
245	    n = 4;
246	    dst += 12;
247	}
248	dstLine += dstStride;
249    }
250}
251#endif
252#endif
253
254void
255fbPolyGlyphBlt (DrawablePtr	pDrawable,
256		GCPtr		pGC,
257		int		x,
258		int		y,
259		unsigned int	nglyph,
260		CharInfoPtr	*ppci,
261		pointer		pglyphBase)
262{
263    FbGCPrivPtr	    pPriv = fbGetGCPrivate (pGC);
264    CharInfoPtr	    pci;
265    unsigned char   *pglyph;		/* pointer bits in glyph */
266    int		    gx, gy;
267    int		    gWidth, gHeight;	/* width and height of glyph */
268    FbStride	    gStride;		/* stride of glyph */
269#ifndef FBNOPIXADDR
270    void	    (*glyph) (FbBits *,
271			      FbStride,
272			      int,
273			      FbStip *,
274			      FbBits,
275			      int,
276			      int);
277    FbBits	    *dst = 0;
278    FbStride	    dstStride = 0;
279    int		    dstBpp = 0;
280    int		    dstXoff = 0, dstYoff = 0;
281
282    glyph = 0;
283    if (pGC->fillStyle == FillSolid && pPriv->and == 0)
284    {
285	dstBpp = pDrawable->bitsPerPixel;
286	switch (dstBpp) {
287	case 8:	    glyph = fbGlyph8; break;
288	case 16:    glyph = fbGlyph16; break;
289#ifdef FB_24BIT
290	case 24:    glyph = fbGlyph24; break;
291#endif
292	case 32:    glyph = fbGlyph32; break;
293	}
294    }
295#endif
296    x += pDrawable->x;
297    y += pDrawable->y;
298
299    while (nglyph--)
300    {
301	pci = *ppci++;
302	pglyph = FONTGLYPHBITS(pglyphBase, pci);
303	gWidth = GLYPHWIDTHPIXELS(pci);
304	gHeight = GLYPHHEIGHTPIXELS(pci);
305	if (gWidth && gHeight)
306	{
307	    gx = x + pci->metrics.leftSideBearing;
308	    gy = y - pci->metrics.ascent;
309#ifndef FBNOPIXADDR
310	    if (glyph && gWidth <= sizeof (FbStip) * 8 &&
311		fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
312	    {
313		fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
314		(*glyph) (dst + (gy + dstYoff) * dstStride,
315			  dstStride,
316			  dstBpp,
317			  (FbStip *) pglyph,
318			  pPriv->xor,
319			  gx + dstXoff,
320			  gHeight);
321		fbFinishAccess (pDrawable);
322	    }
323	    else
324#endif
325	    {
326		gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
327		fbPushImage (pDrawable,
328			     pGC,
329
330			     (FbStip *) pglyph,
331			     gStride,
332			     0,
333
334			     gx,
335			     gy,
336			     gWidth, gHeight);
337	    }
338	}
339	x += pci->metrics.characterWidth;
340    }
341}
342
343
344void
345fbImageGlyphBlt (DrawablePtr	pDrawable,
346		 GCPtr		pGC,
347		 int		x,
348		 int		y,
349		 unsigned int	nglyph,
350		 CharInfoPtr	*ppciInit,
351		 pointer	pglyphBase)
352{
353    FbGCPrivPtr	    pPriv = fbGetGCPrivate(pGC);
354    CharInfoPtr	    *ppci;
355    CharInfoPtr	    pci;
356    unsigned char   *pglyph;		/* pointer bits in glyph */
357    int		    gWidth, gHeight;	/* width and height of glyph */
358    FbStride	    gStride;		/* stride of glyph */
359    Bool	    opaque;
360    int		    n;
361    int		    gx, gy;
362#ifndef FBNOPIXADDR
363    void	    (*glyph) (FbBits *,
364			      FbStride,
365			      int,
366			      FbStip *,
367			      FbBits,
368			      int,
369			      int);
370    FbBits	    *dst = 0;
371    FbStride	    dstStride = 0;
372    int		    dstBpp = 0;
373    int		    dstXoff = 0, dstYoff = 0;
374
375    glyph = 0;
376    if (pPriv->and == 0)
377    {
378	dstBpp = pDrawable->bitsPerPixel;
379	switch (dstBpp) {
380	case 8:	    glyph = fbGlyph8; break;
381	case 16:    glyph = fbGlyph16; break;
382#ifdef FB_24BIT
383	case 24:    glyph = fbGlyph24; break;
384#endif
385	case 32:    glyph = fbGlyph32; break;
386	}
387    }
388#endif
389
390    x += pDrawable->x;
391    y += pDrawable->y;
392
393    if (TERMINALFONT (pGC->font)
394#ifndef FBNOPIXADDR
395	&& !glyph
396#endif
397	)
398    {
399	opaque = TRUE;
400    }
401    else
402    {
403	int		xBack, widthBack;
404	int		yBack, heightBack;
405
406	ppci = ppciInit;
407	n = nglyph;
408	widthBack = 0;
409	while (n--)
410	    widthBack += (*ppci++)->metrics.characterWidth;
411
412        xBack = x;
413	if (widthBack < 0)
414	{
415	    xBack += widthBack;
416	    widthBack = -widthBack;
417	}
418	yBack = y - FONTASCENT(pGC->font);
419	heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
420	fbSolidBoxClipped (pDrawable,
421			   fbGetCompositeClip(pGC),
422			   xBack,
423			   yBack,
424			   xBack + widthBack,
425			   yBack + heightBack,
426			   fbAnd(GXcopy,pPriv->bg,pPriv->pm),
427			   fbXor(GXcopy,pPriv->bg,pPriv->pm));
428	opaque = FALSE;
429    }
430
431    ppci = ppciInit;
432    while (nglyph--)
433    {
434	pci = *ppci++;
435	pglyph = FONTGLYPHBITS(pglyphBase, pci);
436	gWidth = GLYPHWIDTHPIXELS(pci);
437	gHeight = GLYPHHEIGHTPIXELS(pci);
438	if (gWidth && gHeight)
439	{
440	    gx = x + pci->metrics.leftSideBearing;
441	    gy = y - pci->metrics.ascent;
442#ifndef FBNOPIXADDR
443	    if (glyph && gWidth <= sizeof (FbStip) * 8 &&
444		fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
445	    {
446		fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
447		(*glyph) (dst + (gy + dstYoff) * dstStride,
448			  dstStride,
449			  dstBpp,
450			  (FbStip *) pglyph,
451			  pPriv->fg,
452			  gx + dstXoff,
453			  gHeight);
454		fbFinishAccess (pDrawable);
455	    }
456	    else
457#endif
458	    {
459		gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
460		fbPutXYImage (pDrawable,
461			      fbGetCompositeClip(pGC),
462			      pPriv->fg,
463			      pPriv->bg,
464			      pPriv->pm,
465			      GXcopy,
466			      opaque,
467
468			      gx,
469			      gy,
470			      gWidth, gHeight,
471
472			      (FbStip *) pglyph,
473			      gStride,
474			      0);
475	    }
476	}
477	x += pci->metrics.characterWidth;
478    }
479}
480