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, (unsigned)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, (unsigned)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, (unsigned)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 _X_UNUSED, 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 & (CARD32)(((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 = l_pixel & (unsigned long)(((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)    (CARD16)((((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)    (CARD16)((((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,cast) \
394        ( ((t) = (cast)((a) * (b) + 0x80)), \
395          ( ( ( (t) >> 8 ) + (t) ) >> 8 ) )
396
397#define XftIntDiv(a,b)	 (((CARD16) (a) * 255) / (b))
398
399#define XftGet8(v,i)   ((CARD16) (CARD8) ((v) >> i))
400
401/*
402 * There are two ways of handling alpha -- either as a single unified value or
403 * a separate value for each component, hence each macro must have two
404 * versions.  The unified alpha version has a 'U' at the end of the name,
405 * the component version has a 'C'.  Similarly, functions which deal with
406 * this difference will have two versions using the same convention.
407 */
408
409#define XftOverU(x,y,i,a,t) \
410        ((t) = (CARD16) XftIntMult(XftGet8(y,i),(a),(t),CARD16) + \
411               XftGet8(x,i),\
412         (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
413
414#define XftOverC(x,y,i,a,t) \
415        ((t) = (CARD16) XftIntMult(XftGet8(y,i),XftGet8(a,i),(t),CARD16) + \
416               XftGet8(x,i),\
417         (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
418
419#define XftInU(x,i,a,t) \
420        ((CARD32) XftIntMult(XftGet8(x,i),(a),(t),CARD16) << (i))
421
422#define XftInC(x,i,a,t) \
423        ((CARD32) XftIntMult(XftGet8(x,i),XftGet8(a,i),(t),CARD32) << (i))
424
425#define XftGen(x,y,i,ax,ay,t,u,v) \
426        ((t) = (XftIntMult(XftGet8(y,i),ay,(u),CARD32) + \
427                XftIntMult(XftGet8(x,i),ax,(v),CARD32)),\
428         (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
429
430#define XftAdd(x,y,i,t)	\
431        ((t) = XftGet8(x,i) + XftGet8(y,i), \
432         (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
433
434
435static CARD32
436fbOver24 (CARD32 x, CARD32 y)
437{
438    CARD16  a = (CARD16)(~x >> 24);
439    CARD16  t = 0;
440    CARD32  m,n,o;
441
442    m = XftOverU(x,y,0,a,t);
443    n = XftOverU(x,y,8,a,t);
444    o = XftOverU(x,y,16,a,t);
445    return m|n|o;
446}
447
448static CARD32
449fbIn (CARD32 x, CARD8 y)
450{
451    CARD16  a = y;
452    CARD16  t;
453    CARD32  m,n,o,p;
454
455    m = XftInU(x,0,a,t);
456    n = XftInU(x,8,a,t);
457    o = XftInU(x,16,a,t);
458    p = XftInU(x,24,a,t);
459    return m|n|o|p;
460}
461
462static void
463_XftSmoothGlyphGray8888 (XImage		    *image,
464			 _Xconst XftGlyph   *xftg,
465			 int		    x,
466			 int		    y,
467			 _Xconst XftColor   *color)
468{
469    CARD32	src, srca;
470    CARD32	r, g, b;
471    CARD32	*dstLine, *dst, d;
472    CARD8	*maskLine, *mask, m;
473    int		dstStride, maskStride;
474    int		width, height;
475    int		w;
476
477    srca = color->color.alpha >> 8;
478
479    /* This handles only RGB and BGR */
480    g = (color->color.green & 0xff00);
481    if (image->red_mask == 0xff0000)
482    {
483	r = (color->color.red & 0xff00) << 8;
484	b = color->color.blue >> 8;
485    }
486    else
487    {
488	r = color->color.red >> 8;
489	b = (color->color.blue & 0xff00) << 8;
490    }
491    src = (srca << 24) | r | g | b;
492
493    width = xftg->metrics.width;
494    height = xftg->metrics.height;
495
496    x -= xftg->metrics.x;
497    y -= xftg->metrics.y;
498
499    dstLine = (CARD32 *) (image->data + image->bytes_per_line * y + (x << 2));
500    dstStride = image->bytes_per_line >> 2;
501    maskLine = (unsigned char *) xftg->bitmap;
502    maskStride = (width + 3) & ~3;
503
504    while (height--)
505    {
506	dst = dstLine;
507	dstLine += dstStride;
508	mask = maskLine;
509	maskLine += maskStride;
510	w = width;
511
512	while (w--)
513	{
514	    m = *mask++;
515	    if (m == 0xff)
516	    {
517		if (srca == 0xff)
518		    *dst = src;
519		else
520		    *dst = fbOver24 (src, *dst);
521	    }
522	    else if (m)
523	    {
524		d = fbIn (src, m);
525		*dst = fbOver24 (d, *dst);
526	    }
527	    dst++;
528	}
529    }
530}
531
532static void
533_XftSmoothGlyphGray565 (XImage		    *image,
534			_Xconst XftGlyph    *xftg,
535			int		    x,
536			int		    y,
537			_Xconst XftColor    *color)
538{
539    CARD32	src, srca;
540    CARD32	r, g, b;
541    CARD32	d;
542    CARD16	*dstLine, *dst;
543    CARD8	*maskLine, *mask, m;
544    int		dstStride, maskStride;
545    int		width, height;
546    int		w;
547
548    srca = color->color.alpha >> 8;
549
550    /* This handles only RGB and BGR */
551    g = (color->color.green & 0xff00);
552    if (image->red_mask == 0xf800)
553    {
554	r = (color->color.red & 0xff00) << 8;
555	b = color->color.blue >> 8;
556    }
557    else
558    {
559	r = color->color.red >> 8;
560	b = (color->color.blue & 0xff00) << 8;
561    }
562    src = (srca << 24) | r | g | b;
563
564    width = xftg->metrics.width;
565    height = xftg->metrics.height;
566
567    x -= xftg->metrics.x;
568    y -= xftg->metrics.y;
569
570    dstLine = (CARD16 *) (image->data + image->bytes_per_line * y + (x << 1));
571    dstStride = image->bytes_per_line >> 1;
572    maskLine = (unsigned char *) xftg->bitmap;
573    maskStride = (width + 3) & ~3;
574
575    while (height--)
576    {
577	dst = dstLine;
578	dstLine += dstStride;
579	mask = maskLine;
580	maskLine += maskStride;
581	w = width;
582
583	while (w--)
584	{
585	    m = *mask++;
586	    if (m == 0xff)
587	    {
588		if (srca == 0xff)
589		    d = src;
590		else
591		{
592		    d = *dst;
593		    d = fbOver24 (src, cvt0565to8888(d));
594		}
595		*dst = cvt8888to0565(d);
596	    }
597	    else if (m)
598	    {
599		d = *dst;
600		d = fbOver24 (fbIn(src,m), cvt0565to8888(d));
601		*dst = cvt8888to0565(d);
602	    }
603	    dst++;
604	}
605    }
606}
607
608static void
609_XftSmoothGlyphGray555 (XImage		    *image,
610			_Xconst XftGlyph    *xftg,
611			int		    x,
612			int		    y,
613			_Xconst XftColor    *color)
614{
615    CARD32	src, srca;
616    CARD32	r, g, b;
617    CARD32	d;
618    CARD16	*dstLine, *dst;
619    CARD8	*maskLine, *mask, m;
620    int		dstStride, maskStride;
621    int		width, height;
622    int		w;
623
624    srca = color->color.alpha >> 8;
625
626    /* This handles only RGB and BGR */
627    g = (color->color.green & 0xff00);
628    if (image->red_mask == 0xf800)
629    {
630	r = (color->color.red & 0xff00) << 8;
631	b = color->color.blue >> 8;
632    }
633    else
634    {
635	r = color->color.red >> 8;
636	b = (color->color.blue & 0xff00) << 8;
637    }
638    src = (srca << 24) | r | g | b;
639
640    width = xftg->metrics.width;
641    height = xftg->metrics.height;
642
643    x -= xftg->metrics.x;
644    y -= xftg->metrics.y;
645
646    dstLine = (CARD16 *) (image->data + image->bytes_per_line * y + (x << 1));
647    dstStride = image->bytes_per_line >> 1;
648    maskLine = (unsigned char *) xftg->bitmap;
649    maskStride = (width + 3) & ~3;
650
651    while (height--)
652    {
653	dst = dstLine;
654	dstLine += dstStride;
655	mask = maskLine;
656	maskLine += maskStride;
657	w = width;
658
659	while (w--)
660	{
661	    m = *mask++;
662	    if (m == 0xff)
663	    {
664		if (srca == 0xff)
665		    d = src;
666		else
667		{
668		    d = *dst;
669		    d = fbOver24 (src, cvt0555to8888(d));
670		}
671		*dst = cvt8888to0555(d);
672	    }
673	    else if (m)
674	    {
675		d = *dst;
676		d = fbOver24 (fbIn(src,m), cvt0555to8888(d));
677		*dst = cvt8888to0555(d);
678	    }
679	    dst++;
680	}
681    }
682}
683
684static void
685_XftSmoothGlyphGray (XImage		*image,
686		     _Xconst XftGlyph	*xftg,
687		     int		x,
688		     int		y,
689		     _Xconst XftColor   *color)
690{
691    CARD32	    src, srca;
692    int		    r_shift, r_len;
693    int		    g_shift, g_len;
694    int		    b_shift, b_len;
695    CARD8	    *maskLine, *mask, m;
696    int		    maskStride;
697    CARD32	    d;
698    unsigned long   pixel;
699    int		    width, height;
700    int		    w, tx;
701
702    srca = color->color.alpha >> 8;
703    src = (srca << 24 |
704	   (CARD32)((color->color.red & 0xff00) << 8) |
705	   (color->color.green & 0xff00) |
706	   (color->color.blue) >> 8);
707    x -= xftg->metrics.x;
708    y -= xftg->metrics.y;
709    width = xftg->metrics.width;
710    height = xftg->metrics.height;
711
712    maskLine = (unsigned char *) xftg->bitmap;
713    maskStride = (width + 3) & ~3;
714
715    _XftExamineBitfield (image->red_mask, &r_shift, &r_len);
716    _XftExamineBitfield (image->green_mask, &g_shift, &g_len);
717    _XftExamineBitfield (image->blue_mask, &b_shift, &b_len);
718    while (height--)
719    {
720	mask = maskLine;
721	maskLine += maskStride;
722	w = width;
723	tx = x;
724
725	while (w--)
726	{
727	    m = *mask++;
728	    if (m == 0xff)
729	    {
730		if (srca == 0xff)
731		    d = src;
732		else
733		{
734		    pixel = XGetPixel (image, tx, y);
735		    d = (_XftGetField (pixel, r_shift, r_len) << 16 |
736			 _XftGetField (pixel, g_shift, g_len) << 8 |
737			 _XftGetField (pixel, b_shift, b_len));
738		    d = fbOver24 (src, d);
739		}
740		pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
741			 _XftPutField ((d >>  8) & 0xff, g_shift, g_len) |
742			 _XftPutField ((d      ) & 0xff, b_shift, b_len));
743		XPutPixel (image, tx, y, pixel);
744	    }
745	    else if (m)
746	    {
747		pixel = XGetPixel (image, tx, y);
748		d = (_XftGetField (pixel, r_shift, r_len) << 16 |
749		     _XftGetField (pixel, g_shift, g_len) << 8 |
750		     _XftGetField (pixel, b_shift, b_len));
751		d = fbOver24 (fbIn(src,m), d);
752		pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
753			 _XftPutField ((d >>  8) & 0xff, g_shift, g_len) |
754			 _XftPutField ((d      ) & 0xff, b_shift, b_len));
755		XPutPixel (image, tx, y, pixel);
756	    }
757	    tx++;
758	}
759	y++;
760    }
761}
762
763static void
764_XftSmoothGlyphRgba (XImage		*image,
765		     _Xconst XftGlyph	*xftg,
766		     int		x,
767		     int		y,
768		     _Xconst XftColor   *color)
769{
770    CARD32	    src, srca;
771    int		    r_shift, r_len;
772    int		    g_shift, g_len;
773    int		    b_shift, b_len;
774    CARD32	    *mask, ma;
775    CARD32	    d;
776    unsigned long   pixel;
777    int		    width, height;
778    int		    w, tx;
779
780    srca = color->color.alpha >> 8;
781    src = (srca << 24 |
782	   (CARD32)((color->color.red & 0xff00) << 8) |
783	   (color->color.green & 0xff00) |
784	   (color->color.blue) >> 8);
785    x -= xftg->metrics.x;
786    y -= xftg->metrics.y;
787    width = xftg->metrics.width;
788    height = xftg->metrics.height;
789
790    mask = (CARD32 *) xftg->bitmap;
791
792    _XftExamineBitfield (image->red_mask, &r_shift, &r_len);
793    _XftExamineBitfield (image->green_mask, &g_shift, &g_len);
794    _XftExamineBitfield (image->blue_mask, &b_shift, &b_len);
795    while (height--)
796    {
797	w = width;
798	tx = x;
799
800	while (w--)
801	{
802	    ma = *mask++;
803	    if (ma == 0xffffffff)
804	    {
805		if (srca == 0xff)
806		    d = src;
807		else
808		{
809		    pixel = XGetPixel (image, tx, y);
810		    d = (_XftGetField (pixel, r_shift, r_len) << 16 |
811			 _XftGetField (pixel, g_shift, g_len) << 8 |
812			 _XftGetField (pixel, b_shift, b_len));
813		    d = fbOver24 (src, d);
814		}
815		pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
816			 _XftPutField ((d >>  8) & 0xff, g_shift, g_len) |
817			 _XftPutField ((d      ) & 0xff, b_shift, b_len));
818		XPutPixel (image, tx, y, pixel);
819	    }
820	    else if (ma)
821	    {
822		CARD32	m,n,o;
823		pixel = XGetPixel (image, tx, y);
824		d = (_XftGetField (pixel, r_shift, r_len) << 16 |
825		     _XftGetField (pixel, g_shift, g_len) << 8 |
826		     _XftGetField (pixel, b_shift, b_len));
827#define XftInOverC(src,srca,msk,dst,i,result) { \
828    CARD16  __a = XftGet8(msk,i); \
829    CARD32  __t, __ta; \
830    CARD32  __i; \
831    __t = XftIntMult (XftGet8(src,i), __a,__i,CARD32); \
832    __ta = (CARD8) ~XftIntMult (srca, __a,__i,CARD32); \
833    __t = __t + XftIntMult(XftGet8(dst,i),__ta,__i,CARD32); \
834    __t = (CARD32) (CARD8) (__t | (-(__t >> 8))); \
835    result = __t << (i); \
836}
837		XftInOverC(src,srca,ma,d,0,m);
838		XftInOverC(src,srca,ma,d,8,n);
839		XftInOverC(src,srca,ma,d,16,o);
840		d = m | n | o;
841		pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
842			 _XftPutField ((d >>  8) & 0xff, g_shift, g_len) |
843			 _XftPutField ((d      ) & 0xff, b_shift, b_len));
844		XPutPixel (image, tx, y, pixel);
845	    }
846	    tx++;
847	}
848	y++;
849    }
850}
851
852static FcBool
853_XftSmoothGlyphPossible (XftDraw *draw)
854{
855    if (!draw->visual)
856	return FcFalse;
857    if (draw->visual->class != TrueColor)
858	return FcFalse;
859    return FcTrue;
860}
861
862typedef	void (*XftSmoothGlyph) (XImage		    *image,
863				_Xconst XftGlyph    *xftg,
864				int		    x,
865				int		    y,
866				_Xconst XftColor    *color);
867
868static XftSmoothGlyph
869_XftSmoothGlyphFind (XftDraw *draw, XftFont *public)
870{
871    XftFontInt *font = (XftFontInt *) public;
872
873    if (!font->info.antialias)
874	return _XftSmoothGlyphMono;
875    else switch (font->info.rgba) {
876    case FC_RGBA_RGB:
877    case FC_RGBA_BGR:
878    case FC_RGBA_VRGB:
879    case FC_RGBA_VBGR:
880	return _XftSmoothGlyphRgba;
881    default:
882	switch (XftDrawBitsPerPixel (draw)) {
883	case 32:
884	    if ((draw->visual->red_mask   == 0xff0000 &&
885		 draw->visual->green_mask == 0x00ff00 &&
886		 draw->visual->blue_mask  == 0x0000ff) ||
887		(draw->visual->red_mask   == 0x0000ff &&
888		 draw->visual->green_mask == 0x00ff00 &&
889		 draw->visual->blue_mask  == 0xff0000))
890	    {
891		return _XftSmoothGlyphGray8888;
892	    }
893	    break;
894	case 16:
895	    if ((draw->visual->red_mask   == 0xf800 &&
896		 draw->visual->green_mask == 0x07e0 &&
897		 draw->visual->blue_mask  == 0x001f) ||
898		(draw->visual->red_mask   == 0x001f &&
899		 draw->visual->green_mask == 0x07e0 &&
900		 draw->visual->blue_mask  == 0xf800))
901	    {
902		return _XftSmoothGlyphGray565;
903	    }
904	    if ((draw->visual->red_mask   == 0x7c00 &&
905		 draw->visual->green_mask == 0x03e0 &&
906		 draw->visual->blue_mask  == 0x001f) ||
907		(draw->visual->red_mask   == 0x001f &&
908		 draw->visual->green_mask == 0x03e0 &&
909		 draw->visual->blue_mask  == 0x7c00))
910	    {
911		return _XftSmoothGlyphGray555;
912	    }
913	    break;
914	default:
915	    break;
916	}
917	return _XftSmoothGlyphGray;
918    }
919}
920
921static XftGlyph *
922_XftGlyphDefault (Display *dpy, XftFont   *public)
923{
924    XftFontInt	    *font = (XftFontInt *) public;
925    FT_UInt	    missing[XFT_NMISSING];
926    int		    nmissing = 0;
927    FcBool	    glyphs_loaded = FcFalse;
928
929    if (XftFontCheckGlyph (dpy, public, FcTrue, 0, missing, &nmissing))
930	glyphs_loaded = FcTrue;
931    if (nmissing)
932	XftFontLoadGlyphs (dpy, public, glyphs_loaded, missing, nmissing);
933    return font->glyphs[0];
934}
935
936static int XftGetImageErrorHandler (Display *dpy _X_UNUSED, XErrorEvent *error_event _X_UNUSED)
937{
938    return 0;
939}
940
941_X_HIDDEN void
942XftGlyphCore (XftDraw		*draw,
943	      _Xconst XftColor	*color,
944	      XftFont		*public,
945	      int		x,
946	      int		y,
947	      _Xconst FT_UInt	*glyphs,
948	      int		nglyphs)
949{
950    Display	    *dpy = draw->dpy;
951    XftFontInt	    *font = (XftFontInt *) public;
952    XftGlyph	    *xftg;
953    FT_UInt	    glyph;
954    _Xconst FT_UInt *g;
955    FT_UInt	    missing[XFT_NMISSING];
956    FcBool	    glyphs_loaded;
957    int		    nmissing;
958    int		    n;
959    XErrorHandler   prev_error;
960
961    /*
962     * Load missing glyphs
963     */
964    g = glyphs;
965    n = nglyphs;
966    nmissing = 0;
967    glyphs_loaded = FcFalse;
968    while (n--)
969	if (XftFontCheckGlyph (dpy, public, FcTrue, *g++, missing, &nmissing))
970	    glyphs_loaded = FcTrue;
971    if (nmissing)
972	XftFontLoadGlyphs (dpy, public, FcTrue, missing, nmissing);
973
974    g = glyphs;
975    n = nglyphs;
976    if ((font->info.antialias || color->color.alpha != 0xffff) &&
977	_XftSmoothGlyphPossible (draw))
978    {
979	XGlyphInfo	gi;
980	XImage		*image;
981        unsigned int    depth;
982	int		ox, oy;
983	XftSmoothGlyph	smooth = _XftSmoothGlyphFind (draw, public);
984
985	XftGlyphExtents (dpy, public, glyphs, nglyphs, &gi);
986	if (!gi.width || !gi.height)
987	    goto bail1;
988	ox = x - gi.x;
989	oy = y - gi.y;
990	/*
991	 * Try to get bits directly from the drawable; if that fails,
992	 * use a temporary pixmap.  When it does fail, assume it
993	 * will probably fail for a while and keep using temporary
994	 * pixmaps for a while to avoid double round trips.
995	 */
996	if (draw->core.use_pixmap == 0)
997	{
998	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
999	    image = XGetImage (dpy, draw->drawable,
1000			       ox, oy,
1001			       gi.width, gi.height, AllPlanes,
1002			       ZPixmap);
1003	    XSetErrorHandler (prev_error);
1004	    if (!image)
1005		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
1006	}
1007	else
1008	{
1009	    draw->core.use_pixmap--;
1010	    image = NULL;
1011	}
1012	if (!image && (depth = XftDrawDepth (draw)))
1013	{
1014	    Pixmap	pix;
1015	    GC		gc;
1016	    XGCValues	gcv;
1017
1018	    pix = XCreatePixmap (dpy, draw->drawable,
1019				 gi.width, gi.height, depth);
1020	    gcv.graphics_exposures = False;
1021	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
1022	    XCopyArea (dpy, draw->drawable, pix, gc, ox, oy,
1023		       gi.width, gi.height, 0, 0);
1024	    XFreeGC (dpy, gc);
1025	    image = XGetImage (dpy, pix, 0, 0, gi.width, gi.height, AllPlanes,
1026			       ZPixmap);
1027	    XFreePixmap (dpy, pix);
1028	}
1029	if (!image)
1030	    goto bail1;
1031	image->red_mask = draw->visual->red_mask;
1032	image->green_mask = draw->visual->green_mask;
1033	image->blue_mask = draw->visual->blue_mask;
1034	if (image->byte_order != XftNativeByteOrder ())
1035	    XftSwapImage (image);
1036	while (n--)
1037	{
1038	    glyph = *g++;
1039	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1040		xftg = _XftGlyphDefault (dpy, public);
1041	    if (xftg)
1042	    {
1043		(*smooth) (image, xftg, x - ox, y - oy, color);
1044		x += xftg->metrics.xOff;
1045		y += xftg->metrics.yOff;
1046	    }
1047	}
1048	if (image->byte_order != XftNativeByteOrder ())
1049	    XftSwapImage (image);
1050	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, ox, oy,
1051		   gi.width, gi.height);
1052	XDestroyImage (image);
1053    }
1054    else
1055    {
1056	XftSharpGlyph	sharp = _XftSharpGlyphFind (draw, public);
1057	while (n--)
1058	{
1059	    glyph = *g++;
1060	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1061		xftg = _XftGlyphDefault (dpy, public);
1062	    if (xftg)
1063	    {
1064		(*sharp) (draw, xftg, x, y);
1065		x += xftg->metrics.xOff;
1066		y += xftg->metrics.yOff;
1067	    }
1068	}
1069    }
1070bail1:
1071    if (glyphs_loaded)
1072	_XftFontManageMemory (dpy, public);
1073}
1074
1075#define NUM_LOCAL   1024
1076
1077_X_HIDDEN void
1078XftGlyphSpecCore (XftDraw		*draw,
1079		  _Xconst XftColor	*color,
1080		  XftFont		*public,
1081		  _Xconst XftGlyphSpec	*glyphs,
1082		  int			nglyphs)
1083{
1084    Display	    *dpy = draw->dpy;
1085    XftFontInt	    *font = (XftFontInt *) public;
1086    XftGlyph	    *xftg;
1087    FT_UInt	    missing[XFT_NMISSING];
1088    FcBool	    glyphs_loaded;
1089    int		    nmissing;
1090    int		    i;
1091    XErrorHandler   prev_error;
1092    int		    x1, y1, x2, y2;
1093
1094    /*
1095     * Load missing glyphs
1096     */
1097    glyphs_loaded = FcFalse;
1098    x1 = y1 = x2 = y2 = 0;
1099    for (i = 0; i < nglyphs; i++)
1100    {
1101	XGlyphInfo	gi;
1102	int		g_x1, g_x2, g_y1, g_y2;
1103
1104	nmissing = 0;
1105	if (XftFontCheckGlyph (dpy, public, FcTrue, glyphs[i].glyph, missing, &nmissing))
1106	    glyphs_loaded = FcTrue;
1107	if (nmissing)
1108	    XftFontLoadGlyphs (dpy, public, FcTrue, missing, nmissing);
1109
1110	XftGlyphExtents (dpy, public, &glyphs[i].glyph, 1, &gi);
1111	g_x1 = glyphs[i].x - gi.x;
1112	g_y1 = glyphs[i].y - gi.y;
1113	g_x2 = g_x1 + gi.width;
1114	g_y2 = g_y1 + gi.height;
1115	if (i)
1116	{
1117	    if (g_x1 < x1)
1118		x1 = g_x1;
1119	    if (g_y1 < y1)
1120		y1 = g_y1;
1121	    if (g_x2 > x2)
1122		x2 = g_x2;
1123	    if (g_y2 > y2)
1124		y2 = g_y2;
1125	}
1126	else
1127	{
1128	    x1 = g_x1;
1129	    y1 = g_y1;
1130	    x2 = g_x2;
1131	    y2 = g_y2;
1132	}
1133    }
1134
1135    if (x1 == x2 || y1 == y2)
1136	goto bail1;
1137
1138    if ((font->info.antialias || color->color.alpha != 0xffff) &&
1139	_XftSmoothGlyphPossible (draw))
1140    {
1141	XImage		*image;
1142        unsigned int    depth;
1143	int		width = x2 - x1, height = y2 - y1;
1144	XftSmoothGlyph	smooth = _XftSmoothGlyphFind (draw, public);
1145
1146	/*
1147	 * Try to get bits directly from the drawable; if that fails,
1148	 * use a temporary pixmap.  When it does fail, assume it
1149	 * will probably fail for a while and keep using temporary
1150	 * pixmaps for a while to avoid double round trips.
1151	 */
1152	if (draw->core.use_pixmap == 0)
1153	{
1154	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
1155	    image = XGetImage (dpy, draw->drawable,
1156			       x1, y1,
1157			       (unsigned)width, (unsigned)height, AllPlanes,
1158			       ZPixmap);
1159	    XSetErrorHandler (prev_error);
1160	    if (!image)
1161		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
1162	}
1163	else
1164	{
1165	    draw->core.use_pixmap--;
1166	    image = NULL;
1167	}
1168	if (!image && (depth = XftDrawDepth (draw)))
1169	{
1170	    Pixmap	pix;
1171	    GC		gc;
1172	    XGCValues	gcv;
1173
1174	    pix = XCreatePixmap (dpy, draw->drawable,
1175				 (unsigned)width, (unsigned)height, depth);
1176	    gcv.graphics_exposures = False;
1177	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
1178	    XCopyArea (dpy, draw->drawable, pix, gc, x1, y1,
1179		       (unsigned)width, (unsigned)height, 0, 0);
1180	    XFreeGC (dpy, gc);
1181	    image = XGetImage (dpy, pix, 0, 0, (unsigned)width, (unsigned)height, AllPlanes,
1182			       ZPixmap);
1183	    XFreePixmap (dpy, pix);
1184	}
1185	if (!image)
1186	    goto bail1;
1187	image->red_mask = draw->visual->red_mask;
1188	image->green_mask = draw->visual->green_mask;
1189	image->blue_mask = draw->visual->blue_mask;
1190	if (image->byte_order != XftNativeByteOrder ())
1191	    XftSwapImage (image);
1192	for (i = 0; i < nglyphs; i++)
1193	{
1194	    FT_UInt glyph = glyphs[i].glyph;
1195	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1196		xftg = _XftGlyphDefault (dpy, public);
1197	    if (xftg)
1198	    {
1199		(*smooth) (image, xftg, glyphs[i].x - x1,
1200			   glyphs[i].y - y1, color);
1201	    }
1202	}
1203	if (image->byte_order != XftNativeByteOrder ())
1204	    XftSwapImage (image);
1205	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, x1, y1,
1206		   (unsigned)width, (unsigned)height);
1207	XDestroyImage (image);
1208    }
1209    else
1210    {
1211	XftSharpGlyph	sharp = _XftSharpGlyphFind (draw, public);
1212	for (i = 0; i < nglyphs; i++)
1213	{
1214	    FT_UInt glyph = glyphs[i].glyph;
1215	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1216		xftg = _XftGlyphDefault (dpy, public);
1217	    if (xftg)
1218		(*sharp) (draw, xftg, glyphs[i].x, glyphs[i].y);
1219	}
1220    }
1221bail1:
1222    if (glyphs_loaded)
1223	_XftFontManageMemory (dpy, public);
1224}
1225
1226_X_HIDDEN void
1227XftGlyphFontSpecCore (XftDraw			*draw,
1228		      _Xconst XftColor		*color,
1229		      _Xconst XftGlyphFontSpec	*glyphs,
1230		      int			nglyphs)
1231{
1232    Display	    *dpy = draw->dpy;
1233    XftGlyph	    *xftg;
1234    FT_UInt	    missing[XFT_NMISSING];
1235    FcBool	    glyphs_loaded;
1236    int		    nmissing;
1237    int		    i;
1238    XErrorHandler   prev_error;
1239    int		    x1, y1, x2, y2;
1240
1241    /*
1242     * Load missing glyphs
1243     */
1244    glyphs_loaded = FcFalse;
1245    x1 = y1 = x2 = y2 = 0;
1246    for (i = 0; i < nglyphs; i++)
1247    {
1248	XftFont		*public = glyphs[i].font;
1249	XGlyphInfo	gi;
1250	int		g_x1, g_x2, g_y1, g_y2;
1251
1252	nmissing = 0;
1253	if (XftFontCheckGlyph (dpy, public, FcTrue, glyphs[i].glyph, missing, &nmissing))
1254	    glyphs_loaded = FcTrue;
1255	if (nmissing)
1256	    XftFontLoadGlyphs (dpy, public, FcTrue, missing, nmissing);
1257
1258	XftGlyphExtents (dpy, public, &glyphs[i].glyph, 1, &gi);
1259	g_x1 = glyphs[i].x - gi.x;
1260	g_y1 = glyphs[i].y - gi.y;
1261	g_x2 = g_x1 + gi.width;
1262	g_y2 = g_y1 + gi.height;
1263	if (i)
1264	{
1265	    if (g_x1 < x1)
1266	    {
1267		if (g_x1 < 0)
1268		{
1269		    /* do nothing if the given glyphs are out of range */
1270		    short t = (short)(glyphs[i-1].font->max_advance_width
1271				      + glyphs[i-1].x);
1272		    if (t < 0 && glyphs[i-1].x > 0)
1273			goto bail1;
1274		}
1275		x1 = g_x1;
1276	    }
1277	    if (g_y1 < y1)
1278		y1 = g_y1;
1279	    if (g_x2 > x2)
1280		x2 = g_x2;
1281	    if (g_y2 > y2)
1282		y2 = g_y2;
1283	}
1284	else
1285	{
1286	    x1 = g_x1;
1287	    y1 = g_y1;
1288	    x2 = g_x2;
1289	    y2 = g_y2;
1290	}
1291    }
1292
1293    if (x1 == x2 || y1 == y2)
1294	goto bail1;
1295
1296    for (i = 0; i < nglyphs; i++)
1297	if (((XftFontInt *) glyphs[i].font)->info.antialias)
1298	    break;
1299
1300    if ((i != nglyphs || color->color.alpha != 0xffff) &&
1301	_XftSmoothGlyphPossible (draw))
1302    {
1303	XImage		*image;
1304        unsigned int    depth;
1305	int		width = x2 - x1, height = y2 - y1;
1306
1307	/*
1308	 * Try to get bits directly from the drawable; if that fails,
1309	 * use a temporary pixmap.  When it does fail, assume it
1310	 * will probably fail for a while and keep using temporary
1311	 * pixmaps for a while to avoid double round trips.
1312	 */
1313	if (draw->core.use_pixmap == 0)
1314	{
1315	    prev_error = XSetErrorHandler (XftGetImageErrorHandler);
1316	    image = XGetImage (dpy, draw->drawable,
1317			       x1, y1,
1318			       (unsigned)width, (unsigned)height, AllPlanes,
1319			       ZPixmap);
1320	    XSetErrorHandler (prev_error);
1321	    if (!image)
1322		draw->core.use_pixmap = XFT_ASSUME_PIXMAP;
1323	}
1324	else
1325	{
1326	    draw->core.use_pixmap--;
1327	    image = NULL;
1328	}
1329	if (!image && (depth = XftDrawDepth (draw)))
1330	{
1331	    Pixmap	pix;
1332	    GC		gc;
1333	    XGCValues	gcv;
1334
1335	    pix = XCreatePixmap (dpy, draw->drawable,
1336				 (unsigned)width, (unsigned)height, depth);
1337	    gcv.graphics_exposures = False;
1338	    gc = XCreateGC (dpy, pix, GCGraphicsExposures, &gcv);
1339	    XCopyArea (dpy, draw->drawable, pix, gc, x1, y1,
1340		       (unsigned)width, (unsigned)height, 0, 0);
1341	    XFreeGC (dpy, gc);
1342	    image = XGetImage (dpy, pix, 0, 0, (unsigned)width, (unsigned)height, AllPlanes,
1343			       ZPixmap);
1344	    XFreePixmap (dpy, pix);
1345	}
1346	if (!image)
1347	    goto bail1;
1348	image->red_mask = draw->visual->red_mask;
1349	image->green_mask = draw->visual->green_mask;
1350	image->blue_mask = draw->visual->blue_mask;
1351	if (image->byte_order != XftNativeByteOrder ())
1352	    XftSwapImage (image);
1353	for (i = 0; i < nglyphs; i++)
1354	{
1355	    XftFont	    *public = glyphs[i].font;
1356	    XftFontInt	    *font = (XftFontInt *) public;
1357	    XftSmoothGlyph  smooth = _XftSmoothGlyphFind (draw, public);
1358	    FT_UInt	    glyph = glyphs[i].glyph;
1359
1360	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1361		xftg = _XftGlyphDefault (dpy, public);
1362	    if (xftg)
1363	    {
1364		(*smooth) (image, xftg, glyphs[i].x - x1,
1365			   glyphs[i].y - y1, color);
1366	    }
1367	}
1368	if (image->byte_order != XftNativeByteOrder ())
1369	    XftSwapImage (image);
1370	XPutImage (dpy, draw->drawable, draw->core.gc, image, 0, 0, x1, y1,
1371		   (unsigned)width, (unsigned)height);
1372	XDestroyImage (image);
1373    }
1374    else
1375    {
1376	for (i = 0; i < nglyphs; i++)
1377	{
1378	    XftFont		*public = glyphs[i].font;
1379	    XftFontInt		*font = (XftFontInt *) public;
1380	    XftSharpGlyph	sharp = _XftSharpGlyphFind (draw, public);
1381	    FT_UInt		glyph = glyphs[i].glyph;
1382
1383	    if (glyph >= font->num_glyphs || !(xftg = font->glyphs[glyph]))
1384		xftg = _XftGlyphDefault (dpy, public);
1385	    if (xftg)
1386		(*sharp) (draw, xftg, glyphs[i].x, glyphs[i].y);
1387	}
1388    }
1389bail1:
1390    if (glyphs_loaded)
1391	for (i = 0; i < nglyphs; i++)
1392	    _XftFontManageMemory (dpy, glyphs[i].font);
1393}
1394