Determine where a line breaks

Is there a way to determine the position of a line break in UiToolkit, I want to be able to get the position in a string where it wraps onto a new line.

The closest I’ve got is to use UnityEngine.TextGenerator to generate the string and get the lines from that although it doesn’t seem 100% accurate.

my current implemention:

public static IList<UILineInfo> GetTextLineData(TextElement element)
		{
			var style = element.resolvedStyle;
			var settings = new TextGenerationSettings
			{
				font = style.unityFont,
				fontSize = 12,
				richText = true,
				scaleFactor = 1,
				fontStyle = style.unityFontStyleAndWeight,
				textAnchor = style.unityTextAlign,
				resizeTextForBestFit = false,
				updateBounds = false,
				horizontalOverflow = HorizontalWrapMode.Wrap,
				verticalOverflow = VerticalWrapMode.Truncate,
				generationExtents = new Vector2(element.contentRect.width, element.contentRect.height),
				alignByGeometry = true
			};

			var generator = new TextGenerator();
			var isvalid = generator.Populate(element.text, settings);
			Debug.Log($"Generated {generator.lineCount} Lines : Is Valid {isvalid}");
			return generator.lines;
		}

So i’ve got a working solution:

public static IList<int> GetTextLineData(TextElement element)
		{
			var startLineIndices = new List<int>();
			
			var bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
			var uitkTextHandleField = typeof(TextElement).GetProperty("uitkTextHandle", bindingFlags);
			if (uitkTextHandleField == null) return startLineIndices;
			
			var uitkTextHandle = uitkTextHandleField.GetValue(element);

			if (uitkTextHandleField.PropertyType.BaseType == null) return startLineIndices;
			
			var textInfoField = uitkTextHandleField.PropertyType.BaseType.GetField("m_TextInfo", bindingFlags);
			if (textInfoField == null) return startLineIndices;
			
			var textInfo = textInfoField.GetValue(uitkTextHandle);

			if (textInfo == null) return startLineIndices;

			var lineInfoArrayField = textInfoField.FieldType.GetField("lineInfo", bindingFlags);
			if (lineInfoArrayField == null) return startLineIndices;
			
			var lineInfoArray = (Array)lineInfoArrayField.GetValue(textInfo);

			var lineInfoType = lineInfoArray.GetType().GetElementType();
			if (lineInfoType == null) return startLineIndices;
			
			var firstCharacterIndexField = lineInfoType.GetField("firstCharacterIndex", bindingFlags);
			foreach (var lineInfo in lineInfoArray)
			{
				if (firstCharacterIndexField != null)
				{
					startLineIndices.Add((int)firstCharacterIndexField.GetValue(lineInfo));
				}
			}

			return startLineIndices;
		}

This finds the TextHandle in the TextElement, get the TextInfo that is generated when the textelement generates the text to be shown, I then get the LineInfo array go through all LineInfos to get the indices in the string where new lines start.

All of these fields and classes are internal so reflection was the only way to get this information.
It’s also worth noting that it looks like this data isn’t populated straight away so might need to wait on some event, i’m not sure.