I wanted to create a small Slate Widget that displays two pieces of text in diffrent font sizes directly next to each other. After rendering the first piece, and advancing my rendering position by the value UCanvas::StrLen( … ) for it, I drew the second piece. The result was the following:
As you can see, the second piece is displaced. After tracing the problem through the sourcecode, I discovered that UCanvas::MeasureStringInternal used the Kerningvalues returned by UFont::GetCharKerning(…), and that these seem be 0 for all characters, which seems to be connected to the newer SlateFonts, whose Kerning values are stored in the FSlateFontCache. My solution to this problem was to write a new measuring method. Please keep in mind that this most likely does not cover all diffrent types of text formatting that can occur:
FVector2D CalculateStringLength(FString String, FSlateFontInfo& FontInfo,float Scale)
{
//Emtpy string
if (String.Len() == 0)
{
return FVector2D(0, 0);
}
//Characterlist from the SlateFontCache
TSharedRef<FSlateFontCache> FontCache = FSlateApplication::Get().GetRenderer()->GetFontCache();
FCharacterList& CharacterList = FontCache->GetCharacterList(FontInfo, Scale);
const TCHAR* pCurrentPos; //where are we now in the string ?
const TCHAR* pPrevPos = 0; //which was the last string ( needed to scaling )
const TCHAR* pText = *String; //Chararray to be iterated
const int32 TextLength = String.Len(); //Length of the String
const int32 YIncrement = FontCache->GetMaxCharacterHeight(FontInfo, Scale);
FVector2D Size = FVector2D(0, YIncrement);
//While our pointer is valid and we are within the bounds of the chararray ...
for (pCurrentPos = pText; *pCurrentPos && pCurrentPos < pText + TextLength; ++pCurrentPos)
{
TCHAR currentChar = *pCurrentPos;
Size.X += CharacterList[currentChar].XAdvance; //Add the width of the current char to the counter
if (currentChar == TEXT('\n') && pCurrentPos + 1 < pText + TextLength && pCurrentPos + 1)
{ // Char is a newline and string is not at end
Size.Y += YIncrement;
pPrevPos = 0; //No kerning when beginning a new line
}
else if (pPrevPos != 0)
{
//Do not forget to take Kerning into account
Size.X += FontCache->GetKerning(FontCache->GetDefaultFontData(FontInfo), FontInfo.Size, *pPrevPos, currentChar, Scale);
}
//Cache last char
pPrevPos = pCurrentPos;
}
return Size;
}
These one uses the values provided by the SlateFontInfo and yields correct result:
Can anyone else confirm this problem ?