Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

textLineBoundedIO sometimes produces incorrect envelopes #19

Closed
byorgey opened this Issue · 4 comments

3 participants

@byorgey
Owner

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...

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

indeed prints 0.

@duplode

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

ct1

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

ct2

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

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

ct3

...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

ct4

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
    where
    extentsToBounds (fe, te) =
        let (xa, _) = unr2 $ CT.advance te
            fh = CT.height fe
        in (xa / fh, 1)
    textBounds = (extentsToBounds <$>)
        . CT.queryCairo . CT.getExtents mempty

ct5

...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.

@byorgey
Owner

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.