Skip to content

Commit 2fc3adf

Browse files
authored
Merge pull request #22714 from ramezgerges/text_trimming_crash
fix: don't use grapheme clusters after they have removed from a line due to TextTrimming or MaxLines
2 parents c073ad8 + d7c3dee commit 2fc3adf

File tree

2 files changed

+77
-13
lines changed

2 files changed

+77
-13
lines changed

src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBlock.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,6 +1871,79 @@ public async Task When_Layered_FlowDirection(string setup)
18711871
_ => throw new InvalidOperationException()
18721872
};
18731873
}
1874+
1875+
[TestMethod]
1876+
[DataRow(TextTrimming.CharacterEllipsis, 0, TextWrapping.NoWrap)]
1877+
[DataRow(TextTrimming.WordEllipsis, 0, TextWrapping.NoWrap)]
1878+
[DataRow(TextTrimming.CharacterEllipsis, 1, TextWrapping.Wrap)]
1879+
[DataRow(TextTrimming.WordEllipsis, 1, TextWrapping.Wrap)]
1880+
[DataRow(TextTrimming.None, 1, TextWrapping.Wrap)]
1881+
public async Task When_Pointer_Selection_Lines_Trimmed(TextTrimming textTrimming, int maxLines, TextWrapping textWrapping)
1882+
{
1883+
var SUT = new TextBlock
1884+
{
1885+
Width = 600,
1886+
TextTrimming = textTrimming,
1887+
TextWrapping = textWrapping,
1888+
MaxLines = maxLines,
1889+
LineHeight = 20,
1890+
LineStackingStrategy = LineStackingStrategy.BlockLineHeight,
1891+
IsTextSelectionEnabled = true,
1892+
Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec dignissim interdum sodales. Aliquam diam eros, malesuada a malesuada vel, congue semper enim. Donec justo magna, consectetur eget facilisis tincidunt, luctus sit amet mauris. Suspendisse sed suscipit velit. Donec egestas, lorem a accumsan faucibus, lectus nibh rutrum nisl, in convallis nulla elit nec velit. Maecenas sollicitudin lacus est, in ultrices leo auctor ut. Phasellus eget leo volutpat ante fermentum porttitor at non enim. Donec convallis sem at scelerisque porttitor. Curabitur ac eleifend libero, et blandit turpis. Aliquam erat volutpat. Phasellus eu rhoncus sapien. Nullam non tortor a turpis luctus pulvinar."
1893+
};
1894+
1895+
var bounds = await UITestHelper.Load(new Border { Child = SUT });
1896+
Assert.AreEqual(bounds.Height, SUT.LineHeight * 1);
1897+
Assert.IsGreaterThan(100, SUT.DesiredSize.Width); // just to make sure that the layout didn't crash
1898+
1899+
var injector = InputInjector.TryCreate() ?? throw new InvalidOperationException("Failed to init the InputInjector");
1900+
using var mouse = injector.GetMouse();
1901+
1902+
mouse.Press(bounds.GetCenter());
1903+
await UITestHelper.WaitForIdle();
1904+
mouse.MoveTo(new Point(bounds.Right + 10, bounds.Bottom + 10));
1905+
await UITestHelper.WaitForIdle();
1906+
mouse.Release();
1907+
await UITestHelper.WaitForIdle();
1908+
1909+
Assert.IsTrue(SUT.SelectedText.Contains(SUT.Text[^20..])); // selection goes to the end of text
1910+
}
1911+
1912+
[TestMethod]
1913+
[CombinatorialData]
1914+
public async Task When_Individual_Run_Has_FlowDirection_Set(FlowDirection flowDirection)
1915+
{
1916+
var SUT = new TextBlock
1917+
{
1918+
Inlines =
1919+
{
1920+
new Run { Text = "english" },
1921+
new Run { Text = "كلام بالعربي!", FlowDirection = flowDirection },
1922+
new Run { Text = "english" },
1923+
}
1924+
};
1925+
1926+
SUT.TextHighlighters.Add(new TextHighlighter
1927+
{
1928+
Ranges = { new TextRange { StartIndex = SUT.Text.IndexOf('!'), Length = 1 } },
1929+
Background = new SolidColorBrush(Colors.Red)
1930+
});
1931+
1932+
await UITestHelper.Load(new Border { Child = SUT });
1933+
var screenshot = await UITestHelper.ScreenShot(SUT);
1934+
var leftHalf = new Rectangle(0, 0, screenshot.Width / 2, screenshot.Height);
1935+
var rightHalf = new Rectangle(screenshot.Width / 2, 0, screenshot.Width / 2, screenshot.Height);
1936+
if (flowDirection is FlowDirection.LeftToRight)
1937+
{
1938+
ImageAssert.HasColorInRectangle(screenshot, rightHalf, Colors.Red);
1939+
ImageAssert.DoesNotHaveColorInRectangle(screenshot, leftHalf, Colors.Red);
1940+
}
1941+
else
1942+
{
1943+
ImageAssert.HasColorInRectangle(screenshot, leftHalf, Colors.Red);
1944+
ImageAssert.DoesNotHaveColorInRectangle(screenshot, rightHalf, Colors.Red);
1945+
}
1946+
}
18741947
#endif
18751948
}
18761949
}

