From a8b14fd29cf7cebd10d46cb44f99253085cfe43b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 27 Jan 2023 10:08:41 +0100 Subject: [PATCH] Fix the 4rd hardest problem in computer science. Off by one errors. --- .../Automation/Peers/TextBoxAutomationPeer.cs | 2 +- .../Automation/Provider/TextRange.cs | 8 ++-- .../Automation/AutomationTextRange.cs | 38 ++++++++++++++++--- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs index 19bfcc27c6..ec70fd2831 100644 --- a/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs @@ -63,7 +63,7 @@ namespace Avalonia.Automation.Peers public IReadOnlyList GetSelection() { - var range = TextRange.FromInclusiveStartEnd(Owner.SelectionStart, Owner.SelectionEnd); + var range = TextRange.FromStartEnd(Owner.SelectionStart, Owner.SelectionEnd); return new[] { range }; } diff --git a/src/Avalonia.Controls/Automation/Provider/TextRange.cs b/src/Avalonia.Controls/Automation/Provider/TextRange.cs index dd732fb691..0f018ba758 100644 --- a/src/Avalonia.Controls/Automation/Provider/TextRange.cs +++ b/src/Avalonia.Controls/Automation/Provider/TextRange.cs @@ -45,12 +45,12 @@ namespace Avalonia.Automation.Provider public static TextRange Empty => new(0, 0); /// - /// Creates a new from an inclusive start and end index. + /// Creates a new from an exclusive start and end index. /// - /// The inclusive start index of the range. - /// The inclusive end index of the range. + /// The exclusive start index of the range. + /// The exclusive end index of the range. /// - public static TextRange FromInclusiveStartEnd(int start, int end) + public static TextRange FromStartEnd(int start, int end) { var s = Math.Min(start, end); var e = Math.Max(start, end); diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationTextRange.cs b/src/Windows/Avalonia.Win32/Automation/AutomationTextRange.cs index 66dffc3cec..5faf58fcad 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationTextRange.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationTextRange.cs @@ -12,6 +12,8 @@ namespace Avalonia.Win32.Automation internal class AutomationTextRange : ITextRangeProvider { private readonly AutomationNode _owner; + private int _start; + private int _end; public AutomationTextRange(AutomationNode owner, TextRange range) : this(owner, range.Start, range.End) @@ -21,13 +23,37 @@ namespace Avalonia.Win32.Automation public AutomationTextRange(AutomationNode owner, int start, int end) { _owner = owner; - Start = start; - End = end; + _start = start; + _end = end; + } + + public int Start + { + get => _start; + private set + { + if (value < 0) + throw new InvalidOperationException(); + if (value > _end) + _end = value; + _start = value; + } + } + + public int End + { + get => _end; + private set + { + if (value < 0) + throw new InvalidOperationException(); + if (value < _start) + _start = value; + _end = value; + } } - public int Start { get; private set; } - public int End { get; private set; } - public TextRange Range => TextRange.FromInclusiveStartEnd(Start, End); + public TextRange Range => new(Start, End); private AAP.ITextProvider InnerProvider => (AAP.ITextProvider)_owner.Peer; @@ -410,7 +436,7 @@ namespace Avalonia.Win32.Automation case TextUnit.Word: for (moved = 0; moved > count && index > 0; moved--) { - for (index--; index < text.Length && IsWordBreak(text[index]); index--) + for (index--; index >= 0 && IsWordBreak(text[index]); index--) ; for (index--; !AtWordBoundary(text, index); index--) ;