"Orphans" prevention system for Unreal RichTextBlock component

*Goal
We are trying to implement an “Orphans” prevention system for unreal, since it is a big deal for our product.

Issue
The system has already been implemented in Unity, where we created a custom extension of the TMP component and had the needed data available in the TextInfo class.

However, for Unreal the component doesn’t seem to expose such data. We would have to compute it ourselves taking into account all the component and widget parameters.

References
We are trying to implement something similar to the “text-wrap: pretty” in CSS.

Questions

  • Are we missing a way were we can get the “TextInfo” data similar to Unity?
  • If not, what is the most advisable way to perform the computation to generate it ourselves?

Thanks.

I just found the variable I’m looking for (LineViews). Shoutouts to this great article

Unfortunatelly, is private on several levels, and since I don’t know how to work around that without modificating the source code, which is not an option, I’ll have to compute the value myself.

The path to get to the variable from the “TextBlock” is the following, for anywone willing to modify the engine:

For TextBlock:

TextBlock->MyTextBlock->TextLayoutCache->TextLayout->LineViews

For RichTextBlock:

RichTextBlock->MyRichTextBlock->TextLayoutCache->TextLayout->LineViews

Really, the need for the information about how the text component is rendering the text is only needed in the case of an “Orphan” being corrected producing an even worst effect of the last line of a paragraph being larger than the previous one:
image

Being kind of a corner case, it can be ignored and fix the Orphans by just processing the text and adding a NBSP character in the final space of each paragraph like so:

// UCMSTextBlock extends from UTextBlock
#define NBSP (TCHAR)160

void UCMSTextBlock::HandleOrphansFixing()
{
	// Convert text to string
	FString textString = Text.ToString();

	// Replace all NBSPs with normal spaces
	for (int i = 0; i < textString.Len(); i++)
		if (textString[i] == NBSP)
			textString[i] = ' ';

	// Look for line breaks and insert NBSP in the previous space
	int lastSpaceIndex = -1;
	for (int i = 0; i < textString.Len(); i++)
	{
		// Space
		if (textString[i] == ' ') 
			lastSpaceIndex = i;

		// Line break or end of the text, replace last space with NBSP
		if ((textString[i] == '\n' || i == textString.Len() - 1) && 
			lastSpaceIndex > 0)
			textString[lastSpaceIndex] = NBSP;
	}

	// Finally, replace component text
	SetText(FText::FromString(textString));
}