2 * Copyright © 2000 Keith Packard
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.
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.
26 * Ok, this is a pain. To share source pictures across multiple destinations,
27 * the screen for each drawable must be discovered.
31 _XftDrawScreen (Display *dpy, Drawable drawable, Visual *visual)
36 unsigned int width, height, borderWidth, depth;
37 /* Special case the most common environment */
38 if (ScreenCount (dpy) == 1)
41 * If we've got a visual, look for the screen that points at it.
42 * This requires no round trip.
46 for (s = 0; s < ScreenCount (dpy); s++)
48 XVisualInfo template, *ret;
51 template.visualid = visual->visualid;
53 ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask,
63 * Otherwise, as the server for the drawable geometry and find
64 * the screen from the root window.
65 * This takes a round trip.
67 if (XGetGeometry (dpy, drawable, &root, &x, &y, &width, &height,
68 &borderWidth, &depth))
70 for (s = 0; s < ScreenCount (dpy); s++)
72 if (RootWindow (dpy, s) == root)
77 * Make a guess -- it's probably wrong, but then the app probably
78 * handed us a bogus drawable in this case
83 _X_HIDDEN unsigned int
84 XftDrawDepth (XftDraw *draw)
90 unsigned int width, height, borderWidth, depth;
91 if (XGetGeometry (draw->dpy, draw->drawable,
92 &root, &x, &y, &width, &height,
93 &borderWidth, &depth))
99 _X_HIDDEN unsigned int
100 XftDrawBitsPerPixel (XftDraw *draw)
102 if (!draw->bits_per_pixel)
104 XPixmapFormatValues *formats;
108 if ((depth = XftDrawDepth (draw)) &&
109 (formats = XListPixmapFormats (draw->dpy, &nformats)))
113 for (i = 0; i < nformats; i++)
115 if (formats[i].depth == depth)
117 draw->bits_per_pixel = formats[i].bits_per_pixel;
124 return draw->bits_per_pixel;
128 XftDrawCreate (Display *dpy,
135 draw = (XftDraw *) malloc (sizeof (XftDraw));
140 draw->drawable = drawable;
141 draw->screen = _XftDrawScreen (dpy, drawable, visual);
142 draw->depth = 0; /* don't find out unless we need to know */
143 draw->bits_per_pixel = 0; /* don't find out unless we need to know */
144 draw->visual = visual;
145 draw->colormap = colormap;
146 draw->render.pict = 0;
147 draw->core.gc = NULL;
148 draw->core.use_pixmap = 0;
149 draw->clip_type = XftClipTypeNone;
150 draw->subwindow_mode = ClipByChildren;
151 XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
156 XftDrawCreateBitmap (Display *dpy,
161 draw = (XftDraw *) malloc (sizeof (XftDraw));
165 draw->drawable = (Drawable) bitmap;
166 draw->screen = _XftDrawScreen (dpy, bitmap, NULL);
168 draw->bits_per_pixel = 1;
171 draw->render.pict = 0;
172 draw->core.gc = NULL;
173 draw->core.use_pixmap = 0;
174 draw->clip_type = XftClipTypeNone;
175 draw->subwindow_mode = ClipByChildren;
176 XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
181 XftDrawCreateAlpha (Display *dpy,
187 draw = (XftDraw *) malloc (sizeof (XftDraw));
191 draw->drawable = (Drawable) pixmap;
192 draw->screen = _XftDrawScreen (dpy, pixmap, NULL);
194 draw->bits_per_pixel = 0; /* don't find out until we need it */
197 draw->render.pict = 0;
198 draw->core.gc = NULL;
199 draw->core.use_pixmap = 0;
200 draw->clip_type = XftClipTypeNone;
201 draw->subwindow_mode = ClipByChildren;
202 XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
206 static XRenderPictFormat *
207 _XftDrawFormat (XftDraw *draw)
209 XftDisplayInfo *info = _XftDisplayInfoGet (draw->dpy, True);
211 if (!info || !info->hasRender)
214 if (draw->visual == NULL)
216 XRenderPictFormat pf;
218 pf.type = PictTypeDirect;
219 pf.depth = XftDrawDepth (draw);
221 pf.direct.alphaMask = (1 << pf.depth) - 1;
222 return XRenderFindFormat (draw->dpy,
226 PictFormatAlphaMask),
231 return XRenderFindVisualFormat (draw->dpy, draw->visual);
235 XftDrawChange (XftDraw *draw,
238 draw->drawable = drawable;
239 if (draw->render.pict)
241 XRenderFreePicture (draw->dpy, draw->render.pict);
242 draw->render.pict = 0;
246 XFreeGC (draw->dpy, draw->core.gc);
247 draw->core.gc = NULL;
252 XftDrawDisplay (XftDraw *draw)
258 XftDrawDrawable (XftDraw *draw)
260 return draw->drawable;
264 XftDrawColormap (XftDraw *draw)
266 return draw->colormap;
270 XftDrawVisual (XftDraw *draw)
276 XftDrawDestroy (XftDraw *draw)
278 if (draw->render.pict)
279 XRenderFreePicture (draw->dpy, draw->render.pict);
281 XFreeGC (draw->dpy, draw->core.gc);
282 switch (draw->clip_type) {
283 case XftClipTypeRegion:
284 XDestroyRegion (draw->clip.region);
286 case XftClipTypeRectangles:
287 free (draw->clip.rect);
289 case XftClipTypeNone:
292 XftMemFree (XFT_MEM_DRAW, sizeof (XftDraw));
297 XftDrawSrcPicture (XftDraw *draw, _Xconst XftColor *color)
299 Display *dpy = draw->dpy;
300 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True);
302 XftColor bitmapColor;
304 if (!info || !info->solidFormat)
308 * Monochrome targets require special handling; the PictOp controls
309 * the color, and the color must be opaque
311 if (!draw->visual && draw->depth == 1)
313 bitmapColor.color.alpha = 0xffff;
314 bitmapColor.color.red = 0xffff;
315 bitmapColor.color.green = 0xffff;
316 bitmapColor.color.blue = 0xffff;
317 color = &bitmapColor;
321 * See if there's one already available
323 for (i = 0; i < XFT_NUM_SOLID_COLOR; i++)
325 if (info->colors[i].pict &&
326 info->colors[i].screen == draw->screen &&
327 !memcmp ((void *) &color->color,
328 (void *) &info->colors[i].color,
329 sizeof (XRenderColor)))
330 return info->colors[i].pict;
333 * Pick one to replace at random
335 i = (unsigned int) rand () % XFT_NUM_SOLID_COLOR;
337 * Recreate if it was for the wrong screen
339 if (info->colors[i].screen != draw->screen && info->colors[i].pict)
341 XRenderFreePicture (dpy, info->colors[i].pict);
342 info->colors[i].pict = 0;
345 * Create picture if necessary
347 if (!info->colors[i].pict)
350 XRenderPictureAttributes pa;
352 pix = XCreatePixmap (dpy, RootWindow (dpy, draw->screen), 1, 1,
353 info->solidFormat->depth);
355 info->colors[i].pict = XRenderCreatePicture (draw->dpy,
359 XFreePixmap (dpy, pix);
362 * Set to the new color
364 info->colors[i].color = color->color;
365 info->colors[i].screen = draw->screen;
366 XRenderFillRectangle (dpy, PictOpSrc,
367 info->colors[i].pict,
368 &color->color, 0, 0, 1, 1);
369 return info->colors[i].pict;
373 _XftDrawOp (_Xconst XftDraw *draw, _Xconst XftColor *color)
375 if (draw->visual || draw->depth != 1)
377 if (color->color.alpha >= 0x8000)
379 return PictOpOutReverse;
383 _XftDrawRenderPrepare (XftDraw *draw)
385 if (!draw->render.pict)
387 XRenderPictFormat *format;
388 XRenderPictureAttributes pa;
389 unsigned long mask = 0;
391 format = _XftDrawFormat (draw);
395 if (draw->subwindow_mode == IncludeInferiors)
397 pa.subwindow_mode = IncludeInferiors;
398 mask |= CPSubwindowMode;
400 draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable,
402 if (!draw->render.pict)
404 switch (draw->clip_type) {
405 case XftClipTypeRegion:
406 XRenderSetPictureClipRegion (draw->dpy, draw->render.pict,
409 case XftClipTypeRectangles:
410 XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict,
411 draw->clip.rect->xOrigin,
412 draw->clip.rect->yOrigin,
413 XftClipRects(draw->clip.rect),
416 case XftClipTypeNone:
424 _XftDrawCorePrepare (XftDraw *draw, _Xconst XftColor *color)
429 unsigned long mask = 0;
430 if (draw->subwindow_mode == IncludeInferiors)
432 gcv.subwindow_mode = IncludeInferiors;
433 mask |= GCSubwindowMode;
435 draw->core.gc = XCreateGC (draw->dpy, draw->drawable, mask, &gcv);
438 switch (draw->clip_type) {
439 case XftClipTypeRegion:
440 XSetRegion (draw->dpy, draw->core.gc, draw->clip.region);
442 case XftClipTypeRectangles:
443 XSetClipRectangles (draw->dpy, draw->core.gc,
444 draw->clip.rect->xOrigin,
445 draw->clip.rect->yOrigin,
446 XftClipRects (draw->clip.rect),
450 case XftClipTypeNone:
454 XSetForeground (draw->dpy, draw->core.gc, color->pixel);
459 XftDrawPicture (XftDraw *draw)
461 if (!_XftDrawRenderPrepare (draw))
463 return draw->render.pict;
466 #define NUM_LOCAL 1024
469 XftDrawGlyphs (XftDraw *draw,
470 _Xconst XftColor *color,
474 _Xconst FT_UInt *glyphs,
477 XftFontInt *font = (XftFontInt *) pub;
483 if (_XftDrawRenderPrepare (draw) &&
484 (src = XftDrawSrcPicture (draw, color)))
485 XftGlyphRender (draw->dpy, _XftDrawOp (draw, color),
486 src, pub, draw->render.pict,
487 0, 0, x, y, glyphs, nglyphs);
491 if (_XftDrawCorePrepare (draw, color))
492 XftGlyphCore (draw, color, pub, x, y, glyphs, nglyphs);
497 XftDrawString8 (XftDraw *draw,
498 _Xconst XftColor *color,
502 _Xconst FcChar8 *string,
505 FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
508 if (XftDebug () & XFT_DBG_DRAW)
509 printf ("DrawString \"%*.*s\"\n", len, len, string);
511 if (len <= NUM_LOCAL)
512 glyphs = glyphs_local;
515 glyphs = malloc (len * sizeof (FT_UInt));
519 for (i = 0; i < len; i++)
520 glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
521 XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
522 if (glyphs != glyphs_local)
527 XftDrawString16 (XftDraw *draw,
528 _Xconst XftColor *color,
532 _Xconst FcChar16 *string,
535 FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
538 if (len <= NUM_LOCAL)
539 glyphs = glyphs_local;
542 glyphs = malloc (len * sizeof (FT_UInt));
546 for (i = 0; i < len; i++)
547 glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
549 XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
550 if (glyphs != glyphs_local)
555 XftDrawString32 (XftDraw *draw,
556 _Xconst XftColor *color,
560 _Xconst FcChar32 *string,
563 FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
566 if (len <= NUM_LOCAL)
567 glyphs = glyphs_local;
570 glyphs = malloc (len * sizeof (FT_UInt));
574 for (i = 0; i < len; i++)
575 glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
577 XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
578 if (glyphs != glyphs_local)
583 XftDrawStringUtf8 (XftDraw *draw,
584 _Xconst XftColor *color,
588 _Xconst FcChar8 *string,
591 FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
598 glyphs = glyphs_local;
600 while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0)
604 glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
607 if (glyphs != glyphs_local)
611 memcpy (glyphs_new, glyphs, size * sizeof (FT_UInt));
613 if (glyphs != glyphs_local)
617 glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4);
621 XftDrawGlyphs (draw, color, pub, x, y, glyphs, i);
622 if (glyphs != glyphs_local)
627 XftDrawStringUtf16 (XftDraw *draw,
628 _Xconst XftColor *color,
632 _Xconst FcChar8 *string,
636 FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
643 glyphs = glyphs_local;
645 while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0)
649 glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
652 if (glyphs != glyphs_local)
656 memcpy (glyphs_new, glyphs, size * sizeof (FT_UInt));
658 if (glyphs != glyphs_local)
662 glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4);
666 XftDrawGlyphs (draw, color, pub, x, y, glyphs, i);
667 if (glyphs != glyphs_local)
672 XftDrawGlyphSpec (XftDraw *draw,
673 _Xconst XftColor *color,
675 _Xconst XftGlyphSpec *glyphs,
678 XftFontInt *font = (XftFontInt *) pub;
684 if (_XftDrawRenderPrepare (draw) &&
685 (src = XftDrawSrcPicture (draw, color)))
687 XftGlyphSpecRender (draw->dpy, _XftDrawOp (draw, color),
688 src, pub, draw->render.pict,
694 if (_XftDrawCorePrepare (draw, color))
695 XftGlyphSpecCore (draw, color, pub, glyphs, len);
700 XftDrawGlyphFontSpec (XftDraw *draw,
701 _Xconst XftColor *color,
702 _Xconst XftGlyphFontSpec *glyphs,
712 if (((XftFontInt *) glyphs[i].font)->format)
715 while (i < len && ((XftFontInt *) glyphs[i].font)->format)
717 if (_XftDrawRenderPrepare (draw) &&
718 (src = XftDrawSrcPicture (draw, color)))
720 XftGlyphFontSpecRender (draw->dpy, _XftDrawOp (draw, color),
721 src, draw->render.pict,
722 0, 0, glyphs + start , i - start);
727 while (i < len && !((XftFontInt *) glyphs[i].font)->format)
729 if (_XftDrawCorePrepare (draw, color))
730 XftGlyphFontSpecCore (draw, color, glyphs + start, i - start);
736 XftDrawCharSpec (XftDraw *draw,
737 _Xconst XftColor *color,
739 _Xconst XftCharSpec *chars,
742 XftGlyphSpec *glyphs, glyphs_local[NUM_LOCAL];
745 if (len <= NUM_LOCAL)
746 glyphs = glyphs_local;
749 glyphs = malloc (len * sizeof (XftGlyphSpec));
753 for (i = 0; i < len; i++)
755 glyphs[i].glyph = XftCharIndex(draw->dpy, pub, chars[i].ucs4);
756 glyphs[i].x = chars[i].x;
757 glyphs[i].y = chars[i].y;
760 XftDrawGlyphSpec (draw, color, pub, glyphs, len);
761 if (glyphs != glyphs_local)
766 XftDrawCharFontSpec (XftDraw *draw,
767 _Xconst XftColor *color,
768 _Xconst XftCharFontSpec *chars,
771 XftGlyphFontSpec *glyphs, glyphs_local[NUM_LOCAL];
774 if (len <= NUM_LOCAL)
775 glyphs = glyphs_local;
778 glyphs = malloc (len * sizeof (XftGlyphFontSpec));
782 for (i = 0; i < len; i++)
784 glyphs[i].font = chars[i].font;
785 glyphs[i].glyph = XftCharIndex(draw->dpy, glyphs[i].font, chars[i].ucs4);
786 glyphs[i].x = chars[i].x;
787 glyphs[i].y = chars[i].y;
790 XftDrawGlyphFontSpec (draw, color, glyphs, len);
791 if (glyphs != glyphs_local)
796 XftDrawRect (XftDraw *draw,
797 _Xconst XftColor *color,
803 if (_XftDrawRenderPrepare (draw))
805 XRenderFillRectangle (draw->dpy, PictOpSrc, draw->render.pict,
806 &color->color, x, y, width, height);
808 else if (_XftDrawCorePrepare (draw, color))
810 /* note: not XftRectCore() */
811 XSetForeground (draw->dpy, draw->core.gc, color->pixel);
812 XFillRectangle (draw->dpy, draw->drawable, draw->core.gc,
813 x, y, width, height);
818 XftDrawSetClip (XftDraw *draw,
824 * Check for quick exits
826 if (!r && draw->clip_type == XftClipTypeNone)
830 draw->clip_type == XftClipTypeRegion &&
831 XEqualRegion (r, draw->clip.region))
837 * Duplicate the region so future changes can be short circuited
841 n = XCreateRegion ();
844 if (!XUnionRegion (n, r, n))
853 * Destroy existing clip
855 switch (draw->clip_type) {
856 case XftClipTypeRegion:
857 XDestroyRegion (draw->clip.region);
859 case XftClipTypeRectangles:
860 free (draw->clip.rect);
862 case XftClipTypeNone:
871 draw->clip_type = XftClipTypeRegion;
872 draw->clip.region = n;
876 draw->clip_type = XftClipTypeNone;
879 * Apply new clip to existing objects
881 if (draw->render.pict)
884 XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, n);
887 XRenderPictureAttributes pa;
889 XRenderChangePicture (draw->dpy, draw->render.pict,
896 XSetRegion (draw->dpy, draw->core.gc, draw->clip.region);
898 XSetClipMask (draw->dpy, draw->core.gc, None);
904 XftDrawSetClipRectangles (XftDraw *draw,
907 _Xconst XRectangle *rects,
910 XftClipRect *new = NULL;
913 * Check for quick exit
915 if (draw->clip_type == XftClipTypeRectangles &&
916 draw->clip.rect->n == n &&
917 (n == 0 || (draw->clip.rect->xOrigin == xOrigin &&
918 draw->clip.rect->yOrigin == yOrigin)) &&
919 !memcmp (XftClipRects (draw->clip.rect), rects, n * sizeof (XRectangle)))
925 * Duplicate the region so future changes can be short circuited
927 new = malloc (sizeof (XftClipRect) + n * sizeof (XRectangle));
932 new->xOrigin = xOrigin;
933 new->yOrigin = yOrigin;
934 memcpy (XftClipRects (new), rects, n * sizeof (XRectangle));
937 * Destroy existing clip
939 switch (draw->clip_type) {
940 case XftClipTypeRegion:
941 XDestroyRegion (draw->clip.region);
943 case XftClipTypeRectangles:
944 free (draw->clip.rect);
946 case XftClipTypeNone:
953 draw->clip_type = XftClipTypeRectangles;
954 draw->clip.rect = new;
956 * Apply new clip to existing objects
958 if (draw->render.pict)
960 XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict,
968 XSetClipRectangles (draw->dpy, draw->core.gc,
979 XftDrawSetSubwindowMode (XftDraw *draw, int mode)
981 if (mode == draw->subwindow_mode)
983 draw->subwindow_mode = mode;
984 if (draw->render.pict)
986 XRenderPictureAttributes pa;
988 pa.subwindow_mode = mode;
989 XRenderChangePicture (draw->dpy, draw->render.pict,
990 CPSubwindowMode, &pa);
993 XSetSubwindowMode (draw->dpy, draw->core.gc, mode);