diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs
index 7e2bbc13bc..097815cc69 100644
--- a/nukebuild/Build.cs
+++ b/nukebuild/Build.cs
@@ -138,9 +138,19 @@ partial class Build : NukeBuild
.SetWorkingDirectory(webappDir)
.SetCommand("dist"));
});
-
- Target Compile => _ => _
+
+ Target CompileNative => _ => _
.DependsOn(Clean)
+ .OnlyWhenStatic(() => EnvironmentInfo.IsOsx)
+ .Executes(() =>
+ {
+ var project = $"{RootDirectory}/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/";
+ var args = $"-project {project} -configuration {Parameters.Configuration} CONFIGURATION_BUILD_DIR={RootDirectory}/Build/Products/Release";
+ ProcessTasks.StartProcess("xcodebuild", args).AssertZeroExitCode();
+ });
+
+ Target Compile => _ => _
+ .DependsOn(Clean, CompileNative)
.DependsOn(CompileHtmlPreviewer)
.Executes(async () =>
{
diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml
index d045626c2c..cacc2204bd 100644
--- a/samples/ControlCatalog/Pages/DataGridPage.xaml
+++ b/samples/ControlCatalog/Pages/DataGridPage.xaml
@@ -11,12 +11,17 @@
-
+
DataGrid
A control for displaying and interacting with a data source.
-
+
+
+
+
+
+
@@ -39,13 +44,13 @@
-
+
-
-
-
+
+
+
diff --git a/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs b/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
index 7f15845596..ddee880288 100644
--- a/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
+++ b/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
@@ -61,7 +61,6 @@ namespace RenderDemo.Pages
{
Foreground = Brushes.Black,
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _glyphIndices),
- BaselineOrigin = new Point(0, -_glyphTypeface.Ascent * scale)
};
drawingGroup.Children.Add(glyphRunDrawing);
@@ -69,7 +68,7 @@ namespace RenderDemo.Pages
var geometryDrawing = new GeometryDrawing
{
Pen = new Pen(Brushes.Black),
- Geometry = new RectangleGeometry { Rect = glyphRunDrawing.GlyphRun.Bounds }
+ Geometry = new RectangleGeometry { Rect = new Rect(glyphRunDrawing.GlyphRun.Size) }
};
drawingGroup.Children.Add(geometryDrawing);
diff --git a/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
new file mode 100644
index 0000000000..82472c505a
--- /dev/null
+++ b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
@@ -0,0 +1,5 @@
+Compat issues with assembly Avalonia.Controls.DataGrid:
+MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.DataGridTextColumn.FontFamilyProperty' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public System.String Avalonia.Controls.DataGridTextColumn.FontFamily.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Controls.DataGridTextColumn.FontFamily.set(System.String)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 3
diff --git a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
index f1bbea9949..e2a067ac61 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
@@ -17,9 +17,7 @@ namespace Avalonia.Controls
///
public class DataGridCheckBoxColumn : DataGridBoundColumn
{
-
private bool _beganEditWithKeyboard;
- private bool _isThreeState;
private CheckBox _currentCheckBox;
private DataGrid _owningGrid;
@@ -31,6 +29,12 @@ namespace Avalonia.Controls
BindingTarget = CheckBox.IsCheckedProperty;
}
+ ///
+ /// Defines the property.
+ ///
+ public static StyledProperty IsThreeStateProperty =
+ CheckBox.IsThreeStateProperty.AddOwner();
+
///
/// Gets or sets a value that indicates whether the hosted controls allow three states or two.
///
@@ -39,17 +43,17 @@ namespace Avalonia.Controls
///
public bool IsThreeState
{
- get
- {
- return _isThreeState;
- }
- set
+ get => GetValue(IsThreeStateProperty);
+ set => SetValue(IsThreeStateProperty, value);
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == IsThreeStateProperty)
{
- if (_isThreeState != value)
- {
- _isThreeState = value;
- NotifyPropertyChanged(nameof(IsThreeState));
- }
+ NotifyPropertyChanged(change.Property.Name);
}
}
@@ -203,9 +207,9 @@ namespace Avalonia.Controls
{
throw new ArgumentNullException("element");
}
- if(element is CheckBox checkBox)
+ if (element is CheckBox checkBox)
{
- checkBox.IsThreeState = IsThreeState;
+ DataGridHelper.SyncColumnProperty(this, checkBox, IsThreeStateProperty);
}
else
{
@@ -229,7 +233,7 @@ namespace Avalonia.Controls
{
checkBox.HorizontalAlignment = HorizontalAlignment.Center;
checkBox.VerticalAlignment = VerticalAlignment.Center;
- checkBox.IsThreeState = IsThreeState;
+ DataGridHelper.SyncColumnProperty(this, checkBox, IsThreeStateProperty);
}
private bool EnsureOwningGrid()
diff --git a/src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs
index d31204b9e6..1cf6ab68ac 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs
@@ -20,11 +20,6 @@ namespace Avalonia.Controls
{
private const string DATAGRID_TextColumnCellTextBlockMarginKey = "DataGridTextColumnCellTextBlockMargin";
- private double? _fontSize;
- private FontStyle? _fontStyle;
- private FontWeight? _fontWeight;
- private IBrush _foreground;
-
///
/// Initializes a new instance of the class.
///
@@ -36,18 +31,24 @@ namespace Avalonia.Controls
///
/// Identifies the FontFamily dependency property.
///
- public static readonly StyledProperty FontFamilyProperty =
- AvaloniaProperty.Register(nameof(FontFamily));
+ public static readonly AttachedProperty FontFamilyProperty =
+ TextBlock.FontFamilyProperty.AddOwner();
///
/// Gets or sets the font name.
///
- public string FontFamily
+ public FontFamily FontFamily
{
- get { return GetValue(FontFamilyProperty); }
- set { SetValue(FontFamilyProperty, value); }
+ get => GetValue(FontFamilyProperty);
+ set => SetValue(FontFamilyProperty, value);
}
+ ///
+ /// Identifies the FontSize dependency property.
+ ///
+ public static readonly AttachedProperty FontSizeProperty =
+ TextBlock.FontSizeProperty.AddOwner();
+
///
/// Gets or sets the font size.
///
@@ -55,74 +56,66 @@ namespace Avalonia.Controls
[DefaultValue(double.NaN)]
public double FontSize
{
- get
- {
- return _fontSize ?? Double.NaN;
- }
- set
- {
- if (_fontSize != value)
- {
- _fontSize = value;
- NotifyPropertyChanged(nameof(FontSize));
- }
- }
+ get => GetValue(FontSizeProperty);
+ set => SetValue(FontSizeProperty, value);
}
+ ///
+ /// Identifies the FontStyle dependency property.
+ ///
+ public static readonly AttachedProperty FontStyleProperty =
+ TextBlock.FontStyleProperty.AddOwner();
+
///
/// Gets or sets the font style.
///
public FontStyle FontStyle
{
- get
- {
- return _fontStyle ?? FontStyle.Normal;
- }
- set
- {
- if (_fontStyle != value)
- {
- _fontStyle = value;
- NotifyPropertyChanged(nameof(FontStyle));
- }
- }
+ get => GetValue(FontStyleProperty);
+ set => SetValue(FontStyleProperty, value);
}
+ ///
+ /// Identifies the FontWeight dependency property.
+ ///
+ public static readonly AttachedProperty FontWeightProperty =
+ TextBlock.FontWeightProperty.AddOwner();
+
///
/// Gets or sets the font weight or thickness.
///
public FontWeight FontWeight
{
- get
- {
- return _fontWeight ?? FontWeight.Normal;
- }
- set
- {
- if (_fontWeight != value)
- {
- _fontWeight = value;
- NotifyPropertyChanged(nameof(FontWeight));
- }
- }
+ get => GetValue(FontWeightProperty);
+ set => SetValue(FontWeightProperty, value);
}
+ ///
+ /// Identifies the Foreground dependency property.
+ ///
+ public static readonly AttachedProperty ForegroundProperty =
+ TextBlock.ForegroundProperty.AddOwner();
+
///
/// Gets or sets a brush that describes the foreground of the column cells.
///
public IBrush Foreground
{
- get
- {
- return _foreground;
- }
- set
+ get => GetValue(ForegroundProperty);
+ set => SetValue(ForegroundProperty, value);
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == FontFamilyProperty
+ || change.Property == FontSizeProperty
+ || change.Property == FontStyleProperty
+ || change.Property == FontWeightProperty
+ || change.Property == ForegroundProperty)
{
- if (_foreground != value)
- {
- _foreground = value;
- NotifyPropertyChanged(nameof(Foreground));
- }
+ NotifyPropertyChanged(change.Property.Name);
}
}
@@ -154,26 +147,7 @@ namespace Avalonia.Controls
Background = new SolidColorBrush(Colors.Transparent)
};
- if (IsSet(FontFamilyProperty))
- {
- textBox.FontFamily = FontFamily;
- }
- if (_fontSize.HasValue)
- {
- textBox.FontSize = _fontSize.Value;
- }
- if (_fontStyle.HasValue)
- {
- textBox.FontStyle = _fontStyle.Value;
- }
- if (_fontWeight.HasValue)
- {
- textBox.FontWeight = _fontWeight.Value;
- }
- if (_foreground != null)
- {
- textBox.Foreground = _foreground;
- }
+ SyncProperties(textBox);
return textBox;
}
@@ -192,26 +166,8 @@ namespace Avalonia.Controls
VerticalAlignment = VerticalAlignment.Center
};
- if (IsSet(FontFamilyProperty))
- {
- textBlockElement.FontFamily = FontFamily;
- }
- if (_fontSize.HasValue)
- {
- textBlockElement.FontSize = _fontSize.Value;
- }
- if (_fontStyle.HasValue)
- {
- textBlockElement.FontStyle = _fontStyle.Value;
- }
- if (_fontWeight.HasValue)
- {
- textBlockElement.FontWeight = _fontWeight.Value;
- }
- if (_foreground != null)
- {
- textBlockElement.Foreground = _foreground;
- }
+ SyncProperties(textBlockElement);
+
if (Binding != null)
{
textBlockElement.Bind(TextBlock.TextProperty, Binding);
@@ -261,99 +217,42 @@ namespace Avalonia.Controls
throw new ArgumentNullException("element");
}
- if(element is TextBox textBox)
+ if (element is AvaloniaObject content)
{
if (propertyName == nameof(FontFamily))
{
- textBox.FontFamily = FontFamily;
+ DataGridHelper.SyncColumnProperty(this, content, FontFamilyProperty);
}
else if (propertyName == nameof(FontSize))
{
- SetTextFontSize(textBox, TextBox.FontSizeProperty);
+ DataGridHelper.SyncColumnProperty(this, content, FontSizeProperty);
}
else if (propertyName == nameof(FontStyle))
{
- textBox.FontStyle = FontStyle;
+ DataGridHelper.SyncColumnProperty(this, content, FontStyleProperty);
}
else if (propertyName == nameof(FontWeight))
{
- textBox.FontWeight = FontWeight;
+ DataGridHelper.SyncColumnProperty(this, content, FontWeightProperty);
}
else if (propertyName == nameof(Foreground))
{
- textBox.Foreground = Foreground;
- }
- else
- {
- if (FontFamily != null)
- {
- textBox.FontFamily = FontFamily;
- }
- SetTextFontSize(textBox, TextBox.FontSizeProperty);
- textBox.FontStyle = FontStyle;
- textBox.FontWeight = FontWeight;
- if (Foreground != null)
- {
- textBox.Foreground = Foreground;
- }
- }
-
- }
- else if (element is TextBlock textBlock)
- {
- if (propertyName == nameof(FontFamily))
- {
- textBlock.FontFamily = FontFamily;
- }
- else if (propertyName == nameof(FontSize))
- {
- SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
- }
- else if (propertyName == nameof(FontStyle))
- {
- textBlock.FontStyle = FontStyle;
- }
- else if (propertyName == nameof(FontWeight))
- {
- textBlock.FontWeight = FontWeight;
- }
- else if (propertyName == nameof(Foreground))
- {
- textBlock.Foreground = Foreground;
- }
- else
- {
- if (FontFamily != null)
- {
- textBlock.FontFamily = FontFamily;
- }
- SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
- textBlock.FontStyle = FontStyle;
- textBlock.FontWeight = FontWeight;
- if (Foreground != null)
- {
- textBlock.Foreground = Foreground;
- }
+ DataGridHelper.SyncColumnProperty(this, content, ForegroundProperty);
}
}
else
{
- throw DataGridError.DataGrid.ValueIsNotAnInstanceOfEitherOr("element", typeof(TextBox), typeof(TextBlock));
+ throw DataGridError.DataGrid.ValueIsNotAnInstanceOf("element", typeof(AvaloniaObject));
}
}
- private void SetTextFontSize(AvaloniaObject textElement, AvaloniaProperty fontSizeProperty)
+ private void SyncProperties(AvaloniaObject content)
{
- double newFontSize = FontSize;
- if (double.IsNaN(newFontSize))
- {
- textElement.ClearValue(fontSizeProperty);
- }
- else
- {
- textElement.SetValue(fontSizeProperty, newFontSize);
- }
+ DataGridHelper.SyncColumnProperty(this, content, FontFamilyProperty);
+ DataGridHelper.SyncColumnProperty(this, content, FontSizeProperty);
+ DataGridHelper.SyncColumnProperty(this, content, FontStyleProperty);
+ DataGridHelper.SyncColumnProperty(this, content, FontWeightProperty);
+ DataGridHelper.SyncColumnProperty(this, content, ForegroundProperty);
}
-
}
}
diff --git a/src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs b/src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs
new file mode 100644
index 0000000000..2cf41082ca
--- /dev/null
+++ b/src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs
@@ -0,0 +1,22 @@
+namespace Avalonia.Controls
+{
+ internal static class DataGridHelper
+ {
+ internal static void SyncColumnProperty(AvaloniaObject column, AvaloniaObject content, AvaloniaProperty property)
+ {
+ SyncColumnProperty(column, content, property, property);
+ }
+
+ internal static void SyncColumnProperty(AvaloniaObject column, AvaloniaObject content, AvaloniaProperty contentProperty, AvaloniaProperty columnProperty)
+ {
+ if (!column.IsSet(columnProperty))
+ {
+ content.ClearValue(contentProperty);
+ }
+ else
+ {
+ content.SetValue(contentProperty, column.GetValue(columnProperty));
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/IconElement.cs b/src/Avalonia.Controls/IconElement.cs
new file mode 100644
index 0000000000..82b7a0660c
--- /dev/null
+++ b/src/Avalonia.Controls/IconElement.cs
@@ -0,0 +1,9 @@
+using Avalonia.Controls.Primitives;
+
+namespace Avalonia.Controls
+{
+ public abstract class IconElement : TemplatedControl
+ {
+
+ }
+}
diff --git a/src/Avalonia.Controls/PathIcon.cs b/src/Avalonia.Controls/PathIcon.cs
new file mode 100644
index 0000000000..764f245249
--- /dev/null
+++ b/src/Avalonia.Controls/PathIcon.cs
@@ -0,0 +1,21 @@
+using Avalonia.Media;
+
+namespace Avalonia.Controls
+{
+ public class PathIcon : IconElement
+ {
+ static PathIcon()
+ {
+ AffectsRender(DataProperty);
+ }
+
+ public static readonly StyledProperty DataProperty =
+ AvaloniaProperty.Register(nameof(Data));
+
+ public Geometry Data
+ {
+ get { return GetValue(DataProperty); }
+ set { SetValue(DataProperty, value); }
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/Primitives/AccessText.cs b/src/Avalonia.Controls/Primitives/AccessText.cs
index 89f672deaa..7a5e6ce426 100644
--- a/src/Avalonia.Controls/Primitives/AccessText.cs
+++ b/src/Avalonia.Controls/Primitives/AccessText.cs
@@ -126,7 +126,7 @@ namespace Avalonia.Controls.Primitives
if (shapedTextCharacters.GlyphRun.Characters.End < textPosition)
{
- currentX += shapedTextCharacters.GlyphRun.Bounds.Width;
+ currentX += shapedTextCharacters.Size.Width;
continue;
}
@@ -143,7 +143,7 @@ namespace Avalonia.Controls.Primitives
width = 0.0;
}
- return new Rect(currentX, currentY, width, shapedTextCharacters.GlyphRun.Bounds.Height);
+ return new Rect(currentX, currentY, width, shapedTextCharacters.Size.Height);
}
}
diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs
index d8477840af..d61519e697 100644
--- a/src/Avalonia.Controls/TextBlock.cs
+++ b/src/Avalonia.Controls/TextBlock.cs
@@ -434,7 +434,10 @@ namespace Avalonia.Controls
var padding = Padding;
- TextLayout.Draw(context, new Point(padding.Left + offsetX, padding.Top));
+ using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, padding.Top)))
+ {
+ TextLayout.Draw(context);
+ }
}
///
diff --git a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
index 3ae6c8c30e..4f6af0a41b 100644
--- a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
+++ b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
@@ -385,7 +385,7 @@ namespace Avalonia.Headless
}
- public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
+ public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
}
diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj
index f084411c2f..49bd578290 100644
--- a/src/Avalonia.Native/Avalonia.Native.csproj
+++ b/src/Avalonia.Native/Avalonia.Native.csproj
@@ -1,7 +1,8 @@
- false
+ $([MSBuild]::IsOSPlatform(OSX))
+ $(PackAvaloniaNative)
true
netstandard2.0
/usr/bin/castxml
@@ -10,8 +11,9 @@
false
-
+
+ libAvaloniaNative.dylib
runtimes/osx/native/libAvaloniaNative.dylib
true
PreserveNewest
@@ -26,4 +28,4 @@
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml
index 44dfb9ea48..5f18bac44a 100644
--- a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml
+++ b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml
@@ -72,5 +72,8 @@
18
8
+
+ 20
+ 20
diff --git a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
index 9ed3207235..30c6d39856 100644
--- a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
+++ b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
@@ -75,5 +75,8 @@
18
8
+
+ 20
+ 20
diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml
index e5b654b490..625b409598 100644
--- a/src/Avalonia.Themes.Default/DefaultTheme.xaml
+++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml
@@ -12,7 +12,7 @@
-
+
@@ -21,6 +21,7 @@
+
diff --git a/src/Avalonia.Themes.Default/PathIcon.xaml b/src/Avalonia.Themes.Default/PathIcon.xaml
new file mode 100644
index 0000000000..a2d01f7b5b
--- /dev/null
+++ b/src/Avalonia.Themes.Default/PathIcon.xaml
@@ -0,0 +1,18 @@
+
+
+
diff --git a/src/Avalonia.Themes.Fluent/Accents/Base.xaml b/src/Avalonia.Themes.Fluent/Accents/Base.xaml
index 46488c1c57..134e804c53 100644
--- a/src/Avalonia.Themes.Fluent/Accents/Base.xaml
+++ b/src/Avalonia.Themes.Fluent/Accents/Base.xaml
@@ -20,5 +20,7 @@
1
2
10,6,6,5
+ 20
+ 20
diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.xaml b/src/Avalonia.Themes.Fluent/FluentTheme.xaml
index 00ab9bc375..90c0f55b68 100644
--- a/src/Avalonia.Themes.Fluent/FluentTheme.xaml
+++ b/src/Avalonia.Themes.Fluent/FluentTheme.xaml
@@ -11,7 +11,7 @@
-
+
@@ -20,6 +20,7 @@
+
diff --git a/src/Avalonia.Themes.Fluent/PathIcon.xaml b/src/Avalonia.Themes.Fluent/PathIcon.xaml
new file mode 100644
index 0000000000..0a2c747514
--- /dev/null
+++ b/src/Avalonia.Themes.Fluent/PathIcon.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+ M14 9.50006C11.5147 9.50006 9.5 11.5148 9.5 14.0001C9.5 16.4853 11.5147 18.5001 14 18.5001C15.3488 18.5001 16.559 17.9066 17.3838 16.9666C18.0787 16.1746 18.5 15.1365 18.5 14.0001C18.5 13.5401 18.431 13.0963 18.3028 12.6784C17.7382 10.8381 16.0253 9.50006 14 9.50006ZM11 14.0001C11 12.3432 12.3431 11.0001 14 11.0001C15.6569 11.0001 17 12.3432 17 14.0001C17 15.6569 15.6569 17.0001 14 17.0001C12.3431 17.0001 11 15.6569 11 14.0001Z M21.7093 22.3948L19.9818 21.6364C19.4876 21.4197 18.9071 21.4515 18.44 21.7219C17.9729 21.9924 17.675 22.4693 17.6157 23.0066L17.408 24.8855C17.3651 25.273 17.084 25.5917 16.7055 25.682C14.9263 26.1061 13.0725 26.1061 11.2933 25.682C10.9148 25.5917 10.6336 25.273 10.5908 24.8855L10.3834 23.0093C10.3225 22.4731 10.0112 21.9976 9.54452 21.7281C9.07783 21.4586 8.51117 21.4269 8.01859 21.6424L6.29071 22.4009C5.93281 22.558 5.51493 22.4718 5.24806 22.1859C4.00474 20.8536 3.07924 19.2561 2.54122 17.5137C2.42533 17.1384 2.55922 16.7307 2.8749 16.4977L4.40219 15.3703C4.83721 15.0501 5.09414 14.5415 5.09414 14.0007C5.09414 13.4598 4.83721 12.9512 4.40162 12.6306L2.87529 11.5051C2.55914 11.272 2.42513 10.8638 2.54142 10.4882C3.08038 8.74734 4.00637 7.15163 5.24971 5.82114C5.51684 5.53528 5.93492 5.44941 6.29276 5.60691L8.01296 6.36404C8.50793 6.58168 9.07696 6.54881 9.54617 6.27415C10.0133 6.00264 10.3244 5.52527 10.3844 4.98794L10.5933 3.11017C10.637 2.71803 10.9245 2.39704 11.3089 2.31138C12.19 2.11504 13.0891 2.01071 14.0131 2.00006C14.9147 2.01047 15.8128 2.11485 16.6928 2.31149C17.077 2.39734 17.3643 2.71823 17.4079 3.11017L17.617 4.98937C17.7116 5.85221 18.4387 6.50572 19.3055 6.50663C19.5385 6.507 19.769 6.45838 19.9843 6.36294L21.7048 5.60568C22.0626 5.44818 22.4807 5.53405 22.7478 5.81991C23.9912 7.1504 24.9172 8.74611 25.4561 10.487C25.5723 10.8623 25.4386 11.2703 25.1228 11.5035L23.5978 12.6297C23.1628 12.95 22.9 13.4586 22.9 13.9994C22.9 14.5403 23.1628 15.0489 23.5988 15.3698L25.1251 16.4965C25.441 16.7296 25.5748 17.1376 25.4586 17.5131C24.9198 19.2536 23.9944 20.8492 22.7517 22.1799C22.4849 22.4657 22.0671 22.5518 21.7093 22.3948ZM16.263 22.1966C16.4982 21.4685 16.9889 20.8288 17.6884 20.4238C18.5702 19.9132 19.6536 19.8547 20.5841 20.2627L21.9281 20.8526C22.791 19.8538 23.4593 18.7013 23.8981 17.4552L22.7095 16.5778L22.7086 16.5771C21.898 15.98 21.4 15.0277 21.4 13.9994C21.4 12.9719 21.8974 12.0195 22.7073 11.4227L22.7085 11.4218L23.8957 10.545C23.4567 9.2988 22.7881 8.14636 21.9248 7.1477L20.5922 7.73425L20.5899 7.73527C20.1844 7.91463 19.7472 8.00722 19.3039 8.00663C17.6715 8.00453 16.3046 6.77431 16.1261 5.15465L16.1259 5.15291L15.9635 3.69304C15.3202 3.57328 14.6677 3.50872 14.013 3.50017C13.3389 3.50891 12.6821 3.57367 12.0377 3.69328L11.8751 5.15452C11.7625 6.16272 11.1793 7.05909 10.3019 7.56986C9.41937 8.0856 8.34453 8.14844 7.40869 7.73694L6.07273 7.14893C5.20949 8.14751 4.54092 9.29983 4.10196 10.5459L5.29181 11.4233C6.11115 12.0269 6.59414 12.9837 6.59414 14.0007C6.59414 15.0173 6.11142 15.9742 5.29237 16.5776L4.10161 17.4566C4.54002 18.7044 5.2085 19.8585 6.07205 20.8587L7.41742 20.2682C8.34745 19.8613 9.41573 19.9215 10.2947 20.4292C11.174 20.937 11.7593 21.832 11.8738 22.84L11.8744 22.8445L12.0362 24.3088C13.3326 24.5638 14.6662 24.5638 15.9626 24.3088L16.1247 22.8418C16.1491 22.6217 16.1955 22.4055 16.263 22.1966Z
+
+
+
+
+
+
diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt
index 5aa497861d..148916932f 100644
--- a/src/Avalonia.Visuals/ApiCompatBaseline.txt
+++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt
@@ -1,15 +1,33 @@
Compat issues with assembly Avalonia.Visuals:
+MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Media.GlyphRunDrawing.BaselineOrigin.set(Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotSealType : Type 'Avalonia.Media.Typeface' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract.
TypeCannotChangeClassification : Type 'Avalonia.Media.Typeface' is a 'struct' in the implementation but is a 'class' in the contract.
CannotMakeMemberNonVirtual : Member 'public System.Boolean Avalonia.Media.Typeface.Equals(System.Object)' is non-virtual in the implementation but is virtual in the contract.
CannotMakeMemberNonVirtual : Member 'public System.Int32 Avalonia.Media.Typeface.GetHashCode()' is non-virtual in the implementation but is virtual in the contract.
TypesMustExist : Type 'Avalonia.Media.Fonts.FontKey' does not exist in the implementation but it does exist in the contract.
+CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size' is abstract in the implementation but is missing in the contract.
+MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.DrawableTextRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
+CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
+MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
+CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size.get()' is abstract in the implementation but is missing in the contract.
+MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.ShapedTextCharacters.Bounds.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.ShapedTextCharacters.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLayout.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak' is abstract in the implementation but is missing in the contract.
+CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
+MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.LineBreak.get()' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak.get()' is abstract in the implementation but is missing in the contract.
+InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun)' is present in the implementation but not in the contract.
+InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' is present in the contract but not in the implementation.
+MembersMustExist : Member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract.
-Total Issues: 13
+Total Issues: 31
diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs
index ba7191d7a6..ae4c927ae2 100644
--- a/src/Avalonia.Visuals/Media/DrawingContext.cs
+++ b/src/Avalonia.Visuals/Media/DrawingContext.cs
@@ -206,14 +206,13 @@ namespace Avalonia.Media
///
/// The foreground brush.
/// The glyph run.
- /// The baseline origin of the glyph run.
- public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
+ public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
Contract.Requires(glyphRun != null);
if (foreground != null)
{
- PlatformImpl.DrawGlyphRun(foreground, glyphRun, baselineOrigin);
+ PlatformImpl.DrawGlyphRun(foreground, glyphRun);
}
}
diff --git a/src/Avalonia.Visuals/Media/GlyphRun.cs b/src/Avalonia.Visuals/Media/GlyphRun.cs
index da3a1f721c..14ab083b4f 100644
--- a/src/Avalonia.Visuals/Media/GlyphRun.cs
+++ b/src/Avalonia.Visuals/Media/GlyphRun.cs
@@ -16,8 +16,9 @@ namespace Avalonia.Media
private IGlyphRunImpl _glyphRunImpl;
private GlyphTypeface _glyphTypeface;
private double _fontRenderingEmSize;
- private Rect? _bounds;
+ private Size? _size;
private int _biDiLevel;
+ private Point? _baselineOrigin;
private ReadOnlySlice _glyphIndices;
private ReadOnlySlice _glyphAdvances;
@@ -89,6 +90,20 @@ namespace Avalonia.Media
set => Set(ref _fontRenderingEmSize, value);
}
+ ///
+ /// Gets or sets the baseline origin of the.
+ ///
+ public Point BaselineOrigin
+ {
+ get
+ {
+ _baselineOrigin ??= CalculateBaselineOrigin();
+
+ return _baselineOrigin.Value;
+ }
+ set => Set(ref _baselineOrigin, value);
+ }
+
///
/// Gets or sets an array of values that represent the glyph indices in the rendering physical font.
///
@@ -156,16 +171,13 @@ namespace Avalonia.Media
///
/// Gets or sets the conservative bounding box of the .
///
- public Rect Bounds
+ public Size Size
{
get
{
- if (_bounds == null)
- {
- _bounds = CalculateBounds();
- }
+ _size ??= CalculateSize();
- return _bounds.Value;
+ return _size.Value;
}
}
@@ -200,7 +212,7 @@ namespace Avalonia.Media
if (characterHit.FirstCharacterIndex + characterHit.TrailingLength > Characters.End)
{
- return Bounds.Width;
+ return Size.Width;
}
var glyphIndex = FindGlyphIndex(characterHit.FirstCharacterIndex);
@@ -257,7 +269,7 @@ namespace Avalonia.Media
}
//After
- if (distance > Bounds.Size.Width)
+ if (distance > Size.Width)
{
isInside = false;
@@ -529,12 +541,21 @@ namespace Avalonia.Media
}
///
- /// Calculates the bounds of the .
+ /// Calculates the default baseline origin of the .
+ ///
+ /// The baseline origin.
+ private Point CalculateBaselineOrigin()
+ {
+ return new Point(0, -GlyphTypeface.Ascent * Scale);
+ }
+
+ ///
+ /// Calculates the size of the .
///
///
/// The calculated bounds.
///
- private Rect CalculateBounds()
+ private Size CalculateSize()
{
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
@@ -555,7 +576,7 @@ namespace Avalonia.Media
}
}
- return new Rect(0, GlyphTypeface.Ascent * Scale, width, height);
+ return new Size(width, height);
}
private void Set(ref T field, T value)
@@ -590,11 +611,15 @@ namespace Avalonia.Media
throw new InvalidOperationException();
}
+ _baselineOrigin = new Point(0, -GlyphTypeface.Ascent * Scale);
+
var platformRenderInterface = AvaloniaLocator.Current.GetService();
_glyphRunImpl = platformRenderInterface.CreateGlyphRun(this, out var width);
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
+
+ _size = new Size(width, height);
}
void IDisposable.Dispose()
diff --git a/src/Avalonia.Visuals/Media/GlyphRunDrawing.cs b/src/Avalonia.Visuals/Media/GlyphRunDrawing.cs
index d0ea113a6f..7e0d5c3c81 100644
--- a/src/Avalonia.Visuals/Media/GlyphRunDrawing.cs
+++ b/src/Avalonia.Visuals/Media/GlyphRunDrawing.cs
@@ -8,9 +8,6 @@
public static readonly StyledProperty GlyphRunProperty =
AvaloniaProperty.Register(nameof(GlyphRun));
- public static readonly StyledProperty BaselineOriginProperty =
- AvaloniaProperty.Register(nameof(BaselineOrigin));
-
public IBrush Foreground
{
get => GetValue(ForegroundProperty);
@@ -23,12 +20,6 @@
set => SetValue(GlyphRunProperty, value);
}
- public Point BaselineOrigin
- {
- get => GetValue(BaselineOriginProperty);
- set => SetValue(BaselineOriginProperty, value);
- }
-
public override void Draw(DrawingContext context)
{
if (GlyphRun == null)
@@ -36,12 +27,12 @@
return;
}
- context.DrawGlyphRun(Foreground, GlyphRun, BaselineOrigin);
+ context.DrawGlyphRun(Foreground, GlyphRun);
}
public override Rect GetBounds()
{
- return GlyphRun?.Bounds ?? default;
+ return GlyphRun != null ? new Rect(GlyphRun.Size) : Rect.Empty;
}
}
}
diff --git a/src/Avalonia.Visuals/Media/TextDecoration.cs b/src/Avalonia.Visuals/Media/TextDecoration.cs
index 681fc5d499..d9b3f664ce 100644
--- a/src/Avalonia.Visuals/Media/TextDecoration.cs
+++ b/src/Avalonia.Visuals/Media/TextDecoration.cs
@@ -155,8 +155,7 @@ namespace Avalonia.Media
///
/// The drawing context.
/// The shaped characters that are decorated.
- /// The origin.
- internal void Draw(DrawingContext drawingContext, ShapedTextCharacters shapedTextCharacters, Point origin)
+ internal void Draw(DrawingContext drawingContext, ShapedTextCharacters shapedTextCharacters)
{
var fontRenderingEmSize = shapedTextCharacters.Properties.FontRenderingEmSize;
var fontMetrics = shapedTextCharacters.FontMetrics;
@@ -181,16 +180,20 @@ namespace Avalonia.Media
break;
}
+ var origin = new Point();
+
switch (Location)
{
- case TextDecorationLocation.Overline:
- origin += new Point(0, fontMetrics.Ascent);
+ case TextDecorationLocation.Baseline:
+ origin += shapedTextCharacters.GlyphRun.BaselineOrigin;
break;
case TextDecorationLocation.Strikethrough:
- origin += new Point(0, -fontMetrics.StrikethroughPosition);
+ origin += new Point(shapedTextCharacters.GlyphRun.BaselineOrigin.X,
+ shapedTextCharacters.GlyphRun.BaselineOrigin.Y - fontMetrics.StrikethroughPosition);
break;
case TextDecorationLocation.Underline:
- origin += new Point(0, -fontMetrics.UnderlinePosition);
+ origin += new Point(shapedTextCharacters.GlyphRun.BaselineOrigin.X,
+ shapedTextCharacters.GlyphRun.BaselineOrigin.Y - fontMetrics.UnderlinePosition);
break;
}
@@ -207,7 +210,7 @@ namespace Avalonia.Media
var pen = new Pen(Stroke ?? shapedTextCharacters.Properties.ForegroundBrush, thickness,
new DashStyle(StrokeDashArray, StrokeDashOffset), StrokeLineCap);
- drawingContext.DrawLine(pen, origin, origin + new Point(shapedTextCharacters.Bounds.Width, 0));
+ drawingContext.DrawLine(pen, origin, origin + new Point(shapedTextCharacters.Size.Width, 0));
}
}
}
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs b/src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs
index 56790cc0db..338c92f6b1 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs
@@ -6,15 +6,14 @@
public abstract class DrawableTextRun : TextRun
{
///
- /// Gets the bounds.
+ /// Gets the size.
///
- public abstract Rect Bounds { get; }
+ public abstract Size Size { get; }
///
/// Draws the at the given origin.
///
/// The drawing context.
- /// The origin.
- public abstract void Draw(DrawingContext drawingContext, Point origin);
+ public abstract void Draw(DrawingContext drawingContext);
}
}
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
index 9e67a03f45..09ecc0a026 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
@@ -26,7 +26,7 @@ namespace Avalonia.Media.TextFormatting
public override int TextSourceLength { get; }
///
- public override Rect Bounds => GlyphRun.Bounds;
+ public override Size Size => GlyphRun.Size;
///
/// Gets the font metrics.
@@ -45,7 +45,7 @@ namespace Avalonia.Media.TextFormatting
public GlyphRun GlyphRun { get; }
///
- public override void Draw(DrawingContext drawingContext, Point origin)
+ public override void Draw(DrawingContext drawingContext)
{
if (GlyphRun.GlyphIndices.Length == 0)
{
@@ -64,11 +64,10 @@ namespace Avalonia.Media.TextFormatting
if (Properties.BackgroundBrush != null)
{
- drawingContext.DrawRectangle(Properties.BackgroundBrush, null,
- new Rect(origin.X, origin.Y + FontMetrics.Ascent, Bounds.Width, Bounds.Height));
+ drawingContext.DrawRectangle(Properties.BackgroundBrush, null, new Rect(Size));
}
- drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun, origin);
+ drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun);
if (Properties.TextDecorations == null)
{
@@ -77,7 +76,7 @@ namespace Avalonia.Media.TextFormatting
foreach (var textDecoration in Properties.TextDecorations)
{
- textDecoration.Draw(drawingContext, this, origin);
+ textDecoration.Draw(drawingContext, this);
}
}
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
index b116249fd4..3e85f0f6f0 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
@@ -52,7 +52,7 @@ namespace Avalonia.Media.TextFormatting
{
var glyphRun = textCharacters.GlyphRun;
- if (glyphRun.Bounds.Width < availableWidth)
+ if (glyphRun.Size.Width < availableWidth)
{
return glyphRun.Characters.Length;
}
@@ -348,7 +348,7 @@ namespace Avalonia.Media.TextFormatting
{
var currentRun = textRuns[runIndex];
- if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth)
+ if (currentWidth + currentRun.Size.Width > availableWidth)
{
var measuredLength = MeasureCharacters(currentRun, paragraphWidth - currentWidth);
@@ -421,7 +421,7 @@ namespace Avalonia.Media.TextFormatting
return new TextLineImpl(splitResult.First, textLineMetrics, lineBreak);
}
- currentWidth += currentRun.GlyphRun.Bounds.Width;
+ currentWidth += currentRun.Size.Width;
currentLength += currentRun.GlyphRun.Characters.Length;
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
index df1ecb4067..daa8807bf6 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
@@ -115,22 +115,24 @@ namespace Avalonia.Media.TextFormatting
/// Draws the text layout.
///
/// The drawing context.
- /// The origin.
- public void Draw(DrawingContext context, Point origin)
+ public void Draw(DrawingContext context)
{
if (!TextLines.Any())
{
return;
}
- var currentY = origin.Y;
+ var currentY = 0.0;
foreach (var textLine in TextLines)
{
var offsetX = TextLine.GetParagraphOffsetX(textLine.LineMetrics.Size.Width, Size.Width,
_paragraphProperties.TextAlignment);
- textLine.Draw(context, new Point(origin.X + offsetX, currentY));
+ using (context.PushPostTransform(Matrix.CreateTranslation(offsetX, currentY)))
+ {
+ textLine.Draw(context);
+ }
currentY += textLine.LineMetrics.Size.Height;
}
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
index c052fb8948..8a1efa0611 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
@@ -51,8 +51,7 @@ namespace Avalonia.Media.TextFormatting
/// Draws the at the given origin.
///
/// The drawing context.
- /// The origin.
- public abstract void Draw(DrawingContext drawingContext, Point origin);
+ public abstract void Draw(DrawingContext drawingContext);
///
/// Create a collapsed line based on collapsed text properties.
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
index 51092cddda..f5e87d097b 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
@@ -33,17 +33,18 @@ namespace Avalonia.Media.TextFormatting
public override bool HasCollapsed { get; }
///
- public override void Draw(DrawingContext drawingContext, Point origin)
+ public override void Draw(DrawingContext drawingContext)
{
- var currentX = origin.X;
+ var currentX = 0.0;
foreach (var textRun in _textRuns)
{
- var baselineOrigin = new Point(currentX, origin.Y + LineMetrics.TextBaseline);
-
- textRun.Draw(drawingContext, baselineOrigin);
+ using (drawingContext.PushPostTransform(Matrix.CreateTranslation(currentX, 0)))
+ {
+ textRun.Draw(drawingContext);
+ }
- currentX += textRun.Bounds.Width;
+ currentX += textRun.Size.Width;
}
}
@@ -64,13 +65,13 @@ namespace Avalonia.Media.TextFormatting
var shapedSymbol = CreateShapedSymbol(collapsingProperties.Symbol);
- var availableWidth = collapsingProperties.Width - shapedSymbol.Bounds.Width;
+ var availableWidth = collapsingProperties.Width - shapedSymbol.Size.Width;
while (runIndex < _textRuns.Count)
{
var currentRun = _textRuns[runIndex];
- currentWidth += currentRun.GlyphRun.Bounds.Width;
+ currentWidth += currentRun.Size.Width;
if (currentWidth > availableWidth)
{
@@ -125,7 +126,7 @@ namespace Avalonia.Media.TextFormatting
return new TextLineImpl(shapedTextCharacters, textLineMetrics, TextLineBreak, true);
}
- availableWidth -= currentRun.GlyphRun.Bounds.Width;
+ availableWidth -= currentRun.Size.Width;
collapsedLength += currentRun.GlyphRun.Characters.Length;
@@ -133,7 +134,7 @@ namespace Avalonia.Media.TextFormatting
}
textLineMetrics =
- new TextLineMetrics(LineMetrics.Size.WithWidth(LineMetrics.Size.Width + shapedSymbol.Bounds.Width),
+ new TextLineMetrics(LineMetrics.Size.WithWidth(LineMetrics.Size.Width + shapedSymbol.Size.Width),
LineMetrics.TextBaseline, TextRange, LineMetrics.HasOverflowed);
return new TextLineImpl(new List(_textRuns) { shapedSymbol }, textLineMetrics, null,
@@ -156,12 +157,12 @@ namespace Avalonia.Media.TextFormatting
{
characterHit = run.GlyphRun.GetCharacterHitFromDistance(distance, out _);
- if (distance <= run.Bounds.Width)
+ if (distance <= run.Size.Width)
{
break;
}
- distance -= run.Bounds.Width;
+ distance -= run.Size.Width;
}
return characterHit;
@@ -229,7 +230,7 @@ namespace Avalonia.Media.TextFormatting
{
if (codepointIndex > textRun.Text.End)
{
- currentDistance += textRun.Bounds.Width;
+ currentDistance += textRun.Size.Width;
continue;
}
@@ -405,7 +406,7 @@ namespace Avalonia.Media.TextFormatting
for (var i = 0; i < shapedTextCharacters.Count; i++)
{
- shapedWidth += shapedTextCharacters[i].Bounds.Width;
+ shapedWidth += shapedTextCharacters[i].Size.Width;
}
return shapedWidth;
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs
index 6875cc1c04..c4d7527659 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs
@@ -67,7 +67,7 @@ namespace Avalonia.Media.TextFormatting
var fontMetrics =
new FontMetrics(shapedRun.Properties.Typeface, shapedRun.Properties.FontRenderingEmSize);
- lineWidth += shapedRun.Bounds.Width;
+ lineWidth += shapedRun.Size.Width;
if (ascent > fontMetrics.Ascent)
{
diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
index c87946b3ea..019614ae80 100644
--- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
+++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
@@ -84,8 +84,7 @@ namespace Avalonia.Platform
///
/// The foreground.
/// The glyph run.
- /// The baseline origin of the glyph run.
- void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin);
+ void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun);
///
/// Creates a new that can be used as a render layer
diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs
index 4cce2c925b..7324f5fbd0 100644
--- a/src/Avalonia.Visuals/Point.cs
+++ b/src/Avalonia.Visuals/Point.cs
@@ -267,5 +267,24 @@ namespace Avalonia
{
return new Point(_x, y);
}
+
+ ///
+ /// Deconstructs the point into its X and Y coordinates.
+ ///
+ /// The X coordinate.
+ /// The Y coordinate.
+ public void Deconstruct(out double x, out double y)
+ {
+ x = this._x;
+ y = this._y;
+ }
+
+ ///
+ /// Gets a value indicating whether the X and Y coordinates are zero.
+ ///
+ public bool IsDefault
+ {
+ get { return (_x == 0) && (_y == 0); }
+ }
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
index 4a364998fd..cb6b1f59d4 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
@@ -204,13 +204,13 @@ namespace Avalonia.Rendering.SceneGraph
}
///
- public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
+ public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
var next = NextDrawAs();
if (next == null || !next.Item.Equals(Transform, foreground, glyphRun))
{
- Add(new GlyphRunNode(Transform, foreground, glyphRun, baselineOrigin, CreateChildScene(foreground)));
+ Add(new GlyphRunNode(Transform, foreground, glyphRun, CreateChildScene(foreground)));
}
else
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs
index bdf05c4f86..a6dba1bd32 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using Avalonia.Media;
+using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.VisualTree;
@@ -17,20 +18,17 @@ namespace Avalonia.Rendering.SceneGraph
/// The transform.
/// The foreground brush.
/// The glyph run to draw.
- /// The baseline origin of the glyph run.
/// Child scenes for drawing visual brushes.
public GlyphRunNode(
Matrix transform,
IBrush foreground,
GlyphRun glyphRun,
- Point baselineOrigin,
IDictionary childScenes = null)
- : base(glyphRun.Bounds.Translate(baselineOrigin), transform)
+ : base(new Rect(glyphRun.Size), transform)
{
Transform = transform;
Foreground = foreground?.ToImmutable();
GlyphRun = glyphRun;
- BaselineOrigin = baselineOrigin;
ChildScenes = childScenes;
}
@@ -49,11 +47,6 @@ namespace Avalonia.Rendering.SceneGraph
///
public GlyphRun GlyphRun { get; }
- ///
- /// Gets the baseline origin.
- ///
- public Point BaselineOrigin { get; set; }
-
///
public override IDictionary ChildScenes { get; }
@@ -61,7 +54,7 @@ namespace Avalonia.Rendering.SceneGraph
public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
- context.DrawGlyphRun(Foreground, GlyphRun, BaselineOrigin);
+ context.DrawGlyphRun(Foreground, GlyphRun);
}
///
diff --git a/src/Avalonia.Visuals/Size.cs b/src/Avalonia.Visuals/Size.cs
index f87b336b50..d87d2c5fc2 100644
--- a/src/Avalonia.Visuals/Size.cs
+++ b/src/Avalonia.Visuals/Size.cs
@@ -276,5 +276,24 @@ namespace Avalonia
{
return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _width, _height);
}
+
+ ///
+ /// Deconstructs the size into its Width and Height values.
+ ///
+ /// The width.
+ /// The height.
+ public void Deconstruct(out double width, out double height)
+ {
+ width = this._width;
+ height = this._height;
+ }
+
+ ///
+ /// Gets a value indicating whether the Width and Height values are zero.
+ ///
+ public bool IsDefault
+ {
+ get { return (_width == 0) && (_height == 0); }
+ }
}
}
diff --git a/src/Avalonia.Visuals/Thickness.cs b/src/Avalonia.Visuals/Thickness.cs
index b03e91bf34..6d69c4d9a9 100644
--- a/src/Avalonia.Visuals/Thickness.cs
+++ b/src/Avalonia.Visuals/Thickness.cs
@@ -272,5 +272,28 @@ namespace Avalonia
{
return $"{_left},{_top},{_right},{_bottom}";
}
+
+ ///
+ /// Deconstructor the thickness into its left, top, right and bottom thickness values.
+ ///
+ /// The thickness on the left.
+ /// The thickness on the top.
+ /// The thickness on the right.
+ /// The thickness on the bottom.
+ public void Deconstruct(out double left, out double top, out double right, out double bottom)
+ {
+ left = this._left;
+ top = this._top;
+ right = this._right;
+ bottom = this._bottom;
+ }
+
+ ///
+ /// Gets a value indicating whether the left, top, right and bottom thickness values are zero.
+ ///
+ public bool IsDefault
+ {
+ get { return (_left == 0) && (_top == 0) && (_right == 0) && (_bottom == 0); }
+ }
}
}
diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs
index 6059dc3971..2fcf804f14 100644
--- a/src/Avalonia.Visuals/Vector.cs
+++ b/src/Avalonia.Visuals/Vector.cs
@@ -333,5 +333,24 @@ namespace Avalonia
///
public static Vector UnitY
=> new Vector(0, 1);
+
+ ///
+ /// Deconstructs the vector into its X and Y components.
+ ///
+ /// The X component.
+ /// The Y component.
+ public void Deconstruct(out double x, out double y)
+ {
+ x = this._x;
+ y = this._y;
+ }
+
+ ///
+ /// Gets a value indicating whether the X and Y components are zero.
+ ///
+ public bool IsDefault
+ {
+ get { return (_x == 0) && (_y == 0); }
+ }
}
}
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index 65989610b8..05a8daaec8 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -401,16 +401,16 @@ namespace Avalonia.Skia
}
///
- public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
+ public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
- using (var paintWrapper = CreatePaint(_fillPaint, foreground, glyphRun.Bounds.Size))
+ using (var paintWrapper = CreatePaint(_fillPaint, foreground, glyphRun.Size))
{
var glyphRunImpl = (GlyphRunImpl)glyphRun.GlyphRunImpl;
ConfigureTextRendering(paintWrapper);
- Canvas.DrawText(glyphRunImpl.TextBlob, (float)baselineOrigin.X,
- (float)baselineOrigin.Y, paintWrapper.Paint);
+ Canvas.DrawText(glyphRunImpl.TextBlob, (float)glyphRun.BaselineOrigin.X,
+ (float)glyphRun.BaselineOrigin.Y, paintWrapper.Paint);
}
}
diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
index e0de40525f..258a51db5a 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
@@ -324,13 +324,14 @@ namespace Avalonia.Direct2D1.Media
/// The foreground.
/// The glyph run.
///
- public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin)
+ public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
- using (var brush = CreateBrush(foreground, glyphRun.Bounds.Size))
+ using (var brush = CreateBrush(foreground, glyphRun.Size))
{
var glyphRunImpl = (GlyphRunImpl)glyphRun.GlyphRunImpl;
- _renderTarget.DrawGlyphRun(baselineOrigin.ToSharpDX(), glyphRunImpl.GlyphRun, brush.PlatformBrush, MeasuringMode.Natural);
+ _renderTarget.DrawGlyphRun(glyphRun.BaselineOrigin.ToSharpDX(), glyphRunImpl.GlyphRun,
+ brush.PlatformBrush, MeasuringMode.Natural);
}
}
diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs
index bf41381b52..f3e1c37705 100644
--- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs
+++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs
@@ -369,7 +369,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var glyphRun = shapedRun.GlyphRun;
- var width = glyphRun.Bounds.Width;
+ var width = glyphRun.Size.Width;
var characterHit = glyphRun.GetCharacterHitFromDistance(width, out _);
diff --git a/tests/Avalonia.Visuals.UnitTests/Media/GlyphRunTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/GlyphRunTests.cs
index 219c7ece46..58feb4714a 100644
--- a/tests/Avalonia.Visuals.UnitTests/Media/GlyphRunTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Media/GlyphRunTests.cs
@@ -119,6 +119,56 @@ namespace Avalonia.Visuals.UnitTests.Media
}
}
+ [InlineData(new double[] { 10, 10, 10 }, new ushort[] { 0, 0, 0 }, 0)]
+ [InlineData(new double[] { 10, 10, 10 }, new ushort[] { 0, 0, 0 }, 1)]
+ [InlineData(new double[] { 10, 10, 10, 10 }, new ushort[] { 0, 0, 0, 3 }, 0)]
+ [InlineData(new double[] { 10, 10, 10, 10 }, new ushort[] { 3, 0, 0, 0 }, 1)]
+ [InlineData(new double[] { 10, 10, 10, 10, 10 }, new ushort[] { 0, 1, 1, 1, 4 }, 0)]
+ [InlineData(new double[] { 10, 10, 10, 10, 10 }, new ushort[] { 4, 1, 1, 1, 0 }, 1)]
+ [Theory]
+ public void Should_Find_Glyph_Index(double[] advances, ushort[] clusters, int bidiLevel)
+ {
+ using (var glyphRun = CreateGlyphRun(advances, clusters, bidiLevel))
+ {
+ if (glyphRun.IsLeftToRight)
+ {
+ for (var i = 0; i < clusters.Length; i++)
+ {
+ var cluster = clusters[i];
+
+ var found = glyphRun.FindGlyphIndex(cluster);
+
+ var expected = i;
+
+ while (expected - 1 >= 0 && clusters[expected - 1] == cluster)
+ {
+ expected--;
+ }
+
+ Assert.Equal(expected, found);
+ }
+ }
+ else
+ {
+ for (var i = clusters.Length - 1; i > 0; i--)
+ {
+ var cluster = clusters[i];
+
+ var found = glyphRun.FindGlyphIndex(cluster);
+
+ var expected = i;
+
+ while (expected + 1 < clusters.Length && clusters[expected + 1] == cluster)
+ {
+ expected++;
+ }
+
+ Assert.Equal(expected, found);
+ }
+ }
+ }
+ }
+
private static GlyphRun CreateGlyphRun(double[] glyphAdvances, ushort[] glyphClusters, int bidiLevel = 0)
{
var count = glyphAdvances.Length;