994 lines
22 KiB
C
994 lines
22 KiB
C
|
/*
|
||
|
* $Id: xftdraw.c,v 1.1.1.1 2006/11/25 17:21:38 matthieu Exp $
|
||
|
*
|
||
|
* Copyright © 2000 Keith Packard
|
||
|
*
|
||
|
* 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 "xftint.h"
|
||
|
|
||
|
/*
|
||
|
* Ok, this is a pain. To share source pictures across multiple destinations,
|
||
|
* the screen for each drawable must be discovered.
|
||
|
*/
|
||
|
|
||
|
static int
|
||
|
_XftDrawScreen (Display *dpy, Drawable drawable, Visual *visual)
|
||
|
{
|
||
|
int s;
|
||
|
Window root;
|
||
|
int x, y;
|
||
|
unsigned int width, height, borderWidth, depth;
|
||
|
/* Special case the most common environment */
|
||
|
if (ScreenCount (dpy) == 1)
|
||
|
return 0;
|
||
|
/*
|
||
|
* If we've got a visual, look for the screen that points at it.
|
||
|
* This requires no round trip.
|
||
|
*/
|
||
|
if (visual)
|
||
|
{
|
||
|
for (s = 0; s < ScreenCount (dpy); s++)
|
||
|
{
|
||
|
XVisualInfo template, *ret;
|
||
|
int nret;
|
||
|
|
||
|
template.visualid = visual->visualid;
|
||
|
template.screen = s;
|
||
|
ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask,
|
||
|
&template, &nret);
|
||
|
if (ret)
|
||
|
{
|
||
|
XFree (ret);
|
||
|
return s;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Otherwise, as the server for the drawable geometry and find
|
||
|
* the screen from the root window.
|
||
|
* This takes a round trip.
|
||
|
*/
|
||
|
if (XGetGeometry (dpy, drawable, &root, &x, &y, &width, &height,
|
||
|
&borderWidth, &depth))
|
||
|
{
|
||
|
for (s = 0; s < ScreenCount (dpy); s++)
|
||
|
{
|
||
|
if (RootWindow (dpy, s) == root)
|
||
|
return s;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Make a guess -- it's probably wrong, but then the app probably
|
||
|
* handed us a bogus drawable in this case
|
||
|
*/
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
_X_HIDDEN unsigned int
|
||
|
XftDrawDepth (XftDraw *draw)
|
||
|
{
|
||
|
if (!draw->depth)
|
||
|
{
|
||
|
Window root;
|
||
|
int x, y;
|
||
|
unsigned int width, height, borderWidth, depth;
|
||
|
if (XGetGeometry (draw->dpy, draw->drawable,
|
||
|
&root, &x, &y, &width, &height,
|
||
|
&borderWidth, &depth))
|
||
|
draw->depth = depth;
|
||
|
}
|
||
|
return draw->depth;
|
||
|
}
|
||
|
|
||
|
_X_HIDDEN unsigned int
|
||
|
XftDrawBitsPerPixel (XftDraw *draw)
|
||
|
{
|
||
|
if (!draw->bits_per_pixel)
|
||
|
{
|
||
|
XPixmapFormatValues *formats;
|
||
|
int nformats;
|
||
|
unsigned int depth;
|
||
|
|
||
|
if ((depth = XftDrawDepth (draw)) &&
|
||
|
(formats = XListPixmapFormats (draw->dpy, &nformats)))
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < nformats; i++)
|
||
|
{
|
||
|
if (formats[i].depth == depth)
|
||
|
{
|
||
|
draw->bits_per_pixel = formats[i].bits_per_pixel;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
XFree (formats);
|
||
|
}
|
||
|
}
|
||
|
return draw->bits_per_pixel;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT 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->screen = _XftDrawScreen (dpy, drawable, visual);
|
||
|
draw->depth = 0; /* don't find out unless we need to know */
|
||
|
draw->bits_per_pixel = 0; /* don't find out unless we need to know */
|
||
|
draw->visual = visual;
|
||
|
draw->colormap = colormap;
|
||
|
draw->render.pict = 0;
|
||
|
draw->core.gc = 0;
|
||
|
draw->core.use_pixmap = 0;
|
||
|
draw->clip_type = XftClipTypeNone;
|
||
|
draw->subwindow_mode = ClipByChildren;
|
||
|
XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
|
||
|
return draw;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT 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->screen = _XftDrawScreen (dpy, bitmap, 0);
|
||
|
draw->depth = 1;
|
||
|
draw->bits_per_pixel = 1;
|
||
|
draw->visual = 0;
|
||
|
draw->colormap = 0;
|
||
|
draw->render.pict = 0;
|
||
|
draw->core.gc = 0;
|
||
|
draw->core.use_pixmap = 0;
|
||
|
draw->clip_type = XftClipTypeNone;
|
||
|
draw->subwindow_mode = ClipByChildren;
|
||
|
XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
|
||
|
return draw;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT XftDraw *
|
||
|
XftDrawCreateAlpha (Display *dpy,
|
||
|
Pixmap pixmap,
|
||
|
int depth)
|
||
|
{
|
||
|
XftDraw *draw;
|
||
|
|
||
|
draw = (XftDraw *) malloc (sizeof (XftDraw));
|
||
|
if (!draw)
|
||
|
return 0;
|
||
|
draw->dpy = dpy;
|
||
|
draw->drawable = (Drawable) pixmap;
|
||
|
draw->screen = _XftDrawScreen (dpy, pixmap, 0);
|
||
|
draw->depth = depth;
|
||
|
draw->bits_per_pixel = 0; /* don't find out until we need it */
|
||
|
draw->visual = 0;
|
||
|
draw->colormap = 0;
|
||
|
draw->render.pict = 0;
|
||
|
draw->core.gc = 0;
|
||
|
draw->core.use_pixmap = 0;
|
||
|
draw->clip_type = XftClipTypeNone;
|
||
|
draw->subwindow_mode = ClipByChildren;
|
||
|
XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw));
|
||
|
return draw;
|
||
|
}
|
||
|
|
||
|
static XRenderPictFormat *
|
||
|
_XftDrawFormat (XftDraw *draw)
|
||
|
{
|
||
|
XftDisplayInfo *info = _XftDisplayInfoGet (draw->dpy, True);
|
||
|
|
||
|
if (!info || !info->hasRender)
|
||
|
return 0;
|
||
|
|
||
|
if (draw->visual == 0)
|
||
|
{
|
||
|
XRenderPictFormat pf;
|
||
|
|
||
|
pf.type = PictTypeDirect;
|
||
|
pf.depth = XftDrawDepth (draw);
|
||
|
pf.direct.alpha = 0;
|
||
|
pf.direct.alphaMask = (1 << pf.depth) - 1;
|
||
|
return XRenderFindFormat (draw->dpy,
|
||
|
(PictFormatType|
|
||
|
PictFormatDepth|
|
||
|
PictFormatAlpha|
|
||
|
PictFormatAlphaMask),
|
||
|
&pf,
|
||
|
0);
|
||
|
}
|
||
|
else
|
||
|
return XRenderFindVisualFormat (draw->dpy, draw->visual);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawChange (XftDraw *draw,
|
||
|
Drawable drawable)
|
||
|
{
|
||
|
draw->drawable = drawable;
|
||
|
if (draw->render.pict)
|
||
|
{
|
||
|
XRenderFreePicture (draw->dpy, draw->render.pict);
|
||
|
draw->render.pict = 0;
|
||
|
}
|
||
|
if (draw->core.gc)
|
||
|
{
|
||
|
XFreeGC (draw->dpy, draw->core.gc);
|
||
|
draw->core.gc = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Display *
|
||
|
XftDrawDisplay (XftDraw *draw)
|
||
|
{
|
||
|
return draw->dpy;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Drawable
|
||
|
XftDrawDrawable (XftDraw *draw)
|
||
|
{
|
||
|
return draw->drawable;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Colormap
|
||
|
XftDrawColormap (XftDraw *draw)
|
||
|
{
|
||
|
return draw->colormap;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Visual *
|
||
|
XftDrawVisual (XftDraw *draw)
|
||
|
{
|
||
|
return draw->visual;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawDestroy (XftDraw *draw)
|
||
|
{
|
||
|
if (draw->render.pict)
|
||
|
XRenderFreePicture (draw->dpy, draw->render.pict);
|
||
|
if (draw->core.gc)
|
||
|
XFreeGC (draw->dpy, draw->core.gc);
|
||
|
switch (draw->clip_type) {
|
||
|
case XftClipTypeRegion:
|
||
|
XDestroyRegion (draw->clip.region);
|
||
|
break;
|
||
|
case XftClipTypeRectangles:
|
||
|
free (draw->clip.rect);
|
||
|
break;
|
||
|
case XftClipTypeNone:
|
||
|
break;
|
||
|
}
|
||
|
XftMemFree (XFT_MEM_DRAW, sizeof (XftDraw));
|
||
|
free (draw);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Picture
|
||
|
XftDrawSrcPicture (XftDraw *draw, _Xconst XftColor *color)
|
||
|
{
|
||
|
Display *dpy = draw->dpy;
|
||
|
XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True);
|
||
|
int i;
|
||
|
XftColor bitmapColor;
|
||
|
|
||
|
if (!info)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
* Monochrome targets require special handling; the PictOp controls
|
||
|
* the color, and the color must be opaque
|
||
|
*/
|
||
|
if (!draw->visual && draw->depth == 1)
|
||
|
{
|
||
|
bitmapColor.color.alpha = 0xffff;
|
||
|
bitmapColor.color.red = 0xffff;
|
||
|
bitmapColor.color.green = 0xffff;
|
||
|
bitmapColor.color.blue = 0xffff;
|
||
|
color = &bitmapColor;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* See if there's one already available
|
||
|
*/
|
||
|
for (i = 0; i < XFT_NUM_SOLID_COLOR; i++)
|
||
|
{
|
||
|
if (info->colors[i].pict &&
|
||
|
info->colors[i].screen == draw->screen &&
|
||
|
!memcmp ((void *) &color->color,
|
||
|
(void *) &info->colors[i].color,
|
||
|
sizeof (XRenderColor)))
|
||
|
return info->colors[i].pict;
|
||
|
}
|
||
|
/*
|
||
|
* Pick one to replace at random
|
||
|
*/
|
||
|
i = (unsigned int) rand () % XFT_NUM_SOLID_COLOR;
|
||
|
/*
|
||
|
* Recreate if it was for the wrong screen
|
||
|
*/
|
||
|
if (info->colors[i].screen != draw->screen && info->colors[i].pict)
|
||
|
{
|
||
|
XRenderFreePicture (dpy, info->colors[i].pict);
|
||
|
info->colors[i].pict = 0;
|
||
|
}
|
||
|
/*
|
||
|
* Create picture if necessary
|
||
|
*/
|
||
|
if (!info->colors[i].pict)
|
||
|
{
|
||
|
Pixmap pix;
|
||
|
XRenderPictureAttributes pa;
|
||
|
|
||
|
pix = XCreatePixmap (dpy, RootWindow (dpy, draw->screen), 1, 1,
|
||
|
info->solidFormat->depth);
|
||
|
pa.repeat = True;
|
||
|
info->colors[i].pict = XRenderCreatePicture (draw->dpy,
|
||
|
pix,
|
||
|
info->solidFormat,
|
||
|
CPRepeat, &pa);
|
||
|
XFreePixmap (dpy, pix);
|
||
|
}
|
||
|
/*
|
||
|
* Set to the new color
|
||
|
*/
|
||
|
info->colors[i].color = color->color;
|
||
|
info->colors[i].screen = draw->screen;
|
||
|
XRenderFillRectangle (dpy, PictOpSrc,
|
||
|
info->colors[i].pict,
|
||
|
&color->color, 0, 0, 1, 1);
|
||
|
return info->colors[i].pict;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
_XftDrawOp (_Xconst XftDraw *draw, _Xconst XftColor *color)
|
||
|
{
|
||
|
if (draw->visual || draw->depth != 1)
|
||
|
return PictOpOver;
|
||
|
if (color->color.alpha >= 0x8000)
|
||
|
return PictOpOver;
|
||
|
return PictOpOutReverse;
|
||
|
}
|
||
|
|
||
|
static FcBool
|
||
|
_XftDrawRenderPrepare (XftDraw *draw)
|
||
|
{
|
||
|
if (!draw->render.pict)
|
||
|
{
|
||
|
XRenderPictFormat *format;
|
||
|
XRenderPictureAttributes pa;
|
||
|
unsigned long mask = 0;
|
||
|
|
||
|
format = _XftDrawFormat (draw);
|
||
|
if (!format)
|
||
|
return FcFalse;
|
||
|
|
||
|
if (draw->subwindow_mode == IncludeInferiors)
|
||
|
{
|
||
|
pa.subwindow_mode = IncludeInferiors;
|
||
|
mask |= CPSubwindowMode;
|
||
|
}
|
||
|
draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable,
|
||
|
format, mask, &pa);
|
||
|
if (!draw->render.pict)
|
||
|
return FcFalse;
|
||
|
switch (draw->clip_type) {
|
||
|
case XftClipTypeRegion:
|
||
|
XRenderSetPictureClipRegion (draw->dpy, draw->render.pict,
|
||
|
draw->clip.region);
|
||
|
break;
|
||
|
case XftClipTypeRectangles:
|
||
|
XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict,
|
||
|
draw->clip.rect->xOrigin,
|
||
|
draw->clip.rect->yOrigin,
|
||
|
XftClipRects(draw->clip.rect),
|
||
|
draw->clip.rect->n);
|
||
|
break;
|
||
|
case XftClipTypeNone:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return FcTrue;
|
||
|
}
|
||
|
|
||
|
static FcBool
|
||
|
_XftDrawCorePrepare (XftDraw *draw, _Xconst XftColor *color)
|
||
|
{
|
||
|
if (!draw->core.gc)
|
||
|
{
|
||
|
XGCValues gcv;
|
||
|
unsigned long mask = 0;
|
||
|
if (draw->subwindow_mode == IncludeInferiors)
|
||
|
{
|
||
|
gcv.subwindow_mode = IncludeInferiors;
|
||
|
mask |= GCSubwindowMode;
|
||
|
}
|
||
|
draw->core.gc = XCreateGC (draw->dpy, draw->drawable, mask, &gcv);
|
||
|
if (!draw->core.gc)
|
||
|
return FcFalse;
|
||
|
switch (draw->clip_type) {
|
||
|
case XftClipTypeRegion:
|
||
|
XSetRegion (draw->dpy, draw->core.gc, draw->clip.region);
|
||
|
break;
|
||
|
case XftClipTypeRectangles:
|
||
|
XSetClipRectangles (draw->dpy, draw->core.gc,
|
||
|
draw->clip.rect->xOrigin,
|
||
|
draw->clip.rect->yOrigin,
|
||
|
XftClipRects (draw->clip.rect),
|
||
|
draw->clip.rect->n,
|
||
|
Unsorted);
|
||
|
break;
|
||
|
case XftClipTypeNone:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
XSetForeground (draw->dpy, draw->core.gc, color->pixel);
|
||
|
return FcTrue;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Picture
|
||
|
XftDrawPicture (XftDraw *draw)
|
||
|
{
|
||
|
if (!_XftDrawRenderPrepare (draw))
|
||
|
return 0;
|
||
|
return draw->render.pict;
|
||
|
}
|
||
|
|
||
|
#define NUM_LOCAL 1024
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawGlyphs (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
XftFont *pub,
|
||
|
int x,
|
||
|
int y,
|
||
|
_Xconst FT_UInt *glyphs,
|
||
|
int nglyphs)
|
||
|
{
|
||
|
XftFontInt *font = (XftFontInt *) pub;
|
||
|
|
||
|
if (font->format)
|
||
|
{
|
||
|
Picture src;
|
||
|
|
||
|
if (_XftDrawRenderPrepare (draw) &&
|
||
|
(src = XftDrawSrcPicture (draw, color)))
|
||
|
XftGlyphRender (draw->dpy, _XftDrawOp (draw, color),
|
||
|
src, pub, draw->render.pict,
|
||
|
0, 0, x, y, glyphs, nglyphs);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (_XftDrawCorePrepare (draw, color))
|
||
|
XftGlyphCore (draw, color, pub, x, y, glyphs, nglyphs);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawString8 (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
XftFont *pub,
|
||
|
int x,
|
||
|
int y,
|
||
|
_Xconst FcChar8 *string,
|
||
|
int len)
|
||
|
{
|
||
|
FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
|
||
|
int i;
|
||
|
|
||
|
if (XftDebug () & XFT_DBG_DRAW)
|
||
|
printf ("DrawString \"%*.*s\"\n", len, len, string);
|
||
|
|
||
|
if (len <= NUM_LOCAL)
|
||
|
glyphs = glyphs_local;
|
||
|
else
|
||
|
{
|
||
|
glyphs = malloc (len * sizeof (FT_UInt));
|
||
|
if (!glyphs)
|
||
|
return;
|
||
|
}
|
||
|
for (i = 0; i < len; i++)
|
||
|
glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
|
||
|
XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawString16 (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
XftFont *pub,
|
||
|
int x,
|
||
|
int y,
|
||
|
_Xconst FcChar16 *string,
|
||
|
int len)
|
||
|
{
|
||
|
FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
|
||
|
int i;
|
||
|
|
||
|
if (len <= NUM_LOCAL)
|
||
|
glyphs = glyphs_local;
|
||
|
else
|
||
|
{
|
||
|
glyphs = malloc (len * sizeof (FT_UInt));
|
||
|
if (!glyphs)
|
||
|
return;
|
||
|
}
|
||
|
for (i = 0; i < len; i++)
|
||
|
glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
|
||
|
|
||
|
XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawString32 (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
XftFont *pub,
|
||
|
int x,
|
||
|
int y,
|
||
|
_Xconst FcChar32 *string,
|
||
|
int len)
|
||
|
{
|
||
|
FT_UInt *glyphs, glyphs_local[NUM_LOCAL];
|
||
|
int i;
|
||
|
|
||
|
if (len <= NUM_LOCAL)
|
||
|
glyphs = glyphs_local;
|
||
|
else
|
||
|
{
|
||
|
glyphs = malloc (len * sizeof (FT_UInt));
|
||
|
if (!glyphs)
|
||
|
return;
|
||
|
}
|
||
|
for (i = 0; i < len; i++)
|
||
|
glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
|
||
|
|
||
|
XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawStringUtf8 (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
XftFont *pub,
|
||
|
int x,
|
||
|
int y,
|
||
|
_Xconst FcChar8 *string,
|
||
|
int len)
|
||
|
{
|
||
|
FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
|
||
|
FcChar32 ucs4;
|
||
|
int i;
|
||
|
int l;
|
||
|
int size;
|
||
|
|
||
|
i = 0;
|
||
|
glyphs = glyphs_local;
|
||
|
size = NUM_LOCAL;
|
||
|
while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0)
|
||
|
{
|
||
|
if (i == size)
|
||
|
{
|
||
|
glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
|
||
|
if (!glyphs_new)
|
||
|
{
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
return;
|
||
|
}
|
||
|
memcpy (glyphs_new, glyphs, size * sizeof (FT_UInt));
|
||
|
size *= 2;
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
glyphs = glyphs_new;
|
||
|
}
|
||
|
glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4);
|
||
|
string += l;
|
||
|
len -= l;
|
||
|
}
|
||
|
XftDrawGlyphs (draw, color, pub, x, y, glyphs, i);
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawStringUtf16 (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
XftFont *pub,
|
||
|
int x,
|
||
|
int y,
|
||
|
_Xconst FcChar8 *string,
|
||
|
FcEndian endian,
|
||
|
int len)
|
||
|
{
|
||
|
FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
|
||
|
FcChar32 ucs4;
|
||
|
int i;
|
||
|
int l;
|
||
|
int size;
|
||
|
|
||
|
i = 0;
|
||
|
glyphs = glyphs_local;
|
||
|
size = NUM_LOCAL;
|
||
|
while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0)
|
||
|
{
|
||
|
if (i == size)
|
||
|
{
|
||
|
glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
|
||
|
if (!glyphs_new)
|
||
|
{
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
return;
|
||
|
}
|
||
|
memcpy (glyphs_new, glyphs, size * sizeof (FT_UInt));
|
||
|
size *= 2;
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
glyphs = glyphs_new;
|
||
|
}
|
||
|
glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4);
|
||
|
string += l;
|
||
|
len -= l;
|
||
|
}
|
||
|
XftDrawGlyphs (draw, color, pub, x, y, glyphs, i);
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawGlyphSpec (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
XftFont *pub,
|
||
|
_Xconst XftGlyphSpec *glyphs,
|
||
|
int len)
|
||
|
{
|
||
|
XftFontInt *font = (XftFontInt *) pub;
|
||
|
|
||
|
if (font->format)
|
||
|
{
|
||
|
Picture src;
|
||
|
|
||
|
if (_XftDrawRenderPrepare (draw) &&
|
||
|
(src = XftDrawSrcPicture (draw, color)))
|
||
|
{
|
||
|
XftGlyphSpecRender (draw->dpy, _XftDrawOp (draw, color),
|
||
|
src, pub, draw->render.pict,
|
||
|
0, 0, glyphs, len);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (_XftDrawCorePrepare (draw, color))
|
||
|
XftGlyphSpecCore (draw, color, pub, glyphs, len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawGlyphFontSpec (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
_Xconst XftGlyphFontSpec *glyphs,
|
||
|
int len)
|
||
|
{
|
||
|
int i;
|
||
|
int start;
|
||
|
|
||
|
i = 0;
|
||
|
while (i < len)
|
||
|
{
|
||
|
start = i;
|
||
|
if (((XftFontInt *) glyphs[i].font)->format)
|
||
|
{
|
||
|
Picture src;
|
||
|
while (i < len && ((XftFontInt *) glyphs[i].font)->format)
|
||
|
i++;
|
||
|
if (_XftDrawRenderPrepare (draw) &&
|
||
|
(src = XftDrawSrcPicture (draw, color)))
|
||
|
{
|
||
|
XftGlyphFontSpecRender (draw->dpy, _XftDrawOp (draw, color),
|
||
|
src, draw->render.pict,
|
||
|
0, 0, glyphs + start , i - start);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while (i < len && !((XftFontInt *) glyphs[i].font)->format)
|
||
|
i++;
|
||
|
if (_XftDrawCorePrepare (draw, color))
|
||
|
XftGlyphFontSpecCore (draw, color, glyphs + start, i - start);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawCharSpec (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
XftFont *pub,
|
||
|
_Xconst XftCharSpec *chars,
|
||
|
int len)
|
||
|
{
|
||
|
XftGlyphSpec *glyphs, glyphs_local[NUM_LOCAL];
|
||
|
int i;
|
||
|
|
||
|
if (len <= NUM_LOCAL)
|
||
|
glyphs = glyphs_local;
|
||
|
else
|
||
|
{
|
||
|
glyphs = malloc (len * sizeof (XftGlyphSpec));
|
||
|
if (!glyphs)
|
||
|
return;
|
||
|
}
|
||
|
for (i = 0; i < len; i++)
|
||
|
{
|
||
|
glyphs[i].glyph = XftCharIndex(draw->dpy, pub, chars[i].ucs4);
|
||
|
glyphs[i].x = chars[i].x;
|
||
|
glyphs[i].y = chars[i].y;
|
||
|
}
|
||
|
|
||
|
XftDrawGlyphSpec (draw, color, pub, glyphs, len);
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawCharFontSpec (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
_Xconst XftCharFontSpec *chars,
|
||
|
int len)
|
||
|
{
|
||
|
XftGlyphFontSpec *glyphs, glyphs_local[NUM_LOCAL];
|
||
|
int i;
|
||
|
|
||
|
if (len <= NUM_LOCAL)
|
||
|
glyphs = glyphs_local;
|
||
|
else
|
||
|
{
|
||
|
glyphs = malloc (len * sizeof (XftGlyphFontSpec));
|
||
|
if (!glyphs)
|
||
|
return;
|
||
|
}
|
||
|
for (i = 0; i < len; i++)
|
||
|
{
|
||
|
glyphs[i].font = chars[i].font;
|
||
|
glyphs[i].glyph = XftCharIndex(draw->dpy, glyphs[i].font, chars[i].ucs4);
|
||
|
glyphs[i].x = chars[i].x;
|
||
|
glyphs[i].y = chars[i].y;
|
||
|
}
|
||
|
|
||
|
XftDrawGlyphFontSpec (draw, color, glyphs, len);
|
||
|
if (glyphs != glyphs_local)
|
||
|
free (glyphs);
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawRect (XftDraw *draw,
|
||
|
_Xconst XftColor *color,
|
||
|
int x,
|
||
|
int y,
|
||
|
unsigned int width,
|
||
|
unsigned int height)
|
||
|
{
|
||
|
if (_XftDrawRenderPrepare (draw))
|
||
|
{
|
||
|
XRenderFillRectangle (draw->dpy, PictOpSrc, draw->render.pict,
|
||
|
&color->color, x, y, width, height);
|
||
|
}
|
||
|
else if (_XftDrawCorePrepare (draw, color))
|
||
|
{
|
||
|
XftRectCore (draw, color, x, y, width, height);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Bool
|
||
|
XftDrawSetClip (XftDraw *draw,
|
||
|
Region r)
|
||
|
{
|
||
|
Region n = 0;
|
||
|
|
||
|
/*
|
||
|
* Check for quick exits
|
||
|
*/
|
||
|
if (!r && draw->clip_type == XftClipTypeNone)
|
||
|
return True;
|
||
|
|
||
|
if (r &&
|
||
|
draw->clip_type == XftClipTypeRegion &&
|
||
|
XEqualRegion (r, draw->clip.region))
|
||
|
{
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Duplicate the region so future changes can be short circuited
|
||
|
*/
|
||
|
if (r)
|
||
|
{
|
||
|
n = XCreateRegion ();
|
||
|
if (n)
|
||
|
{
|
||
|
if (!XUnionRegion (n, r, n))
|
||
|
{
|
||
|
XDestroyRegion (n);
|
||
|
return False;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Destroy existing clip
|
||
|
*/
|
||
|
switch (draw->clip_type) {
|
||
|
case XftClipTypeRegion:
|
||
|
XDestroyRegion (draw->clip.region);
|
||
|
break;
|
||
|
case XftClipTypeRectangles:
|
||
|
free (draw->clip.rect);
|
||
|
break;
|
||
|
case XftClipTypeNone:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Set the clip
|
||
|
*/
|
||
|
if (n)
|
||
|
{
|
||
|
draw->clip_type = XftClipTypeRegion;
|
||
|
draw->clip.region = n;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
draw->clip_type = XftClipTypeNone;
|
||
|
}
|
||
|
/*
|
||
|
* Apply new clip to existing objects
|
||
|
*/
|
||
|
if (draw->render.pict)
|
||
|
{
|
||
|
if (n)
|
||
|
XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, n);
|
||
|
else
|
||
|
{
|
||
|
XRenderPictureAttributes pa;
|
||
|
pa.clip_mask = None;
|
||
|
XRenderChangePicture (draw->dpy, draw->render.pict,
|
||
|
CPClipMask, &pa);
|
||
|
}
|
||
|
}
|
||
|
if (draw->core.gc)
|
||
|
{
|
||
|
if (n)
|
||
|
XSetRegion (draw->dpy, draw->core.gc, draw->clip.region);
|
||
|
else
|
||
|
XSetClipMask (draw->dpy, draw->core.gc, None);
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Bool
|
||
|
XftDrawSetClipRectangles (XftDraw *draw,
|
||
|
int xOrigin,
|
||
|
int yOrigin,
|
||
|
_Xconst XRectangle *rects,
|
||
|
int n)
|
||
|
{
|
||
|
XftClipRect *new = 0;
|
||
|
|
||
|
/*
|
||
|
* Check for quick exit
|
||
|
*/
|
||
|
if (draw->clip_type == XftClipTypeRectangles &&
|
||
|
draw->clip.rect->n == n &&
|
||
|
(n == 0 || (draw->clip.rect->xOrigin == xOrigin &&
|
||
|
draw->clip.rect->yOrigin == yOrigin)) &&
|
||
|
!memcmp (XftClipRects (draw->clip.rect), rects, n * sizeof (XRectangle)))
|
||
|
{
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Duplicate the region so future changes can be short circuited
|
||
|
*/
|
||
|
new = malloc (sizeof (XftClipRect) + n * sizeof (XRectangle));
|
||
|
if (!new)
|
||
|
return False;
|
||
|
|
||
|
new->n = n;
|
||
|
new->xOrigin = xOrigin;
|
||
|
new->yOrigin = yOrigin;
|
||
|
memcpy (XftClipRects (new), rects, n * sizeof (XRectangle));
|
||
|
|
||
|
/*
|
||
|
* Destroy existing clip
|
||
|
*/
|
||
|
switch (draw->clip_type) {
|
||
|
case XftClipTypeRegion:
|
||
|
XDestroyRegion (draw->clip.region);
|
||
|
break;
|
||
|
case XftClipTypeRectangles:
|
||
|
free (draw->clip.rect);
|
||
|
break;
|
||
|
case XftClipTypeNone:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Set the clip
|
||
|
*/
|
||
|
draw->clip_type = XftClipTypeRectangles;
|
||
|
draw->clip.rect = new;
|
||
|
/*
|
||
|
* Apply new clip to existing objects
|
||
|
*/
|
||
|
if (draw->render.pict)
|
||
|
{
|
||
|
XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict,
|
||
|
new->xOrigin,
|
||
|
new->yOrigin,
|
||
|
XftClipRects(new),
|
||
|
new->n);
|
||
|
}
|
||
|
if (draw->core.gc)
|
||
|
{
|
||
|
XSetClipRectangles (draw->dpy, draw->core.gc,
|
||
|
new->xOrigin,
|
||
|
new->yOrigin,
|
||
|
XftClipRects (new),
|
||
|
new->n,
|
||
|
Unsorted);
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
XftDrawSetSubwindowMode (XftDraw *draw, int mode)
|
||
|
{
|
||
|
if (mode == draw->subwindow_mode)
|
||
|
return;
|
||
|
draw->subwindow_mode = mode;
|
||
|
if (draw->render.pict)
|
||
|
{
|
||
|
XRenderPictureAttributes pa;
|
||
|
|
||
|
pa.subwindow_mode = mode;
|
||
|
XRenderChangePicture (draw->dpy, draw->render.pict,
|
||
|
CPSubwindowMode, &pa);
|
||
|
}
|
||
|
if (draw->core.gc)
|
||
|
XSetSubwindowMode (draw->dpy, draw->core.gc, mode);
|
||
|
}
|