2
* $XFree86: xc/lib/Xft/xftdraw.c,v 1.25 2002/10/11 17:53:02 keithp Exp $
4
* Copyright � 2000 Keith Packard, member of The XFree86 Project, Inc.
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.
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.
30
#include <X11/Xutil.h>
33
* Ok, this is a pain. To share source pictures across multiple destinations,
34
* the screen for each drawable must be discovered.
38
_XftDrawScreen (Display *dpy, Drawable drawable, Visual *visual)
43
unsigned int width, height, borderWidth, depth;
44
/* Special case the most common environment */
45
if (ScreenCount (dpy) == 1)
48
* If we've got a visual, look for the screen that points at it.
49
* This requires no round trip.
53
for (s = 0; s < ScreenCount (dpy); s++)
55
XVisualInfo template, *ret;
58
template.visualid = visual->visualid;
60
ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask,
70
* Otherwise, as the server for the drawable geometry and find
71
* the screen from the root window.
72
* This takes a round trip.
74
if (XGetGeometry (dpy, drawable, &root, &x, &y, &width, &height,
75
&borderWidth, &depth))
77
for (s = 0; s < ScreenCount (dpy); s++)
79
if (RootWindow (dpy, s) == root)
84
* Make a guess -- it's probably wrong, but then the app probably
85
* handed us a bogus drawable in this case
91
XftDrawDepth (XftDraw *draw)
97
unsigned int width, height, borderWidth, depth;
98
if (XGetGeometry (draw->dpy, draw->drawable,
99
&root, &x, &y, &width, &height,
100
&borderWidth, &depth))
107
XftDrawBitsPerPixel (XftDraw *draw)
109
if (!draw->bits_per_pixel)
111
XPixmapFormatValues *formats;
115
if ((depth = XftDrawDepth (draw)) &&
116
(formats = XListPixmapFormats (draw->dpy, &nformats)))
120
for (i = 0; i < nformats; i++)
122
if (formats[i].depth == depth)
124
draw->bits_per_pixel = formats[i].bits_per_pixel;
131
return draw->bits_per_pixel;
135
XftDrawCreate (Display *dpy,
142
draw = (XftDraw *) malloc (sizeof (XftDraw));
147
draw->drawable = drawable;
148
draw->screen = _XftDrawScreen (dpy, drawable, visual);
149
draw->depth = 0; /* don't find out unless we need to know */
150
draw->bits_per_pixel = 0; /* don't find out unless we need to know */
151
draw->visual = visual;
152
draw->colormap = colormap;
153
draw->render.pict = 0;
155
draw->core.use_pixmap = 0;
156
draw->clip_type = XftClipTypeNone;
157
draw->subwindow_mode = ClipByChildren;
158
XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
163
XftDrawCreateBitmap (Display *dpy,
168
draw = (XftDraw *) malloc (sizeof (XftDraw));
172
draw->drawable = (Drawable) bitmap;
173
draw->screen = _XftDrawScreen (dpy, bitmap, 0);
175
draw->bits_per_pixel = 1;
178
draw->render.pict = 0;
180
draw->clip_type = XftClipTypeNone;
181
draw->subwindow_mode = ClipByChildren;
182
XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
187
XftDrawCreateAlpha (Display *dpy,
193
draw = (XftDraw *) malloc (sizeof (XftDraw));
197
draw->drawable = (Drawable) pixmap;
198
draw->screen = _XftDrawScreen (dpy, pixmap, 0);
200
draw->bits_per_pixel = 0; /* don't find out until we need it */
203
draw->render.pict = 0;
205
draw->clip_type = XftClipTypeNone;
206
draw->subwindow_mode = ClipByChildren;
207
XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
211
static XRenderPictFormat *
212
_XftDrawFormat (XftDraw *draw)
214
XftDisplayInfo *info = _XftDisplayInfoGet (draw->dpy, True);
216
if (!info->hasRender)
219
if (draw->visual == 0)
221
XRenderPictFormat pf;
223
pf.type = PictTypeDirect;
224
pf.depth = XftDrawDepth (draw);
226
pf.direct.alphaMask = (1 << pf.depth) - 1;
227
return XRenderFindFormat (draw->dpy,
231
PictFormatAlphaMask),
236
return XRenderFindVisualFormat (draw->dpy, draw->visual);
240
XftDrawChange (XftDraw *draw,
243
draw->drawable = drawable;
244
if (draw->render.pict)
246
XRenderFreePicture (draw->dpy, draw->render.pict);
247
draw->render.pict = 0;
251
XFreeGC (draw->dpy, draw->core.gc);
257
XftDrawDisplay (XftDraw *draw)
263
XftDrawDrawable (XftDraw *draw)
265
return draw->drawable;
269
XftDrawColormap (XftDraw *draw)
271
return draw->colormap;
275
XftDrawVisual (XftDraw *draw)
281
XftDrawDestroy (XftDraw *draw)
283
if (draw->render.pict)
284
XRenderFreePicture (draw->dpy, draw->render.pict);
286
XFreeGC (draw->dpy, draw->core.gc);
287
switch (draw->clip_type) {
288
case XftClipTypeRegion:
289
XDestroyRegion (draw->clip.region);
291
case XftClipTypeRectangles:
292
free (draw->clip.rect);
294
case XftClipTypeNone:
297
XftMemFree (XFT_MEM_DRAW, sizeof (XftDraw));
302
XftDrawSrcPicture (XftDraw *draw, _Xconst XftColor *color)
304
Display *dpy = draw->dpy;
305
XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True);
307
XftColor bitmapColor;
313
* Monochrome targets require special handling; the PictOp controls
314
* the color, and the color must be opaque
316
if (!draw->visual && draw->depth == 1)
318
bitmapColor.color.alpha = 0xffff;
319
bitmapColor.color.red = 0xffff;
320
bitmapColor.color.green = 0xffff;
321
bitmapColor.color.blue = 0xffff;
322
color = &bitmapColor;
326
* See if there's one already available
328
for (i = 0; i < XFT_NUM_SOLID_COLOR; i++)
330
if (info->colors[i].pict &&
331
info->colors[i].screen == draw->screen &&
332
!memcmp ((void *) &color->color,
333
(void *) &info->colors[i].color,
334
sizeof (XRenderColor)))
335
return info->colors[i].pict;
338
* Pick one to replace at random
340
i = (unsigned int) rand () % XFT_NUM_SOLID_COLOR;
342
* Recreate if it was for the wrong screen
344
if (info->colors[i].screen != draw->screen && info->colors[i].pict)
346
XRenderFreePicture (dpy, info->colors[i].pict);
347
info->colors[i].pict = 0;
350
* Create picture if necessary
352
if (!info->colors[i].pict)
355
XRenderPictureAttributes pa;
357
pix = XCreatePixmap (dpy, RootWindow (dpy, draw->screen), 1, 1,
358
info->solidFormat->depth);
360
info->colors[i].pict = XRenderCreatePicture (draw->dpy,
364
XFreePixmap (dpy, pix);
367
* Set to the new color
369
info->colors[i].color = color->color;
370
info->colors[i].screen = draw->screen;
371
XRenderFillRectangle (dpy, PictOpSrc,
372
info->colors[i].pict,
373
&color->color, 0, 0, 1, 1);
374
return info->colors[i].pict;
378
_XftDrawOp (_Xconst XftDraw *draw, _Xconst XftColor *color)
380
if (draw->visual || draw->depth != 1)
382
if (color->color.alpha >= 0x8000)
384
return PictOpOutReverse;
388
_XftDrawRenderPrepare (XftDraw *draw)
390
if (!draw->render.pict)
392
XRenderPictFormat *format;
393
XRenderPictureAttributes pa;
394
unsigned long mask = 0;
396
format = _XftDrawFormat (draw);
400
if (draw->subwindow_mode == IncludeInferiors)
402
pa.subwindow_mode = IncludeInferiors;
403
mask |= CPSubwindowMode;
405
draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable,
407
if (!draw->render.pict)
409
switch (draw->clip_type) {
410
case XftClipTypeRegion:
411
XRenderSetPictureClipRegion (draw->dpy, draw->render.pict,
414
case XftClipTypeRectangles:
415
XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict,
416
draw->clip.rect->xOrigin,
417
draw->clip.rect->yOrigin,
418
XftClipRects(draw->clip.rect),
421
case XftClipTypeNone:
429
_XftDrawCorePrepare (XftDraw *draw, _Xconst XftColor *color)
434
unsigned long mask = 0;
435
if (draw->subwindow_mode == IncludeInferiors)
437
gcv.subwindow_mode = IncludeInferiors;
438
mask |= GCSubwindowMode;
440
draw->core.gc = XCreateGC (draw->dpy, draw->drawable, mask, &gcv);
443
switch (draw->clip_type) {
444
case XftClipTypeRegion:
445
XSetRegion (draw->dpy, draw->core.gc, draw->clip.region);
447
case XftClipTypeRectangles:
448
XSetClipRectangles (draw->dpy, draw->core.gc,
449
draw->clip.rect->xOrigin,
450
draw->clip.rect->yOrigin,
451
XftClipRects (draw->clip.rect),
455
case XftClipTypeNone:
459
XSetForeground (draw->dpy, draw->core.gc, color->pixel);
464
XftDrawPicture (XftDraw *draw)
466
if (!_XftDrawRenderPrepare (draw))
468
return draw->render.pict;
471
#define NUM_LOCAL 1024
474
XftDrawGlyphs (XftDraw *draw,
475
_Xconst XftColor *color,
479
_Xconst FT_UInt *glyphs,
482
XftFontInt *font = (XftFontInt *) pub;
488
if (_XftDrawRenderPrepare (draw) &&
489
(src = XftDrawSrcPicture (draw, color)))
490
XftGlyphRender (draw->dpy, _XftDrawOp (draw, color),
491
src, pub, draw->render.pict,
492
0, 0, x, y, glyphs, nglyphs);
496
if (_XftDrawCorePrepare (draw, color))
497
XftGlyphCore (draw, color, pub, x, y, glyphs, nglyphs);
502
XftDrawString8 (XftDraw *draw,
503
_Xconst XftColor *color,
507
_Xconst FcChar8 *string,
510
FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
513
if (XftDebug () & XFT_DBG_DRAW)
514
printf ("DrawString \"%*.*s\"\n", len, len, string);
516
if (len <= NUM_LOCAL)
517
glyphs = glyphs_local;
520
glyphs = malloc (len * sizeof (FT_UInt));
524
for (i = 0; i < len; i++)
525
glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
526
XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
527
if (glyphs != glyphs_local)
532
XftDrawString16 (XftDraw *draw,
533
_Xconst XftColor *color,
537
_Xconst FcChar16 *string,
540
FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
543
if (len <= NUM_LOCAL)
544
glyphs = glyphs_local;
547
glyphs = malloc (len * sizeof (FT_UInt));
551
for (i = 0; i < len; i++)
552
glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
554
XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
555
if (glyphs != glyphs_local)
560
XftDrawString32 (XftDraw *draw,
561
_Xconst XftColor *color,
565
_Xconst FcChar32 *string,
568
FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
571
if (len <= NUM_LOCAL)
572
glyphs = glyphs_local;
575
glyphs = malloc (len * sizeof (FT_UInt));
579
for (i = 0; i < len; i++)
580
glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
582
XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
583
if (glyphs != glyphs_local)
588
XftDrawStringUtf8 (XftDraw *draw,
589
_Xconst XftColor *color,
593
_Xconst FcChar8 *string,
596
FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
603
glyphs = glyphs_local;
605
while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0)
609
glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
612
if (glyphs != glyphs_local)
616
memcpy (glyphs_new, glyphs, size * sizeof (FT_UInt));
618
if (glyphs != glyphs_local)
622
glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4);
626
XftDrawGlyphs (draw, color, pub, x, y, glyphs, i);
627
if (glyphs != glyphs_local)
632
XftDrawStringUtf16 (XftDraw *draw,
633
_Xconst XftColor *color,
637
_Xconst FcChar8 *string,
641
FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
648
glyphs = glyphs_local;
650
while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0)
654
glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
657
if (glyphs != glyphs_local)
661
memcpy (glyphs_new, glyphs, size * sizeof (FT_UInt));
663
if (glyphs != glyphs_local)
667
glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4);
671
XftDrawGlyphs (draw, color, pub, x, y, glyphs, i);
672
if (glyphs != glyphs_local)
677
XftDrawGlyphSpec (XftDraw *draw,
678
_Xconst XftColor *color,
680
_Xconst XftGlyphSpec *glyphs,
683
XftFontInt *font = (XftFontInt *) pub;
689
if (_XftDrawRenderPrepare (draw) &&
690
(src = XftDrawSrcPicture (draw, color)))
692
XftGlyphSpecRender (draw->dpy, _XftDrawOp (draw, color),
693
src, pub, draw->render.pict,
699
if (_XftDrawCorePrepare (draw, color))
700
XftGlyphSpecCore (draw, color, pub, glyphs, len);
705
XftDrawGlyphFontSpec (XftDraw *draw,
706
_Xconst XftColor *color,
707
_Xconst XftGlyphFontSpec *glyphs,
717
if (((XftFontInt *) glyphs[i].font)->format)
720
while (i < len && ((XftFontInt *) glyphs[i].font)->format)
722
if (_XftDrawRenderPrepare (draw) &&
723
(src = XftDrawSrcPicture (draw, color)))
725
XftGlyphFontSpecRender (draw->dpy, _XftDrawOp (draw, color),
726
src, draw->render.pict,
727
0, 0, glyphs, i - start);
732
while (i < len && !((XftFontInt *) glyphs[i].font)->format)
734
if (_XftDrawCorePrepare (draw, color))
735
XftGlyphFontSpecCore (draw, color, glyphs, len);
741
XftDrawCharSpec (XftDraw *draw,
742
_Xconst XftColor *color,
744
_Xconst XftCharSpec *chars,
747
XftGlyphSpec *glyphs, glyphs_local[NUM_LOCAL];
750
if (len <= NUM_LOCAL)
751
glyphs = glyphs_local;
754
glyphs = malloc (len * sizeof (XftGlyphSpec));
758
for (i = 0; i < len; i++)
760
glyphs[i].glyph = XftCharIndex(draw->dpy, pub, chars[i].ucs4);
761
glyphs[i].x = chars[i].x;
762
glyphs[i].y = chars[i].y;
765
XftDrawGlyphSpec (draw, color, pub, glyphs, len);
766
if (glyphs != glyphs_local)
771
XftDrawCharFontSpec (XftDraw *draw,
772
_Xconst XftColor *color,
773
_Xconst XftCharFontSpec *chars,
776
XftGlyphFontSpec *glyphs, glyphs_local[NUM_LOCAL];
779
if (len <= NUM_LOCAL)
780
glyphs = glyphs_local;
783
glyphs = malloc (len * sizeof (XftGlyphFontSpec));
787
for (i = 0; i < len; i++)
789
glyphs[i].font = chars[i].font;
790
glyphs[i].glyph = XftCharIndex(draw->dpy, glyphs[i].font, chars[i].ucs4);
791
glyphs[i].x = chars[i].x;
792
glyphs[i].y = chars[i].y;
795
XftDrawGlyphFontSpec (draw, color, glyphs, len);
796
if (glyphs != glyphs_local)
801
XftDrawRect (XftDraw *draw,
802
_Xconst XftColor *color,
808
if (_XftDrawRenderPrepare (draw))
810
XRenderFillRectangle (draw->dpy, PictOpOver, draw->render.pict,
811
&color->color, x, y, width, height);
813
else if (_XftDrawCorePrepare (draw, color))
815
XftRectCore (draw, color, x, y, width, height);
820
XftDrawSetClip (XftDraw *draw,
826
* Check for quick exits
828
if (!r && draw->clip_type == XftClipTypeNone)
832
draw->clip_type == XftClipTypeRegion &&
833
XEqualRegion (r, draw->clip.region))
839
* Duplicate the region so future changes can be short circuited
843
n = XCreateRegion ();
846
if (!XUnionRegion (n, r, n))
855
* Destroy existing clip
857
switch (draw->clip_type) {
858
case XftClipTypeRegion:
859
XDestroyRegion (draw->clip.region);
861
case XftClipTypeRectangles:
862
free (draw->clip.rect);
864
case XftClipTypeNone:
873
draw->clip_type = XftClipTypeRegion;
874
draw->clip.region = n;
878
draw->clip_type = XftClipTypeNone;
881
* Apply new clip to existing objects
883
if (draw->render.pict)
886
XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, n);
889
XRenderPictureAttributes pa;
891
XRenderChangePicture (draw->dpy, draw->render.pict,
898
XSetRegion (draw->dpy, draw->core.gc, draw->clip.region);
900
XSetClipMask (draw->dpy, draw->core.gc, None);
906
XftDrawSetClipRectangles (XftDraw *draw,
909
_Xconst XRectangle *rects,
912
XftClipRect *new = 0;
915
* Check for quick exit
917
if (draw->clip_type == XftClipTypeRectangles &&
918
!memcmp (XftClipRects (draw->clip.rect), rects, n * sizeof (XRectangle)))
924
* Duplicate the region so future changes can be short circuited
926
new = malloc (sizeof (XftClipRect) + n * sizeof (XRectangle));
931
new->xOrigin = xOrigin;
932
new->yOrigin = yOrigin;
933
memcpy (XftClipRects (new), rects, n * sizeof (XRectangle));
936
* Destroy existing clip
938
switch (draw->clip_type) {
939
case XftClipTypeRegion:
940
XDestroyRegion (draw->clip.region);
942
case XftClipTypeRectangles:
943
free (draw->clip.rect);
945
case XftClipTypeNone:
952
draw->clip_type = XftClipTypeRectangles;
953
draw->clip.rect = new;
955
* Apply new clip to existing objects
957
if (draw->render.pict)
959
XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict,
967
XSetClipRectangles (draw->dpy, draw->core.gc,
978
XftDrawSetSubwindowMode (XftDraw *draw, int mode)
980
if (mode == draw->subwindow_mode)
982
draw->subwindow_mode = mode;
983
if (draw->render.pict)
985
XRenderPictureAttributes pa;
987
pa.subwindow_mode = mode;
988
XRenderChangePicture (draw->dpy, draw->render.pict,
989
CPSubwindowMode, &pa);
992
XSetSubwindowMode (draw->dpy, draw->core.gc, mode);