Fixes to make XftFontDescription>>example1 to render something. Sometimes it segfaults
authorJan Vrany <jan.vrany@fit.cvut.cz>
Sun, 29 Dec 2013 12:03:28 +0100
changeset 6182 8bf2372670d9
parent 6181 d90dd329fe6a
child 6183 a21827076de1
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)
XftFontDescription.st
--- a/XftFontDescription.st	Tue Dec 24 12:16:04 2013 +0100
+++ b/XftFontDescription.st	Sun Dec 29 12:03:28 2013 +0100
@@ -1,7 +1,8 @@
 "{ Package: 'stx:libview' }"
 
 FontDescription subclass:#XftFontDescription
-	instanceVariableNames:'device fontId drawId'
+	instanceVariableNames:'device fontId drawId lasrFgColor lastFgColorId lastBgColor
+		lastBgColorId'
 	classVariableNames:''
 	poolDictionaries:''
 	category:'Graphics-Support'
@@ -20,13 +21,24 @@
 #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>
-# define __XftFontVal(handle) ((XftFont*)__externalAddressVal(handle))
-# define __XftPatternVal(handle) ((XftPattern*)__externalAddressVal(handle))
-# define __XftDrawVal(handle) ((XftDraw*)__externalAddressVal(handle))
-# define __XftColorVal(handle) ((XftColor*)__externalAddressVal(handle))
+
 #endif
 
 %}
@@ -81,7 +93,7 @@
 
     textView := EditTextView new.
     textView origin:0.0 @ 0.0 corner:1.0 @ 1.0.
-    textView basicFont: (XftFontDescription family: 'helvetica' size: 30).
+    textView basicFont: (XftFontDescription family: 'helvetica' size: 16).
 
     top addSubView:textView.
 
@@ -90,6 +102,65 @@
     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'!
@@ -135,7 +206,7 @@
         ] ifFalse:[
             self xftPatternAdd: myPatternId attribute: 'size' value: size.
         ].
-        newFontId := self xftFontOpenPattern: aGraphicsDevice displayId pattern: myPatternId.  
+        newFontId := self xftFontOpenPattern: aGraphicsDevice displayId pattern: myPatternId.
         newFontId notNil ifTrue:[
             "/ Good, this font exist!!
             fontId := newFontId.
@@ -159,7 +230,7 @@
             newFontId isNil ifTrue:[
                 self error: 'Pattern matched, but font could be open (should not happen)'.
             ].
-            ^ self class new                
+            ^ self class new
                 setDevice: aGraphicsDevice patternId: closestPatternId2 fontId: newFontId;
                 yourself.
         ].
@@ -194,7 +265,7 @@
     device := deviceArg.
     fontId := fontIdArg.
 
-    family  := self xftPatternGet: patternIdArg attribute: 'family' index: 0.  
+    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'].
@@ -219,6 +290,251 @@
     "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 |
@@ -231,7 +547,7 @@
         error = @symbol(BadArg1);
         goto err;
     }
-    v = ((XftFont*)__externalAddressVal(fontIdArg))->ascent;
+    v = XFT_FONT(fontIdArg)->ascent;
     RETURN ( __MKINT( v ) );
     err:;
 #endif
@@ -253,7 +569,7 @@
         error = @symbol(BadArg1);
         goto err;
     }
-    v = ((XftFont*)__externalAddressVal(fontIdArg))->descent;
+    v = XFT_FONT(fontIdArg)->descent;
     RETURN ( __MKINT( v ) );
     err:;
 #endif
@@ -275,7 +591,7 @@
         error = @symbol(BadArg1);
         goto err;
     }
-    v = ((XftFont*)__externalAddressVal(fontIdArg))->height;
+    v = XFT_FONT(fontIdArg)->height;
     RETURN ( __MKINT( v ) );
     err:;
 #endif
@@ -297,7 +613,7 @@
         error = @symbol(BadArg1);
         goto err;
     }
-    p = ((XftFont*)__externalAddressVal(fontIdArg))->pattern;
+    p = XFT_FONT(fontIdArg)->pattern;
     if (p == NULL) {
         RETURN ( nil );
     } else {
@@ -334,7 +650,7 @@
         goto err;
     }
 
-    p = XftFontMatch( __externalAddressVal(displayId) , __intVal( screen ), __externalAddressVal( patternId ), &r );
+    p = XftFontMatch( DISPLAY(displayId) , SCREEN( screen ), XFT_PATTERN( patternId ), &r );
     if (r == XftResultMatch) {
         RETURN ( __MKEXTERNALADDRESS ( p ) );
     } else {
@@ -368,7 +684,7 @@
         goto err;
     }
 
-    f = XftFontOpenPattern( __externalAddressVal(displayId) , __externalAddressVal( patternId ) );
+    f = XftFontOpenPattern( DISPLAY(displayId) , XFT_PATTERN( patternId ) );
     if (f == NULL) {
         RETURN ( nil );
     } else {
@@ -438,7 +754,7 @@
     	error = @symbol(BadArg3);
     	goto err;
     }
-    b = XftPatternAdd( __externalAddressVal(pattern), __stringVal(attribute), v, append == true ? True : False );
+    b = XftPatternAdd( XFT_PATTERN(pattern), __stringVal(attribute), v, append == true ? True : False );
     RETURN ( b == True ? true : false );
 
     err:;
@@ -477,7 +793,7 @@
     	error = @symbol(BadArg2);
     	goto err;
     }
-    XftPatternDel( __externalAddressVal(pattern), __stringVal ( attribute ) );
+    XftPatternDel( XFT_PATTERN(pattern), __stringVal ( attribute ) );
     RETURN ( self );
 
     err:;
@@ -501,7 +817,7 @@
         error = @symbol(BadArg1);
         goto err;
     }
-    XftPatternDestroy( __externalAddressVal(addr) );
+    XftPatternDestroy( XFT_PATTERN(addr) );
     RETURN ( self );
 
     err:;
@@ -526,7 +842,7 @@
         error = @symbol(BadArg1);
         goto err;
     }
-    RETURN ( __MKEXTERNALADDRESS ( XftPatternDuplicate( __externalAddressVal(addr) ) ) );
+    RETURN ( __MKEXTERNALADDRESS ( XftPatternDuplicate( XFT_PATTERN(addr) ) ) );
     err:;
 #endif
 %}.
@@ -559,7 +875,7 @@
         error = @symbol(BadArg3);
         goto err;
     }
-    r = XftPatternGet(__externalAddressVal( pattern ), __stringVal( attribute ), __intVal( index ), &v);
+    r = XftPatternGet(XFT_PATTERN(pattern), __stringVal( attribute ), __intVal( index ), &v);
     if ( r != XftResultMatch) {
         RETURN ( nil );
     }
@@ -584,6 +900,61 @@
 
     "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'!
@@ -610,15 +981,36 @@
     ^ 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.3 2013-12-21 00:21:22 vrany Exp $'
+    ^ '$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.3 2013-12-21 00:21:22 vrany Exp $'
+    ^ '$Header: /cvs/stx/stx/libview/XftFontDescription.st,v 1.4 2013-12-29 11:03:28 vrany Exp $'
 ! !