XftFontDescription.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Sun, 29 Dec 2013 12:03:28 +0100
changeset 6182 8bf2372670d9
parent 6180 6034bf4c5022
child 6183 a21827076de1
permissions -rw-r--r--
Fixes to make XftFontDescription>>example1 to render something. Sometimes it segfaults and also there are some artefacts (invalid font metrics, rendering twice without clearing, maybe something else)

"{ Package: 'stx:libview' }"

FontDescription subclass:#XftFontDescription
	instanceVariableNames:'device fontId drawId lasrFgColor lastFgColorId lastBgColor
		lastBgColorId'
	classVariableNames:''
	poolDictionaries:''
	category:'Graphics-Support'
!

!XftFontDescription primitiveDefinitions!
%{

/*
 * includes, defines, structure definitions
 * and typedefs come here.
 */

#undef True
#undef False
#undef Time
#define Time XTime


#ifdef XFT
# define __externalAddressValCasted(type, externalAddress) \
	((type)__externalAddressVal(externalAddress))
# define DISPLAY(x)    __externalAddressValCasted(Display*, x)
# define SCREEN(x)     ((int)(__intVal(x)))
# define DRAWABLE(x)   __externalAddressValCasted(Drawable, x)
# define GC(x)         __externalAddressValCasted(GC, x)
# define VISUAL(x)     __externalAddressValCasted(Visual*, x)
# define COLORMAP(x)   __externalAddressValCasted(Colormap, x)
# define XFT_FONT(x)      __externalAddressValCasted(XftFont*, x)
# define XFT_PATTERN(x)   __externalAddressValCasted(XftPattern*, x)
# define XFT_DRAW(x)      __externalAddressValCasted(XftDraw*, x)
# define XFT_COLOR(x)     __externalAddressValCasted(XftColor*, x)

# include <X11/Xft/Xft.h>
# include <X11/Xft/XftCompat.h>

#endif

%}
! !

!XftFontDescription class methodsFor:'documentation'!

documentation
"
    WARNING: Unfinished.

    Experimental implementation of custom font rendered using
    Xft library (UNIX / X Window only), To actually use it,
    add following definitions to the end of stx/configurations/myConf
    (works on Ubuntu 12.10)

    --- snip ---
    XDEFS+=-DXFT
    XINCLUDE+=$(shell pkg-config --cflags xft)
    LIB_XFT=-l:libXft.so.2 -l:libfontconfig.so.1
    --- snip --

    NOTE: This class should be named XftFont, however then
    there would be a name clash with XftFont structure
    defined in Xft.h - therefore the class is named
    XftFontDescription to avoid that name clash.


    [author:]
	Jan Vrany <jan.vrany@fit.cvut.cz>

    [instance variables:]

    [class variables:]

    [see also:]

"
! !

!XftFontDescription class methodsFor:'examples'!

example1

    "
    XftFontDescription example1
    "
    |top textView|

    top := StandardSystemView new.
    top extent:300@200.

    textView := EditTextView new.
    textView origin:0.0 @ 0.0 corner:1.0 @ 1.0.
    textView basicFont: (XftFontDescription family: 'helvetica' size: 16).

    top addSubView:textView.

    textView contents:('/etc/hosts' asFilename contentsOfEntireFile).

    top open.

    "Created: / 20-12-2013 / 00:04:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 29-12-2013 / 10:28:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!XftFontDescription methodsFor:'displaying'!

