xftcore.c revision 0d590c07
1/*
2 * Copyright © 2000 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#include "xftint.h"
24
25_X_HIDDEN void
26XftRectCore (XftDraw		*draw,
27	     _Xconst XftColor	*color,
28	     int		x,
29	     int		y,
30	     unsigned int	width,
31	     unsigned int	height)
32{
33    if (color->color.alpha >= 0x8000)
34    {
35	XSetForeground (draw->dpy, draw->core.gc, color->pixel);
36	XFillRectangle (draw->dpy, draw->drawable, draw->core.gc,
37			x, y, width, height);
38    }
39}
40
41/*
42 * Use the core protocol to draw the glyphs
43 */
44
45static void
46_XftSharpGlyphMono (XftDraw	*draw,
47		    XftGlyph	*glyph,
48		    int		x,
49		    int		y)
50{
51    unsigned char   *srcLine = glyph->bitmap, *src;
52    unsigned char   bits, bitsMask;
53    int		    width = glyph->metrics.width;
54    int		    stride = ((width + 31) & ~31) >> 3;
55    int		    height = glyph->metrics.height;
56    int		    w;
57    int		    xspan, lenspan;
58
59    x -= glyph->metrics.x;
60    y -= glyph->metrics.y;
61    while (height--)
62    {
63	src = srcLine;
64	srcLine += stride;
65	w = width;
66
67	bitsMask = 0x80;    /* FreeType is always MSB first */
68	bits = *src++;
69
70	xspan = x;
71	while (w)
72	{
73	    if (bits & bitsMask)
74	    {
75		lenspan = 0;
76		do
77		{
78		    lenspan++;
79		    if (lenspan == w)
80			break;
81		    bitsMask = bitsMask >> 1;
82		    if (!bitsMask)
83		    {
84			bits = *src++;
85			bitsMask = 0x80;
86		    }
87		} while (bits & bitsMask);
88		XFillRectangle (draw->dpy, draw->drawable,
89				draw->core.gc, xspan, y, lenspan, 1);
90		xspan += lenspan;
91		w -= lenspan;
92	    }
93	    else
94	    {
95		do
96		{
97		    w--;
98		    xspan++;
99		    if (!w)
100			break;
101		    bitsMask = bitsMask >> 1;
102		    if (!bitsMask)
103		    {
104			bits = *src++;
105			bitsMask = 0x80;
106		    }
107		} while (!(bits & bitsMask));
108	    }
109	}
110	y++;
111    }
112}
113
114/*
115 * Draw solid color text from an anti-aliased bitmap.  This is a
116 * fallback for cases where a particular drawable has no AA code
117 */
118static void
119_XftSharpGlyphGray (XftDraw	*draw,
120		    XftGlyph	*glyph,
121		    int		x,
122		    int		y)
123{
124    unsigned char   *srcLine = glyph->bitmap, *src, bits;
125    int		    width = glyph->metrics.width;
126    int		    stride = ((width + 3) & ~3);
127    int		    height = glyph->metrics.height;
128    int		    w;
129    int		    xspan, lenspan;
130
131    x -= glyph->metrics.x;
132    y -= glyph->metrics.y;
133    while (height--)
134    {
135	src = srcLine;
136	srcLine += stride;
137	w = width;
138
139	bits = *src++;
140	xspan = x;
141	while (w)
142	{
143	    if (bits >= 0x80)
144	    {
145		lenspan = 0;
146		do
147		{
148		    lenspan++;
149		    if (lenspan == w)
150			break;
151		    bits = *src++;
152		} while (bits >= 0x80);
153		XFillRectangle (draw->dpy, draw->drawable,
154				draw->core.gc, xspan, y, lenspan, 1);
155		xspan += lenspan;
156		w -= lenspan;
157	    }
158	    else
159	    {
160		do
161		{
162		    w--;
163		    xspan++;
164		    if (!w)
165			break;
166		    bits = *src++;
167		} while (bits < 0x80);
168	    }
169	}
170	y++;
171    }
172}
173
174static void
175_XftSharpGlyphRgba (XftDraw	*draw,
176		    XftGlyph	*glyph,
177		    int		x,
178		    int		y)
179{
180    CARD32	    *srcLine = glyph->bitmap, *src, bits;
181    int		    width = glyph->metrics.width;
182    int		    stride = ((width + 3) & ~3);
183    int		    height = glyph->metrics.height;
184    int		    w;
185    int		    xspan, lenspan;
186
187    x -= glyph->metrics.x;
188    y -= glyph->metrics.y;
189    while (height--)
190    {
191	src = srcLine;
192	srcLine += stride;
193	w = width;
194
195	bits = *src++;
196	xspan = x;
197	while (w)
198	{
199	    if (bits >= 0x80000000)
200	    {
201		lenspan = 0;
202		do
203		{
204		    lenspan++;
205		    if (lenspan == w)
206			break;
207		    bits = *src++;
208		} while (bits >= 0x80000000);
209		XFillRectangle (draw->dpy, draw->drawable,
210				draw->core.gc, xspan, y, lenspan, 1);
211		xspan += lenspan;
212		w -= lenspan;
213	    }
214	    else
215	    {
216		do
217		{
218		    w--;
219		    xspan++;
220		    if (!w)
221			break;
222		    bits = *src++;
223		} while (bits < 0x80000000);
224	    }
225	}
226	y++;
227    }
228}
229
230typedef void (*XftSharpGlyph) (XftDraw	*draw,
231			       XftGlyph	*glyph,
232			       int	x,
233			       int	y);
234
235static XftSharpGlyph
236_XftSharpGlyphFind (XftDraw *draw, XftFont *public)
237{
238    XftFontInt *font = (XftFontInt *) public;
239
240    if (!font->info.antialias)
241	return _XftSharpGlyphMono;
242    else switch (font->info.rgba) {
243    case FC_RGBA_RGB:
244    case FC_RGBA_BGR:
245    case FC_RGBA_VRGB:
246    case FC_RGBA_VBGR:
247	return _XftSharpGlyphRgba;
248    default:
249	return _XftSharpGlyphGray;
250    }
251}
252
253/*
254 * Draw glyphs to a target that supports anti-aliasing
255 */
256
257/*
258 * Primitives for converting between RGB values and TrueColor pixels
259 */
260
261static void
262_XftExamineBitfield (unsigned long mask, int *shift, int *len)
263{
264    int	s, l;
265
266    s = 0;
267    while ((mask & 1) == 0)
268    {
269	mask >>= 1;
270	s++;
271    }
272    l = 0;
273    while ((mask & 1) == 1)
274    {
275	mask >>= 1;
276	l++;
277    }
278    *shift = s;
279    *len = l;
280}
281
282static CARD32
283_XftGetField (unsigned long l_pixel, int shift, int len)
284{
285    CARD32  pixel = (CARD32) l_pixel;
286
287    pixel = pixel & (((1 << (len)) - 1) << shift);
288    pixel = pixel << (32 - (shift + len)) >> 24;
289    while (len < 8)
290    {
291	pixel |= (pixel >> len);
292	len <<= 1;
293    }
294    return pixel;
295}
296
297static unsigned long
298_XftPutField (CARD32 pixel, int shift, int len)
299{
300    unsigned long   l_pixel = (unsigned long) pixel;
301
302    shift = shift - (8 - len);
303    if (len <= 8)
304	l_pixel &= (((1 << len) - 1) << (8 - len));
305    if (shift < 0)
306	l_pixel >>= -shift;
307    else
308	l_pixel <<= shift;
309    return l_pixel;
310}
311
312/*
313 * This is used when doing XftCharFontSpec/XftGlyphFontSpec where
314 * some of the fonts are bitmaps and some are anti-aliased to handle
315 * the bitmap portions
316 */
317static void
318_XftSmoothGlyphMono (XImage		*image,
319		     _Xconst XftGlyph	*xftg,
320		     int		x,
321		     int		y,
322		     _Xconst XftColor   *color)
323{
324    unsigned char   *srcLine = xftg->bitmap, *src;
325    unsigned char   bits, bitsMask;
326    int		    width = xftg->metrics.width;
327    int		    stride = ((width + 31) & ~31) >> 3;
328    int		    height = xftg->metrics.height;
329    int		    w;
330    int		    xspan;
331    int		    r_shift, r_len;
332    int		    g_shift, g_len;
333    int		    b_shift, b_len;
334    unsigned long   pixel;
335
336    _XftExamineBitfield (image->red_mask, &r_shift, &r_len);
337    _XftExamineBitfield (image->green_mask, &g_shift, &g_len);
338    _XftExamineBitfield (image->blue_mask, &b_shift, &b_len);
339    pixel = (_XftPutField (color->color.red >> 8, r_shift, r_len) |
340	     _XftPutField (color->color.green >> 8, g_shift, g_len) |
341	     _XftPutField (color->color.blue >> 8, b_shift, b_len));
342    x -= xftg->metrics.x;
343    y -= xftg->metrics.y;
344    while (height--)
345    {
346	src = srcLine;
347	srcLine += stride;
348	w = width;
349
350	bitsMask = 0x80;    /* FreeType is always MSB first */
351	bits = *src++;
352
353	xspan = x;
354	while (w--)
355	{
356	    if (bits & bitsMask)
357		XPutPixel (image, xspan, y, pixel);
358    	    bitsMask = bitsMask >> 1;
359    	    if (!bitsMask)
360    	    {
361    		bits = *src++;
362    		bitsMask = 0x80;
363    	    }
364	    xspan++;
365	}
366	y++;
367    }
368}
369
370/*
371 * As simple anti-aliasing is likely to be common, there are three
372 * optimized versions for the usual true color pixel formats (888, 565, 555).
373 * Other formats are handled by the general case
374 */
375
376#define cvt8888to0565(s)    ((((s) >> 3) & 0x001f) | \
377			     (((s) >> 5) & 0x07e0) | \
378			     (((s) >> 8) & 0xf800))
379
380#define cvt0565to8888(s)    (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
381			     ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
382			     ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)))
383
384#define cvt8888to0555(s)    ((((s) >> 3) & 0x001f) | \
385			     (((s) >> 6) & 0x03e0) | \
386			     (((s) >> 7) & 0x7c00))
387
388#define cvt0555to8888(s)    (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
389			     ((((s) << 6) & 0xf800) | (((s) >> 0) & 0x300)) | \
390			     ((((s) << 9) & 0xf80000) | (((s) << 4) & 0x70000)))
391
392
393#define XftIntMult(a,b,t) ( (t) = (a) * (b) + 0x80, ( ( ( (t)>>8 ) + (t) )>>8 ) )
394#define XftIntDiv(a,b)	 (((CARD16) (a) * 255) / (b))
395
396#define XftGet8(v,i)   ((CARD16) (CARD8) ((v) >> i))
397
398/*
399 * There are two ways of handling alpha -- either as a single unified value or
400 * a separate value for each component, hence each macro must have two
401 * versions.  The unified alpha version has a 'U' at the end of the name,
402 * the component version has a 'C'.  Similarly, functions which deal with
403 * this difference will have two versions using the same convention.
404 */
405
406#define XftOverU(x,y,i,a,t) ((t) = XftIntMult(XftGet8(y,i),(a),(t)) + XftGet8(x,i),\
407			   (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
408
409#define XftOverC(x,y,i,a,t) ((t) = XftIntMult(XftGet8(y,i),XftGet8(a,i),(t)) + XftGet8(x,i),\
410			    (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
411
412#define XftInU(x,i,a,t) ((CARD32) XftIntMult(XftGet8(x,i),(a),(t)) << (i))
413
414#define XftInC(x,i,a,t) ((CARD32) XftIntMult(XftGet8(x,i),XftGet8(a,i),(t)) << (i))
415
416#define XftGen(x,y,i,ax,ay,t,u,v) ((t) = (XftIntMult(XftGet8(y,i),ay,(u)) + \
417					 XftIntMult(XftGet8(x,i),ax,(v))),\
418				  (CARD32) ((CARD8) ((t) | \
419						     (0 - ((t) >> 8)))) << (i))
420
421#define XftAdd(x,y,i,t)	((t) = XftGet8(x,i) + XftGet8(y,i), \
422			 (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
423
424
425static CARD32
426fbOver24 (CARD32 x, CARD32 y)
427{
428    CARD16  a = ~x >> 24;
429    CARD16  t;
430    CARD32  m,n,o;
431
432    m = XftOverU(x,y,0,a,t);
433    n = XftOverU(x,y,8,a,t);
434    o = XftOverU(x,y,16,a,t);
435    return m|n|o;
436}
437
438static CARD32
439fbIn (CARD32 x, CARD8 y)
440{
441    CARD16  a = y;
442    CARD16  t;
443    CARD32  m,n,o,p;
444
445    m = XftInU(x,0,a,t);
446    n = XftInU(x,8,a,t);
447    o = XftInU(x,16,a,t);
448    p = XftInU(x,24,a,t);
449    return m|n|o|p;
450}
451
452static void
453_XftSmoothGlyphGray8888 (XImage		    *image,
454			 _Xconst XftGlyph   *xftg,
455			 int		    x,
456			 int		    y,
457			 _Xconst XftColor   *color)
458{
459    CARD32	src, srca;
460    CARD32	r, g, b;
461    CARD32	*dstLine, *dst, d;
462    CARD8	*maskLine, *mask, m;
463    int		dstStride, maskStride;
464    int		width, height;
465    int		w;
466
467    srca = color->color.alpha >> 8;
468
469    /* This handles only RGB and BGR */
470    g = (color->color.green & 0xff00);
471    if (image->red_mask == 0xff0000)
472    {
473	r = (color->color.red & 0xff00) << 8;
474	b = color->color.blue >> 8;
475    }
476    else
477    {
478	r = color->color.red >> 8;
479	b = (color->color.blue & 0xff00) << 8;
480    }
481    src = (srca << 24) | r | g | b;
482
483    width = xftg->metrics.width;
484    height = xftg->metrics.height;
485
486    x -= xftg->metrics.x;
487    y -= xftg->metrics.y;
488
489    dstLine = (CARD32 *) (image->data + image->bytes_per_line * y + (x << 2));
490    dstStride = image->bytes_per_line >> 2;
491    maskLine = (unsigned char *) xftg->bitmap;
492    maskStride = (width + 3) & ~3;
493
494    while (height--)
495    {
496	dst = dstLine;
497	dstLine += dstStride;
498	mask = maskLine;
499	maskLine += maskStride;
500	w = width;
501
502	while (w--)
503	{
504	    m = *mask++;
505	    if (m == 0xff)
506	    {
507		if (srca == 0xff)
508		    *dst = src;
509		else
510		    *dst = fbOver24 (src, *dst);
511	    }
512	    else if (m)
513	    {
514		d = fbIn (src, m);
515		*dst = fbOver24 (d, *dst);
516	    }
517	    dst++;
518	}
519    }
520}
521
522static void
523_XftSmoothGlyphGray565 (XImage		    *image,
524			_Xconst XftGlyph    *xftg,
525			int		    x,
526			int		    y,
527			_Xconst XftColor    *color)
528{
529    CARD32	src, srca;
530    CARD32	r, g, b;
531    CARD32	d;
532    CARD16	*dstLine, *dst;
533    CARD8	*maskLine, *mask, m;
534    int		dstStride, maskStride;
535    int		width, height;
536    int		w;
537
538    srca = color->color.alpha >> 8;
539
540    /* This handles only RGB and BGR */
541    g = (color->color.green & 0xff00);
542    if (image->red_mask == 0xf800)
543    {
544	r = (color->color.red & 0xff00) << 8;
545	b = color->color.blue >> 8;
546    }
547    else
548    {
549	r = color->color.red >> 8;
550	b = (color->color.blue & 0xff00) << 8;
551    }
552    src = (srca << 24) | r | g | b;
553
554    width = xftg->metrics.width;
555    height = xftg->metrics.height;
556
557    x -= xftg->metrics.x;
558    y -= xftg->metrics.y;
559
560    dstLine = (CARD16 *) (image->data + image->bytes_per_line * y + (x << 1));
561    dstStride = image->bytes_per_line >> 1;
562    maskLine = (unsigned char *) xftg->bitmap;
563    maskStride = (width + 3) & ~3;
564
565    while (height--)
566    {
567	dst = dstLine;
568	dstLine += dstStride;
569	mask = maskLine;
570	maskLine += maskStride;
571	w = width;
572
573	while (w--)
574	{
575	    m = *mask++;
576	    if (m == 0xff)
577	    {
578		if (srca == 0xff)
579		    d = src;
580		else
581		{
582		    d = *dst;
583		    d = fbOver24 (src, cvt0565to8888(d));
584		}
585		*dst = cvt8888to0565(d);
586	    }
587	    else if (m)
588	    {
589		d = *dst;
590		d = fbOver24 (fbIn(src,m), cvt0565to8888(d));
591		*dst = cvt8888to0565(d);
592	    }
593	    dst++;
594	}
595    }
596}
597
598static void
599_XftSmoothGlyphGray555 (XImage		    *image,
600			_Xconst XftGlyph    *xftg,
601			int		    x,
602			int		    y,
603			_Xconst XftColor    *color)
604{
605    CARD32	src, srca;
606    CARD32	r, g, b;
607    CARD32	d;
608    CARD16	*dstLine, *dst;
609    CARD8	*maskLine, *mask, m;
610    int		dstStride, maskStride;
611    int		width, height;
612    int		w;
613
614    srca = color->color.alpha >> 8;
615
616    /* This handles only RGB and BGR */
617    g = (color->color.green & 0xff00);
618    if (image->red_mask == 0xf800)
619    {
620	r = (color->color.red & 0xff00) << 8;
621	b = color->color.blue >> 8;
622    }
623    else
624    {
625	r = color->color.red >> 8;
626	b = (color->color.blue & 0xff00) << 8;
627    }
628    src = (srca << 24) | r | g | b;
629
630    width = xftg->metrics.width;
631    height = xftg->metrics.height;
632
633    x -= xftg->metrics.x;
634    y -= xftg->metrics.y;
635
636    dstLine = (CARD16 *) (image->data + image->bytes_per_line * y + (x << 1));
637    dstStride = image->bytes_per_line >> 1;
638    maskLine = (unsigned char *) xftg->bitmap;
639    maskStride = (width + 3) & ~3;
640
641    while (height--)
642    {
643	dst = dstLine;
644	dstLine += dstStride;
645	mask = maskLine;
646	maskLine += maskStride;
647	w = width;
648
649	while (w--)
650	{
651	    m = *mask++;
652	    if (m == 0xff)
653	    {
654		if (srca == 0xff)
655		    d = src;
656		else
657		{
658		    d = *dst;
659		    d = fbOver24 (src, cvt0555to8888(d));
660		}
661		*dst = cvt8888to0555(d);
662	    }
663	    else if (m)
664	    {
665		d = *dst;
666		d = fbOver24 (fbIn(src,m), cvt0555to8888(d));
667		*dst = cvt8888to0555(d);
668	    }
669	    dst++;
670	}
671    }
672}
673
674static void
675_XftSmoothGlyphGray (XImage		*image,
676		     _Xconst XftGlyph	*xftg,
677		     int		x,
678		     int		y,
679		     _Xconst XftColor   *color)
680{
681    CARD32	    src, srca;
682    int		    r_shift, r_len;
683    int		    g_shift, g_len;
684    int		    b_shift, b_len;
685    CARD8	    *maskLine, *mask, m;
686    int		    maskStride;
687    CARD32	    d;
688    unsigned long   pixel;
689    int		    width, height;
690    int		    w, tx;
691
692    srca = color->color.alpha >> 8;
693    src = (srca << 24 |
694	   (color->color.red & 0xff00) << 8 |
695	   (color->color.green & 0xff00) |
696	   (color->color.blue) >> 8);
697    x -= xftg->metrics.x;
698    y -= xftg->metrics.y;
699    width = xftg->metrics.width;
700    height = xftg->metrics.height;
701
702    maskLine = (unsigned char *) xftg->bitmap;
703    maskStride = (width + 3) & ~3;
704
705    _XftExamineBitfield (image->red_mask, &r_shift, &r_len);
706    _XftExamineBitfield (image->green_mask, &g_shift, &g_len);
707    _XftExamineBitfield (image->blue_mask, &b_shift, &b_len);
708    while (height--)
709    {
710	mask = maskLine;
711	maskLine += maskStride;
712	w = width;
713	tx = x;
714
715	while (w--)
716	{
717	    m = *mask++;
718	    if (m == 0xff)
719	    {
720		if (srca == 0xff)
721		    d = src;
722		else
723		{
724		    pixel = XGetPixel (image, tx, y);
725		    d = (_XftGetField (pixel, r_shift, r_len) << 16 |
726			 _XftGetField (pixel, g_shift, g_len) << 8 |
727			 _XftGetField (pixel, b_shift, b_len));
728		    d = fbOver24 (src, d);
729		}
730		pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
731			 _XftPutField ((d >>  8) & 0xff, g_shift, g_len) |
732			 _XftPutField ((d      ) & 0xff, b_shift, b_len));
733		XPutPixel (image, tx, y, pixel);
734	    }
735	    else if (m)
736	    {
737		pixel = XGetPixel (image, tx, y);
738		d = (_XftGetField (pixel, r_shift, r_len) << 16 |
739		     _XftGetField (pixel, g_shift, g_len) << 8 |
740		     _XftGetField (pixel, b_shift, b_len));
741		d = fbOver24 (fbIn(src,m), d);
742		pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
743			 _XftPutField ((d >>  8) & 0xff, g_shift, g_len) |
744			 _XftPutField ((d      ) & 0xff, b_shift, b_len));
745		XPutPixel (image, tx, y, pixel);
746	    }
747	    tx++;
748	}
749	y++;
750    }
751}
752
753static void
754_XftSmoothGlyphRgba (XImage		*image,
755		     _Xconst XftGlyph	*xftg,
756		     int		x,
757		     int		y,
758		     _Xconst XftColor   *color)
759{
760    CARD32	    src, srca;
761    int		    r_shift, r_len;
762    int		    g_shift, g_len;
763    int		    b_shift, b_len;
764    CARD32	    *mask, ma;
765    CARD32	    d;
766    unsigned long   pixel;
767    int		    width, height;
768    int		    w, tx;
769
770    srca = color->color.alpha >> 8;
771    src = (srca << 24 |
772	   (color->color.red & 0xff00) << 8 |
773	   (color->color.green & 0xff00) |
774	   (color->color.blue) >> 8);
775    x -= xftg->metrics.x;
776    y -= xftg->metrics.y;
777    width = xftg->metrics.width;
778    height = xftg->metrics.height;
779
780    mask = (CARD32 *) xftg->bitmap;
781
782    _XftExamineBitfield (image->red_mask, &r_shift, &r_len);
783    _XftExamineBitfield (image->green_mask, &g_shift, &g_len);
784    _XftExamineBitfield (image->blue_mask, &b_shift, &b_len);
785    while (height--)
786    {
787	w = width;
788	tx = x;
789
790	while (w--)
791	{
792	    ma = *mask++;
793	    if (ma == 0xffffffff)
794	    {
795		if (srca == 0xff)
796		    d = src;
797		else
798		{
799		    pixel = XGetPixel (image, tx, y);
800		    d = (_XftGetField (pixel, r_shift, r_len) << 16 |
801			 _XftGetField (pixel, g_shift, g_len) << 8 |
802			 _XftGetField (pixel, b_shift, b_len));
803		    d = fbOver24 (src, d);
804		}
805		pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
806			 _XftPutField ((d >>  8) & 0xff, g_shift, g_len) |
807			 _XftPutField ((d      ) & 0xff, b_shift, b_len));
808		XPutPixel (image, tx, y, pixel);
809	    }
810	    else if (ma)
811	    {
812		CARD32	m,n,o;
813		pixel = XGetPixel (image, tx, y);
814		d = (_XftGetField (pixel, r_shift, r_len) << 16 |
815		     _XftGetField (pixel, g_shift, g_len) << 8 |
816		     _XftGetField (pixel, b_shift, b_len));
817#define XftInOverC(src,srca,msk,dst,i,result) { \
818    CARD16  __a = XftGet8(msk,i); \
819    CARD32  __t, __ta; \
820    CARD32  __i; \
821    __t = XftIntMult (XftGet8(src,i), __a,__i); \
822    __ta = (CARD8) ~XftIntMult (srca, __a,__i); \
823    __t = __t + XftIntMult(XftGet8(dst,i),__ta,__i); \
824    __t = (CARD32) (CARD8) (__t | (-(__t >> 8))); \
825    result = __t << (i); \
826}
827		XftInOverC(src,srca,ma,d,0,m);
828		XftInOverC(src,srca,ma,d,8,n);
829		XftInOverC(src,srca,ma,d,16,o);
830		d = m | n | o;
831		pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
832			 _XftPutField ((d >>  8) & 0xff, g_shift, g_len) |
833			 _XftPutField ((d      ) & 0xff, b_shift, b_len));
834		XPutPixel (image, tx, y, pixel);
835	    }
836	    tx++;
837	}
838	y++;
839    }
840}
841
842static FcBool
843_XftSmoothGlyphPossible (XftDraw *draw)
844{
845    if (!draw->visual)
846	return FcFalse;
847    if (draw->visual->class != TrueColor)
848	return FcFalse;
849    return FcTrue;
850}
851
852typedef	void (*XftSmoothGlyph) (XImage		    *image,
853				_Xconst XftGlyph    *xftg,
854				int		    x,
855				int		    y,
856				_Xconst XftColor    *color);
857
858static XftSmoothGlyph
859_XftSmoothGlyphFind (XftDraw *draw, XftFont *public)
860{
861    XftFontInt *font = (XftFontInt *) public;
862
863    if (!font->info.antialias)
864	return _XftSmoothGlyphMono;
865    else switch (font->info.rgba) {
866    case FC_RGBA_RGB:
867    case FC_RGBA_BGR:
868    case FC_RGBA_VRGB:
869    case FC_RGBA_VBGR:
870	return _XftSmoothGlyphRgba;
871    default:
872	switch (XftDrawBitsPerPixel (draw)) {
873	case 32:
874	    if ((draw->visual->red_mask   == 0xff0000 &&
875		 draw->visual->green_mask == 0x00ff00 &&
876		 draw->visual->blue_mask  == 0x0000ff) ||
877		(draw->visual->red_mask   == 0x0000ff &&
878		 draw->visual->green_mask == 0x00ff00 &&
879		 draw->visual->blue_mask  == 0xff0000))
880	    {
881		return _XftSmoothGlyphGray8888;
882	    }
883	    break;
884	case 16:
885	    if ((draw->visual->red_mask   == 0xf800 &&
886		 draw->visual->green_mask == 0x07e0 &&
887		 draw->visual->blue_mask  == 0x001f) ||
888		(draw->visual->red_mask   == 0x001f &&
889		 draw->visual->green_mask == 0x07e0 &&
890		 draw->visual->blue_mask  == 0xf800))
891	    {
892		return _XftSmoothGlyphGray565;
893	    }
894	    if ((draw->visual->red_mask   == 0x7c00 &&
895		 draw->visual->green_mask == 0x03e0 &&
896		 draw->visual->blue_mask  == 0x001f) ||
897		(draw->visual->red_mask   == 0x001f &&
898		 draw->visual->green_mask == 0x03e0 &&
899		 draw->visual->blue_mask  == 0x7c00))
900	    {
901		return _XftSmoothGlyphGray555;
902	    }
903	    break;
904	default:
905	    break;
906	}
907	return _XftSmoothGlyphGray;
908    }
909}
910
911static XftGlyph *
912_XftGlyphDefault (Display *dpy, XftFont   *public)
913{
914    XftFontInt	    *font = (XftFontInt *) public;
915    FT_UInt	    missing[XFT_NMISSING];
916    int		    nmissing;
917    FcBool	    glyphs_loaded = FcFalse;
918
919    if (XftFontCheckGlyph (dpy, public, FcTrue, 0, missing, &nmissing))
920	glyphs_loaded = FcTrue;
921    if (nmissing)
922	XftFontLoadGlyphs (dpy, public, glyphs_loaded, missing, nmissing);
923    return font->glyphs[0];
924}
925
926static int XftGetImageErrorHandler (Display *dpy, XErrorEvent *error_event)
927{
928    return 0;
929}
930
931_X_HIDDEN void
932XftGlyphCore (XftDraw		*draw,
933	      _Xconst XftColor	*color,
934	      XftFont		*public,
935	      int		x,
936	      int		y,
937	      _Xconst FT_UInt	*glyphs,
938	      int		nglyphs)
939{
940    Display	    *dpy = draw->dpy;
941    XftFontInt	    *font = (XftFontInt *) public;
942    XftGlyph	    *xftg;
943    FT_UInt	    glyph;
944    _Xconst FT_UInt *g;
945    FT_UInt	    missing[XFT_NMISSING];
946    FcBool	    glyphs_loaded;
947    int		    nmissing;
948    int		    n;
949    XErrorHandler   prev_error;
950
951    /*
952     * Load missing glyphs
953     */
954    g = glyphs;
955    n = nglyphs;
956    nmissing = 0;
957    glyphs_loaded = FcFalse;
958    while (n--)
959	if (XftFontCheckGlyph (dpy, public, FcTrue, *g++, missing, &nmissing))
960	    glyphs_loaded = FcTrue;
961    if (nmissing)
962	XftFontLoadGlyphs (dpy, public, FcTrue, missing, nmissing);
963
964    g = glyphs;
965    n = nglyphs;
966    if ((font->info.antialias || color->color.alpha != 0xffff) &&
967	_XftSmoothGlyphPossible (draw))
968    {
969	XGlyphInfo	gi;
970	XImage		*image;
971        unsigned int    depth;
972	int		ox, oy;
973	XftSmoothGlyph	smooth = _XftSmoothGlyphFind (draw, public);
974
975	XftGlyphExtents (dpy, public, glyphs, nglyphs, &gi);
976	if (!gi.width || !gi.height)
977	    goto bail1;
978	ox = x - gi.x;
979	oy = y - gi.y;
980	/*
981	 * Try to get bits directly from the drawable; if that fails,
982	 * use a temporary pixmap.  When it does fail, assume it
983	 * will probably fail for a while and keep using temporary
984	 * pixmaps for a while to avoid double round trips.
985	 */
986	if (draw->core.use_pixmap == 0)
987	{
988	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
989	    image = XGetImage (dpy, draw->drawable,
990			       ox, oy,
991			       gi.width, gi.height, AllPlanes,
992			       ZPixmap);
993	    XSetErrorHandler (prev_error);
994	    if (!image)
995		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
996	}
997	else
998	{
999	    draw->core.use_pixmap--;
1000	    image = NULL;
1001	}
1002	if (!image && (depth = XftDrawDepth (draw)))
1003	{
1004	    Pixmap	pix;
1005	    GC		gc;
1006	    XGCValues	gcv;
1007
1008	    pix = XCreatePixmap (dpy, draw->drawable,
1009				 gi.width, gi.height, depth);
1010	    gcv.graphics_exposures = False;
1011	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
1012	    XCopyArea (dpy, draw->drawable, pix, gc, ox, oy,
1013		       gi.width, gi.height, 0, 0);
1014	    XFreeGC (dpy, gc);
1015	    image = XGetImage (dpy, pix, 0, 0, gi.width, gi.height, AllPlanes,
1016			       ZPixmap);
1017	    XFreePixmap (dpy, pix);
1018	}
1019	if (!image)
1020	    goto bail1;
1021	image->red_mask = draw->visual->red_mask;
1022	image->green_mask = draw->visual->green_mask;
1023	image->blue_mask = draw->visual->blue_mask;
1024	if (image->byte_order != XftNativeByteOrder ())
1025	    XftSwapImage (image);
1026	while (n--)
1027	{
1028	    glyph = *g++;
1029	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1030		xftg = _XftGlyphDefault (dpy, public);
1031	    if (xftg)
1032	    {
1033		(*smooth) (image, xftg, x - ox, y - oy, color);
1034		x += xftg->metrics.xOff;
1035		y += xftg->metrics.yOff;
1036	    }
1037	}
1038	if (image->byte_order != XftNativeByteOrder ())
1039	    XftSwapImage (image);
1040	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, ox, oy,
1041		   gi.width, gi.height);
1042	XDestroyImage (image);
1043    }
1044    else
1045    {
1046	XftSharpGlyph	sharp = _XftSharpGlyphFind (draw, public);
1047	while (n--)
1048	{
1049	    glyph = *g++;
1050	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1051		xftg = _XftGlyphDefault (dpy, public);
1052	    if (xftg)
1053	    {
1054		(*sharp) (draw, xftg, x, y);
1055		x += xftg->metrics.xOff;
1056		y += xftg->metrics.yOff;
1057	    }
1058	}
1059    }
1060bail1:
1061    if (glyphs_loaded)
1062	_XftFontManageMemory (dpy, public);
1063}
1064
1065#define NUM_LOCAL   1024
1066
1067_X_HIDDEN void
1068XftGlyphSpecCore (XftDraw		*draw,
1069		  _Xconst XftColor	*color,
1070		  XftFont		*public,
1071		  _Xconst XftGlyphSpec	*glyphs,
1072		  int			nglyphs)
1073{
1074    Display	    *dpy = draw->dpy;
1075    XftFontInt	    *font = (XftFontInt *) public;
1076    XftGlyph	    *xftg;
1077    FT_UInt	    missing[XFT_NMISSING];
1078    FcBool	    glyphs_loaded;
1079    int		    nmissing;
1080    int		    i;
1081    XErrorHandler   prev_error;
1082    int		    x1, y1, x2, y2;
1083
1084    /*
1085     * Load missing glyphs
1086     */
1087    glyphs_loaded = FcFalse;
1088    x1 = y1 = x2 = y2 = 0;
1089    for (i = 0; i < nglyphs; i++)
1090    {
1091	XGlyphInfo	gi;
1092	int		g_x1, g_x2, g_y1, g_y2;
1093
1094	nmissing = 0;
1095	if (XftFontCheckGlyph (dpy, public, FcTrue, glyphs[i].glyph, missing, &nmissing))
1096	    glyphs_loaded = FcTrue;
1097	if (nmissing)
1098	    XftFontLoadGlyphs (dpy, public, FcTrue, missing, nmissing);
1099
1100	XftGlyphExtents (dpy, public, &glyphs[i].glyph, 1, &gi);
1101	g_x1 = glyphs[i].x - gi.x;
1102	g_y1 = glyphs[i].y - gi.y;
1103	g_x2 = g_x1 + gi.width;
1104	g_y2 = g_y1 + gi.height;
1105	if (i)
1106	{
1107	    if (g_x1 < x1)
1108		x1 = g_x1;
1109	    if (g_y1 < y1)
1110		y1 = g_y1;
1111	    if (g_x2 > x2)
1112		x2 = g_x2;
1113	    if (g_y2 > y2)
1114		y2 = g_y2;
1115	}
1116	else
1117	{
1118	    x1 = g_x1;
1119	    y1 = g_y1;
1120	    x2 = g_x2;
1121	    y2 = g_y2;
1122	}
1123    }
1124
1125    if (x1 == x2 || y1 == y2)
1126	goto bail1;
1127
1128    if ((font->info.antialias || color->color.alpha != 0xffff) &&
1129	_XftSmoothGlyphPossible (draw))
1130    {
1131	XImage		*image;
1132        unsigned int    depth;
1133	int		width = x2 - x1, height = y2 - y1;
1134	XftSmoothGlyph	smooth = _XftSmoothGlyphFind (draw, public);
1135
1136	/*
1137	 * Try to get bits directly from the drawable; if that fails,
1138	 * use a temporary pixmap.  When it does fail, assume it
1139	 * will probably fail for a while and keep using temporary
1140	 * pixmaps for a while to avoid double round trips.
1141	 */
1142	if (draw->core.use_pixmap == 0)
1143	{
1144	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
1145	    image = XGetImage (dpy, draw->drawable,
1146			       x1, y1,
1147			       width, height, AllPlanes,
1148			       ZPixmap);
1149	    XSetErrorHandler (prev_error);
1150	    if (!image)
1151		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
1152	}
1153	else
1154	{
1155	    draw->core.use_pixmap--;
1156	    image = NULL;
1157	}
1158	if (!image && (depth = XftDrawDepth (draw)))
1159	{
1160	    Pixmap	pix;
1161	    GC		gc;
1162	    XGCValues	gcv;
1163
1164	    pix = XCreatePixmap (dpy, draw->drawable,
1165				 width, height, depth);
1166	    gcv.graphics_exposures = False;
1167	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
1168	    XCopyArea (dpy, draw->drawable, pix, gc, x1, y1,
1169		       width, height, 0, 0);
1170	    XFreeGC (dpy, gc);
1171	    image = XGetImage (dpy, pix, 0, 0, width, height, AllPlanes,
1172			       ZPixmap);
1173	    XFreePixmap (dpy, pix);
1174	}
1175	if (!image)
1176	    goto bail1;
1177	image->red_mask = draw->visual->red_mask;
1178	image->green_mask = draw->visual->green_mask;
1179	image->blue_mask = draw->visual->blue_mask;
1180	if (image->byte_order != XftNativeByteOrder ())
1181	    XftSwapImage (image);
1182	for (i = 0; i < nglyphs; i++)
1183	{
1184	    FT_UInt glyph = glyphs[i].glyph;
1185	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1186		xftg = _XftGlyphDefault (dpy, public);
1187	    if (xftg)
1188	    {
1189		(*smooth) (image, xftg, glyphs[i].x - x1,
1190			   glyphs[i].y - y1, color);
1191	    }
1192	}
1193	if (image->byte_order != XftNativeByteOrder ())
1194	    XftSwapImage (image);
1195	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, x1, y1,
1196		   width, height);
1197	XDestroyImage (image);
1198    }
1199    else
1200    {
1201	XftSharpGlyph	sharp = _XftSharpGlyphFind (draw, public);
1202	for (i = 0; i < nglyphs; i++)
1203	{
1204	    FT_UInt glyph = glyphs[i].glyph;
1205	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1206		xftg = _XftGlyphDefault (dpy, public);
1207	    if (xftg)
1208		(*sharp) (draw, xftg, glyphs[i].x, glyphs[i].y);
1209	}
1210    }
1211bail1:
1212    if (glyphs_loaded)
1213	_XftFontManageMemory (dpy, public);
1214}
1215
1216_X_HIDDEN void
1217XftGlyphFontSpecCore (XftDraw			*draw,
1218		      _Xconst XftColor		*color,
1219		      _Xconst XftGlyphFontSpec	*glyphs,
1220		      int			nglyphs)
1221{
1222    Display	    *dpy = draw->dpy;
1223    XftGlyph	    *xftg;
1224    FT_UInt	    missing[XFT_NMISSING];
1225    FcBool	    glyphs_loaded;
1226    int		    nmissing;
1227    int		    i;
1228    XErrorHandler   prev_error;
1229    int		    x1, y1, x2, y2;
1230
1231    /*
1232     * Load missing glyphs
1233     */
1234    glyphs_loaded = FcFalse;
1235    x1 = y1 = x2 = y2 = 0;
1236    for (i = 0; i < nglyphs; i++)
1237    {
1238	XftFont		*public = glyphs[i].font;
1239	XGlyphInfo	gi;
1240	int		g_x1, g_x2, g_y1, g_y2;
1241
1242	nmissing = 0;
1243	if (XftFontCheckGlyph (dpy, public, FcTrue, glyphs[i].glyph, missing, &nmissing))
1244	    glyphs_loaded = FcTrue;
1245	if (nmissing)
1246	    XftFontLoadGlyphs (dpy, public, FcTrue, missing, nmissing);
1247
1248	XftGlyphExtents (dpy, public, &glyphs[i].glyph, 1, &gi);
1249	g_x1 = glyphs[i].x - gi.x;
1250	g_y1 = glyphs[i].y - gi.y;
1251	g_x2 = g_x1 + gi.width;
1252	g_y2 = g_y1 + gi.height;
1253	if (i)
1254	{
1255	    if (g_x1 < x1)
1256		x1 = g_x1;
1257	    if (g_y1 < y1)
1258		y1 = g_y1;
1259	    if (g_x2 > x2)
1260		x2 = g_x2;
1261	    if (g_y2 > y2)
1262		y2 = g_y2;
1263	}
1264	else
1265	{
1266	    x1 = g_x1;
1267	    y1 = g_y1;
1268	    x2 = g_x2;
1269	    y2 = g_y2;
1270	}
1271    }
1272
1273    if (x1 == x2 || y1 == y2)
1274	goto bail1;
1275
1276    for (i = 0; i < nglyphs; i++)
1277	if (((XftFontInt *) glyphs[i].font)->info.antialias)
1278	    break;
1279
1280    if ((i != nglyphs || color->color.alpha != 0xffff) &&
1281	_XftSmoothGlyphPossible (draw))
1282    {
1283	XImage		*image;
1284        unsigned int    depth;
1285	int		width = x2 - x1, height = y2 - y1;
1286
1287	/*
1288	 * Try to get bits directly from the drawable; if that fails,
1289	 * use a temporary pixmap.  When it does fail, assume it
1290	 * will probably fail for a while and keep using temporary
1291	 * pixmaps for a while to avoid double round trips.
1292	 */
1293	if (draw->core.use_pixmap == 0)
1294	{
1295	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
1296	    image = XGetImage (dpy, draw->drawable,
1297			       x1, y1,
1298			       width, height, AllPlanes,
1299			       ZPixmap);
1300	    XSetErrorHandler (prev_error);
1301	    if (!image)
1302		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
1303	}
1304	else
1305	{
1306	    draw->core.use_pixmap--;
1307	    image = NULL;
1308	}
1309	if (!image && (depth = XftDrawDepth (draw)))
1310	{
1311	    Pixmap	pix;
1312	    GC		gc;
1313	    XGCValues	gcv;
1314
1315	    pix = XCreatePixmap (dpy, draw->drawable,
1316				 width, height, depth);
1317	    gcv.graphics_exposures = False;
1318	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
1319	    XCopyArea (dpy, draw->drawable, pix, gc, x1, y1,
1320		       width, height, 0, 0);
1321	    XFreeGC (dpy, gc);
1322	    image = XGetImage (dpy, pix, 0, 0, width, height, AllPlanes,
1323			       ZPixmap);
1324	    XFreePixmap (dpy, pix);
1325	}
1326	if (!image)
1327	    goto bail1;
1328	image->red_mask = draw->visual->red_mask;
1329	image->green_mask = draw->visual->green_mask;
1330	image->blue_mask = draw->visual->blue_mask;
1331	if (image->byte_order != XftNativeByteOrder ())
1332	    XftSwapImage (image);
1333	for (i = 0; i < nglyphs; i++)
1334	{
1335	    XftFont	    *public = glyphs[i].font;
1336	    XftFontInt	    *font = (XftFontInt *) public;
1337	    XftSmoothGlyph  smooth = _XftSmoothGlyphFind (draw, public);
1338	    FT_UInt	    glyph = glyphs[i].glyph;
1339
1340	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1341		xftg = _XftGlyphDefault (dpy, public);
1342	    if (xftg)
1343	    {
1344		(*smooth) (image, xftg, glyphs[i].x - x1,
1345			   glyphs[i].y - y1, color);
1346	    }
1347	}
1348	if (image->byte_order != XftNativeByteOrder ())
1349	    XftSwapImage (image);
1350	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, x1, y1,
1351		   width, height);
1352	XDestroyImage (image);
1353    }
1354    else
1355    {
1356	for (i = 0; i < nglyphs; i++)
1357	{
1358	    XftFont		*public = glyphs[i].font;
1359	    XftFontInt		*font = (XftFontInt *) public;
1360	    XftSharpGlyph	sharp = _XftSharpGlyphFind (draw, public);
1361	    FT_UInt		glyph = glyphs[i].glyph;
1362
1363	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1364		xftg = _XftGlyphDefault (dpy, public);
1365	    if (xftg)
1366		(*sharp) (draw, xftg, glyphs[i].x, glyphs[i].y);
1367	}
1368    }
1369bail1:
1370    if (glyphs_loaded)
1371	for (i = 0; i < nglyphs; i++)
1372	    _XftFontManageMemory (dpy, glyphs[i].font);
1373}
1374