/* * $XFree86: xc/lib/Xft/xftdraw.c,v 1.15 2001/05/16 19:20:43 keithp Exp $ * * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "xftint.h" #include <X11/Xutil.h> XftDraw * XftDrawCreate (Display *dpy, Drawable drawable, Visual *visual, Colormap colormap) { XftDraw *draw; draw = (XftDraw *) malloc (sizeof (XftDraw)); if (!draw) return 0; draw->dpy = dpy; draw->drawable = drawable; draw->visual = visual; draw->colormap = colormap; draw->core_set = False; draw->render_set = False; draw->render_able = False; draw->clip = 0; return draw; } XftDraw * XftDrawCreateBitmap (Display *dpy, Pixmap bitmap) { XftDraw *draw; draw = (XftDraw *) malloc (sizeof (XftDraw)); if (!draw) return 0; draw->dpy = dpy; draw->drawable = (Drawable) bitmap; draw->visual = 0; draw->colormap = 0; draw->core_set = False; draw->render_set = False; draw->render_able = False; draw->clip = 0; return draw; } static XRenderPictFormat * _XftDrawFormat (XftDraw *draw) { if (draw->visual == 0) { XRenderPictFormat pf; pf.type = PictTypeDirect; pf.depth = 1; pf.direct.alpha = 0; pf.direct.alphaMask = 1; return XRenderFindFormat (draw->dpy, (PictFormatType| PictFormatDepth| PictFormatAlpha| PictFormatAlphaMask), &pf, 0); } else return XRenderFindVisualFormat (draw->dpy, draw->visual); } static XRenderPictFormat * _XftDrawFgFormat (XftDraw *draw) { XRenderPictFormat pf; if (draw->visual == 0) { pf.type = PictTypeDirect; pf.depth = 1; pf.direct.alpha = 0; pf.direct.alphaMask = 1; return XRenderFindFormat (draw->dpy, (PictFormatType| PictFormatDepth| PictFormatAlpha| PictFormatAlphaMask), &pf, 0); } else { pf.type = PictTypeDirect; pf.depth = 32; pf.direct.redMask = 0xff; pf.direct.greenMask = 0xff; pf.direct.blueMask = 0xff; pf.direct.alphaMask = 0xff; return XRenderFindFormat (draw->dpy, (PictFormatType| PictFormatDepth| PictFormatRedMask| PictFormatGreenMask| PictFormatBlueMask| PictFormatAlphaMask), &pf, 0); } } void XftDrawChange (XftDraw *draw, Drawable drawable) { draw->drawable = drawable; if (draw->render_able) { XRenderPictFormat *format; XRenderFreePicture (draw->dpy, draw->render.pict); format = XRenderFindVisualFormat (draw->dpy, draw->visual); draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable, format, 0, 0); } } void XftDrawDestroy (XftDraw *draw) { int n; if (draw->render_able) { XRenderFreePicture (draw->dpy, draw->render.pict); for (n = 0; n < XFT_DRAW_N_SRC; n++) XRenderFreePicture (draw->dpy, draw->render.src[n].pict); } if (draw->core_set) XFreeGC (draw->dpy, draw->core.draw_gc); if (draw->clip) XDestroyRegion (draw->clip); free (draw); } Bool XftDrawRenderPrepare (XftDraw *draw, XftColor *color, XftFont *font, int src) { if (!draw->render_set) { XRenderPictFormat *format; XRenderPictFormat *pix_format; XRenderPictureAttributes pa; int n; Pixmap pix; draw->render_set = True; draw->render_able = False; format = _XftDrawFormat (draw); pix_format = _XftDrawFgFormat (draw); if (format && pix_format) { draw->render_able = True; draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable, format, 0, 0); for (n = 0; n < XFT_DRAW_N_SRC; n++) { pix = XCreatePixmap (draw->dpy, draw->drawable, 1, 1, pix_format->depth); pa.repeat = True; draw->render.src[n].pict = XRenderCreatePicture (draw->dpy, pix, pix_format, CPRepeat, &pa); XFreePixmap (draw->dpy, pix); draw->render.src[n].color = color->color; XRenderFillRectangle (draw->dpy, PictOpSrc, draw->render.src[n].pict, &color->color, 0, 0, 1, 1); } if (draw->clip) XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, draw->clip); } } if (!draw->render_able) return False; if (memcmp (&color->color, &draw->render.src[src].color, sizeof (XRenderColor))) { if (_XftFontDebug () & XFT_DBG_DRAW) { printf ("Switching to color %04x,%04x,%04x,%04x\n", color->color.alpha, color->color.red, color->color.green, color->color.blue); } XRenderFillRectangle (draw->dpy, PictOpSrc, draw->render.src[src].pict, &color->color, 0, 0, 1, 1); draw->render.src[src].color = color->color; } return True; } Bool XftDrawCorePrepare (XftDraw *draw, XftColor *color, XftFont *font) { if (!draw->core_set) { XGCValues gcv; unsigned long mask; draw->core_set = True; draw->core.fg = color->pixel; gcv.foreground = draw->core.fg; mask = GCForeground; if (font) { draw->core.font = font->u.core.font->fid; gcv.font = draw->core.font; mask |= GCFont; } draw->core.draw_gc = XCreateGC (draw->dpy, draw->drawable, mask, &gcv); if (draw->clip) XSetRegion (draw->dpy, draw->core.draw_gc, draw->clip); } if (draw->core.fg != color->pixel) { draw->core.fg = color->pixel; XSetForeground (draw->dpy, draw->core.draw_gc, draw->core.fg); } if (font && draw->core.font != font->u.core.font->fid) { draw->core.font = font->u.core.font->fid; XSetFont (draw->dpy, draw->core.draw_gc, draw->core.font); } return True; } void XftDrawString8 (XftDraw *draw, XftColor *color, XftFont *font, int x, int y, XftChar8 *string, int len) { if (_XftFontDebug () & XFT_DBG_DRAW) { printf ("DrawString \"%*.*s\"\n", len, len, string); } if (font->core) { XftDrawCorePrepare (draw, color, font); XDrawString (draw->dpy, draw->drawable, draw->core.draw_gc, x, y, (char *) string, len); } #ifdef FREETYPE2 else if (XftDrawRenderPrepare (draw, color, font, XFT_DRAW_SRC_TEXT)) { XftRenderString8 (draw->dpy, draw->render.src[XFT_DRAW_SRC_TEXT].pict, font->u.ft.font, draw->render.pict, 0, 0, x, y, string, len); } #endif } #define N16LOCAL 256 void XftDrawString16 (XftDraw *draw, XftColor *color, XftFont *font, int x, int y, XftChar16 *string, int len) { if (font->core) { XChar2b *xc; XChar2b xcloc[XFT_CORE_N16LOCAL]; XftDrawCorePrepare (draw, color, font); xc = XftCoreConvert16 (string, len, xcloc); XDrawString16 (draw->dpy, draw->drawable, draw->core.draw_gc, x, y, xc, len); if (xc != xcloc) free (xc); } #ifdef FREETYPE2 else if (XftDrawRenderPrepare (draw, color, font, XFT_DRAW_SRC_TEXT)) { XftRenderString16 (draw->dpy, draw->render.src[XFT_DRAW_SRC_TEXT].pict, font->u.ft.font, draw->render.pict, 0, 0, x, y, string, len); } #endif } void XftDrawString32 (XftDraw *draw, XftColor *color, XftFont *font, int x, int y, XftChar32 *string, int len) { if (font->core) { XChar2b *xc; XChar2b xcloc[XFT_CORE_N16LOCAL]; XftDrawCorePrepare (draw, color, font); xc = XftCoreConvert32 (string, len, xcloc); XDrawString16 (draw->dpy, draw->drawable, draw->core.draw_gc, x, y, xc, len); if (xc != xcloc) free (xc); } #ifdef FREETYPE2 else if (XftDrawRenderPrepare (draw, color, font, XFT_DRAW_SRC_TEXT)) { XftRenderString32 (draw->dpy, draw->render.src[XFT_DRAW_SRC_TEXT].pict, font->u.ft.font, draw->render.pict, 0, 0, x, y, string, len); } #endif } void XftDrawStringUtf8 (XftDraw *draw, XftColor *color, XftFont *font, int x, int y, XftChar8 *string, int len) { if (font->core) { XChar2b *xc; XChar2b xcloc[XFT_CORE_N16LOCAL]; int n; XftDrawCorePrepare (draw, color, font); xc = XftCoreConvertUtf8 (string, len, xcloc, &n); if (xc) { XDrawString16 (draw->dpy, draw->drawable, draw->core.draw_gc, x, y, xc, n); } if (xc != xcloc) free (xc); } #ifdef FREETYPE2 else if (XftDrawRenderPrepare (draw, color, font, XFT_DRAW_SRC_TEXT)) { XftRenderStringUtf8 (draw->dpy, draw->render.src[XFT_DRAW_SRC_TEXT].pict, font->u.ft.font, draw->render.pict, 0, 0, x, y, string, len); } #endif } void XftDrawRect (XftDraw *draw, XftColor *color, int x, int y, unsigned int width, unsigned int height) { if (XftDrawRenderPrepare (draw, color, 0, XFT_DRAW_SRC_RECT)) { XRenderFillRectangle (draw->dpy, PictOpOver, draw->render.pict, &color->color, x, y, width, height); } else { XftDrawCorePrepare (draw, color, 0); XFillRectangle (draw->dpy, draw->drawable, draw->core.draw_gc, x, y, width, height); } } Bool XftDrawSetClip (XftDraw *draw, Region r) { Region n = 0; if (!r && !draw->clip) return True; if (r) { n = XCreateRegion (); if (n) { if (!XUnionRegion (n, r, n)) { XDestroyRegion (n); return False; } } } if (draw->clip) { XDestroyRegion (draw->clip); } draw->clip = n; if (draw->render_able) { XRenderPictureAttributes pa; if (n) { XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, n); } else { pa.clip_mask = None; XRenderChangePicture (draw->dpy, draw->render.pict, CPClipMask, &pa); } } if (draw->core_set) { XGCValues gv; if (n) XSetRegion (draw->dpy, draw->core.draw_gc, n); else { gv.clip_mask = None; XChangeGC (draw->dpy, draw->core.draw_gc, GCClipMask, &gv); } } return True; }