Pango

Has anyone here used Pango rendering before? I can't seem to aquire a font map in order to retrieve font metrics. I can render text (it's beautiful) but OpenMotif specifically relies on laying out widgets using the font ascent, descent, and average character width.

Some of you may recall from a while back, I had some questions regarding bidirectional text rendering with OpenMotif. Here's a link: http://www.cplusplus.com/forum/unices/19501/

I have since moved in the direction of manually integrating Pango into OpenMotif to support my requirements. I've encountered a lot of resistance in my efforts but I'm finally getting very close.

I think my approach/use of the library may be wrong. Could anyone give me a brief high-level set of steps to render text with Pango?

Here's what I have been trying:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//
// to get the font metrics
//
PangoFontMetrics * MY_GetFontMetrics( Display * display,
                                      PangoFontDescription * font )                                                              
{
    PangoFontMetrics * metrics = 0;
    PangoFontMap * fontmap = pango_cairo_font_map_get_default();  // this doesn't work (returns null)
    if( fontmap )
    {
        PangoContext * context
            = pango_cairo_font_map_create_context( (PangoCairoFontMap *)fontmap );
        if( context )
        {
            pango_context_set_font_description( context, font );
            PangoLanguage * lang = pango_language_from_string( "en_US" );
            metrics = (PangoFontMetrics *)pango_context_get_metrics( context, font, lang );
            g_object_unref( context );
        }
    }
    return metrics;                   
}


//
// to render a string (works)
//
void MY_RenderString( Display * display, Drawable d, GC gc,
                      PangoFontDescription * font,
                      int x, int y,
                      char * string, int length )
{  
    // cairo surface dimensions (max)
    XRectangle ink, logical;
    MY_TextExtents( string, length, font, &ink, &logical ); // see note below about this
    const int SIZEX = logical.width;
    const int SIZEY = logical.height;
     
    // create a cairo surface
    cairo_surface_t * cs = cairo_xlib_surface_create( display, d,
                                                      DefaultVisual( display, 0 ),
                                                      SIZEX, SIZEY );
    if( cs )
    {
        cairo_t * cr = cairo_create( cs );
        if( cr )
        {
            cairo_translate( cr, x, y );
                                                                                                                        
            PangoLayout * layout = pango_cairo_create_layout( cr );
            if( layout )               
            {           
                pango_layout_set_text( layout, string, length );
                pango_layout_set_font_description( layout, font );

//              the function to get the text extents basically does the same
//              thing as this function to get a surface, context, and layout then calls this:
//              pango_layout_get_extents( layout, &ink_rect, &logical_rect );

                // extract the foreground Pixel from the GC
                XGCValues gcv;         
                XGetGCValues( display, gc, GCForeground, &gcv );
                XColor xcolor;         
                xcolor.pixel = gcv.foreground;
                                       
                // convert the Pixel to RGB values
                Colormap cmap = DefaultColormap( display, 0 );
                XQueryColor( display, cmap, &xcolor );
                // set the source RGB in cairo
                cairo_set_source_rgb( cr, xcolor.red   / (float)0xFFFF,
                                          xcolor.green / (float)0xFFFF,
                                          xcolor.blue  / (float)0xFFFF );
             
                pango_cairo_update_layout( cr, layout );
                pango_cairo_show_layout( cr, layout );
        
                g_object_unref( layout );
            }                  
            cairo_destroy( cr );
        }
    }                          
    cairo_surface_destroy( cs );
}


The application only stores a PangoFontDescription *, acquired one time only like this:
 
PangoFontDescription * font = pango_font_description_from_string( "Sans 13" );


Now, call me crazy, but I can run this in one of my VMs and it works but on the physical machine it does not. I created another VM (same configuration to the best of my knowledge) and it did not work in it, either. All three are RHEL 5.2 using the libraries that came on the disc (I installed everything).

Any ideas?
Last edited on
I have an update! I'll explain some details in hopes that someday this will help someone else with a similar situation.

From the Pango mailing list (gtk-i18n-list), I had the impression that a PangoFontMap * should be retained for the life of the application. While I was trying to hack together a few tests to narrow down my problem, I created a global pointer, fontmap, and an initialize function to set it only once. I could compile and link my test application but it still would not run on the other two machines... I was getting a "symbol lookup error: undefined reference" for my initialize function. This seemed odd at the time because it would link... I thought, "Am I using the right library?"

