Skip to content


Subversion checkout URL

You can clone with
Download ZIP


textLineBoundedIO sometimes produces incorrect envelopes #19

byorgey opened this Issue · 4 comments

3 participants


Consider the following code:

main = do
  txt <- textLineBoundedIO (mempty # fontSize 1) "Washington"
  defaultMain $ (txt <> boundingRect txt) # centerXY # pad 1.1

Here's the output I get:

As you can see, the envelope extends too far to the right. (Just to clarify, I believe the envelope is correct vertically, given the intended semantics of textLineBoundedIO.)

I thought it might have something to do with proportional-width fonts, so I tried the same program but with "Washington" replaced by "iiiiiiiiii". That made the program crash with

user error (invalid matrix (not invertible))

and I'm not sure exactly where that's coming from. Perhaps the envelope has zero width...

main = do
  txt <- textLineBoundedIO (mempty # fontSize 1) "iiiiiiiiii"
  print (width txt)

indeed prints 0.


Some experiments on this issue, performed on Linux with diagrams(-cairo) 0.7 and Cairo 1.12.14. First of all, the invalid matrix issue only happens, it seems, with fontSize set to 1; so the following works:

import Diagrams.Prelude
import Diagrams.Backend.Cairo.CmdLine
import qualified Diagrams.Backend.Cairo.Text as CT

main = issue19 >>= defaultMain

issue19 = do
    txt <- CT.textLineBoundedIO (mempty # fontSize 2) "iiiiiiiiii"
    return $ (txt <> boundingRect txt) # centerXY # pad 1.1


The bounding box, as you likely expected, is even wider relative to the text. Using 'W's instead of 'i's...

issue19W = do
    txt <- CT.textLineBoundedIO (mempty # fontSize 2) "WWWWWWWWWW"
    return $ (txt <> boundingRect txt) # centerXY # pad 1.1


...makes it look almost right; and switching to the monospace font family...

issue19Monospace = do
    txt <- CT.textLineBoundedIO (mempty # fontSize 2 # font "monospace")
    return $ (txt <> boundingRect txt) # centerXY # pad 1.1


...actually goes too far, at least with the fonts available here. All of that suggests Cairo assumes some fixed width value for the characters, regardless of the font.

I also found interesting what happens if you don't set a font size, though I don't know if this is expected behaviour or not.

issue19NoSize = do
    txt <- CT.textLineBoundedIO mempty "iiiiiiiiii"
    return $ (txt <> boundingRect txt) # centerXY # pad 1.1


It goes haywire. Finally, fooling around (literally in my case, as I know nothing about the Cairo API) with the rest of Diagrams.Backend.Cairo.Text shows that scaling down the dimensions given by getTextExtents by the font height from getFontExtents...

issue19ExtentsHack = do
    let ii = "iiiiiiiiii"
    txt <- CT.textLineBoundedIO mempty ii
    bounds <- textBounds ii
    let boundsRect = uncurry rect bounds # pad 1.1 # alignBL
    return $ (txt <> boundsRect)
        # withEnvelope (boundsRect # pad 2) # centerXY
    extentsToBounds (fe, te) =
        let (xa, _) = unr2 $ CT.advance te
            fh = CT.height fe
        in (xa / fh, 1)
    textBounds = (extentsToBounds <$>)
        . CT.queryCairo . CT.getExtents mempty


...results in a rectangle which at least falls within the correct order of magnitude. Incidentally, I actually managed to work around the issue in this way - all I needed was a rectangle which could be used as background for a caption of unspecified length, and with enough ad hoc corrections to the values from getExtents I eventually got a rectangle with acceptable size and alignment.


Thanks for the additional data! My conclusion is that the "toy" text API that comes with cairo is total crap. We really ought to switch to using pango.

This was referenced
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.