displayString:aString from:index1 to:index2 x:x y:y in:aGC opaque:opaque
    "display a partial string at some position in aGC."

    | y0 extents |

    y0 := y - self ascent.

    drawId isNil ifTrue:[
        drawId := self xftDrawCreate: device displayId screen: device screen drawable: aGC id.
    ] ifFalse:[
        self xftDrawChange: drawId drawable: aGC id
    ].
    lasrFgColor ~= aGC paint ifTrue:[
        lastFgColorId notNil ifTrue:[
            self xftColorDestroy: device displayId screen: device screen color: lastFgColorId.
        ].
        lasrFgColor := aGC paint.
        lastFgColorId := self xftColorCreate: device displayId screen: device screen color: lasrFgColor.
    ].
    extents :=  self xftTextExtents: device displayId font: fontId string: aString from: index1 to: index2.

    opaque ifTrue:[

        lastBgColor ~= aGC backgroundPaint ifTrue:[
            lastBgColorId notNil ifTrue:[
                self xftColorDestroy: device displayId screen: device screen color: lastBgColorId.
            ].
            lastBgColor := aGC backgroundPaint.
            lastBgColorId := self xftColorCreate: device displayId screen: device screen color: lastBgColor.
        ].
        self xftDrawRect: drawId color: lastBgColorId  x: x y:y0 width: extents first height: extents second

    ].
    "true"false ifTrue:[
        | w p |

        w := self widthOf: aString   from: index1 to: index2.
        p :=  aGC paint.
        aGC paint: Color red.
        aGC displayLineFromX: x  y: y toX: x + w y: y.
        aGC paint: Color blue.
        aGC displayLineFromX: x  y: y - self ascent toX: x + w y: y - self ascent.
        aGC paint: Color yellow.
        aGC displayLineFromX: x  y: y + self descent toX: x + w y: y + self descent.


        aGC paint: p.


    ].
    self xftDrawString: drawId color: lastFgColorId font: fontId x: x y: y  string: aString from: index1 to: index2

    "Created: / 21-12-2013 / 21:11:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 29-12-2013 / 11:38:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!XftFontDescription methodsFor:'error reporting'!

primitiveFailedIfNoXft
    <resource: #skipInDebuggersWalkBack>
%{
#ifdef XFT
    RETURN ( self );
#endif
%}.
    self primitiveFailed: 'Xft support not available'

    "Created: / 20-12-2013 / 21:13:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!XftFontDescription methodsFor:'getting a device font'!

onDevice:aGraphicsDevice
    "Create a new XftFont representing the closes font as
     myself on aDevice; if one already exists, return the one."

    | myPatternId closestPatternId1 closestPatternId2 newFontId |

    "if I am already assigned to that device ..."
    (device == aGraphicsDevice) ifTrue:[^ self].

    (aGraphicsDevice isNil and:[device notNil]) ifTrue:[
        ^ self
    ].

    aGraphicsDevice deviceFonts do:[:aFont |
        (self sameDeviceFontAs:aFont) ifTrue:[
            ^ aFont
        ].
    ].

    [
        myPatternId := self xftPatternCreate.
        self xftPatternAdd: myPatternId attribute: 'family' value: family.
        pixelSize notNil ifTrue:[
            self xftPatternAdd: myPatternId attribute: 'pixelsize' value: pixelSize.
        ] ifFalse:[
            self xftPatternAdd: myPatternId attribute: 'size' value: size.
        ].
        newFontId := self xftFontOpenPattern: aGraphicsDevice displayId pattern: myPatternId.
        newFontId notNil ifTrue:[
            "/ Good, this font exist!!
            fontId := newFontId.
            device := aGraphicsDevice.
            self shouldImplement. "/ Register font...
            ^ self.
        ] ifFalse:[
            | family size |
            closestPatternId1 := self xftFontMatch: aGraphicsDevice displayId screen: aGraphicsDevice screen pattern: myPatternId.
            closestPatternId1 isNil ifTrue:[
                self error: 'No font matches'.
            ].
            "
            self xftPatternGet: closestPatternId attribute: 'family' index: 0.
            self xftPatternGet: closestPatternId attribute: 'size' index: 0.
            "
            closestPatternId2 := self xftPatternDuplicate: closestPatternId1.
            newFontId := self xftFontOpenPattern: aGraphicsDevice displayId pattern: closestPatternId1.
            "/ !!!!!!!! closestPatternId is no longer valid !!!!!!!!
            closestPatternId1 :=  nil.
            newFontId isNil ifTrue:[
                self error: 'Pattern matched, but font could be open (should not happen)'.
            ].
            ^ self class new
                setDevice: aGraphicsDevice patternId: closestPatternId2 fontId: newFontId;
                yourself.
        ].
    ] ensure:[
        self xftPatternDestroy: myPatternId.
        self xftPatternDestroy: closestPatternId1.
        self xftPatternDestroy: closestPatternId2.
    ].

    "
     (XftFontDescription family:'monospace' size:16) onDevice:Screen current
    "

    "Modified: / 14-04-1997 / 18:22:31 / cg"
    "Modified: / 21-12-2013 / 01:15:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

onDevice:aDevice ifAbsent:exceptionBlock
    "Create a new XftFont representing the same font as
     myself on aDevice. This does NOT try to look for existing
     or replacement fonts (i.e. can be used to get physical fonts)."

    ^ self shouldImplement

    "Modified: / 20-12-2013 / 10:54:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!XftFontDescription methodsFor:'initialization'!

