For the record I use this function to do the job. If it becomes a bottleneck, I will only check characters at the start and ends of lines, rather than looping through all of them, but it's not going to be called very often at all, so...
Also, there are a couple of hacks for the width detection, which I couldn't get quite right.
sf::FloatRect get_string_area(const sf::String& str) {
const sf::Font& font = str.GetFont();
const std::string& text = str.GetText();
float right, bottom;
sf::FloatRect r; //Start with relative positions to begin with
for (uint char_i = 0; char_i < text.length(); ++char_i) {
const sf::Vector2f& pos = str.GetCharacterPos(char_i);
const sf::IntRect& glyph_rect = font.GetGlyph(text[char_i]).Rectangle;
const sf::Vector2f size(glyph_rect.GetWidth(), glyph_rect.GetHeight());
right = pos.x + size.x; bottom = pos.y + size.y;
if (pos.y < r.Top) { r.Top = pos.y; }
if (pos.x < r.Left) { r.Left = pos.x; }
if (right > r.Right) { r.Right = right; }
if (bottom > r.Bottom) { r.Bottom = bottom; }
}
const sf::FloatRect& str_r = str.GetRect();
sf::Vector2f pos = str.GetPosition();
pos.y += str_r.GetHeight() - r.GetHeight(); //Deals with the offset
pos.x += (str_r.GetWidth() - r.GetWidth()) / 2;
r.Left += pos.x + 2; r.Right += pos.x; //The plus 2 is a hack.
r.Top += pos.y; r.Bottom += pos.y;
return r;
}