src/Uno.UI/UI/Xaml/Documents/UnicodeText.skia.cs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,8 @@ internal unsafe UnicodeText(
593593
totalHeight += _endingNewLineLineHeight ?? 0;
594594

595595
float maxLineWidthWithoutTrailingSpaces = 0;
596-
_indexToCluster = new List<(int start, int end, LinkedListNode<Cluster> cluster)>(clusterBreaks.Count);
596+
_indexToCluster = new List<(int start, int end, LinkedListNode<Cluster> cluster)>();
597+
_clustersInLogicalOrder = new();
597598
for (var lineIndex = 0; lineIndex < lines.Count; lineIndex++)
598599
{
599600
var line = lines[lineIndex];
@@ -602,23 +603,14 @@ internal unsafe UnicodeText(
602603
{
603604
node.Value = node.Value with { lineIndex = lineIndex };
604605
_indexToCluster.Add((node.Value.start, node.Value.end, node));
606+
_clustersInLogicalOrder.Add(node);
605607
if (node == line.clusterLast)
606608
{
607609
break;
608610
}
609611
}
610612
}
611613

612-
_clustersInLogicalOrder = new(clusterBreaks.Count);
613-
for (var node = clusterBreaks.First; ; node = node!.Next)
614-
{
615-
_clustersInLogicalOrder.Add(node!);
616-
if (node == clusterBreaks.Last)
617-
{
618-
break;
619-
}
620-
}
621-
622614
for (var lineIndex = 0; lineIndex < lines.Count; lineIndex++)
623615
{
624616
var line = lines[lineIndex];
@@ -739,10 +731,9 @@ private static (IEnumerable<LinkedListNode<Cluster>> possibleTrimPoints, int nex
739731
var possibleTrimPoints = new Stack<LinkedListNode<Cluster>>();
740732
var currentCluster = line.clusterStart;
741733
for (var currentlineBreakOpportunity = lineBreakOpportunities[lineBreakOpportunitiesLookupStart];
742-
lineBreakOpportunitiesLookupStart < lineBreakOpportunities.Count && currentlineBreakOpportunity <= line.end;
734+
lineBreakOpportunitiesLookupStart < lineBreakOpportunities.Count && (currentlineBreakOpportunity = lineBreakOpportunities[lineBreakOpportunitiesLookupStart]) <= line.end;
743735
lineBreakOpportunitiesLookupStart++)
744736
{
745-
currentlineBreakOpportunity = lineBreakOpportunities[lineBreakOpportunitiesLookupStart];
746737
while (currentCluster.Value.end < currentlineBreakOpportunity)
747738
{
748739
currentCluster = currentCluster.Next!;

0 commit comments

Comments
 (0)