3.5 Using the low-level interface

Using Pangomonium's low-level interface is more difficult than using the high-level interface because it allows you to access Pango and Cairo APIs directly. This means that you should first make yourself familiar with those APIs so that you know how they are designed and how they can serve your purposes.

On top of the core Pango and Cairo APIs, Pangomonium also offers some special functions that can be used to bridge Pango/Cairo calls and Hollywood functions. One of the key functions that serves as such a bridge is csurface:ToBrush() which allows you to convert a Cairo surface to a Hollywood brush. Conversely, it is also possible to create Cairo surfaces from Hollywood brushes by using the cairo.ImageSurfaceFromBrush() function.

By using these bridging functions, you can use Pango/Cairo APIs directly and then convert the result to a Hollywood brush. For example, drawing text using Pango typically involves the following steps:

  1. Create a Pango fontmap
  2. Create a Pango context from the fontmap
  3. Create a Pango layout from the context
  4. Create a Pango font description and assign it to the layout
  5. Load a font into the fontmap
  6. Set text that is to be rendered
  7. Create a Cairo surface
  8. Create a Cairo context from the surface
  9. Show the Pango layout on the Cairo context
  10. Convert the Cairo surface to a Hollywood brush

As you can see, it's quite some work to draw text with Pangomonium when using the Pango/Cairo APIs directly. It's much easier to do it with the high-level interface but only the low-level interface allows you to access all of Pango's and Cairo's features.

Here is what the steps described above look like in actual code:

 
@REQUIRE "pangomonium"
@DISPLAY {Color = #WHITE}

fontmap = pango.FontMap(#CAIRO_FONT_TYPE_FT)
context = fontmap:CreateContext()
layout = pango.Layout(context)
fontdesc = pango.FontDescription("DejaVu Sans 72")
layout:SetFontDescription(fontdesc)
fontmap:LoadFont(context, fontdesc)
layout:SetText("Hello World")
img = cairo.ImageSurface(#CAIRO_FORMAT_ARGB32, 640, 480)
cr = cairo.Context(img)
cr:ShowLayout(layout)
img:ToBrush(1)
DisplayBrush(1, 0, 0)

When using the low-level interface you also need to think about freeing objects when they are no longer in use. This can be done by calling the Free() methods of the individual objects, e.g. pcontext:Free() to free a Pango context. Alternatively, you can also set the object to Nil. This signals Hollywood's garbage collector that the object is no longer in use and can be freed. However, keep in mind that garbage collection will only occur if there are really no more references to the object anywhere. Thus, it might be safer to explicitly call the Free() methods instead of setting objects to Nil.

If you put the code from the example above in a function and use local variables only, however, you can get away without explicitly calling Free() on all objects because local variables will automatically be garbage-collected once they go out of scope. Consider the following code, which is the same as above with the only difference that the code is now wrapped inside a function:

 
Function p_DrawText(t$, brush)
   Local fontmap = pango.FontMap()
   Local context = fontmap:CreateContext()
   Local layout = pango.Layout(context)
   Local fontdesc = pango.FontDescription("DejaVu Sans 72")
   layout:SetFontDescription(fontdesc)
   fontmap:LoadFont(context, fontdesc)
   layout:SetText(t$)
   Local img = cairo.ImageSurface(#CAIRO_FORMAT_ARGB32, 640, 480)
   Local cr = cairo.Context(img)
   cr:ShowLayout(layout)
   img:ToBrush(brush)
EndFunction

Since all Pango and Cairo objects are stored inside local variables, everything will be marked for garbage collection as soon as the function returns. Thus, in this case it isn't necessary to explicitly free objects by calling Free(), even though it might be considered good practice to do so nevertheless.

For more information on the Pango and Cairo APIs, please refer to the following chapters.


Show TOC