The way it works is there is a baseline that characters sit on (the bottom of normal text). This baseline is set at a Y of the position + characterSize.
So if your text position is 0,0 and the font is size 20, the baseline will be at a Y of 20.
Each glyph (character) in a font has a relative size compared to the baseline. For example 'G' has a relative rectangle of 1,-15,13,15. This means it starts 1 pixel to the right of the current cursor and 15 pixels above the baseline, then is for 13 pixels wide and 15 pixels high. So it sits on the baseline.
A character like 'y' hangs the tail below the baseline. 'y' is 0,-11,10,15. So it goes 11 above the baseline and 4 below (and including) the baseline. That means the actual global bounds of the letter 'y' with a character size of 20 would be from Y=9 to Y=23.
I did a quick test, in the standard ascii characters (0-127) with arial font at size 20, the tallest characters (like '$') would have a top at Y=3 and the most hanging down characters have a bottom at Y=23 (like brackets, 'y', etc).
Yeah, it's a bit annoying, but that's how fonts work.
You can ask a font for the size of each character using font.getGlyph. (Got to do it one at a time).
So basically if you have arial.ttf at size 20, you need a text box at least 24 pixels high to fit in characters that go below the baseline.
I don't think there's an easy way to know the min/max of an entire font other than to loop over every glyph and find them yourself. Although I also haven't looked hard, I just wanted to find the numbers so a loop was fine.