diff --git a/build/SharedVersion.props b/build/SharedVersion.props
index 2849262591..3239ca830a 100644
--- a/build/SharedVersion.props
+++ b/build/SharedVersion.props
@@ -4,7 +4,7 @@
Avalonia
11.0.999
Avalonia Team
- Copyright 2022 © The AvaloniaUI Project
+ Copyright 2013-$([System.DateTime]::Now.ToString(`yyyy`)) © The AvaloniaUI Project
https://avaloniaui.net
https://github.com/AvaloniaUI/Avalonia/
true
diff --git a/samples/Sandbox/Sandbox.csproj b/samples/Sandbox/Sandbox.csproj
index d2e66988e0..7a57a13529 100644
--- a/samples/Sandbox/Sandbox.csproj
+++ b/samples/Sandbox/Sandbox.csproj
@@ -5,6 +5,7 @@
net6.0
true
true
+
diff --git a/src/Avalonia.Base/Interactivity/RoutedPropertyChangedEventArgs.cs b/src/Avalonia.Base/Interactivity/RoutedPropertyChangedEventArgs.cs
deleted file mode 100644
index 22134b518d..0000000000
--- a/src/Avalonia.Base/Interactivity/RoutedPropertyChangedEventArgs.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-namespace Avalonia.Interactivity
-{
- ///
- /// Provides both old and new property values with a routed event.
- ///
- /// The type of values.
- public class RoutedPropertyChangedEventArgs : RoutedEventArgs
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The old property value.
- /// The new property value.
- /// The routed event associated with these event args.
- public RoutedPropertyChangedEventArgs(T oldValue, T newValue, RoutedEvent? routedEvent)
- : base(routedEvent)
- {
- OldValue = oldValue;
- NewValue = newValue;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The old property value.
- /// The new property value.
- /// The routed event associated with these event args.
- /// The source object that raised the routed event.
- public RoutedPropertyChangedEventArgs(T oldValue, T newValue, RoutedEvent? routedEvent, object? source)
- : base(routedEvent, source)
- {
- OldValue = oldValue;
- NewValue = newValue;
- }
-
- ///
- /// Gets the old value of the property.
- ///
- public T OldValue { get; init; }
-
- ///
- /// Gets the new value of the property.
- ///
- public T NewValue { get; init; }
- }
-}
diff --git a/src/Avalonia.Base/Media/CharacterHit.cs b/src/Avalonia.Base/Media/CharacterHit.cs
index 6bbbff4f5b..27cf3a42dc 100644
--- a/src/Avalonia.Base/Media/CharacterHit.cs
+++ b/src/Avalonia.Base/Media/CharacterHit.cs
@@ -19,6 +19,7 @@ namespace Avalonia.Media
/// Index of the first character that got hit.
/// In the case of a leading edge, this value is 0. In the case of a trailing edge,
/// this value is the number of code points until the next valid caret position.
+ [DebuggerStepThrough]
public CharacterHit(int firstCharacterIndex, int trailingLength = 0)
{
FirstCharacterIndex = firstCharacterIndex;
diff --git a/src/Avalonia.Base/Media/TextFormatting/BidiReorderer.cs b/src/Avalonia.Base/Media/TextFormatting/BidiReorderer.cs
index 4db55fae6d..39ef8cce48 100644
--- a/src/Avalonia.Base/Media/TextFormatting/BidiReorderer.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/BidiReorderer.cs
@@ -18,14 +18,14 @@ namespace Avalonia.Media.TextFormatting
public static BidiReorderer Instance
=> t_instance ??= new();
- public void BidiReorder(Span textRuns, FlowDirection flowDirection)
+ public IndexedTextRun[] BidiReorder(Span textRuns, FlowDirection flowDirection, int firstTextSourceIndex)
{
Debug.Assert(_runs.Length == 0);
Debug.Assert(_ranges.Length == 0);
if (textRuns.IsEmpty)
{
- return;
+ return Array.Empty();
}
try
@@ -46,6 +46,22 @@ namespace Avalonia.Media.TextFormatting
// Reorder them into visual order.
var firstIndex = LinearReorder();
+ var indexedTextRuns = new IndexedTextRun[textRuns.Length];
+
+ for (var i = 0; i < textRuns.Length; i++)
+ {
+ var currentRun = textRuns[i];
+
+ indexedTextRuns[i] = new IndexedTextRun
+ {
+ TextRun = currentRun,
+ TextSourceCharacterIndex = firstTextSourceIndex,
+ RunIndex = i,
+ NextRunIndex = i + 1
+ };
+
+ firstTextSourceIndex += currentRun.Length;
+ }
// Now perform a recursive reversal of each run.
// From the highest level found in the text to the lowest odd level on each line, including intermediate levels
@@ -76,7 +92,7 @@ namespace Avalonia.Media.TextFormatting
if (max == 0 || (min == max && (max & 1) == 0))
{
// Nothing to reverse.
- return;
+ return indexedTextRuns;
}
// Now apply the reversal and replace the original contents.
@@ -107,13 +123,25 @@ namespace Avalonia.Media.TextFormatting
var index = 0;
currentIndex = firstIndex;
+
while (currentIndex >= 0)
{
ref var current = ref _runs[currentIndex];
- textRuns[index++] = current.Run;
+
+ textRuns[index] = current.Run;
+
+ var indexedRun = indexedTextRuns[index];
+
+ indexedRun.RunIndex = current.RunIndex;
+
+ indexedRun.NextRunIndex = current.NextRunIndex;
+
+ index++;
currentIndex = current.NextRunIndex;
}
+
+ return indexedTextRuns;
}
finally
{
@@ -227,25 +255,6 @@ namespace Avalonia.Media.TextFormatting
return previousIndex;
}
- private struct OrderedBidiRun
- {
- public OrderedBidiRun(int runIndex, TextRun run, sbyte level)
- {
- RunIndex = runIndex;
- Run = run;
- Level = level;
- NextRunIndex = -1;
- }
-
- public int RunIndex { get; }
-
- public sbyte Level { get; }
-
- public TextRun Run { get; }
-
- public int NextRunIndex { get; set; } // -1 if none
- }
-
private struct BidiRange
{
public BidiRange(sbyte level, int leftRunIndex, int rightRunIndex, int previousRangeIndex)
@@ -265,4 +274,23 @@ namespace Avalonia.Media.TextFormatting
public int PreviousRangeIndex { get; } // -1 if none
}
}
+
+ internal struct OrderedBidiRun
+ {
+ public OrderedBidiRun(int runIndex, TextRun run, sbyte level)
+ {
+ RunIndex = runIndex;
+ Run = run;
+ Level = level;
+ NextRunIndex = -1;
+ }
+
+ public int RunIndex { get; }
+
+ public sbyte Level { get; }
+
+ public TextRun Run { get; }
+
+ public int NextRunIndex { get; set; } // -1 if none
+ }
}
diff --git a/src/Avalonia.Base/Media/TextFormatting/IndexedTextRun.cs b/src/Avalonia.Base/Media/TextFormatting/IndexedTextRun.cs
new file mode 100644
index 0000000000..0eb98533d2
--- /dev/null
+++ b/src/Avalonia.Base/Media/TextFormatting/IndexedTextRun.cs
@@ -0,0 +1,10 @@
+namespace Avalonia.Media.TextFormatting
+{
+ internal class IndexedTextRun
+ {
+ public int TextSourceCharacterIndex { get; init; }
+ public int RunIndex { get; set; }
+ public int NextRunIndex { get; set; }
+ public TextRun? TextRun { get; init; }
+ }
+}
diff --git a/src/Avalonia.Base/Media/TextFormatting/TextBounds.cs b/src/Avalonia.Base/Media/TextFormatting/TextBounds.cs
index 93edf68348..946c2e6931 100644
--- a/src/Avalonia.Base/Media/TextFormatting/TextBounds.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/TextBounds.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Diagnostics;
namespace Avalonia.Media.TextFormatting
{
@@ -10,6 +11,7 @@ namespace Avalonia.Media.TextFormatting
///
/// Constructing TextBounds object
///
+ [DebuggerStepThrough]
internal TextBounds(Rect bounds, FlowDirection flowDirection, IList runBounds)
{
Rectangle = bounds;
diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
index a0d7cabefd..c2ec78e187 100644
--- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
@@ -4,8 +4,12 @@ using Avalonia.Utilities;
namespace Avalonia.Media.TextFormatting
{
- internal sealed class TextLineImpl : TextLine
+ internal class TextLineImpl : TextLine
{
+ internal static Comparer TextBoundsComparer { get; } =
+ Comparer.Create((x, y) => x.Rectangle.Left.CompareTo(y.Rectangle.Left));
+
+ private IReadOnlyList? _indexedTextRuns;
private readonly TextRun[] _textRuns;
private readonly double _paragraphWidth;
private readonly TextParagraphProperties _paragraphProperties;
@@ -338,184 +342,169 @@ namespace Avalonia.Media.TextFormatting
///
public override double GetDistanceFromCharacterHit(CharacterHit characterHit)
{
- var flowDirection = _paragraphProperties.FlowDirection;
- var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
- var currentPosition = FirstTextSourceIndex;
- var remainingLength = characterIndex - FirstTextSourceIndex;
-
- var currentDistance = Start;
-
- if (flowDirection == FlowDirection.LeftToRight)
+ if (_indexedTextRuns is null || _indexedTextRuns.Count == 0)
{
- for (var index = 0; index < _textRuns.Length; index++)
- {
- var currentRun = _textRuns[index];
-
- if (currentRun is ShapedTextRun shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight)
- {
- var i = index;
-
- var rightToLeftWidth = shapedRun.Size.Width;
-
- while (i + 1 <= _textRuns.Length - 1)
- {
- var nextRun = _textRuns[i + 1];
-
- if (nextRun is ShapedTextRun nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight)
- {
- i++;
+ return Start;
+ }
- rightToLeftWidth += nextShapedRun.Size.Width;
+ var characterIndex = Math.Min(
+ characterHit.FirstCharacterIndex + characterHit.TrailingLength,
+ FirstTextSourceIndex + Length);
- continue;
- }
+ var currentPosition = FirstTextSourceIndex;
- break;
- }
+ static FlowDirection GetDirection(TextRun textRun, FlowDirection currentDirection)
+ {
+ if (textRun is ShapedTextRun shapedTextRun)
+ {
+ return shapedTextRun.ShapedBuffer.IsLeftToRight ?
+ FlowDirection.LeftToRight :
+ FlowDirection.RightToLeft;
+ }
- if (i > index)
- {
- while (i >= index)
- {
- currentRun = _textRuns[i];
+ return currentDirection;
+ }
- if (currentRun is DrawableTextRun drawable)
- {
- rightToLeftWidth -= drawable.Size.Width;
- }
+ IndexedTextRun FindIndexedRun()
+ {
+ var i = 0;
- if (currentPosition + currentRun.Length >= characterIndex)
- {
- break;
- }
+ IndexedTextRun currentIndexedRun = _indexedTextRuns[i];
- currentPosition += currentRun.Length;
+ while(currentIndexedRun.TextSourceCharacterIndex != currentPosition)
+ {
+ if(i + 1 < _indexedTextRuns.Count)
+ {
+ i++;
- remainingLength -= currentRun.Length;
+ currentIndexedRun = _indexedTextRuns[i];
+ }
+ }
- i--;
- }
+ return currentIndexedRun;
+ }
- currentDistance += rightToLeftWidth;
- }
- }
+ double GetPreceedingDistance(int firstIndex)
+ {
+ var distance = 0.0;
- if (currentPosition + currentRun.Length >= characterIndex &&
- TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, flowDirection, out var distance, out _))
- {
- return Math.Max(0, currentDistance + distance);
- }
+ for (var i = 0; i < firstIndex; i++)
+ {
+ var currentRun = _textRuns[i];
if (currentRun is DrawableTextRun drawableTextRun)
{
- currentDistance += drawableTextRun.Size.Width;
+ distance += drawableTextRun.Size.Width;
}
-
- //No hit hit found so we add the full width
-
- currentPosition += currentRun.Length;
- remainingLength -= currentRun.Length;
}
+
+ return distance;
}
- else
+
+ TextRun? currentTextRun = null;
+ var currentIndexedRun = FindIndexedRun();
+
+ while (currentPosition < FirstTextSourceIndex + Length)
{
- currentDistance += WidthIncludingTrailingWhitespace;
+ currentTextRun = currentIndexedRun.TextRun;
- for (var index = _textRuns.Length - 1; index >= 0; index--)
+ if (currentTextRun == null)
{
- var currentRun = _textRuns[index];
+ break;
+ }
- if (TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength,
- flowDirection, out var distance, out var currentGlyphRun))
+ if (currentIndexedRun.TextSourceCharacterIndex + currentTextRun.Length <= characterHit.FirstCharacterIndex)
+ {
+ if (currentPosition + currentTextRun.Length < FirstTextSourceIndex + Length)
{
- if (currentGlyphRun != null)
- {
- currentDistance -= currentGlyphRun.Bounds.Width;
- }
+ currentPosition += currentTextRun.Length;
- return currentDistance + distance;
- }
+ currentIndexedRun = FindIndexedRun();
- if (currentRun is DrawableTextRun drawableTextRun)
- {
- currentDistance -= drawableTextRun.Size.Width;
+ continue;
}
-
- //No hit hit found so we add the full width
- currentPosition += currentRun.Length;
- remainingLength -= currentRun.Length;
}
+
+ break;
}
- return Math.Max(0, currentDistance);
- }
+ if (currentTextRun == null)
+ {
+ return 0;
+ }
- private static bool TryGetDistanceFromCharacterHit(
- TextRun currentRun,
- CharacterHit characterHit,
- int currentPosition,
- int remainingLength,
- FlowDirection flowDirection,
- out double distance,
- out GlyphRun? currentGlyphRun)
- {
- var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
- var isTrailingHit = characterHit.TrailingLength > 0;
+ var directionalWidth = 0.0;
+ var firstRunIndex = currentIndexedRun.RunIndex;
+ var lastRunIndex = firstRunIndex;
- distance = 0;
- currentGlyphRun = null;
+ var currentDirection = GetDirection(currentTextRun, _resolvedFlowDirection);
- switch (currentRun)
+ var currentX = Start + GetPreceedingDistance(currentIndexedRun.RunIndex);
+
+ if (currentTextRun is DrawableTextRun currentDrawable)
{
- case ShapedTextRun shapedTextCharacters:
- {
- currentGlyphRun = shapedTextCharacters.GlyphRun;
+ directionalWidth = currentDrawable.Size.Width;
+ }
- if (currentPosition + remainingLength <= currentPosition + currentRun.Length)
- {
- characterHit = new CharacterHit(currentPosition + remainingLength);
+ if (currentTextRun is not TextEndOfLine)
+ {
+ if (currentDirection == FlowDirection.LeftToRight)
+ {
+ // Find consecutive runs of same direction
+ for (; lastRunIndex + 1 < _textRuns.Length; lastRunIndex++)
+ {
+ var nextRun = _textRuns[lastRunIndex + 1];
- distance = currentGlyphRun.GetDistanceFromCharacterHit(characterHit);
+ var nextDirection = GetDirection(nextRun, currentDirection);
- return true;
+ if (currentDirection != nextDirection)
+ {
+ break;
}
- if (currentPosition + remainingLength == currentPosition + currentRun.Length && isTrailingHit)
+ if (nextRun is DrawableTextRun nextDrawable)
{
- if (currentGlyphRun.IsLeftToRight || flowDirection == FlowDirection.RightToLeft)
- {
- distance = currentGlyphRun.Bounds.Width;
- }
-
- return true;
+ directionalWidth += nextDrawable.Size.Width;
}
-
- break;
}
- case DrawableTextRun drawableTextRun:
+ }
+ else
+ {
+ // Find consecutive runs of same direction
+ for (; firstRunIndex - 1 > 0; firstRunIndex--)
{
- if (characterIndex == currentPosition)
+ var previousRun = _textRuns[firstRunIndex - 1];
+
+ var previousDirection = GetDirection(previousRun, currentDirection);
+
+ if (currentDirection != previousDirection)
{
- return true;
+ break;
}
- if (characterIndex == currentPosition + currentRun.Length)
+ if (previousRun is DrawableTextRun previousDrawable)
{
- distance = drawableTextRun.Size.Width;
-
- return true;
+ directionalWidth += previousDrawable.Size.Width;
+ currentX -= previousDrawable.Size.Width;
}
+ }
+ }
+ }
- break;
+ switch (currentDirection)
+ {
+ case FlowDirection.RightToLeft:
+ {
+ return GetTextRunBoundsRightToLeft(firstRunIndex, lastRunIndex, currentX + directionalWidth, characterIndex,
+ currentPosition, 1, out _, out _).Rectangle.Right;
}
default:
{
- return false;
+ return GetTextBoundsLeftToRight(firstRunIndex, lastRunIndex, currentX, characterIndex,
+ currentPosition, 1, out _, out _).Rectangle.Left;
}
}
-
- return false;
}
///
@@ -585,7 +574,7 @@ namespace Avalonia.Media.TextFormatting
public override IReadOnlyList GetTextBounds(int firstTextSourceIndex, int textLength)
{
- if (_textRuns.Length == 0)
+ if (_indexedTextRuns is null || _indexedTextRuns.Count == 0)
{
return Array.Empty();
}
@@ -607,303 +596,154 @@ namespace Avalonia.Media.TextFormatting
return currentDirection;
}
- if (_paragraphProperties.FlowDirection == FlowDirection.LeftToRight)
+ IndexedTextRun FindIndexedRun()
{
- var currentX = Start;
+ var i = 0;
- for (int i = 0; i < _textRuns.Length; i++)
- {
- var currentRun = _textRuns[i];
+ IndexedTextRun currentIndexedRun = _indexedTextRuns[i];
- var firstRunIndex = i;
- var lastRunIndex = firstRunIndex;
- var currentDirection = GetDirection(currentRun, FlowDirection.LeftToRight);
- var directionalWidth = 0.0;
-
- if (currentRun is DrawableTextRun currentDrawable)
+ while (currentIndexedRun.TextSourceCharacterIndex != currentPosition)
+ {
+ if (i + 1 < _indexedTextRuns.Count)
{
- directionalWidth = currentDrawable.Size.Width;
- }
+ i++;
- // Find consecutive runs of same direction
- for (; lastRunIndex + 1 < _textRuns.Length; lastRunIndex++)
- {
- var nextRun = _textRuns[lastRunIndex + 1];
+ currentIndexedRun = _indexedTextRuns[i];
+ }
+ }
- var nextDirection = GetDirection(nextRun, currentDirection);
+ return currentIndexedRun;
+ }
- if (currentDirection != nextDirection)
- {
- break;
- }
+ double GetPreceedingDistance(int firstIndex)
+ {
+ var distance = 0.0;
- if (nextRun is DrawableTextRun nextDrawable)
- {
- directionalWidth += nextDrawable.Size.Width;
- }
- }
+ for (var i = 0; i < firstIndex; i++)
+ {
+ var currentRun = _textRuns[i];
- //Skip runs that are not part of the hit test range
- switch (currentDirection)
+ if (currentRun is DrawableTextRun drawableTextRun)
{
- case FlowDirection.RightToLeft:
- {
- for (; lastRunIndex >= firstRunIndex; lastRunIndex--)
- {
- currentRun = _textRuns[lastRunIndex];
+ distance += drawableTextRun.Size.Width;
+ }
+ }
- if (currentPosition + currentRun.Length > firstTextSourceIndex)
- {
- break;
- }
+ return distance;
+ }
- currentPosition += currentRun.Length;
+ while (remainingLength > 0 && currentPosition < FirstTextSourceIndex + Length)
+ {
+ var currentIndexedRun = FindIndexedRun();
- if (currentRun is DrawableTextRun drawableTextRun)
- {
- directionalWidth -= drawableTextRun.Size.Width;
- currentX += drawableTextRun.Size.Width;
- }
+ if (currentIndexedRun == null)
+ {
+ break;
+ }
- if (lastRunIndex - 1 < 0)
- {
- break;
- }
- }
+ var directionalWidth = 0.0;
+ var firstRunIndex = currentIndexedRun.RunIndex;
+ var lastRunIndex = firstRunIndex;
+ var currentTextRun = currentIndexedRun.TextRun;
- break;
- }
- default:
- {
- for (; firstRunIndex <= lastRunIndex; firstRunIndex++)
- {
- currentRun = _textRuns[firstRunIndex];
-
- if (currentPosition + currentRun.Length > firstTextSourceIndex)
- {
- break;
- }
+ if (currentTextRun == null)
+ {
+ break;
+ }
- currentPosition += currentRun.Length;
+ var currentDirection = GetDirection(currentTextRun, _resolvedFlowDirection);
- if (currentRun is DrawableTextRun drawableTextRun)
- {
- currentX += drawableTextRun.Size.Width;
- directionalWidth -= drawableTextRun.Size.Width;
- }
+ if (currentIndexedRun.TextSourceCharacterIndex + currentTextRun.Length <= firstTextSourceIndex)
+ {
+ currentPosition += currentTextRun.Length;
- if (firstRunIndex + 1 == _textRuns.Length)
- {
- break;
- }
- }
+ continue;
+ }
- break;
- }
- }
+ var currentX = Start + GetPreceedingDistance(currentIndexedRun.RunIndex);
- i = lastRunIndex;
+ if (currentTextRun is DrawableTextRun currentDrawable)
+ {
+ directionalWidth = currentDrawable.Size.Width;
+ }
- //Possible overlap at runs of different direction
- if (directionalWidth == 0 && i < _textRuns.Length - 1)
+ if (currentTextRun is not TextEndOfLine)
+ {
+ if (currentDirection == FlowDirection.LeftToRight)
{
- //In case a run only contains a linebreak we don't want to skip it.
- if (currentRun is ShapedTextRun shaped)
- {
- if (currentRun.Length - shaped.GlyphRun.Metrics.NewLineLength > 0)
- {
- continue;
- }
- }
- else
+ // Find consecutive runs of same direction
+ for (; lastRunIndex + 1 < _textRuns.Length; lastRunIndex++)
{
- continue;
- }
- }
+ var nextRun = _textRuns[lastRunIndex + 1];
- int coveredLength;
- TextBounds? textBounds;
+ var nextDirection = GetDirection(nextRun, currentDirection);
- switch (currentDirection)
- {
-
- case FlowDirection.RightToLeft:
+ if (currentDirection != nextDirection)
{
- textBounds = GetTextRunBoundsRightToLeft(firstRunIndex, lastRunIndex, currentX + directionalWidth, firstTextSourceIndex,
- currentPosition, remainingLength, out coveredLength, out currentPosition);
-
- currentX += directionalWidth;
-
break;
}
- default:
- {
- textBounds = GetTextBoundsLeftToRight(firstRunIndex, lastRunIndex, currentX, firstTextSourceIndex,
- currentPosition, remainingLength, out coveredLength, out currentPosition);
- currentX = textBounds.Rectangle.Right;
-
- break;
+ if (nextRun is DrawableTextRun nextDrawable)
+ {
+ directionalWidth += nextDrawable.Size.Width;
}
+ }
}
-
- if (coveredLength > 0)
- {
- result.Add(textBounds);
-
- remainingLength -= coveredLength;
- }
-
- if (remainingLength <= 0)
- {
- break;
- }
- }
- }
- else
- {
- var currentX = Start + WidthIncludingTrailingWhitespace;
-
- for (int i = _textRuns.Length - 1; i >= 0; i--)
- {
- var currentRun = _textRuns[i];
- var firstRunIndex = i;
- var lastRunIndex = firstRunIndex;
- var currentDirection = GetDirection(currentRun, FlowDirection.RightToLeft);
- var directionalWidth = 0.0;
-
- if (currentRun is DrawableTextRun currentDrawable)
- {
- directionalWidth = currentDrawable.Size.Width;
- }
-
- // Find consecutive runs of same direction
- for (; firstRunIndex - 1 > 0; firstRunIndex--)
+ else
{
- var previousRun = _textRuns[firstRunIndex - 1];
-
- var previousDirection = GetDirection(previousRun, currentDirection);
-
- if (currentDirection != previousDirection)
+ // Find consecutive runs of same direction
+ for (; firstRunIndex - 1 > 0; firstRunIndex--)
{
- break;
- }
+ var previousRun = _textRuns[firstRunIndex - 1];
- if (currentRun is DrawableTextRun previousDrawable)
- {
- directionalWidth += previousDrawable.Size.Width;
- }
- }
+ var previousDirection = GetDirection(previousRun, currentDirection);
- //Skip runs that are not part of the hit test range
- switch (currentDirection)
- {
- case FlowDirection.RightToLeft:
+ if (currentDirection != previousDirection)
{
- for (; lastRunIndex >= firstRunIndex; lastRunIndex--)
- {
- currentRun = _textRuns[lastRunIndex];
-
- if (currentPosition + currentRun.Length <= firstTextSourceIndex)
- {
- currentPosition += currentRun.Length;
-
- if (currentRun is DrawableTextRun drawableTextRun)
- {
- currentX -= drawableTextRun.Size.Width;
- directionalWidth -= drawableTextRun.Size.Width;
- }
-
- continue;
- }
-
- break;
- }
-
break;
}
- default:
- {
- for (; firstRunIndex <= lastRunIndex; firstRunIndex++)
- {
- currentRun = _textRuns[firstRunIndex];
-
- if (currentPosition + currentRun.Length <= firstTextSourceIndex)
- {
- currentPosition += currentRun.Length;
-
- if (currentRun is DrawableTextRun drawableTextRun)
- {
- currentX += drawableTextRun.Size.Width;
- directionalWidth -= drawableTextRun.Size.Width;
- }
- continue;
- }
-
- break;
- }
+ if (previousRun is DrawableTextRun previousDrawable)
+ {
+ directionalWidth += previousDrawable.Size.Width;
- break;
+ currentX -= previousDrawable.Size.Width;
}
+ }
}
+ }
- i = firstRunIndex;
+ int coveredLength;
+ TextBounds? textBounds;
- //Possible overlap at runs of different direction
- if (directionalWidth == 0 && i > 0)
- {
- //In case a run only contains a linebreak we don't want to skip it.
- if (currentRun is ShapedTextRun shaped)
+ switch (currentDirection)
+ {
+ case FlowDirection.RightToLeft:
{
- if (currentRun.Length - shaped.GlyphRun.Metrics.NewLineLength > 0)
- {
- continue;
- }
+ textBounds = GetTextRunBoundsRightToLeft(firstRunIndex, lastRunIndex, currentX + directionalWidth, firstTextSourceIndex,
+ currentPosition, remainingLength, out coveredLength, out currentPosition);
+
+ break;
}
- else
+ default:
{
- continue;
- }
- }
-
- int coveredLength;
- TextBounds? textBounds;
-
- switch (currentDirection)
- {
- case FlowDirection.LeftToRight:
- {
- textBounds = GetTextBoundsLeftToRight(firstRunIndex, lastRunIndex, currentX - directionalWidth, firstTextSourceIndex,
- currentPosition, remainingLength, out coveredLength, out currentPosition);
-
- currentX -= directionalWidth;
-
- break;
- }
- default:
- {
- textBounds = GetTextRunBoundsRightToLeft(firstRunIndex, lastRunIndex, currentX, firstTextSourceIndex,
- currentPosition, remainingLength, out coveredLength, out currentPosition);
-
- currentX = textBounds.Rectangle.Left;
+ textBounds = GetTextBoundsLeftToRight(firstRunIndex, lastRunIndex, currentX, firstTextSourceIndex,
+ currentPosition, remainingLength, out coveredLength, out currentPosition);
- break;
- }
- }
+ break;
+ }
+ }
- //Visual order is always left to right so we need to insert
- result.Insert(0, textBounds);
+ if (coveredLength > 0)
+ {
+ result.Add(textBounds);
remainingLength -= coveredLength;
-
- if (remainingLength <= 0)
- {
- break;
- }
}
}
+ result.Sort(TextBoundsComparer);
+
return result;
}
@@ -1164,7 +1004,7 @@ namespace Avalonia.Media.TextFormatting
_textLineBreak = new TextLineBreak(textEndOfLine);
}
- BidiReorderer.Instance.BidiReorder(_textRuns, _resolvedFlowDirection);
+ _indexedTextRuns = BidiReorderer.Instance.BidiReorder(_textRuns, _paragraphProperties.FlowDirection, FirstTextSourceIndex);
}
///
@@ -1211,13 +1051,6 @@ namespace Avalonia.Media.TextFormatting
return true;
}
- //var characterIndex = codepointIndex - shapedRun.Text.Start;
-
- //if (characterIndex < 0 && shapedRun.ShapedBuffer.IsLeftToRight)
- //{
- // foundCharacterHit = new CharacterHit(foundCharacterHit.FirstCharacterIndex);
- //}
-
nextCharacterHit = isAtEnd || characterHit.TrailingLength != 0 ?
foundCharacterHit :
new CharacterHit(foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength);
@@ -1556,8 +1389,8 @@ namespace Avalonia.Media.TextFormatting
TrailingWhitespaceLength = trailingWhitespaceLength,
Width = width,
WidthIncludingTrailingWhitespace = widthIncludingWhitespace,
- OverhangLeading= overhangLeading,
- OverhangTrailing= overhangTrailing,
+ OverhangLeading = overhangLeading,
+ OverhangTrailing = overhangTrailing,
OverhangAfter = overhangAfter
};
}
@@ -1615,8 +1448,7 @@ namespace Avalonia.Media.TextFormatting
return Math.Max(0, start);
case TextAlignment.Right:
- return Math.Max(0, _paragraphWidth - width);
-
+ return Math.Max(0, _paragraphWidth - widthIncludingTrailingWhitespace);
default:
return 0;
}
diff --git a/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs b/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
index 264a86b014..620cd4723d 100644
--- a/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
+++ b/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
@@ -127,7 +127,7 @@ namespace Avalonia.Build.Tasks
public bool Execute()
{
- Enum.TryParse(ReportImportance, out _reportImportance);
+ Enum.TryParse(ReportImportance, true, out _reportImportance);
BuildEngine.LogMessage($"GenerateAvaloniaResourcesTask -> Root: {Root}, {Resources?.Count()} resources, Output:{Output}", _reportImportance < MessageImportance.Low ? MessageImportance.High : _reportImportance);
var resources = BuildResourceSources();
diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
index d71070e818..d4c4ae8667 100644
--- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
+++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
@@ -288,6 +288,24 @@ namespace Avalonia.Build.Tasks
if (precompileText != "true")
throw new XamlParseException("Invalid value for x:Precompile", precompileDirective);
}
+
+ var classModifierDirective = initialRoot.Children.OfType()
+ .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "ClassModifier");
+ bool? classModifierPublic = null;
+ if (classModifierDirective != null)
+ {
+ var classModifierText = (classModifierDirective.Values[0] as XamlAstTextNode)?.Text.Trim()
+ .ToLowerInvariant();
+ if ("Public".Equals(classModifierText, StringComparison.OrdinalIgnoreCase))
+ classModifierPublic = true;
+ // XAML spec uses "Public" and "NotPublic" values,
+ // When WPF documentation uses "public" and "internal".
+ else if ("NotPublic".Equals(classModifierText, StringComparison.OrdinalIgnoreCase)
+ || "Internal".Equals(classModifierText, StringComparison.OrdinalIgnoreCase))
+ classModifierPublic = false;
+ else
+ throw new XamlParseException("Invalid value for x:ClassModifier. Expected value are: Public, NotPublic (internal).", precompileDirective);
+ }
var classDirective = initialRoot.Children.OfType()
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class");
@@ -297,8 +315,21 @@ namespace Avalonia.Build.Tasks
if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlAstTextNode tn))
throw new XamlParseException("x:Class should have a string value", classDirective);
classType = typeSystem.TargetAssembly.FindType(tn.Text);
+
if (classType == null)
throw new XamlParseException($"Unable to find type `{tn.Text}`", classDirective);
+
+ var isClassPublic = typeSystem.GetTypeReference(classType).Resolve().IsPublic;
+ classModifierPublic ??= isClassPublic;
+
+ // We do not really need x:ClassModifier support for x:Class, but we can at least use it for validation here.
+ if (classModifierPublic != isClassPublic)
+ {
+ throw new XamlParseException(
+ "XAML file x:ClassModifier doesn't match the x:Class type modifiers.",
+ precompileDirective);
+ }
+
compiler.OverrideRootType(parsed,
new XamlAstClrTypeReference(classDirective, classType, false));
initialRoot.Children.Remove(classDirective);
@@ -312,6 +343,8 @@ namespace Avalonia.Build.Tasks
var classTypeDefinition =
classType == null ? null : typeSystem.GetTypeReference(classType).Resolve();
+ // All XAML files are public by default.
+ classModifierPublic ??= true;
var populateBuilder = classTypeDefinition == null ?
builder :
@@ -319,10 +352,11 @@ namespace Avalonia.Build.Tasks
((List)parsedXamlDocuments).Add(new XamlDocumentResource(
parsed, res.Uri, res, classType,
+ classModifierPublic.Value,
populateBuilder,
compiler.DefinePopulateMethod(populateBuilder, parsed, populateName,
- classTypeDefinition == null),
- buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, true)));
+ classTypeDefinition == null && classModifierPublic.Value),
+ buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value)));
}
catch (Exception e)
{
@@ -368,7 +402,7 @@ namespace Avalonia.Build.Tasks
document.PopulateMethod,
document.BuildMethod,
builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name,
- true),
+ document.IsPublic),
(closureName, closureBaseType) =>
populateBuilder.DefineSubType(closureBaseType, closureName, false),
(closureName, returnType, parameterTypes) =>
@@ -502,7 +536,8 @@ namespace Avalonia.Build.Tasks
}
- if (document.BuildMethod != null || classTypeDefinition != null)
+ if (document.IsPublic
+ && (document.BuildMethod != null || classTypeDefinition != null))
{
var compiledBuildMethod = document.BuildMethod == null ?
null :
diff --git a/src/Avalonia.Controls/Border.cs b/src/Avalonia.Controls/Border.cs
index 78ba23c1dd..e7373a813e 100644
--- a/src/Avalonia.Controls/Border.cs
+++ b/src/Avalonia.Controls/Border.cs
@@ -47,30 +47,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty BoxShadowProperty =
AvaloniaProperty.Register(nameof(BoxShadow));
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty BorderDashOffsetProperty =
- AvaloniaProperty.Register(nameof(BorderDashOffset));
-
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty?> BorderDashArrayProperty =
- AvaloniaProperty.Register?>(nameof(BorderDashArray));
-
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty BorderLineCapProperty =
- AvaloniaProperty.Register(nameof(BorderLineCap), PenLineCap.Flat);
-
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty BorderLineJoinProperty =
- AvaloniaProperty.Register(nameof(BorderLineJoin), PenLineJoin.Miter);
-
private readonly BorderRenderHelper _borderRenderHelper = new BorderRenderHelper();
private Thickness? _layoutThickness;
private double _scale;
@@ -86,10 +62,6 @@ namespace Avalonia.Controls
BorderBrushProperty,
BorderThicknessProperty,
CornerRadiusProperty,
- BorderDashArrayProperty,
- BorderLineCapProperty,
- BorderLineJoinProperty,
- BorderDashOffsetProperty,
BoxShadowProperty);
AffectsMeasure(BorderThicknessProperty);
}
@@ -115,8 +87,8 @@ namespace Avalonia.Controls
///
public IBrush? Background
{
- get { return GetValue(BackgroundProperty); }
- set { SetValue(BackgroundProperty, value); }
+ get => GetValue(BackgroundProperty);
+ set => SetValue(BackgroundProperty, value);
}
///
@@ -124,17 +96,8 @@ namespace Avalonia.Controls
///
public IBrush? BorderBrush
{
- get { return GetValue(BorderBrushProperty); }
- set { SetValue(BorderBrushProperty, value); }
- }
-
- ///
- /// Gets or sets a collection of values that indicate the pattern of dashes and gaps that is used to outline shapes.
- ///
- public AvaloniaList? BorderDashArray
- {
- get { return GetValue(BorderDashArrayProperty); }
- set { SetValue(BorderDashArrayProperty, value); }
+ get => GetValue(BorderBrushProperty);
+ set => SetValue(BorderBrushProperty, value);
}
///
@@ -142,35 +105,8 @@ namespace Avalonia.Controls
///
public Thickness BorderThickness
{
- get { return GetValue(BorderThicknessProperty); }
- set { SetValue(BorderThicknessProperty, value); }
- }
-
- ///
- /// Gets or sets a value that specifies the distance within the dash pattern where a dash begins.
- ///
- public double BorderDashOffset
- {
- get { return GetValue(BorderDashOffsetProperty); }
- set { SetValue(BorderDashOffsetProperty, value); }
- }
-
- ///
- /// Gets or sets a enumeration value that describes the shape at the ends of a line.
- ///
- public PenLineCap BorderLineCap
- {
- get { return GetValue(BorderLineCapProperty); }
- set { SetValue(BorderLineCapProperty, value); }
- }
-
- ///
- /// Gets or sets a enumeration value that specifies the type of join that is used at the vertices of a Shape.
- ///
- public PenLineJoin BorderLineJoin
- {
- get { return GetValue(BorderLineJoinProperty); }
- set { SetValue(BorderLineJoinProperty, value); }
+ get => GetValue(BorderThicknessProperty);
+ set => SetValue(BorderThicknessProperty, value);
}
///
@@ -178,8 +114,8 @@ namespace Avalonia.Controls
///
public CornerRadius CornerRadius
{
- get { return GetValue(CornerRadiusProperty); }
- set { SetValue(CornerRadiusProperty, value); }
+ get => GetValue(CornerRadiusProperty);
+ set => SetValue(CornerRadiusProperty, value);
}
///
@@ -227,8 +163,14 @@ namespace Avalonia.Controls
/// The drawing context.
public sealed override void Render(DrawingContext context)
{
- _borderRenderHelper.Render(context, Bounds.Size, LayoutThickness, CornerRadius, Background, BorderBrush,
- BoxShadow, BorderDashOffset, BorderLineCap, BorderLineJoin, BorderDashArray);
+ _borderRenderHelper.Render(
+ context,
+ Bounds.Size,
+ LayoutThickness,
+ CornerRadius,
+ Background,
+ BorderBrush,
+ BoxShadow);
}
///
diff --git a/src/Avalonia.Controls/Primitives/RangeBase.cs b/src/Avalonia.Controls/Primitives/RangeBase.cs
index ebf7879412..33ab78b66f 100644
--- a/src/Avalonia.Controls/Primitives/RangeBase.cs
+++ b/src/Avalonia.Controls/Primitives/RangeBase.cs
@@ -45,14 +45,14 @@ namespace Avalonia.Controls.Primitives
///
/// Defines the event.
///
- public static readonly RoutedEvent> ValueChangedEvent =
- RoutedEvent.Register>(
+ public static readonly RoutedEvent ValueChangedEvent =
+ RoutedEvent.Register(
nameof(ValueChanged), RoutingStrategies.Bubble);
///
/// Occurs when the property changes.
///
- public event EventHandler>? ValueChanged
+ public event EventHandler? ValueChanged
{
add => AddHandler(ValueChangedEvent, value);
remove => RemoveHandler(ValueChangedEvent, value);
@@ -163,7 +163,7 @@ namespace Avalonia.Controls.Primitives
}
else if (change.Property == ValueProperty)
{
- var valueChangedEventArgs = new RoutedPropertyChangedEventArgs(
+ var valueChangedEventArgs = new RangeBaseValueChangedEventArgs(
change.GetOldValue(),
change.GetNewValue(),
ValueChangedEvent);
diff --git a/src/Avalonia.Controls/Primitives/RangeBaseValueChangedEventArgs.cs b/src/Avalonia.Controls/Primitives/RangeBaseValueChangedEventArgs.cs
new file mode 100644
index 0000000000..480e82e4fc
--- /dev/null
+++ b/src/Avalonia.Controls/Primitives/RangeBaseValueChangedEventArgs.cs
@@ -0,0 +1,47 @@
+using Avalonia.Interactivity;
+
+namespace Avalonia.Controls.Primitives
+{
+ ///
+ /// Provides data specific to a event.
+ ///
+ public class RangeBaseValueChangedEventArgs : RoutedEventArgs
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The old value of the range value property.
+ /// The new value of the range value property.
+ /// The routed event associated with these event args.
+ public RangeBaseValueChangedEventArgs(double oldValue, double newValue, RoutedEvent? routedEvent)
+ : base(routedEvent)
+ {
+ OldValue = oldValue;
+ NewValue = newValue;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The old value of the range value property.
+ /// The new value of the range value property.
+ /// The routed event associated with these event args.
+ /// The source object that raised the routed event.
+ public RangeBaseValueChangedEventArgs(double oldValue, double newValue, RoutedEvent? routedEvent, object? source)
+ : base(routedEvent, source)
+ {
+ OldValue = oldValue;
+ NewValue = newValue;
+ }
+
+ ///
+ /// Gets the old value of the range value property.
+ ///
+ public double OldValue { get; init; }
+
+ ///
+ /// Gets the new value of the range value property.
+ ///
+ public double NewValue { get; init; }
+ }
+}
diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs
index 461dc1c947..a65ac774ef 100644
--- a/src/Avalonia.Controls/Shapes/Shape.cs
+++ b/src/Avalonia.Controls/Shapes/Shape.cs
@@ -126,8 +126,8 @@ namespace Avalonia.Controls.Shapes
///
public IBrush? Fill
{
- get { return GetValue(FillProperty); }
- set { SetValue(FillProperty, value); }
+ get => GetValue(FillProperty);
+ set => SetValue(FillProperty, value);
}
///
@@ -135,8 +135,8 @@ namespace Avalonia.Controls.Shapes
///
public Stretch Stretch
{
- get { return GetValue(StretchProperty); }
- set { SetValue(StretchProperty, value); }
+ get => GetValue(StretchProperty);
+ set => SetValue(StretchProperty, value);
}
///
@@ -144,8 +144,8 @@ namespace Avalonia.Controls.Shapes
///
public IBrush? Stroke
{
- get { return GetValue(StrokeProperty); }
- set { SetValue(StrokeProperty, value); }
+ get => GetValue(StrokeProperty);
+ set => SetValue(StrokeProperty, value);
}
///
@@ -153,8 +153,8 @@ namespace Avalonia.Controls.Shapes
///
public AvaloniaList? StrokeDashArray
{
- get { return GetValue(StrokeDashArrayProperty); }
- set { SetValue(StrokeDashArrayProperty, value); }
+ get => GetValue(StrokeDashArrayProperty);
+ set => SetValue(StrokeDashArrayProperty, value);
}
///
@@ -162,8 +162,8 @@ namespace Avalonia.Controls.Shapes
///
public double StrokeDashOffset
{
- get { return GetValue(StrokeDashOffsetProperty); }
- set { SetValue(StrokeDashOffsetProperty, value); }
+ get => GetValue(StrokeDashOffsetProperty);
+ set => SetValue(StrokeDashOffsetProperty, value);
}
///
@@ -171,8 +171,8 @@ namespace Avalonia.Controls.Shapes
///
public double StrokeThickness
{
- get { return GetValue(StrokeThicknessProperty); }
- set { SetValue(StrokeThicknessProperty, value); }
+ get => GetValue(StrokeThicknessProperty);
+ set => SetValue(StrokeThicknessProperty, value);
}
///
@@ -180,8 +180,8 @@ namespace Avalonia.Controls.Shapes
///
public PenLineCap StrokeLineCap
{
- get { return GetValue(StrokeLineCapProperty); }
- set { SetValue(StrokeLineCapProperty, value); }
+ get => GetValue(StrokeLineCapProperty);
+ set => SetValue(StrokeLineCapProperty, value);
}
///
@@ -189,8 +189,8 @@ namespace Avalonia.Controls.Shapes
///
public PenLineJoin StrokeJoin
{
- get { return GetValue(StrokeJoinProperty); }
- set { SetValue(StrokeJoinProperty, value); }
+ get => GetValue(StrokeJoinProperty);
+ set => SetValue(StrokeJoinProperty, value);
}
public sealed override void Render(DrawingContext context)
diff --git a/src/Avalonia.Controls/TextChangedEventArgs.cs b/src/Avalonia.Controls/TextChangedEventArgs.cs
index 1418154256..f614d2d760 100644
--- a/src/Avalonia.Controls/TextChangedEventArgs.cs
+++ b/src/Avalonia.Controls/TextChangedEventArgs.cs
@@ -3,15 +3,24 @@
namespace Avalonia.Controls
{
///
- /// Provides data specific to a TextChanged event.
+ /// Provides data specific to a event.
///
public class TextChangedEventArgs : RoutedEventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The routed event associated with these event args.
public TextChangedEventArgs(RoutedEvent? routedEvent)
: base (routedEvent)
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The routed event associated with these event args.
+ /// The source object that raised the routed event.
public TextChangedEventArgs(RoutedEvent? routedEvent, Interactive? source)
: base(routedEvent, source)
{
diff --git a/src/Avalonia.Controls/TextChangingEventArgs.cs b/src/Avalonia.Controls/TextChangingEventArgs.cs
index 09e7d5b258..6ec5afd030 100644
--- a/src/Avalonia.Controls/TextChangingEventArgs.cs
+++ b/src/Avalonia.Controls/TextChangingEventArgs.cs
@@ -3,15 +3,24 @@
namespace Avalonia.Controls
{
///
- /// Provides data specific to a TextChanging event.
+ /// Provides data specific to a event.
///
public class TextChangingEventArgs : RoutedEventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The routed event associated with these event args.
public TextChangingEventArgs(RoutedEvent? routedEvent)
: base (routedEvent)
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The routed event associated with these event args.
+ /// The source object that raised the routed event.
public TextChangingEventArgs(RoutedEvent? routedEvent, Interactive? source)
: base(routedEvent, source)
{
diff --git a/src/Avalonia.Themes.Fluent/Accents/BaseColorsPalette.xaml b/src/Avalonia.Themes.Fluent/Accents/BaseColorsPalette.xaml
index 362d543646..620add9045 100644
--- a/src/Avalonia.Themes.Fluent/Accents/BaseColorsPalette.xaml
+++ b/src/Avalonia.Themes.Fluent/Accents/BaseColorsPalette.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Accents/BaseResources.xaml b/src/Avalonia.Themes.Fluent/Accents/BaseResources.xaml
index 517a80fd7e..6f12f1d306 100644
--- a/src/Avalonia.Themes.Fluent/Accents/BaseResources.xaml
+++ b/src/Avalonia.Themes.Fluent/Accents/BaseResources.xaml
@@ -1,7 +1,8 @@
+ xmlns:converters="using:Avalonia.Controls.Converters"
+ x:ClassModifier="internal">
fonts:Inter#Inter, $Default
14
diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentControlResources.xaml b/src/Avalonia.Themes.Fluent/Accents/FluentControlResources.xaml
index 61a74f26a4..397f7ec431 100644
--- a/src/Avalonia.Themes.Fluent/Accents/FluentControlResources.xaml
+++ b/src/Avalonia.Themes.Fluent/Accents/FluentControlResources.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj b/src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj
index e63a0c9c26..660661fc94 100644
--- a/src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj
+++ b/src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj
@@ -1,8 +1,6 @@
net6.0;netstandard2.0
-
- $(NoWarn);IL2026
diff --git a/src/Avalonia.Themes.Fluent/Controls/AdornerLayer.xaml b/src/Avalonia.Themes.Fluent/Controls/AdornerLayer.xaml
index c4b91b4822..fefa1ea055 100644
--- a/src/Avalonia.Themes.Fluent/Controls/AdornerLayer.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/AdornerLayer.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
0
2
1
diff --git a/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml b/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
index 2113ae4cb0..228aeaad17 100644
--- a/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
@@ -1,6 +1,7 @@
+ xmlns:generic="using:System.Collections.Generic"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/Button.xaml b/src/Avalonia.Themes.Fluent/Controls/Button.xaml
index 126f2c22e0..6c6ca967e7 100644
--- a/src/Avalonia.Themes.Fluent/Controls/Button.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/Button.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml
index 3ce4730698..095e801d0c 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml
@@ -1,7 +1,8 @@
+ xmlns:converters="using:Avalonia.Controls.Converters"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml b/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml
index 9c66ea9b84..2f4a444529 100644
--- a/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/Calendar.xaml
@@ -6,7 +6,8 @@
-->
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
index 76b51ca819..206973b7ee 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
@@ -5,7 +5,8 @@
// All other rights reserved.
-->
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
index 2a3496b648..4739a5b9c5 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
@@ -1,6 +1,7 @@
+ xmlns:sys="using:System"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDayButton.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDayButton.xaml
index 6a57cfacd0..904a234ada 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CalendarDayButton.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDayButton.xaml
@@ -5,7 +5,8 @@
// All other rights reserved.
-->
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml
index 7276742e7d..3bbef81695 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml
@@ -6,7 +6,8 @@
-->
+ xmlns:sys="using:System"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml b/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
index 0180c3f395..41d74c6063 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/Carousel.xaml b/src/Avalonia.Themes.Fluent/Controls/Carousel.xaml
index 91e331693e..b94ef9b5d9 100644
--- a/src/Avalonia.Themes.Fluent/Controls/Carousel.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/Carousel.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml b/src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml
index 28f8649e2d..fc0a8c7c66 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml b/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
index bc36ad987e..18bf01ece7 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
@@ -1,6 +1,7 @@
+ xmlns:sys="using:System"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ComboBoxItem.xaml b/src/Avalonia.Themes.Fluent/Controls/ComboBoxItem.xaml
index 581cbaf80a..ea55770a51 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ComboBoxItem.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ComboBoxItem.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ContentControl.xaml b/src/Avalonia.Themes.Fluent/Controls/ContentControl.xaml
index 4caf156366..f277c6f9ae 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ContentControl.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ContentControl.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml b/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml
index f6900f785f..c8e2873eb6 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
+ xmlns:collections="using:System.Collections"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
index e71e733eff..58f181bd23 100644
--- a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
@@ -7,7 +7,8 @@
+ xmlns:sys="using:System"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/DateTimePickerShared.xaml b/src/Avalonia.Themes.Fluent/Controls/DateTimePickerShared.xaml
index 9d21e6e758..9384eff8f4 100644
--- a/src/Avalonia.Themes.Fluent/Controls/DateTimePickerShared.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/DateTimePickerShared.xaml
@@ -6,7 +6,8 @@
-->
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/DropDownButton.xaml b/src/Avalonia.Themes.Fluent/Controls/DropDownButton.xaml
index 421ba0bb18..438ad6cf18 100644
--- a/src/Avalonia.Themes.Fluent/Controls/DropDownButton.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/DropDownButton.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/EmbeddableControlRoot.xaml b/src/Avalonia.Themes.Fluent/Controls/EmbeddableControlRoot.xaml
index ee51ef8085..1fc931db36 100644
--- a/src/Avalonia.Themes.Fluent/Controls/EmbeddableControlRoot.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/EmbeddableControlRoot.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/Expander.xaml b/src/Avalonia.Themes.Fluent/Controls/Expander.xaml
index 37e9b71185..adaecc71ab 100644
--- a/src/Avalonia.Themes.Fluent/Controls/Expander.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/Expander.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml b/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml
index 31b0a01b21..deb7d39a89 100644
--- a/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml
@@ -1,6 +1,7 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/FlyoutPresenter.xaml b/src/Avalonia.Themes.Fluent/Controls/FlyoutPresenter.xaml
index 2dca5b0770..e8c9ed9b2a 100644
--- a/src/Avalonia.Themes.Fluent/Controls/FlyoutPresenter.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/FlyoutPresenter.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
1
diff --git a/src/Avalonia.Themes.Fluent/Controls/GridSplitter.xaml b/src/Avalonia.Themes.Fluent/Controls/GridSplitter.xaml
index ca57eccd13..fc08d6b0b6 100644
--- a/src/Avalonia.Themes.Fluent/Controls/GridSplitter.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/GridSplitter.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ItemsControl.xaml b/src/Avalonia.Themes.Fluent/Controls/ItemsControl.xaml
index 19a29b9466..91f9536847 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ItemsControl.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ItemsControl.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/Label.xaml b/src/Avalonia.Themes.Fluent/Controls/Label.xaml
index ff6909ee87..237da0bfa3 100644
--- a/src/Avalonia.Themes.Fluent/Controls/Label.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/Label.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ListBox.xaml b/src/Avalonia.Themes.Fluent/Controls/ListBox.xaml
index 05bbbe9558..2dde18a523 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ListBox.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ListBox.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ListBoxItem.xaml b/src/Avalonia.Themes.Fluent/Controls/ListBoxItem.xaml
index fc1d0c5ff1..4e74406c92 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ListBoxItem.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ListBoxItem.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/ManagedFileChooser.xaml b/src/Avalonia.Themes.Fluent/Controls/ManagedFileChooser.xaml
index 8519099a27..374daa7ab5 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ManagedFileChooser.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ManagedFileChooser.xaml
@@ -1,7 +1,8 @@
+ xmlns:internal="using:Avalonia.Dialogs.Internal"
+ x:ClassModifier="internal">
diff --git a/src/Avalonia.Themes.Fluent/Controls/Menu.xaml b/src/Avalonia.Themes.Fluent/Controls/Menu.xaml
index e6bbbde632..c1640efa8c 100644
--- a/src/Avalonia.Themes.Fluent/Controls/Menu.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/Menu.xaml
@@ -1,5 +1,6 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:ClassModifier="internal">