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