setDevice: deviceArg patternId: patternIdArg fontId: fontIdArg

    device := deviceArg.
    fontId := fontIdArg.

    family  := self xftPatternGet: patternIdArg attribute: 'family' index: 0.
    size    := self xftPatternGet: patternIdArg attribute: 'size' index: 0.
    face    := self xftPatternGet: patternIdArg attribute: 'slant' index: 0.
    face == 0 ifTrue:[ face := 'roman'].
    face == 100 ifTrue:[ face := 'italic'].
    face == 110 ifTrue:[ face := 'oblique'].
    style   := self xftPatternGet: patternIdArg attribute: 'style' index: 0.
    encoding:= self xftPatternGet: patternIdArg attribute: 'encoding' index: 0.

    "Created: / 21-12-2013 / 00:46:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!XftFontDescription methodsFor:'primitives'!

xftAvailable
%{
#ifdef XFT
    RETURN ( true )
#endif
%}.
    ^ false

    "Created: / 20-12-2013 / 21:10:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftColorCreate: displayId screen: screen color: color

    | error r g b a |

    self primitiveFailedIfNoXft.

    r := color scaledRed.
    g := color scaledGreen.
    b := color scaledBlue.
    a := color alpha * 65535.
%{
#ifdef XFT
    XRenderColor xrcolor;
    XftColor *xftcolor;

    if ( ! __isExternalAddressLike(displayId) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isSmallInteger(screen) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    xrcolor.red   = __intVal(r);
    xrcolor.green = __intVal(g);
    xrcolor.blue  = __intVal(b);
    xrcolor.alpha = __intVal(a);

    xftcolor = (XftColor*) malloc( sizeof( XftColor ) );
    XftColorAllocValue ( DISPLAY( displayId ) ,
                         DefaultVisual( DISPLAY( displayId), SCREEN (screen) ) ,
                         DefaultColormap( DISPLAY( displayId), SCREEN (screen) ),
                         &xrcolor,
                         xftcolor );
    RETURN ( __MKEXTERNALADDRESS( xftcolor ) );
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 28-12-2013 / 11:55:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftColorDestroy: displayId screen: screen color: xftColorId

    | error |

    self primitiveFailedIfNoXft.

%{
#ifdef XFT
    XRenderColor xrcolor;
    XftColor *xftcolor;

    if ( ! __isExternalAddressLike(displayId) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isSmallInteger(screen) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    if ( ! __isExternalAddressLike(xftColorId) ) {
        error = @symbol(BadArg3);
        goto err;
    }

    XftColorFree ( DISPLAY( displayId ) ,
                   DefaultVisual( DISPLAY( displayId), SCREEN (screen) ) ,
                   DefaultColormap( DISPLAY( displayId), SCREEN (screen) ),
                   XFT_COLOR( xftColorId ) );
    free( __externalAddressVal( xftColorId ) );
    __externalAddressVal( xftColorId ) = NULL;
    RETURN ( self );
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 28-12-2013 / 12:21:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftDrawChange: xftDrawId drawable: drawableId

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    if ( ! __isExternalAddressLike(xftDrawId) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isExternalAddressLike(drawableId) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    if (XftDrawDrawable( XFT_DRAW(xftDrawId) ) != DRAWABLE( drawableId ) ) {
        XftDrawChange( XFT_DRAW(xftDrawId) , DRAWABLE( drawableId ) );
    }
    RETURN ( self );
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 26-12-2013 / 12:17:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftDrawCreate: displayId screen: screen drawable: drawableId

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    if ( ! __isExternalAddressLike(displayId) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isSmallInteger(screen) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    if ( ! __isExternalAddressLike(drawableId) ) {
        error = @symbol(BadArg3);
        goto err;
    }
    RETURN ( __MKEXTERNALADDRESS(  XftDrawCreate ( DISPLAY( displayId ) ,
                                                   DRAWABLE( drawableId ) ,
                                                   DefaultVisual( DISPLAY( displayId), SCREEN (screen) ) ,
                                                   DefaultColormap( DISPLAY( displayId), SCREEN (screen) ) ) ) );
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 21-12-2013 / 21:12:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftDrawRect: drawIdArg color: colorIdArg x: x y: y width: w height: h

    | error extents |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    if ( ! __isExternalAddressLike(drawIdArg) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isExternalAddressLike(colorIdArg) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    if ( ! __isSmallInteger(x) ) {
        error = @symbol(BadArg3);
        goto err;
    }
    if ( ! __isSmallInteger(y) ) {
        error = @symbol(BadArg4);
        goto err;
    }
    if ( ! __isSmallInteger(w) ) {
        error = @symbol(BadArg5);
        goto err;
    }
    if ( ! __isSmallInteger(h) ) {
        error = @symbol(BadArg6);
        goto err;
    }
    XftDrawRect(XFT_DRAW(drawIdArg), XFT_COLOR(colorIdArg),
                        __intVal(x), __intVal(y), __intVal(w) ,__intVal(h));

    RETURN ( self );
    err:;
#endif
%}.
    self primitiveFailed: error.

    "Created: / 28-12-2013 / 23:35:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftDrawString: drawIdArg color: colorIdArg font: fontIdArg x: x y: y string: text from: start to: stop

    | error extents |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    int _start, _stop;
    int _x, _y;
    if ( ! __isExternalAddressLike(drawIdArg) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isExternalAddressLike(colorIdArg) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    if ( ! __isExternalAddressLike(fontIdArg) ) {
        error = @symbol(BadArg3);
        goto err;
    }
    if ( ! __isSmallInteger(x) ) {
        error = @symbol(BadArg4);
        goto err;
    }
    _x = __intVal(x);
    if ( ! __isSmallInteger(y) ) {
        error = @symbol(BadArg5);
        goto err;
    }
    _y = __intVal(y);


    if ( ! __isSmallInteger(start) ) {
        error = @symbol(BadArg6);
        goto err;
    }
    _start = __intVal(start);
    if ( ! __isSmallInteger(stop) ) {
        error = @symbol(BadArg7);
        goto err;
    }
    _stop = __intVal(stop);

    if ( __isString(text) ) {
        XftDrawString8(XFT_DRAW(drawIdArg), XFT_COLOR(colorIdArg), XFT_FONT(fontIdArg),
                        _x, _y,
                        __stringVal(text) + (_start - 1), _stop - _start + 1);
        RETURN ( self );
    } else {
        error = @symbol(BadArg5);
        goto err;
    }
    err:;
#endif
%}.
    self primitiveFailed: error.

    "Created: / 28-12-2013 / 12:32:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 29-12-2013 / 11:29:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftFontGetAscent: fontIdArg

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    int v;
    if ( ! __isExternalAddressLike(fontIdArg) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    v = XFT_FONT(fontIdArg)->ascent;
    RETURN ( __MKINT( v ) );
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 21-12-2013 / 00:56:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftFontGetDescent: fontIdArg

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    int v;
    if ( ! __isExternalAddressLike(fontIdArg) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    v = XFT_FONT(fontIdArg)->descent;
    RETURN ( __MKINT( v ) );
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 21-12-2013 / 00:56:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftFontGetHeight: fontIdArg

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    int v;
    if ( ! __isExternalAddressLike(fontIdArg) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    v = XFT_FONT(fontIdArg)->height;
    RETURN ( __MKINT( v ) );
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 21-12-2013 / 00:56:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftFontGetPattern: fontIdArg

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    XftPattern* p;
    if ( ! __isExternalAddressLike(fontIdArg) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    p = XFT_FONT(fontIdArg)->pattern;
    if (p == NULL) {
        RETURN ( nil );
    } else {
        RETURN ( __MKEXTERNALADDRESS ( p ) );
    }
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 21-12-2013 / 00:55:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftFontMatch: displayId screen: screen pattern: patternId

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    XftPattern* p;
    XftResult r;

    if ( ! __isExternalAddressLike(displayId) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isSmallInteger( screen ) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    if ( ! __isExternalAddressLike(patternId) ) {
        error = @symbol(BadArg3);
        goto err;
    }

    p = XftFontMatch( DISPLAY(displayId) , SCREEN( screen ), XFT_PATTERN( patternId ), &r );
    if (r == XftResultMatch) {
        RETURN ( __MKEXTERNALADDRESS ( p ) );
    } else {
        if ( p ) {
            XftPatternDestroy( p );
        }
        RETURN ( nil );
    }
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 21-12-2013 / 00:08:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftFontOpenPattern: displayId pattern: patternId

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    XftFont* f;
    if ( ! __isExternalAddressLike(displayId) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isExternalAddressLike(patternId) ) {
        error = @symbol(BadArg2);
        goto err;
    }

    f = XftFontOpenPattern( DISPLAY(displayId) , XFT_PATTERN( patternId ) );
    if (f == NULL) {
        RETURN ( nil );
    } else {
        RETURN ( __MKEXTERNALADDRESS ( f ) );
    }
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 20-12-2013 / 23:53:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftPatternAdd: pattern attribute: attribute value: value
    "Add a value to the specified pattern element after existing values"

    ^ self xftPatternAdd: pattern attribute: attribute value: value append: true.

    "Created: / 20-12-2013 / 23:43:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftPatternAdd: pattern attribute: attribute value: value append: append
    "Add a value to the specified pattern element.  If 'append' is true, the value
     is added after existing values, otherwise it is added before them."

    | error |

    self primitiveFailedIfNoXft.

%{
#ifdef XFT
    XftValue v;
    Bool b;

    if ( ! __isExternalAddressLike ( pattern ) ) {
    	error = @symbol(BadArg1);
    	goto err;
    }
    if ( ! __isStringLike ( attribute ) ) {
    	error = @symbol(BadArg2);
    	goto err;
    }
    if ( append != true && append != false ) {
    	error = @symbol(BadArg4);
    	goto err;
    }
    if ( __isStringLike ( value ) ) {
    	v.type = FcTypeString;
    	/* Passing pointer inside Smalltalk should be safe,
    	 * Xft/FontConfig libraries seem to allocate and store
    	 * a __copy__ of the string (if I understood the code correctly)
    	 */
    	v.u.s = __stringVal( value);
    } else if ( __isSmallInteger( value ) ) {
    	v.type = XftTypeInteger;
    	v.u.i = (int)__intVal( value );
    } else if ( value == true || value == false ) {
    	v.type = XftTypeBool;
    	v.u.b = value == true ? True : False;
    } else if ( __isFloat ( value ) ) {
    	v.type = XftTypeDouble;
    	v.u.d = __floatVal( value );
    } else if ( value == nil ) {
    	v.type = XftTypeVoid;
    	v.u.f = NULL;
    } else {
    	error = @symbol(BadArg3);
    	goto err;
    }
    b = XftPatternAdd( XFT_PATTERN(pattern), __stringVal(attribute), v, append == true ? True : False );
    RETURN ( b == True ? true : false );

    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 20-12-2013 / 21:50:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftPatternCreate

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    RETURN ( __MKEXTERNALADDRESS( XftPatternCreate() ) );
#endif
%}.
    self primitiveFailed.

    "Created: / 20-12-2013 / 21:19:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftPatternDel: pattern attribute: attribute

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    if ( ! __isExternalAddressLike ( pattern ) ) {
    	error = @symbol(BadArg1);
    	goto err;
    }
    if ( ! __isStringLike ( attribute ) ) {
    	error = @symbol(BadArg2);
    	goto err;
    }
    XftPatternDel( XFT_PATTERN(pattern), __stringVal ( attribute ) );
    RETURN ( self );

    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 20-12-2013 / 21:33:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftPatternDestroy: addr

    | error |

    self primitiveFailedIfNoXft.
    addr isNil ifTrue:[ ^ self ].

%{
#ifdef XFT
    if ( ! __isExternalAddressLike(addr) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    XftPatternDestroy( XFT_PATTERN(addr) );
    RETURN ( self );

    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 20-12-2013 / 21:33:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 20-12-2013 / 23:48:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftPatternDuplicate: addr

    | error |

    self primitiveFailedIfNoXft.
    addr isNil ifTrue:[ ^ self ].

%{
#ifdef XFT
    if ( ! __isExternalAddressLike(addr) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    RETURN ( __MKEXTERNALADDRESS ( XftPatternDuplicate( XFT_PATTERN(addr) ) ) );
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 21-12-2013 / 01:14:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftPatternGet: pattern attribute: attribute index: index
    "Return a value from the specified element -- multiple values can be indexed
     with 'index' starting at zero."

    | error |

    self primitiveFailedIfNoXft.
%{
#ifdef XFT
    XftValue v;
    XftResult r;

    if ( ! __isExternalAddressLike ( pattern ) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isStringLike ( attribute ) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    if ( ! __isSmallInteger( index ) ) {
        error = @symbol(BadArg3);
        goto err;
    }
    r = XftPatternGet(XFT_PATTERN(pattern), __stringVal( attribute ), __intVal( index ), &v);
    if ( r != XftResultMatch) {
        RETURN ( nil );
    }
    if ( v.type == XftTypeString) {
        RETURN ( __MKSTRING(v.u.s) );
    } else if ( v.type == XftTypeInteger ) {
        RETURN ( __MKINT (v.u.i) );
    } else if ( v.type == XftTypeBool ) {
        RETURN ( v.u.b == True ? true : false );
    } else if ( v.type == XftTypeDouble ) {
        RETURN ( __MKFLOAT (v.u.d) );
    } else if ( v.type == XftTypeVoid ) {
        RETURN ( nil );
    } else {
        error = @symbol(UnssuportedTypeValue);
        goto err;
    }
    err:;
#endif
%}.
    self primitiveFailed: error

    "Created: / 20-12-2013 / 21:50:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 21-12-2013 / 01:06:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

xftTextExtents: displayIdArg font: fontIdArg string: text from: start to: stop

    | error extents |

    self primitiveFailedIfNoXft.
    extents :=  Array new: 6.
%{
#ifdef XFT
    XGlyphInfo info;
    int _start, _stop;
    if ( ! __isExternalAddressLike(displayIdArg) ) {
        error = @symbol(BadArg1);
        goto err;
    }
    if ( ! __isExternalAddressLike(fontIdArg) ) {
        error = @symbol(BadArg2);
        goto err;
    }
    if ( ! __isSmallInteger(start) ) {
        error = @symbol(BadArg4);
        goto err;
    }
    _start = __intVal(start);
    if ( ! __isSmallInteger(stop) ) {
        error = @symbol(BadArg5);
        goto err;
    }
    _stop = __intVal(stop);
    if ( __isString(text) ) {
        XftTextExtents8(DISPLAY(displayIdArg), XFT_FONT(fontIdArg),
                        __stringVal(text) + (_start - 1), _stop - _start + 1, &info);
    } else {
        error = @symbol(BadArg3);
        goto err;
    }
    __ArrayInstPtr(extents)->a_element[0] = __MKSMALLINT(info.width);
    __ArrayInstPtr(extents)->a_element[1] = __MKSMALLINT(info.height);
    __ArrayInstPtr(extents)->a_element[2] = __MKSMALLINT(info.x);
    __ArrayInstPtr(extents)->a_element[3] = __MKSMALLINT(info.y);
    __ArrayInstPtr(extents)->a_element[4] = __MKSMALLINT(info.xOff);
    __ArrayInstPtr(extents)->a_element[5] = __MKSMALLINT(info.yOff);
    error = nil;
    err:;
#endif
%}.
    error notNil ifTrue:[
        self primitiveFailed: error.
        ^ nil.
    ].
    ^ extents

    "Created: / 21-12-2013 / 10:42:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 21-12-2013 / 20:53:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!XftFontDescription methodsFor:'queries-dimensions'!

ascent
    "return the ascent - the number of pixels above the baseLine."

    ^ self xftFontGetAscent: fontId

    "Created: / 21-12-2013 / 01:19:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

descent
    "return the descent - the number of pixels below the baseLine."

    ^ self xftFontGetDescent: fontId

    "Created: / 21-12-2013 / 01:20:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

height
    "return the height - the number of pixels above plus below the baseLine."

    ^ self xftFontGetHeight: fontId

    "Created: / 21-12-2013 / 01:20:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

isFixedWidth
    "return true, if this is a fixed pitch font (i.e. all characters
     are of the same width)"

    ^ false "/ How to check?

    "Created: / 21-12-2013 / 10:38:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

widthOf:aString from:start to:stop
    "return the width of a sub string"

    | extents |

    extents := self xftTextExtents: device displayId font: fontId string: aString from: start to: stop.
    "/ extents --> #(width height x y xOff yOff)
    ^ extents first.

    "Created: / 21-12-2013 / 10:42:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!XftFontDescription class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libview/XftFontDescription.st,v 1.4 2013-12-29 11:03:28 vrany Exp $'
!

version_CVS
    ^ '$Header: /cvs/stx/stx/libview/XftFontDescription.st,v 1.4 2013-12-29 11:03:28 vrany Exp $'
! !