Here's some investigation:
[user@lab ~]$ ./a.out 
./a.out: symbol lookup error: ./a.out: undefined symbol: MY_Initialize
[user@lab ~]$ env|grep LD_LIBRARY_PATH
LD_LIBRARY_PATH=/home/user/lib/motif
[user@lab ~]$ ldd -d -r a.out 
undefined symbol: MY_Initialize      (./a.out)
        linux-gate.so.1 =>  (0x00a8d000)
        libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x05cd9000)
        libpng12.so.0 => /usr/lib/libpng12.so.0 (0x0036e000)
        libpango-1.0.so.0 => /usr/lib/libpango-1.0.so.0 (0x06269000)
        libcairo.so.2 => /usr/lib/libcairo.so.2 (0x05df8000)
        libpangocairo-1.0.so.0 => /usr/lib/libpangocairo-1.0.so.0 (0x05ded000)
        libglib-2.0.so.0 => /lib/libglib-2.0.so.0 (0x05c39000)
        libXm.so.4 => /home/user/lib/motif/libXm.so.4 (0x00af4000)
        libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x0018c000)
        libm.so.6 => /lib/libm.so.6 (0x00d66000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x05b02000)
        libc.so.6 => /lib/libc.so.6 (0x003b2000)
        libXt.so.6 => /usr/lib/libXt.so.6 (0x06c0e000)
        libz.so.1 => /usr/lib/libz.so.1 (0x00dae000)
        libgobject-2.0.so.0 => /lib/libgobject-2.0.so.0 (0x05cfd000)
        libgmodule-2.0.so.0 => /lib/libgmodule-2.0.so.0 (0x05d3e000)
        libdl.so.2 => /lib/libdl.so.2 (0x00d8f000)
        libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x05a43000)
        libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0x05ac5000)
        libXrender.so.1 => /usr/lib/libXrender.so.1 (0x00de2000)
        libX11.so.6 => /usr/lib/libX11.so.6 (0x00246000)
        libpangoft2-1.0.so.0 => /usr/lib/libpangoft2-1.0.so.0 (0x06202000)
        librt.so.1 => /lib/librt.so.1 (0x05c24000)
        libXmu.so.6 => /usr/lib/libXmu.so.6 (0x0656a000)
        libXext.so.6 => /usr/lib/libXext.so.6 (0x00dd0000)
        libXp.so.6 => /usr/lib/libXp.so.6 (0x00115000)
        /lib/ld-linux.so.2 (0x00396000)
        libSM.so.6 => /usr/lib/libSM.so.6 (0x05c19000)
        libICE.so.6 => /usr/lib/libICE.so.6 (0x05bfd000)
        libexpat.so.0 => /lib/libexpat.so.0 (0x0034b000)
        libXau.so.6 => /usr/lib/libXau.so.6 (0x00dcb000)
        libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0x00dc3000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x00d95000)
[user@lab ~]$ 

So, it's using the correct library but the symbol is not defined.

[user@lab ~]$ nm lib/motif/libXm.so.4 | c++filt | grep MY_
0013dc30 T MY_DrawString
0013d9e0 T MY_TextExtents
0013dbd0 T MY_XDrawImageString
0013db70 T MY_XDrawString
[user@lab ~]$ 

What about my compile machine?

[user@workstation ~]$ nm lib/motif/libXm.so.4 | c++filt | grep MY
0013ebc0 T MY_AverageCharWidth
0013ef10 T MY_DrawImageString
0013ee00 T MY_DrawString
0013eae0 T MY_FontAscent
0013eb50 T MY_FontDescent
0013ef70 T MY_GetFontMetrics
0013eaa0 T MY_Initialize
0013f030 T MY_RenderString
0013ec30 T MY_TextExtents
0013ee60 T MY_TextFDrawString
[user@workstation ~]$ 


OpenMotif, the library that I am working on, has a few lib directorys, etc.. So, it turns out that I was mistakenly copying over the wrong version of libXm.so the whole time. Here's the information that was hastily overlooked:
Now, call me crazy, but I can run this in one of my VMs and it works but on the physical machine it does not. I created another VM (same configuration to the best of my knowledge) and it did not work in it, either. All three are RHEL 5.2 using the libraries that came on the disc (I installed everything).
When dealing with shared libraries and an application works on one machine but not another, the first thing to verify is that you are using the right library version at runtime.

The snippet above works. :)

Last edited on
Topic archived. No new replies allowed.