Browse Source

Merge branch 'master' into fixes/textbox-caret-index-lost-on-focus-lost

pull/4526/head
danwalmsley 6 years ago
committed by GitHub
parent
commit
1724ea98ef
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/Avalonia.Visuals/Media/GlyphRun.cs
  2. 16
      src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
  3. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs
  4. 6
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
  5. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  6. 60
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

4
src/Avalonia.Visuals/Media/GlyphRun.cs

@ -555,7 +555,7 @@ namespace Avalonia.Media
}
}
return new Rect(0, 0, width, height);
return new Rect(0, GlyphTypeface.Ascent * Scale, width, height);
}
private void Set<T>(ref T field, T value)
@ -595,8 +595,6 @@ namespace Avalonia.Media
_glyphRunImpl = platformRenderInterface.CreateGlyphRun(this, out var width);
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
_bounds = new Rect(0, 0, width, height);
}
void IDisposable.Dispose()

16
src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs

@ -181,6 +181,17 @@ namespace Avalonia.Media.TextFormatting
return nextCharacterHit;
}
if (characterHit.FirstCharacterIndex + characterHit.TrailingLength <= TextRange.Start + TextRange.Length)
{
return characterHit; // Can't move, we're after the last character
}
var runIndex = GetRunIndexAtCodepointIndex(TextRange.End);
var textRun = _textRuns[runIndex];
characterHit = textRun.GlyphRun.GetNextCaretCharacterHit(characterHit);
return characterHit; // Can't move, we're after the last character
}
@ -192,6 +203,11 @@ namespace Avalonia.Media.TextFormatting
return previousCharacterHit;
}
if (characterHit.FirstCharacterIndex < TextRange.Start)
{
characterHit = new CharacterHit(TextRange.Start);
}
return characterHit; // Can't move, we're before the first character
}

2
src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs

@ -25,7 +25,7 @@ namespace Avalonia.Rendering.SceneGraph
GlyphRun glyphRun,
Point baselineOrigin,
IDictionary<IVisual, Scene> childScenes = null)
: base(glyphRun.Bounds, transform)
: base(glyphRun.Bounds.Translate(baselineOrigin), transform)
{
Transform = transform;
Foreground = foreground?.ToImmutable();

6
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs

@ -24,7 +24,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
AvaloniaXamlIlDataContextTypeMetadataNode inferredDataContextTypeNode = null;
AvaloniaXamlIlDataContextTypeMetadataNode directiveDataContextTypeNode = null;
bool isDataTemplate = on.Type.GetClrType().Equals(context.GetAvaloniaTypes().DataTemplate);
for (int i = 0; i < on.Children.Count; ++i)
{
@ -57,7 +56,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
inferredDataContextTypeNode = ParseDataContext(context, on, obj);
}
else if(isDataTemplate
else if(context.GetAvaloniaTypes().DataTemplate.IsAssignableFrom(on.Type.GetClrType())
&& pa.Property.Name == "DataType"
&& pa.Values[0] is XamlTypeExtensionNode dataTypeNode)
{
@ -70,7 +69,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
// do more specialized inference
if (directiveDataContextTypeNode is null)
{
if (isDataTemplate && inferredDataContextTypeNode is null)
if (context.GetAvaloniaTypes().IDataTemplate.IsAssignableFrom(on.Type.GetClrType())
&& inferredDataContextTypeNode is null)
{
// Infer data type from collection binding on a control that displays items.
var parentObject = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault();

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -41,6 +41,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType ResolveByNameExtension { get; }
public IXamlType DataTemplate { get; }
public IXamlType IDataTemplate { get; }
public IXamlType IItemsPresenterHost { get; }
public IXamlType ItemsRepeater { get; }
public IXamlType ReflectionBindingExtension { get; }
@ -98,6 +99,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
CompiledBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindingExtension");
ResolveByNameExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ResolveByNameExtension");
DataTemplate = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.Templates.DataTemplate");
IDataTemplate = cfg.TypeSystem.GetType("Avalonia.Controls.Templates.IDataTemplate");
IItemsPresenterHost = cfg.TypeSystem.GetType("Avalonia.Controls.Presenters.IItemsPresenterHost");
ItemsRepeater = cfg.TypeSystem.GetType("Avalonia.Controls.ItemsRepeater");
ReflectionBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension");

60
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
@ -10,6 +9,65 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{
public class TextLineTests
{
private static readonly string s_multiLineText = "012345678\r\r0123456789";
[Fact]
public void Should_Get_First_CharacterHit()
{
using (Start())
{
var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var textSource = new SingleBufferTextSource(s_multiLineText, defaultProperties);
var formatter = new TextFormatterImpl();
var currentIndex = 0;
while (currentIndex < s_multiLineText.Length)
{
var textLine =
formatter.FormatLine(textSource, currentIndex, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
var firstCharacterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(int.MinValue));
Assert.Equal(textLine.TextRange.Start, firstCharacterHit.FirstCharacterIndex);
currentIndex += textLine.TextRange.Length;
}
}
}
[Fact]
public void Should_Get_Last_CharacterHit()
{
using (Start())
{
var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var textSource = new SingleBufferTextSource(s_multiLineText, defaultProperties);
var formatter = new TextFormatterImpl();
var currentIndex = 0;
while (currentIndex < s_multiLineText.Length)
{
var textLine =
formatter.FormatLine(textSource, currentIndex, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
var lastCharacterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(int.MaxValue));
Assert.Equal(textLine.TextRange.Start + textLine.TextRange.Length,
lastCharacterHit.FirstCharacterIndex + lastCharacterHit.TrailingLength);
currentIndex += textLine.TextRange.Length;
}
}
}
[InlineData("𐐷𐐷𐐷𐐷𐐷")]
[InlineData("𐐷1234")]
[Theory]

Loading…
Cancel
Save