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